Example #1
0
  /**
   * Create KeyStore and add a self-signed X.509 Certificate
   *
   * @param dname the X.509 Distinguished Name, eg "CN=www.google.co.uk, O=\"Google Inc\",
   *     L=\"Mountain View\", S=California, C=US"
   * @param keyAlgorithmName the key algorithm, eg "RSA"
   */
  private static KeyStore generateCertificate(
      String alias,
      char[] keyStorePassword,
      KeyAlgorithmName keyAlgorithmName,
      String dname,
      String... sanDomains)
      throws GeneralSecurityException, IOException {

    CertAndKeyGen certAndKeyGen =
        new CertAndKeyGen(
            keyAlgorithmName.name(), keyAlgorithmName.signatureAlgorithmName, "SunCertificates");
    certAndKeyGen.generate(keyAlgorithmName.keySize);

    PrivateKey privateKey = certAndKeyGen.getPrivateKey();
    X509CertInfo info = new X509CertInfo();
    Date from = new Date();
    Date to = new Date(from.getTime() + TimeUnit.DAYS.toMillis(360));
    CertificateValidity interval = new CertificateValidity(from, to);
    BigInteger sn = new BigInteger(64, new SecureRandom());
    X500Name owner = new X500Name(dname);

    info.set(X509CertInfo.VALIDITY, interval);
    info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
    info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
    info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
    info.set(X509CertInfo.KEY, new CertificateX509Key(certAndKeyGen.getPublicKey()));
    info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
    info.set(
        X509CertInfo.ALGORITHM_ID,
        new CertificateAlgorithmId(new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid)));

    // add subject alternative names
    GeneralNames generalNames = new GeneralNames();
    for (String sanDomain : sanDomains) {
      generalNames.add(new GeneralName(new DNSName(sanDomain)));
    }
    if (generalNames.size() > 0) {
      CertificateExtensions certificateExtensions =
          (CertificateExtensions) info.get(X509CertInfo.EXTENSIONS);
      if (certificateExtensions == null) certificateExtensions = new CertificateExtensions();
      certificateExtensions.set(
          SubjectAlternativeNameExtension.NAME, new SubjectAlternativeNameExtension(generalNames));
      info.set(X509CertInfo.EXTENSIONS, certificateExtensions);
    }

    // Sign the certificate to identify the algorithm that's used.
    X509CertImpl x509Certificate = new X509CertImpl(info);
    x509Certificate.sign(privateKey, keyAlgorithmName.signatureAlgorithmName);

    // update the algorithm, and resign.
    info.set(
        CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM,
        x509Certificate.get(X509CertImpl.SIG_ALG));
    x509Certificate = new X509CertImpl(info);
    x509Certificate.sign(privateKey, keyAlgorithmName.signatureAlgorithmName);

    // add to new key store
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null, keyStorePassword);
    keyStore.setKeyEntry(
        alias, privateKey, keyStorePassword, new X509Certificate[] {x509Certificate});

    return keyStore;
  }
  void verify(List<CertId> certIds, X509Certificate responderCert, Date date, byte[] nonce)
      throws CertPathValidatorException {
    switch (responseStatus) {
      case SUCCESSFUL:
        break;
      case TRY_LATER:
      case INTERNAL_ERROR:
        throw new CertPathValidatorException(
            "OCSP response error: " + responseStatus,
            null,
            null,
            -1,
            BasicReason.UNDETERMINED_REVOCATION_STATUS);
      case UNAUTHORIZED:
      default:
        throw new CertPathValidatorException("OCSP response error: " + responseStatus);
    }

    // Check that the response includes a response for all of the
    // certs that were supplied in the request
    for (CertId certId : certIds) {
      SingleResponse sr = getSingleResponse(certId);
      if (sr == null) {
        if (debug != null) {
          debug.println("No response found for CertId: " + certId);
        }
        throw new CertPathValidatorException(
            "OCSP response does not include a response for a "
                + "certificate supplied in the OCSP request");
      }
      if (debug != null) {
        debug.println(
            "Status of certificate (with serial number "
                + certId.getSerialNumber()
                + ") is: "
                + sr.getCertStatus());
      }
    }

    // Check whether the cert returned by the responder is trusted
    if (!certs.isEmpty()) {
      X509CertImpl cert = certs.get(0);
      // First check if the cert matches the expected responder cert
      if (cert.equals(responderCert)) {
        // cert is trusted, now verify the signed response

        // Next check if the cert was issued by the responder cert
        // which was set locally.
      } else if (cert.getIssuerX500Principal().equals(responderCert.getSubjectX500Principal())) {

        // Check for the OCSPSigning key purpose
        try {
          List<String> keyPurposes = cert.getExtendedKeyUsage();
          if (keyPurposes == null || !keyPurposes.contains(KP_OCSP_SIGNING_OID)) {
            throw new CertPathValidatorException(
                "Responder's certificate not valid for signing " + "OCSP responses");
          }
        } catch (CertificateParsingException cpe) {
          // assume cert is not valid for signing
          throw new CertPathValidatorException(
              "Responder's certificate not valid for signing " + "OCSP responses", cpe);
        }

        // Check algorithm constraints specified in security property
        // "jdk.certpath.disabledAlgorithms".
        AlgorithmChecker algChecker = new AlgorithmChecker(new TrustAnchor(responderCert, null));
        algChecker.init(false);
        algChecker.check(cert, Collections.<String>emptySet());

        // check the validity
        try {
          if (date == null) {
            cert.checkValidity();
          } else {
            cert.checkValidity(date);
          }
        } catch (CertificateException e) {
          throw new CertPathValidatorException(
              "Responder's certificate not within the " + "validity period", e);
        }

        // check for revocation
        //
        // A CA may specify that an OCSP client can trust a
        // responder for the lifetime of the responder's
        // certificate. The CA does so by including the
        // extension id-pkix-ocsp-nocheck.
        //
        Extension noCheck = cert.getExtension(PKIXExtensions.OCSPNoCheck_Id);
        if (noCheck != null) {
          if (debug != null) {
            debug.println(
                "Responder's certificate includes " + "the extension id-pkix-ocsp-nocheck.");
          }
        } else {
          // we should do the revocation checking of the
          // authorized responder in a future update.
        }

        // verify the signature
        try {
          cert.verify(responderCert.getPublicKey());
          responderCert = cert;
          // cert is trusted, now verify the signed response

        } catch (GeneralSecurityException e) {
          responderCert = null;
        }
      } else {
        throw new CertPathValidatorException(
            "Responder's certificate is not authorized to sign " + "OCSP responses");
      }
    }

    // Confirm that the signed response was generated using the public
    // key from the trusted responder cert
    if (responderCert != null) {
      // Check algorithm constraints specified in security property
      // "jdk.certpath.disabledAlgorithms".
      AlgorithmChecker.check(responderCert.getPublicKey(), sigAlgId);

      if (!verifySignature(responderCert)) {
        throw new CertPathValidatorException("Error verifying OCSP Response's signature");
      }
    } else {
      // Need responder's cert in order to verify the signature
      throw new CertPathValidatorException("Unable to verify OCSP Response's signature");
    }

    // Check freshness of OCSPResponse
    if (nonce != null) {
      if (responseNonce != null && !Arrays.equals(nonce, responseNonce)) {
        throw new CertPathValidatorException("Nonces don't match");
      }
    }

    long now = (date == null) ? System.currentTimeMillis() : date.getTime();
    Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW);
    Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW);
    for (SingleResponse sr : singleResponseMap.values()) {
      if (debug != null) {
        String until = "";
        if (sr.nextUpdate != null) {
          until = " until " + sr.nextUpdate;
        }
        debug.println("Response's validity interval is from " + sr.thisUpdate + until);
      }

      // Check that the test date is within the validity interval
      if ((sr.thisUpdate != null && nowPlusSkew.before(sr.thisUpdate))
          || (sr.nextUpdate != null && nowMinusSkew.after(sr.nextUpdate))) {
        throw new CertPathValidatorException(
            "Response is unreliable: its validity " + "interval is out-of-date");
      }
    }
  }