public void checkServerTrusted(X509Certificate[] chain, String authType)
      throws CertificateException {
    calledCheckServerTrusted = true;
    if (!authType.equals("RSA") && !authType.equals("DHE_RSA"))
      throw new CertificateException("Only RSA and DHE_RSA supported, not " + authType);

    if (chain.length != 3) throw new CertificateException("Need three certificates");

    X509Certificate cert0 = chain[0];
    X509Certificate cert1 = chain[1];
    X509Certificate cert2 = chain[2];
    int failedCert = 0;
    try {
      // NOTE: cert0 is a self-signed key used only for SSL
      failedCert = 0;
      cert0.verify(cert0.getPublicKey());
      // NOTE: cert1 is the SSL key signed by the server's Martus key
      failedCert = 1;
      cert1.verify(cert2.getPublicKey());
      // NOTE: cert2 is a self-signed key of and by the server's Martus key
      failedCert = 2;
      cert2.verify(cert2.getPublicKey());
      failedCert = -1;

      PublicKey tryPublicKey = expectedPublicKey;
      if (tryPublicKey == null) {
        if (expectedPublicCode == null) throw new CertificateException("No key or code is trusted");
        String certPublicKeyString = SimpleX509TrustManager.getKeyString(cert2.getPublicKey());
        String certPublicCode = MartusCrypto.computePublicCode(certPublicKeyString);
        if (expectedPublicCode.equals(certPublicCode)) {
          tryPublicKey = cert2.getPublicKey();
        }
      }

      if (tryPublicKey == null) throw new CertificateException("Key is not trusted");
      cert1.verify(tryPublicKey);
      String keyString = SimpleX509TrustManager.getKeyString(tryPublicKey);
      setExpectedPublicKey(keyString);
    } catch (SignatureException e) {
      MartusLogger.logException(e);
      MartusLogger.log("Failed cert: " + failedCert);
      String key0 = SimpleX509TrustManager.getKeyString(cert0.getPublicKey());
      String key1 = SimpleX509TrustManager.getKeyString(cert1.getPublicKey());
      String key2 = SimpleX509TrustManager.getKeyString(cert2.getPublicKey());
      MartusLogger.log("Cert0 public: " + key0);
      if (!key0.equals(key1)) MartusLogger.log("Cert1 public: " + key1);
      MartusLogger.log("Cert2 public: " + key2);
      MartusLogger.log("Cert2 public code: " + MartusCrypto.formatAccountIdForLog(key2));
      String expectedKeyString = SimpleX509TrustManager.getKeyString(expectedPublicKey);
      MartusLogger.log(
          "Expected public code: " + MartusCrypto.formatAccountIdForLog(expectedKeyString));

      throw new CertificateException(e.toString());
    } catch (Exception e) {
      // Tests will cause this to fire
      MartusLogger.logException(e);
      throw new CertificateException(e.toString());
    }
  }
 void verifyPublicInfo(String publicKeyString, String sig) {
   try {
     if (!publicCode.equals(MartusCrypto.computePublicCode(publicKeyString))) {
       System.out.println("Error Retrieved Public Key doesn't match public code!");
       System.exit(3);
     }
     MartusCrypto security = new MartusSecurity();
     byte[] publicKeyBytes = StreamableBase64.decode(publicKeyString);
     ByteArrayInputStream in = new ByteArrayInputStream(publicKeyBytes);
     if (!security.isValidSignatureOfStream(publicKeyString, in, StreamableBase64.decode(sig))) {
       System.out.println("Error Retrieved Public Key bad signature!");
       System.exit(3);
     }
   } catch (Exception e) {
     e.printStackTrace();
     System.out.println("Error Retrieved Public Key invalid!");
     System.exit(3);
   }
 }
  protected BulletinMirroringInformation getNextItemToRetrieve() {
    try {
      while (itemsToRetrieve.size() == 0) {
        String nextAccountId = getNextAccountToRetrieve();
        if (nextAccountId == null) return null;

        int totalIdsReturned = 0;
        String mirroringCallUsed = "listAvailableIdsForMirroring";
        NetworkResponse response =
            gateway.listAvailableIdsForMirroring(getSecurity(), nextAccountId);
        if (networkResponseOk(response)) {
          Vector listwithBulletinMirroringInfo = response.getResultVector();
          totalIdsReturned = listwithBulletinMirroringInfo.size();
          itemsToRetrieve =
              listOnlyPacketsThatWeWantUsingBulletinMirroringInformation(
                  nextAccountId, listwithBulletinMirroringInfo);
        } else {
          mirroringCallUsed = "OLD MIRRORING CALL(listBulletinsForMirroring)";
          response = gateway.listBulletinsForMirroring(getSecurity(), nextAccountId);
          if (networkResponseOk(response)) {
            Vector listWithLocalIds = response.getResultVector();
            totalIdsReturned = listWithLocalIds.size();
            itemsToRetrieve =
                listOnlyPacketsThatWeWantUsingLocalIds(nextAccountId, listWithLocalIds);
          }
        }

        if (networkResponseOk(response)) {
          String publicCode = MartusCrypto.getFormattedPublicCode(nextAccountId);
          if (totalIdsReturned > 0 || itemsToRetrieve.size() > 0)
            logInfo(
                mirroringCallUsed
                    + ": "
                    + publicCode
                    + " -> "
                    + totalIdsReturned
                    + " -> "
                    + itemsToRetrieve.size());
        } else {
          logWarning(
              "MirroringRetriever.getNextItemToRetrieve: Returned NetworkResponse: "
                  + response.getResultCode());
        }
      }

      if (itemsToRetrieve.size() == 0) return null;

      return (BulletinMirroringInformation) itemsToRetrieve.remove(0);

    } catch (Exception e) {
      logError("MirroringRetriever.getNextUidToRetrieve: ", e);
      MartusLogger.logException(e);
      return null;
    }
  }
  boolean confirmPublicCode(String rawPublicCode, String baseTag, String errorBaseTag) {
    String userEnteredPublicCode = "";
    while (true) {
      userEnteredPublicCode = mainWindow.getStringInput(baseTag, "", "", userEnteredPublicCode);
      if (userEnteredPublicCode == null) return false; // user hit cancel
      String normalizedPublicCode = MartusCrypto.removeNonDigits(userEnteredPublicCode);

      if (rawPublicCode.equals(normalizedPublicCode)) return true;

      mainWindow.notifyDlg(errorBaseTag);
    }
  }
  void processArgs(String[] args) {
    port = MirroringInterface.MARTUS_PORT_FOR_MIRRORING;

    for (int i = 0; i < args.length; i++) {
      String value = args[i].substring(args[i].indexOf("=") + 1);

      if (args[i].startsWith("--ip")) ip = value;

      if (args[i].startsWith("--port") && value != null) port = new Integer(value).intValue();

      if (args[i].startsWith("--public-code")) publicCode = MartusCrypto.removeNonDigits(value);

      if (args[i].startsWith("--output-file")) outputFileName = value;
    }

    if (ip == null || publicCode == null || outputFileName == null) {
      System.err.println(
          "Incorrect arguments: RetrievePublicKey --ip=1.2.3.4 [--port=5] --public-code=6.7.8.1.2 --output-file=pubkey.txt\n");
      System.exit(2);
    }
  }
  public void processNextBulletin() {
    if (isSleeping()) return;

    BulletinMirroringInformation item = getNextItemToRetrieve();
    if (item == null) {
      scheduleSleep();
      return;
    }

    // TODO handle delete requests when we are propagating deletes.

    try {
      UniversalId uid = item.getUid();
      String publicCode = MartusCrypto.getFormattedPublicCode(uid.getAccountId());
      logNotice("Getting bulletin: " + publicCode + "->" + uid.getLocalId());
      String bur = retrieveBurFromMirror(uid);
      File zip = File.createTempFile("$$$MirroringRetriever", null);
      try {
        zip.deleteOnExit();
        retrieveOneBulletin(zip, uid);
        long zipSize = zip.length();
        long mTime = item.getmTime();
        BulletinHeaderPacket bhp = store.saveZipFileToDatabase(zip, uid.getAccountId(), mTime);
        store.writeBur(bhp, bur);
        store.deleteDel(bhp.getUniversalId());
        logNotice(
            "Stored bulletin:  " + publicCode + "->" + uid.getLocalId() + " Size: " + zipSize);
      } finally {
        zip.delete();
      }
    } catch (ServerErrorException e) {
      logError("Supplier server:", e);
    } catch (ServerNotAvailableException e) {
      // TODO: Notify once per hour that something is wrong
    } catch (Exception e) {
      logError(e);
    }
  }
 private static void updateKeypairPassphrase(
     File keyPairFile, char[] newPassphrase, MartusCrypto security)
     throws FileNotFoundException, Exception {
   FileOutputStream out = new FileOutputStream(keyPairFile);
   security.writeKeyPair(out, newPassphrase);
 }