/** * Basic Constructor - set up a calculator based on signerInfoGen with a ESSCertID calculated from * the signer's associated certificate using the sha1DigestCalculator. * * @param sha1DigestCalculator calculator for SHA-1 of certificate. * @param signerInfoGen the generator for the signer we are using. * @param tsaPolicy tasPolicy to send. * @throws IllegalArgumentException if calculator is not SHA-1 or there is no associated * certificate for the signer, * @throws TSPException if the signer certificate cannot be processed. */ public TimeStampTokenGenerator( DigestCalculator sha1DigestCalculator, final SignerInfoGenerator signerInfoGen, ASN1ObjectIdentifier tsaPolicy) throws IllegalArgumentException, TSPException { this.signerInfoGen = signerInfoGen; this.tsaPolicyOID = tsaPolicy; if (!sha1DigestCalculator .getAlgorithmIdentifier() .getAlgorithm() .equals(OIWObjectIdentifiers.idSHA1)) { throw new IllegalArgumentException("Digest calculator must be for SHA-1"); } if (!signerInfoGen.hasAssociatedCertificate()) { throw new IllegalArgumentException("SignerInfoGenerator must have an associated certificate"); } TSPUtil.validateCertificate(signerInfoGen.getAssociatedCertificate()); try { OutputStream dOut = sha1DigestCalculator.getOutputStream(); dOut.write(signerInfoGen.getAssociatedCertificate().getEncoded()); dOut.close(); final ESSCertID essCertid = new ESSCertID(sha1DigestCalculator.getDigest()); this.signerInfoGen = new SignerInfoGenerator( signerInfoGen, new CMSAttributeTableGenerator() { public AttributeTable getAttributes(Map parameters) throws CMSAttributeTableGenerationException { AttributeTable table = signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters); return table.add( PKCSObjectIdentifiers.id_aa_signingCertificate, new SigningCertificate(essCertid)); } }, signerInfoGen.getUnsignedAttributeTableGenerator()); } catch (IOException e) { throw new TSPException("Exception processing certificate.", e); } }
public boolean verify(DigestCalculatorProvider calculatorProvider) throws CMSException { try { ContentInfo content = digestedData.getEncapContentInfo(); DigestCalculator calc = calculatorProvider.get(digestedData.getDigestAlgorithm()); OutputStream dOut = calc.getOutputStream(); dOut.write(((ASN1OctetString) content.getContent()).getOctets()); return Arrays.areEqual(digestedData.getDigest(), calc.getDigest()); } catch (OperatorCreationException e) { throw new CMSException("unable to create digest calculator: " + e.getMessage(), e); } catch (IOException e) { throw new CMSException("unable process content: " + e.getMessage(), e); } }
public boolean isVerified( X509CertificateHolder certHolder, DigestCalculatorProvider digesterProvider) throws CMPException { AlgorithmIdentifier digAlg = digestAlgFinder.find(certHolder.toASN1Structure().getSignatureAlgorithm()); if (digAlg == null) { throw new CMPException("cannot find algorithm for digest from signature"); } DigestCalculator digester; try { digester = digesterProvider.get(digAlg); } catch (OperatorCreationException e) { throw new CMPException("unable to create digester: " + e.getMessage(), e); } CMPUtil.derEncodeToStream(certHolder.toASN1Structure(), digester.getOutputStream()); return Arrays.areEqual(certStatus.getCertHash().getOctets(), digester.getDigest()); }
/** * Basic Constructor - set up a calculator based on signerInfoGen with a ESSCertID calculated from * the signer's associated certificate using the sha1DigestCalculator. If alternate values are * required for id-aa-signingCertificate they should be added to the signerInfoGen object before * it is passed in, otherwise a standard digest based value will be added. * * @param signerInfoGen the generator for the signer we are using. * @param digestCalculator calculator for to use for digest of certificate. * @param tsaPolicy tasPolicy to send. * @param isIssuerSerialIncluded should issuerSerial be included in the ESSCertIDs, true if yes, * by default false. * @throws IllegalArgumentException if calculator is not SHA-1 or there is no associated * certificate for the signer, * @throws TSPException if the signer certificate cannot be processed. */ public TimeStampTokenGenerator( final SignerInfoGenerator signerInfoGen, DigestCalculator digestCalculator, ASN1ObjectIdentifier tsaPolicy, boolean isIssuerSerialIncluded) throws IllegalArgumentException, TSPException { this.signerInfoGen = signerInfoGen; this.tsaPolicyOID = tsaPolicy; if (!signerInfoGen.hasAssociatedCertificate()) { throw new IllegalArgumentException("SignerInfoGenerator must have an associated certificate"); } X509CertificateHolder assocCert = signerInfoGen.getAssociatedCertificate(); TSPUtil.validateCertificate(assocCert); try { OutputStream dOut = digestCalculator.getOutputStream(); dOut.write(assocCert.getEncoded()); dOut.close(); if (digestCalculator .getAlgorithmIdentifier() .getAlgorithm() .equals(OIWObjectIdentifiers.idSHA1)) { final ESSCertID essCertid = new ESSCertID( digestCalculator.getDigest(), isIssuerSerialIncluded ? new IssuerSerial( new GeneralNames(new GeneralName(assocCert.getIssuer())), assocCert.getSerialNumber()) : null); this.signerInfoGen = new SignerInfoGenerator( signerInfoGen, new CMSAttributeTableGenerator() { public AttributeTable getAttributes(Map parameters) throws CMSAttributeTableGenerationException { AttributeTable table = signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters); if (table.get(PKCSObjectIdentifiers.id_aa_signingCertificate) == null) { return table.add( PKCSObjectIdentifiers.id_aa_signingCertificate, new SigningCertificate(essCertid)); } return table; } }, signerInfoGen.getUnsignedAttributeTableGenerator()); } else { AlgorithmIdentifier digAlgID = new AlgorithmIdentifier(digestCalculator.getAlgorithmIdentifier().getAlgorithm()); final ESSCertIDv2 essCertid = new ESSCertIDv2( digAlgID, digestCalculator.getDigest(), isIssuerSerialIncluded ? new IssuerSerial( new GeneralNames(new GeneralName(assocCert.getIssuer())), new ASN1Integer(assocCert.getSerialNumber())) : null); this.signerInfoGen = new SignerInfoGenerator( signerInfoGen, new CMSAttributeTableGenerator() { public AttributeTable getAttributes(Map parameters) throws CMSAttributeTableGenerationException { AttributeTable table = signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters); if (table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2) == null) { return table.add( PKCSObjectIdentifiers.id_aa_signingCertificateV2, new SigningCertificateV2(essCertid)); } return table; } }, signerInfoGen.getUnsignedAttributeTableGenerator()); } } catch (IOException e) { throw new TSPException("Exception processing certificate.", e); } }
private boolean doVerify(SignerInformationVerifier verifier) throws CMSException { String digestName = CMSSignedHelper.INSTANCE.getDigestAlgName(this.getDigestAlgOID()); String encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID()); String signatureName = digestName + "with" + encName; try { if (digestCalculator != null) { resultDigest = digestCalculator.getDigest(); } else { DigestCalculator calc = verifier.getDigestCalculator(this.getDigestAlgorithmID()); if (content != null) { OutputStream digOut = calc.getOutputStream(); content.write(digOut); digOut.close(); } else if (signedAttributeSet == null) { // TODO Get rid of this exception and just treat content==null as empty not missing? throw new CMSException("data not encapsulated in signature - use detached constructor."); } resultDigest = calc.getDigest(); } } catch (IOException e) { throw new CMSException("can't process mime object to create signature.", e); } catch (NoSuchAlgorithmException e) { throw new CMSException("can't find algorithm: " + e.getMessage(), e); } catch (OperatorCreationException e) { throw new CMSException("can't create digest calculator: " + e.getMessage(), e); } // RFC 3852 11.1 Check the content-type attribute is correct { DERObject validContentType = getSingleValuedSignedAttribute(CMSAttributes.contentType, "content-type"); if (validContentType == null) { if (!isCounterSignature && signedAttributeSet != null) { throw new CMSException( "The content-type attribute type MUST be present whenever signed attributes are present in signed-data"); } } else { if (isCounterSignature) { throw new CMSException( "[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute"); } if (!(validContentType instanceof DERObjectIdentifier)) { throw new CMSException( "content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'"); } DERObjectIdentifier signedContentType = (DERObjectIdentifier) validContentType; if (!signedContentType.equals(contentType)) { throw new CMSException("content-type attribute value does not match eContentType"); } } } // RFC 3852 11.2 Check the message-digest attribute is correct { DERObject validMessageDigest = getSingleValuedSignedAttribute(CMSAttributes.messageDigest, "message-digest"); if (validMessageDigest == null) { if (signedAttributeSet != null) { throw new CMSException( "the message-digest signed attribute type MUST be present when there are any signed attributes present"); } } else { if (!(validMessageDigest instanceof ASN1OctetString)) { throw new CMSException("message-digest attribute value not of ASN.1 type 'OCTET STRING'"); } ASN1OctetString signedMessageDigest = (ASN1OctetString) validMessageDigest; if (!Arrays.constantTimeAreEqual(resultDigest, signedMessageDigest.getOctets())) { throw new CMSSignerDigestMismatchException( "message-digest attribute value does not match calculated value"); } } } // RFC 3852 11.4 Validate countersignature attribute(s) { AttributeTable signedAttrTable = this.getSignedAttributes(); if (signedAttrTable != null && signedAttrTable.getAll(CMSAttributes.counterSignature).size() > 0) { throw new CMSException("A countersignature attribute MUST NOT be a signed attribute"); } AttributeTable unsignedAttrTable = this.getUnsignedAttributes(); if (unsignedAttrTable != null) { ASN1EncodableVector csAttrs = unsignedAttrTable.getAll(CMSAttributes.counterSignature); for (int i = 0; i < csAttrs.size(); ++i) { Attribute csAttr = (Attribute) csAttrs.get(i); if (csAttr.getAttrValues().size() < 1) { throw new CMSException( "A countersignature attribute MUST contain at least one AttributeValue"); } // Note: We don't recursively validate the countersignature value } } } try { ContentVerifier contentVerifier = verifier.getContentVerifier(sigAlgFinder.find(signatureName)); OutputStream sigOut = contentVerifier.getOutputStream(); if (signedAttributeSet == null) { if (digestCalculator != null) { if (contentVerifier instanceof RawContentVerifier) { RawContentVerifier rawVerifier = (RawContentVerifier) contentVerifier; if (encName.equals("RSA")) { DigestInfo digInfo = new DigestInfo(digestAlgorithm, resultDigest); return rawVerifier.verify(digInfo.getDEREncoded(), this.getSignature()); } return rawVerifier.verify(resultDigest, this.getSignature()); } throw new CMSException("verifier unable to process raw signature"); } else if (content != null) { // TODO Use raw signature of the hash value instead content.write(sigOut); } } else { sigOut.write(this.getEncodedSignedAttributes()); } sigOut.close(); return contentVerifier.verify(this.getSignature()); } catch (IOException e) { throw new CMSException("can't process mime object to create signature.", e); } catch (OperatorCreationException e) { throw new CMSException("can't create content verifier: " + e.getMessage(), e); } }
/** * Calculates message digest using the provided digest calculator. * * @param dc the digest calculator * @param data the data * @return message digest * @throws IOException if the digest cannot be calculated */ public static byte[] calculateDigest(DigestCalculator dc, InputStream data) throws IOException { IOUtils.copy(data, dc.getOutputStream()); dc.getOutputStream().close(); return dc.getDigest(); }
/** * Calculates message digest using the provided digest calculator. * * @param dc the digest calculator * @param data the data * @return message digest * @throws IOException if the digest cannot be calculated */ public static byte[] calculateDigest(DigestCalculator dc, byte[] data) throws IOException { dc.getOutputStream().write(data); dc.getOutputStream().close(); return dc.getDigest(); }