// recupera il signing time di un firmatario private static Date getSigningTime(SignerInformation signer) throws FirmapiuException { AttributeTable signedAttr = signer.getSignedAttributes(); Attribute signingTimeAttr = signedAttr.get(CMSAttributes.signingTime); if (signingTimeAttr != null) { Enumeration<?> en = signingTimeAttr.getAttrValues().getObjects(); Date signingTime = null; Object obj = en.nextElement(); try { if (obj instanceof ASN1UTCTime) { ASN1UTCTime asn1Time = (ASN1UTCTime) obj; signingTime = asn1Time.getDate(); } else if (obj instanceof DERUTCTime) { DERUTCTime derTime = (DERUTCTime) obj; signingTime = derTime.getDate(); } return signingTime; } catch (ParseException e) { // TODO eccezioni ammodo throw new FirmapiuException(); } } else { // non ha trovato il signing time come attributo // TODO eccezioni ammodo throw new FirmapiuException(); } } // fine metodo
// controlla che nel firmatario sia presente l'attributo ESSCertIDv2 e che esso sia valido // in questo caso la busta crittografica è espressa correttamente nel formato CADES-BES secondo // la DELIBERAZIONE ministeriale del N . 45 DEL 21 MAGGIO 2009 private boolean isLegallySigned(SignerInformation signer, X509CertificateHolder cert) throws FirmapiuException, NoSuchAlgorithmException, IOException { AttributeTable signAttr = signer.getSignedAttributes(); if (signAttr == null) throw new FirmapiuException(VERIFY_SIGNER_SIGNINGATTRIBUTE_NOTFOUND); Attribute attr = signAttr.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2); if (attr == null) throw new FirmapiuException(VERIFY_SIGNER_SIGNINGATTRIBUTE_NOTFOUND); ASN1Sequence sequence = ASN1Sequence.getInstance(attr.getAttrValues().getObjectAt(0)); SigningCertificateV2 scv2 = SigningCertificateV2.getInstance(sequence); ESSCertIDv2[] essCert = scv2.getCerts(); if (essCert == null || essCert.length < 1) throw new FirmapiuException(VERIFY_SIGNER_SIGNINGATTRIBUTE_NOTFOUND); // controlla l'hash del certificato se si restituisce true se no restituisce no // aggiungere hash del certificato di sottoscrizione String digestAlgorithm = "SHA-256"; MessageDigest sha = null; sha = MessageDigest.getInstance(digestAlgorithm); byte[] digestedCert = sha.digest(cert.getEncoded()); byte[] essCertHash = essCert[0].getCertHash(); // affinché la firma sia valida digestCert e essCertHash devono essere uguali if (digestedCert.length != essCertHash.length) return false; else { for (int i = 0; i < digestedCert.length; i++) if (digestedCert[i] != essCertHash[i]) { return false; } return true; } // fine if } // fine metodo
private DERObject getSingleValuedSignedAttribute( DERObjectIdentifier attrOID, String printableName) throws CMSException { AttributeTable unsignedAttrTable = this.getUnsignedAttributes(); if (unsignedAttrTable != null && unsignedAttrTable.getAll(attrOID).size() > 0) { throw new CMSException( "The " + printableName + " attribute MUST NOT be an unsigned attribute"); } AttributeTable signedAttrTable = this.getSignedAttributes(); if (signedAttrTable == null) { return null; } ASN1EncodableVector v = signedAttrTable.getAll(attrOID); switch (v.size()) { case 0: return null; case 1: { Attribute t = (Attribute) v.get(0); ASN1Set attrValues = t.getAttrValues(); if (attrValues.size() != 1) { throw new CMSException( "A " + printableName + " attribute MUST have a single attribute value"); } return attrValues.getObjectAt(0).getDERObject(); } default: throw new CMSException( "The SignedAttributes in a signerInfo MUST NOT include multiple instances of the " + printableName + " attribute"); } }
public void multipartMixedTest(MimeBodyPart part1, MimeBodyPart part2) throws Exception { MimeMultipart mp = new MimeMultipart(); mp.addBodyPart(part1); mp.addBodyPart(part2); MimeBodyPart m = new MimeBodyPart(); m.setContent(mp); MimeMultipart smm = generateMultiPartRsa("SHA1withRSA", m, SMIMESignedGenerator.RFC3851_MICALGS); SMIMESigned s = new SMIMESigned(smm); verifySigners(s.getCertificates(), s.getSignerInfos()); AttributeTable attr = ((SignerInformation) s.getSignerInfos().getSigners().iterator().next()) .getSignedAttributes(); Attribute a = attr.get(CMSAttributes.messageDigest); byte[] contentDigest = ASN1OctetString.getInstance(a.getAttrValues().getObjectAt(0)).getOctets(); mp = (MimeMultipart) m.getContent(); ContentType contentType = new ContentType(mp.getContentType()); String boundary = "--" + contentType.getParameter("boundary"); ByteArrayOutputStream bOut = new ByteArrayOutputStream(); LineOutputStream lOut = new LineOutputStream(bOut); Enumeration headers = m.getAllHeaderLines(); while (headers.hasMoreElements()) { lOut.writeln((String) headers.nextElement()); } lOut.writeln(); // CRLF separator lOut.writeln(boundary); writePart(mp.getBodyPart(0), bOut); lOut.writeln(); // CRLF terminator lOut.writeln(boundary); writePart(mp.getBodyPart(1), bOut); lOut.writeln(); lOut.writeln(boundary + "--"); MessageDigest dig = MessageDigest.getInstance("SHA1", BC); assertTrue(Arrays.equals(contentDigest, dig.digest(bOut.toByteArray()))); }
public void testMimeMultipart() throws Exception { MimeBodyPart m = createMultipartMessage(); List certList = new ArrayList(); certList.add(_signCert); certList.add(_origCert); Store certs = new JcaCertStore(certList); ASN1EncodableVector signedAttrs = generateSignedAttributes(); SMIMESignedGenerator gen = new SMIMESignedGenerator("binary"); gen.addSignerInfoGenerator( new JcaSimpleSignerInfoGeneratorBuilder() .setProvider(BC) .setSignedAttributeGenerator(new AttributeTable(signedAttrs)) .build("SHA1withRSA", _signKP.getPrivate(), _signCert)); gen.addCertificates(certs); MimeMultipart mm = gen.generate(m); SMIMESigned s = new SMIMESigned(mm); verifySigners(s.getCertificates(), s.getSignerInfos()); byte[] contentDigest = (byte[]) gen.getGeneratedDigests().get(SMIMESignedGenerator.DIGEST_SHA1); AttributeTable table = ((SignerInformation) s.getSignerInfos().getSigners().iterator().next()) .getSignedAttributes(); Attribute hash = table.get(CMSAttributes.messageDigest); assertTrue( MessageDigest.isEqual( contentDigest, ((ASN1OctetString) hash.getAttrValues().getObjectAt(0)).getOctets())); }
private Date findTimestamp(CMSSignedData cmsSignedData) { Iterator iterator = cmsSignedData.getSignerInfos().getSigners().iterator(); while (iterator.hasNext()) { SignerInformation signerInformation = (SignerInformation) iterator.next(); AttributeTable signedAttrTable = signerInformation.getSignedAttributes(); if (signedAttrTable == null) { continue; } ASN1EncodableVector v = signedAttrTable.getAll(CMSAttributes.signingTime); switch (v.size()) { case 0: continue; case 1: Attribute t = (Attribute) v.get(0); ASN1Set attrValues = t.getAttrValues(); if (attrValues.size() != 1) { continue; } // found it try { return ((ASN1UTCTime) attrValues.getObjectAt(0).getDERObject()).getDate(); } catch (ParseException e) { e.printStackTrace(); } continue; default: continue; } } // no timestamp found return null; }
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); } }
/** @deprecated */ private boolean doVerify(PublicKey key, Provider sigProvider) throws CMSException, NoSuchAlgorithmException { String digestName = CMSSignedHelper.INSTANCE.getDigestAlgName(this.getDigestAlgOID()); String encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID()); String signatureName = digestName + "with" + encName; Signature sig = CMSSignedHelper.INSTANCE.getSignatureInstance(signatureName, sigProvider); MessageDigest digest = CMSSignedHelper.INSTANCE.getDigestInstance(digestName, sigProvider); // TODO [BJA-109] Note: PSSParameterSpec requires JDK1.4+ /* try { DERObjectIdentifier sigAlgOID = encryptionAlgorithm.getObjectId(); DEREncodable sigParams = this.encryptionAlgorithm.getParameters(); if (sigAlgOID.equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) { // RFC 4056 // When the id-RSASSA-PSS algorithm identifier is used for a signature, // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params. if (sigParams == null) { throw new CMSException( "RSASSA-PSS signature must specify algorithm parameters"); } AlgorithmParameters params = AlgorithmParameters.getInstance( sigAlgOID.getId(), sig.getProvider().getName()); params.init(sigParams.getDERObject().getEncoded(), "ASN.1"); PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class); sig.setParameter(spec); } else { // TODO Are there other signature algorithms that provide parameters? if (sigParams != null) { throw new CMSException("unrecognised signature parameters provided"); } } } catch (IOException e) { throw new CMSException("error encoding signature parameters.", e); } catch (InvalidAlgorithmParameterException e) { throw new CMSException("error setting signature parameters.", e); } catch (InvalidParameterSpecException e) { throw new CMSException("error processing signature parameters.", e); } */ try { if (digestCalculator != null) { resultDigest = digestCalculator.getDigest(); } else { if (content != null) { content.write(new DigOutputStream(digest)); } 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 = digest.digest(); } } catch (IOException e) { throw new CMSException("can't process mime object to create signature.", 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 { sig.initVerify(key); if (signedAttributeSet == null) { if (digestCalculator != null) { // need to decrypt signature and check message bytes return verifyDigest(resultDigest, key, this.getSignature(), sigProvider); } else if (content != null) { // TODO Use raw signature of the hash value instead content.write(new SigOutputStream(sig)); } } else { sig.update(this.getEncodedSignedAttributes()); } return sig.verify(this.getSignature()); } catch (InvalidKeyException e) { throw new CMSException("key not appropriate to signature in message.", e); } catch (IOException e) { throw new CMSException("can't process mime object to create signature.", e); } catch (SignatureException e) { throw new CMSException("invalid signature format in message: " + e.getMessage(), e); } }
/** * Return a SignerInformationStore containing the counter signatures attached to this signer. If * no counter signatures are present an empty store is returned. */ public SignerInformationStore getCounterSignatures() { // TODO There are several checks implied by the RFC3852 comments that are missing /* The countersignature attribute MUST be an unsigned attribute; it MUST NOT be a signed attribute, an authenticated attribute, an unauthenticated attribute, or an unprotected attribute. */ AttributeTable unsignedAttributeTable = getUnsignedAttributes(); if (unsignedAttributeTable == null) { return new SignerInformationStore(new ArrayList(0)); } List counterSignatures = new ArrayList(); /* The UnsignedAttributes syntax is defined as a SET OF Attributes. The UnsignedAttributes in a signerInfo may include multiple instances of the countersignature attribute. */ ASN1EncodableVector allCSAttrs = unsignedAttributeTable.getAll(CMSAttributes.counterSignature); for (int i = 0; i < allCSAttrs.size(); ++i) { Attribute counterSignatureAttribute = (Attribute) allCSAttrs.get(i); /* A countersignature attribute can have multiple attribute values. The syntax is defined as a SET OF AttributeValue, and there MUST be one or more instances of AttributeValue present. */ ASN1Set values = counterSignatureAttribute.getAttrValues(); if (values.size() < 1) { // TODO Throw an appropriate exception? } for (Enumeration en = values.getObjects(); en.hasMoreElements(); ) { /* Countersignature values have the same meaning as SignerInfo values for ordinary signatures, except that: 1. The signedAttributes field MUST NOT contain a content-type attribute; there is no content type for countersignatures. 2. The signedAttributes field MUST contain a message-digest attribute if it contains any other attributes. 3. The input to the message-digesting process is the contents octets of the DER encoding of the signatureValue field of the SignerInfo value with which the attribute is associated. */ SignerInfo si = SignerInfo.getInstance(en.nextElement()); String digestName = CMSSignedHelper.INSTANCE.getDigestAlgName( si.getDigestAlgorithm().getObjectId().getId()); counterSignatures.add( new SignerInformation( si, null, null, new CounterSignatureDigestCalculator(digestName, null, getSignature()), new DefaultSignatureAlgorithmIdentifierFinder())); } } return new SignerInformationStore(counterSignatures); }