/** * Copied from org.bouncycastle.asn1.cms.SignerInfo#toASN1Object() and * adapted to be able to use the custom unauthenticatedAttributes * * @param signerInfo * @param signerInfo * @param unauthenticatedAttributes * @return */ private ASN1Sequence getSignerInfoEncoded(final SignerInfo signerInfo, final ASN1Encodable unauthenticatedAttributes) { ASN1EncodableVector v = new ASN1EncodableVector(); v.add(signerInfo.getVersion()); v.add(signerInfo.getSID()); v.add(signerInfo.getDigestAlgorithm()); final DERTaggedObject signedAttributes = CMSUtils.getDERSignedAttributes(signerInformation); if (signedAttributes != null) { v.add(signedAttributes); } v.add(signerInfo.getDigestEncryptionAlgorithm()); v.add(signerInfo.getEncryptedDigest()); if (unauthenticatedAttributes != null) { v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes)); } return new DERSequence(v); }
@Before public void init() throws Exception { DSSDocument signedDocument = getSignedDocument(); ASN1InputStream asn1sInput = new ASN1InputStream(signedDocument.openStream()); ASN1Sequence asn1Seq = (ASN1Sequence) asn1sInput.readObject(); assertEquals(2, asn1Seq.size()); ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(asn1Seq.getObjectAt(0)); assertEquals(PKCSObjectIdentifiers.signedData, oid); ASN1TaggedObject taggedObj = DERTaggedObject.getInstance(asn1Seq.getObjectAt(1)); signedData = SignedData.getInstance(taggedObj.getObject()); ASN1Set signerInfosAsn1 = signedData.getSignerInfos(); assertEquals(1, signerInfosAsn1.size()); signerInfo = SignerInfo.getInstance(ASN1Sequence.getInstance(signerInfosAsn1.getObjectAt(0))); Utils.closeQuietly(asn1sInput); }
SignerInformation( SignerInfo info, ASN1ObjectIdentifier contentType, CMSProcessable content, byte[] resultDigest) { this.info = info; this.contentType = contentType; this.isCounterSignature = contentType == null; SignerIdentifier s = info.getSID(); if (s.isTagged()) { ASN1OctetString octs = ASN1OctetString.getInstance(s.getId()); sid = new SignerId(octs.getOctets()); } else { IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.getInstance(s.getId()); sid = new SignerId(iAnds.getName(), iAnds.getSerialNumber().getValue()); } this.digestAlgorithm = info.getDigestAlgorithm(); this.signedAttributeSet = info.getAuthenticatedAttributes(); this.unsignedAttributeSet = info.getUnauthenticatedAttributes(); this.encryptionAlgorithm = info.getDigestEncryptionAlgorithm(); this.signature = info.getEncryptedDigest().getOctets(); this.content = content; this.resultDigest = resultDigest; }
/** * return the collection of signers that are associated with the * signatures for the message. */ public SignerInformationStore getSignerInfos() { if (signerInfoStore == null) { ASN1Set s = signedData.getSignerInfos(); List signerInfos = new ArrayList(); SignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder(); for (int i = 0; i != s.size(); i++) { SignerInfo info = SignerInfo.getInstance(s.getObjectAt(i)); ASN1ObjectIdentifier contentType = signedData.getEncapContentInfo().getContentType(); if (hashes == null) { signerInfos.add(new SignerInformation(info, contentType, signedContent, null)); } else { Object obj = hashes.keySet().iterator().next(); byte[] hash = (obj instanceof String) ? (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm().getId()) : (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm()); signerInfos.add(new SignerInformation(info, contentType, null, hash)); } } signerInfoStore = new SignerInformationStore(signerInfos); } return signerInfoStore; }
/** * Return a signer information object with passed in SignerInformationStore representing counter * signatures attached as an unsigned attribute. * * @param signerInformation the signerInfo to be used as the basis. * @param counterSigners signer info objects carrying counter signature. * @return a copy of the original SignerInformationObject with the changed attributes. */ public static SignerInformation addCounterSigners( SignerInformation signerInformation, SignerInformationStore counterSigners) { // TODO Perform checks from RFC 3852 11.4 SignerInfo sInfo = signerInformation.info; AttributeTable unsignedAttr = signerInformation.getUnsignedAttributes(); ASN1EncodableVector v; if (unsignedAttr != null) { v = unsignedAttr.toASN1EncodableVector(); } else { v = new ASN1EncodableVector(); } ASN1EncodableVector sigs = new ASN1EncodableVector(); for (Iterator it = counterSigners.getSigners().iterator(); it.hasNext();) { sigs.add(((SignerInformation)it.next()).toASN1Structure()); } v.add(new Attribute(CMSAttributes.counterSignature, new DERSet(sigs))); return new SignerInformation( new SignerInfo(sInfo.getSID(), sInfo.getDigestAlgorithm(), sInfo.getAuthenticatedAttributes(), sInfo.getDigestEncryptionAlgorithm(), sInfo.getEncryptedDigest(), new DERSet(v)), signerInformation.contentType, signerInformation.content, null); }
/** * return the collection of signers that are associated with the * signatures for the message. */ public SignerInformationStore getSignerInfos() { if (signerInfoStore == null) { ASN1Set s = signedData.getSignerInfos(); List signerInfos = new ArrayList(); for (int i = 0; i != s.size(); i++) { SignerInfo info = SignerInfo.getInstance(s.getObjectAt(i)); ASN1ObjectIdentifier contentType = signedData.getEncapContentInfo().getContentType(); if (hashes == null) { signerInfos.add(new SignerInformation(info, contentType, signedContent, null)); } else { Object obj = hashes.keySet().iterator().next(); byte[] hash = (obj instanceof String) ? (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm().getId()) : (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm()); signerInfos.add(new SignerInformation(info, contentType, null, hash)); } } signerInfoStore = new SignerInformationStore(signerInfos); } return signerInfoStore; }
/** * 3) Fields version, sid, digestAlgorithm, signedAttrs, signatureAlgorithm, and * signature within the SignedData.signerInfos’s item corresponding to the signature being archive * time-stamped, in their order of appearance. * * @param signerInformation * @return */ private byte[] getSignedFields(final SignerInformation signerInformation) { final SignerInfo signerInfo = signerInformation.toASN1Structure(); final ASN1Integer version = signerInfo.getVersion(); final SignerIdentifier sid = signerInfo.getSID(); final AlgorithmIdentifier digestAlgorithm = signerInfo.getDigestAlgorithm(); final DERTaggedObject signedAttributes = CMSUtils.getDERSignedAttributes(signerInformation); final AlgorithmIdentifier digestEncryptionAlgorithm = signerInfo.getDigestEncryptionAlgorithm(); final ASN1OctetString encryptedDigest = signerInfo.getEncryptedDigest(); final byte[] derEncodedVersion = DSSASN1Utils.getDEREncoded(version); final byte[] derEncodedSid = DSSASN1Utils.getDEREncoded(sid); final byte[] derEncodedDigestAlgorithm = DSSASN1Utils.getDEREncoded(digestAlgorithm); final byte[] derEncodedSignedAttributes = DSSASN1Utils.getDEREncoded(signedAttributes); final byte[] derEncodedDigestEncryptionAlgorithm = DSSASN1Utils.getDEREncoded(digestEncryptionAlgorithm); final byte[] derEncodedEncryptedDigest = DSSASN1Utils.getDEREncoded(encryptedDigest); if (LOG.isDebugEnabled()) { LOG.debug("getSignedFields Version={}", Utils.toBase64(derEncodedVersion)); LOG.debug("getSignedFields Sid={}", Utils.toBase64(derEncodedSid)); LOG.debug("getSignedFields DigestAlgorithm={}", Utils.toBase64(derEncodedDigestAlgorithm)); LOG.debug("getSignedFields SignedAttributes={}", Utils.toBase64(derEncodedSignedAttributes)); LOG.debug("getSignedFields DigestEncryptionAlgorithm={}", Utils.toBase64(derEncodedDigestEncryptionAlgorithm)); LOG.debug("getSignedFields EncryptedDigest={}", Utils.toBase64(derEncodedEncryptedDigest)); } final byte[] concatenatedArrays = DSSUtils.concatenate(derEncodedVersion, derEncodedSid, derEncodedDigestAlgorithm, derEncodedSignedAttributes, derEncodedDigestEncryptionAlgorithm, derEncodedEncryptedDigest); return concatenatedArrays; }
/** * Return a signer information object with passed in SignerInformationStore representing counter * signatures attached as an unsigned attribute. * * @param signerInformation the signerInfo to be used as the basis. * @param counterSigners signer info objects carrying counter signature. * @return a copy of the original SignerInformationObject with the changed attributes. */ public static SignerInformation addCounterSigners( SignerInformation signerInformation, SignerInformationStore counterSigners) { // TODO Perform checks from RFC 3852 11.4 SignerInfo sInfo = signerInformation.info; AttributeTable unsignedAttr = signerInformation.getUnsignedAttributes(); ASN1EncodableVector v; if (unsignedAttr != null) { v = unsignedAttr.toASN1EncodableVector(); } else { v = new ASN1EncodableVector(); } ASN1EncodableVector sigs = new ASN1EncodableVector(); for (Iterator it = counterSigners.getSigners().iterator(); it.hasNext();) { sigs.add(((SignerInformation)it.next()).toSignerInfo()); } v.add(new Attribute(CMSAttributes.counterSignature, new DERSet(sigs))); return new SignerInformation( new SignerInfo(sInfo.getSID(), sInfo.getDigestAlgorithm(), sInfo.getAuthenticatedAttributes(), sInfo.getDigestEncryptionAlgorithm(), sInfo.getEncryptedDigest(), new DERSet(v)), signerInformation.contentType, signerInformation.content, null); }
/** * return the collection of signers that are associated with the * signatures for the message. * @throws CMSException */ public SignerInformationStore getSignerInfos() throws CMSException { if (_signerInfoStore == null) { populateCertCrlSets(); List signerInfos = new ArrayList(); Map hashes = new HashMap(); Iterator it = digests.keySet().iterator(); while (it.hasNext()) { Object digestKey = it.next(); hashes.put(digestKey, ((DigestCalculator)digests.get(digestKey)).getDigest()); } try { ASN1SetParser s = _signedData.getSignerInfos(); ASN1Encodable o; while ((o = s.readObject()) != null) { SignerInfo info = SignerInfo.getInstance(o.toASN1Primitive()); byte[] hash = (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm()); signerInfos.add(new SignerInformation(info, _signedContentType, null, hash)); } } catch (IOException e) { throw new CMSException("io exception: " + e.getMessage(), e); } _signerInfoStore = new SignerInformationStore(signerInfos); } return _signerInfoStore; }
/** * 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()); counterSignatures.add(new SignerInformation(si, null, new CMSProcessableByteArray(getSignature()), null)); } } return new SignerInformationStore(counterSignatures); }
@Test public void testContentTimeStamp() throws IOException { File file = new File("src/test/resources/plugtest/cades/CAdES-BES/Sample_Set_11/Signature-C-BES-4.p7m"); FileInputStream fis = new FileInputStream(file); ASN1InputStream asn1sInput = new ASN1InputStream(Utils.toByteArray(fis)); ASN1Sequence asn1Seq = (ASN1Sequence) asn1sInput.readObject(); ASN1TaggedObject taggedObj = DERTaggedObject.getInstance(asn1Seq.getObjectAt(1)); ASN1Primitive object = taggedObj.getObject(); SignedData signedData = SignedData.getInstance(object); ASN1Set signerInfosAsn1 = signedData.getSignerInfos(); ASN1Sequence seqSignedInfo = ASN1Sequence.getInstance(signerInfosAsn1.getObjectAt(0)); SignerInfo signedInfo = SignerInfo.getInstance(seqSignedInfo); ASN1Set authenticatedAttributes = signedInfo.getAuthenticatedAttributes(); boolean found = false; for (int i = 0; i < authenticatedAttributes.size(); i++) { ASN1Sequence authAttrSeq = ASN1Sequence.getInstance(authenticatedAttributes.getObjectAt(i)); ASN1ObjectIdentifier attrOid = ASN1ObjectIdentifier.getInstance(authAttrSeq.getObjectAt(0)); if (PKCSObjectIdentifiers.id_aa_ets_contentTimestamp.equals(attrOid)) { found = true; } } assertTrue(found); SignedDocumentValidator validator = SignedDocumentValidator.fromDocument(new FileDocument(file)); validator.setCertificateVerifier(new CommonCertificateVerifier()); Reports reports = validator.validateDocument(); // reports.print(); DiagnosticData diagnosticData = reports.getDiagnosticData(); List<String> timestampIdList = diagnosticData.getTimestampIdList(diagnosticData.getFirstSignatureId()); assertTrue(Utils.isCollectionNotEmpty(timestampIdList)); boolean foundContentTimestamp = false; for (String timestampId : timestampIdList) { String timestampType = diagnosticData.getTimestampType(timestampId); if (TimestampType.CONTENT_TIMESTAMP.name().equals(timestampType)) { foundContentTimestamp = true; } } assertTrue(foundContentTimestamp); Utils.closeQuietly(asn1sInput); Utils.closeQuietly(fis); }