public synchronized void verify(PublicKey key, Provider sigProvider) throws CRLException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { if (signedCRL == null) { throw new CRLException("Uninitialized CRL"); } Signature sigVerf = null; if (sigProvider == null) { sigVerf = Signature.getInstance(sigAlgId.getName()); } else { sigVerf = Signature.getInstance(sigAlgId.getName(), sigProvider); } sigVerf.initVerify(key); if (tbsCertList == null) { throw new CRLException("Uninitialized CRL"); } sigVerf.update(tbsCertList, 0, tbsCertList.length); if (!sigVerf.verify(signature)) { throw new SignatureException("Signature does not match."); } verifiedPublicKey = key; }
public String getSigAlgOID() { if (sigAlgId == null) { return null; } ObjectIdentifier oid = sigAlgId.getOID(); return oid.toString(); }
public byte[] getSigAlgParams() { if (sigAlgId == null) { return null; } try { return sigAlgId.getEncodedParams(); } catch (IOException e) { return null; } }
public void sign(PrivateKey key, String algorithm, String provider) throws CRLException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { try { if (readOnly) { throw new CRLException("cannot over-write existing CRL"); } Signature sigEngine = null; if ((provider == null) || (provider.length() == 0)) { sigEngine = Signature.getInstance(algorithm); } else { sigEngine = Signature.getInstance(algorithm, provider); } sigEngine.initSign(key); sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm()); infoSigAlgId = sigAlgId; DerOutputStream out = new DerOutputStream(); DerOutputStream tmp = new DerOutputStream(); encodeInfo(tmp); sigAlgId.encode(tmp); sigEngine.update(tbsCertList, 0, tbsCertList.length); signature = sigEngine.sign(); tmp.putBitString(signature); out.write(DerValue.tag_Sequence, tmp); signedCRL = out.toByteArray(); readOnly = true; } catch (IOException e) { throw new CRLException("Error while encoding data: " + e.getMessage()); } }
public void encodeInfo(OutputStream out) throws CRLException { try { DerOutputStream tmp = new DerOutputStream(); DerOutputStream rCerts = new DerOutputStream(); DerOutputStream seq = new DerOutputStream(); if (version != 0) { tmp.putInteger(version); } infoSigAlgId.encode(tmp); if ((version == 0) && (issuer.toString() == null)) { throw new CRLException("Null Issuer DN not allowed in v1 CRL"); } issuer.encode(tmp); if (thisUpdate.getTime() < YR_2050) { tmp.putUTCTime(thisUpdate); } else { tmp.putGeneralizedTime(thisUpdate); } if (nextUpdate != null) { if (nextUpdate.getTime() < YR_2050) { tmp.putUTCTime(nextUpdate); } else { tmp.putGeneralizedTime(nextUpdate); } } if (!revokedList.isEmpty()) { for (X509CRLEntry entry : revokedList) { ((X509CRLEntryImpl) entry).encode(rCerts); } tmp.write(DerValue.tag_Sequence, rCerts); } if (extensions != null) { extensions.encode(tmp, isExplicit); } seq.write(DerValue.tag_Sequence, tmp); tbsCertList = seq.toByteArray(); out.write(tbsCertList); } catch (IOException e) { throw new CRLException("Encoding error: " + e.getMessage()); } }
/* * Verify the signature of the OCSP response. * The responder's cert is implicitly trusted. */ private boolean verifySignature(X509Certificate cert) throws CertPathValidatorException { try { Signature respSignature = Signature.getInstance(sigAlgId.getName()); respSignature.initVerify(cert.getPublicKey()); respSignature.update(tbsResponseData); if (respSignature.verify(signature)) { if (debug != null) { debug.println("Verified signature of OCSP Response"); } return true; } else { if (debug != null) { debug.println("Error verifying signature of OCSP Response"); } return false; } } catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException e) { throw new CertPathValidatorException(e); } }
/** * Returns the key associated with the given alias, using the given password to recover it. * * @param alias the alias name * @param password the password for recovering the key. This password is used internally as the * key is exported in a PKCS12 format. * @return the requested key, or null if the given alias does not exist or does not identify a * <i>key entry</i>. * @exception NoSuchAlgorithmException if the algorithm for recovering the key cannot be found * @exception UnrecoverableKeyException if the key cannot be recovered (e.g., the given password * is wrong). */ public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException { permissionCheck(); // An empty password is rejected by MacOS API, no private key data // is exported. If no password is passed (as is the case when // this implementation is used as browser keystore in various // deployment scenarios like Webstart, JFX and applets), create // a dummy password so MacOS API is happy. if (password == null || password.length == 0) { // Must not be a char array with only a 0, as this is an empty // string. if (random == null) { random = new SecureRandom(); } password = Long.toString(random.nextLong()).toCharArray(); } Object entry = entries.get(alias.toLowerCase()); if (entry == null || !(entry instanceof KeyEntry)) { return null; } // This call gives us a PKCS12 bag, with the key inside it. byte[] exportedKeyInfo = _getEncodedKeyData(((KeyEntry) entry).keyRef, password); if (exportedKeyInfo == null) { return null; } PrivateKey returnValue = null; try { byte[] pkcs8KeyData = fetchPrivateKeyFromBag(exportedKeyInfo); byte[] encryptedKey; AlgorithmParameters algParams; ObjectIdentifier algOid; try { // get the encrypted private key EncryptedPrivateKeyInfo encrInfo = new EncryptedPrivateKeyInfo(pkcs8KeyData); encryptedKey = encrInfo.getEncryptedData(); // parse Algorithm parameters DerValue val = new DerValue(encrInfo.getAlgorithm().encode()); DerInputStream in = val.toDerInputStream(); algOid = in.getOID(); algParams = parseAlgParameters(in); } catch (IOException ioe) { UnrecoverableKeyException uke = new UnrecoverableKeyException( "Private key not stored as " + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe); uke.initCause(ioe); throw uke; } // Use JCE to decrypt the data using the supplied password. SecretKey skey = getPBEKey(password); Cipher cipher = Cipher.getInstance(algOid.toString()); cipher.init(Cipher.DECRYPT_MODE, skey, algParams); byte[] decryptedPrivateKey = cipher.doFinal(encryptedKey); PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(decryptedPrivateKey); // Parse the key algorithm and then use a JCA key factory to create the private key. DerValue val = new DerValue(decryptedPrivateKey); DerInputStream in = val.toDerInputStream(); // Ignore this -- version should be 0. int i = in.getInteger(); // Get the Algorithm ID next DerValue[] value = in.getSequence(2); AlgorithmId algId = new AlgorithmId(value[0].getOID()); String algName = algId.getName(); // Get a key factory for this algorithm. It's likely to be 'RSA'. KeyFactory kfac = KeyFactory.getInstance(algName); returnValue = kfac.generatePrivate(kspec); } catch (Exception e) { UnrecoverableKeyException uke = new UnrecoverableKeyException("Get Key failed: " + e.getMessage()); uke.initCause(e); throw uke; } return returnValue; }
/* * Create an OCSP response from its ASN.1 DER encoding. */ OCSPResponse(byte[] bytes) throws IOException { if (dump) { HexDumpEncoder hexEnc = new HexDumpEncoder(); System.out.println("OCSPResponse bytes are..."); System.out.println(hexEnc.encode(bytes)); } DerValue der = new DerValue(bytes); if (der.tag != DerValue.tag_Sequence) { throw new IOException("Bad encoding in OCSP response: " + "expected ASN.1 SEQUENCE tag."); } DerInputStream derIn = der.getData(); // responseStatus int status = derIn.getEnumerated(); if (status >= 0 && status < rsvalues.length) { responseStatus = rsvalues[status]; } else { // unspecified responseStatus throw new IOException("Unknown OCSPResponse status: " + status); } if (debug != null) { debug.println("OCSP response status: " + responseStatus); } if (responseStatus != ResponseStatus.SUCCESSFUL) { // no need to continue, responseBytes are not set. singleResponseMap = Collections.emptyMap(); certs = Collections.<X509CertImpl>emptyList(); sigAlgId = null; signature = null; tbsResponseData = null; responseNonce = null; return; } // responseBytes der = derIn.getDerValue(); if (!der.isContextSpecific((byte) 0)) { throw new IOException( "Bad encoding in responseBytes element " + "of OCSP response: expected ASN.1 context specific tag 0."); } DerValue tmp = der.data.getDerValue(); if (tmp.tag != DerValue.tag_Sequence) { throw new IOException( "Bad encoding in responseBytes element " + "of OCSP response: expected ASN.1 SEQUENCE tag."); } // responseType derIn = tmp.data; ObjectIdentifier responseType = derIn.getOID(); if (responseType.equals((Object) OCSP_BASIC_RESPONSE_OID)) { if (debug != null) { debug.println("OCSP response type: basic"); } } else { if (debug != null) { debug.println("OCSP response type: " + responseType); } throw new IOException("Unsupported OCSP response type: " + responseType); } // BasicOCSPResponse DerInputStream basicOCSPResponse = new DerInputStream(derIn.getOctetString()); DerValue[] seqTmp = basicOCSPResponse.getSequence(2); if (seqTmp.length < 3) { throw new IOException("Unexpected BasicOCSPResponse value"); } DerValue responseData = seqTmp[0]; // Need the DER encoded ResponseData to verify the signature later tbsResponseData = seqTmp[0].toByteArray(); // tbsResponseData if (responseData.tag != DerValue.tag_Sequence) { throw new IOException( "Bad encoding in tbsResponseData " + "element of OCSP response: expected ASN.1 SEQUENCE tag."); } DerInputStream seqDerIn = responseData.data; DerValue seq = seqDerIn.getDerValue(); // version if (seq.isContextSpecific((byte) 0)) { // seq[0] is version if (seq.isConstructed() && seq.isContextSpecific()) { // System.out.println ("version is available"); seq = seq.data.getDerValue(); int version = seq.getInteger(); if (seq.data.available() != 0) { throw new IOException( "Bad encoding in version " + " element of OCSP response: bad format"); } seq = seqDerIn.getDerValue(); } } // responderID short tag = (byte) (seq.tag & 0x1f); if (tag == NAME_TAG) { if (debug != null) { X500Principal responderName = new X500Principal(seq.getData().toByteArray()); debug.println("OCSP Responder name: " + responderName); } } else if (tag == KEY_TAG) { if (debug != null) { byte[] responderKey = seq.getData().getOctetString(); debug.println("OCSP Responder key: " + Debug.toString(responderKey)); } } else { throw new IOException( "Bad encoding in responderID element of " + "OCSP response: expected ASN.1 context specific tag 0 or 1"); } // producedAt seq = seqDerIn.getDerValue(); if (debug != null) { Date producedAtDate = seq.getGeneralizedTime(); debug.println("OCSP response produced at: " + producedAtDate); } // responses DerValue[] singleResponseDer = seqDerIn.getSequence(1); singleResponseMap = new HashMap<>(singleResponseDer.length); if (debug != null) { debug.println("OCSP number of SingleResponses: " + singleResponseDer.length); } for (int i = 0; i < singleResponseDer.length; i++) { SingleResponse singleResponse = new SingleResponse(singleResponseDer[i]); singleResponseMap.put(singleResponse.getCertId(), singleResponse); } // responseExtensions byte[] nonce = null; if (seqDerIn.available() > 0) { seq = seqDerIn.getDerValue(); if (seq.isContextSpecific((byte) 1)) { DerValue[] responseExtDer = seq.data.getSequence(3); for (int i = 0; i < responseExtDer.length; i++) { Extension ext = new Extension(responseExtDer[i]); if (debug != null) { debug.println("OCSP extension: " + ext); } // Only the NONCE extension is recognized if (ext.getExtensionId().equals((Object) OCSP.NONCE_EXTENSION_OID)) { nonce = ext.getExtensionValue(); } else if (ext.isCritical()) { throw new IOException("Unsupported OCSP critical extension: " + ext.getExtensionId()); } } } } responseNonce = nonce; // signatureAlgorithmId sigAlgId = AlgorithmId.parse(seqTmp[1]); // signature signature = seqTmp[2].getBitString(); // if seq[3] is available , then it is a sequence of certificates if (seqTmp.length > 3) { // certs are available DerValue seqCert = seqTmp[3]; if (!seqCert.isContextSpecific((byte) 0)) { throw new IOException( "Bad encoding in certs element of " + "OCSP response: expected ASN.1 context specific tag 0."); } DerValue[] derCerts = seqCert.getData().getSequence(3); certs = new ArrayList<X509CertImpl>(derCerts.length); try { for (int i = 0; i < derCerts.length; i++) { certs.add(new X509CertImpl(derCerts[i].toByteArray())); } } catch (CertificateException ce) { throw new IOException("Bad encoding in X509 Certificate", ce); } } else { certs = Collections.<X509CertImpl>emptyList(); } }
private void parse(DerValue val) throws CRLException, IOException { if (readOnly) { throw new CRLException("cannot over-write existing CRL"); } if (val.getData() == null || val.tag != DerValue.tag_Sequence) { throw new CRLException("Invalid DER-encoded CRL data"); } signedCRL = val.toByteArray(); DerValue seq[] = new DerValue[3]; seq[0] = val.data.getDerValue(); seq[1] = val.data.getDerValue(); seq[2] = val.data.getDerValue(); if (val.data.available() != 0) { throw new CRLException("signed overrun, bytes = " + val.data.available()); } if (seq[0].tag != DerValue.tag_Sequence) { throw new CRLException("signed CRL fields invalid"); } sigAlgId = AlgorithmId.parse(seq[1]); signature = seq[2].getBitString(); if (seq[1].data.available() != 0) { throw new CRLException("AlgorithmId field overrun"); } if (seq[2].data.available() != 0) { throw new CRLException("Signature field overrun"); } tbsCertList = seq[0].toByteArray(); DerInputStream derStrm = seq[0].data; DerValue tmp; byte nextByte; version = 0; nextByte = (byte) derStrm.peekByte(); if (nextByte == DerValue.tag_Integer) { version = derStrm.getInteger(); if (version != 1) { throw new CRLException("Invalid version"); } } tmp = derStrm.getDerValue(); AlgorithmId tmpId = AlgorithmId.parse(tmp); if (!tmpId.equals(sigAlgId)) { throw new CRLException("Signature algorithm mismatch"); } infoSigAlgId = tmpId; issuer = new X500Name(derStrm); if (issuer.isEmpty()) { throw new CRLException("Empty issuer DN not allowed in X509CRLs"); } nextByte = (byte) derStrm.peekByte(); if (nextByte == DerValue.tag_UtcTime) { thisUpdate = derStrm.getUTCTime(); } else if (nextByte == DerValue.tag_GeneralizedTime) { thisUpdate = derStrm.getGeneralizedTime(); } else { throw new CRLException("Invalid encoding for thisUpdate" + " (tag=" + nextByte + ")"); } if (derStrm.available() == 0) { return; } nextByte = (byte) derStrm.peekByte(); if (nextByte == DerValue.tag_UtcTime) { nextUpdate = derStrm.getUTCTime(); } else if (nextByte == DerValue.tag_GeneralizedTime) { nextUpdate = derStrm.getGeneralizedTime(); } if (derStrm.available() == 0) { return; } nextByte = (byte) derStrm.peekByte(); if ((nextByte == DerValue.tag_SequenceOf) && (!((nextByte & 0x0c0) == 0x080))) { DerValue[] badCerts = derStrm.getSequence(4); X500Principal crlIssuer = getIssuerX500Principal(); X500Principal badCertIssuer = crlIssuer; for (int i = 0; i < badCerts.length; i++) { X509CRLEntryImpl entry = new X509CRLEntryImpl(badCerts[i]); badCertIssuer = getCertIssuer(entry, badCertIssuer); entry.setCertificateIssuer(crlIssuer, badCertIssuer); X509IssuerSerial issuerSerial = new X509IssuerSerial(badCertIssuer, entry.getSerialNumber()); revokedMap.put(issuerSerial, entry); revokedList.add(entry); } } if (derStrm.available() == 0) { return; } tmp = derStrm.getDerValue(); if (tmp.isConstructed() && tmp.isContextSpecific((byte) 0)) { extensions = new CRLExtensions(tmp.data); } readOnly = true; }
public String getSigAlgName() { if (sigAlgId == null) { return null; } return sigAlgId.getName(); }
public String toString() { StringBuffer sb = new StringBuffer(); sb.append("X.509 CRL v" + (version + 1) + "\n"); if (sigAlgId != null) { sb.append( "Signature Algorithm: " + sigAlgId.toString() + ", OID=" + (sigAlgId.getOID()).toString() + "\n"); } if (issuer != null) { sb.append("Issuer: " + issuer.toString() + "\n"); } if (thisUpdate != null) { sb.append("\nThis Update: " + thisUpdate.toString() + "\n"); } if (nextUpdate != null) { sb.append("Next Update: " + nextUpdate.toString() + "\n"); } if (revokedList.isEmpty()) { sb.append("\nNO certificates have been revoked\n"); } else { sb.append("\nRevoked Certificates: " + revokedList.size()); int i = 1; for (X509CRLEntry entry : revokedList) { sb.append("\n[" + i++ + "] " + entry.toString()); } } if (extensions != null) { Collection<Extension> allExts = extensions.getAllExtensions(); Object[] objs = allExts.toArray(); sb.append("\nCRL Extensions: " + objs.length); for (int i = 0; i < objs.length; i++) { sb.append("\n[" + (i + 1) + "]: "); Extension ext = (Extension) objs[i]; try { if (OIDMap.getClass(ext.getExtensionId()) == null) { sb.append(ext.toString()); byte[] extValue = ext.getExtensionValue(); if (extValue != null) { DerOutputStream out = new DerOutputStream(); out.putOctetString(extValue); extValue = out.toByteArray(); HexDumpEncoder enc = new HexDumpEncoder(); sb.append( "Extension unknown: " + "DER encoded OCTET string =\n" + enc.encodeBuffer(extValue) + "\n"); } } else { sb.append(ext.toString()); } } catch (Exception e) { sb.append(", Error parsing this extension"); } } } if (signature != null) { HexDumpEncoder encoder = new HexDumpEncoder(); sb.append("\nSignature:\n" + encoder.encodeBuffer(signature) + "\n"); } else { sb.append("NOT signed yet\n"); } return sb.toString(); }