From c609ec2e36f3dc20275592c19325995a54a394e8 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Wed, 18 Dec 2024 23:37:13 +0700 Subject: [PATCH] Rewrite generateCounterSigners - restore null check in ContentInfo constructor --- .../cms/CMSSignedDataGenerator.java | 161 ++++++++++-------- .../bouncycastle/asn1/cms/ContentInfo.java | 11 +- 2 files changed, 98 insertions(+), 74 deletions(-) diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java index 1bf5d393f2..59fc2d8d6b 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java @@ -52,7 +52,6 @@ public class CMSSignedDataGenerator extends CMSSignedGenerator { - private List signerInfs = new ArrayList(); private boolean isDefiniteLength = false; /** @@ -105,12 +104,7 @@ public CMSSignedData generate( boolean encapsulate) throws CMSException { - if (!signerInfs.isEmpty()) - { - throw new IllegalStateException("this method can only be used with SignerInfoGenerator"); - } - - // TODO + // TODO // if (signerInfs.isEmpty()) // { // /* RFC 3852 5.2 @@ -141,7 +135,7 @@ public CMSSignedData generate( // } Set digestAlgs = new LinkedHashSet(); - ASN1EncodableVector signerInfos = new ASN1EncodableVector(); + ASN1EncodableVector signerInfos = new ASN1EncodableVector(); digests.clear(); // clear the current preserved digest state @@ -159,92 +153,59 @@ public CMSSignedData generate( // // add the SignerInfo objects // - ASN1ObjectIdentifier contentTypeOID = content.getContentType(); - - ASN1OctetString octs = null; + ASN1ObjectIdentifier encapContentType = content.getContentType(); + ASN1OctetString encapContent = null; + // TODO[cms] Could be unnecessary copy e.g. if content is CMSProcessableByteArray (add hasContent method?) if (content.getContent() != null) { - ByteArrayOutputStream bOut = null; - if (encapsulate) { - bOut = new ByteArrayOutputStream(); - } - - OutputStream cOut = CMSUtils.attachSignersToOutputStream(signerGens, bOut); - - // Just in case it's unencapsulated and there are no signers! - cOut = CMSUtils.getSafeOutputStream(cOut); - - try - { - content.write(cOut); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - cOut.close(); - } - catch (IOException e) - { - throw new CMSException("data processing exception: " + e.getMessage(), e); - } + writeContentViaSignerGens(content, bOut); - if (encapsulate) - { if (isDefiniteLength) { - octs = new DEROctetString(bOut.toByteArray()); + encapContent = new DEROctetString(bOut.toByteArray()); } else { - octs = new BEROctetString(bOut.toByteArray()); + encapContent = new BEROctetString(bOut.toByteArray()); } } + else + { + writeContentViaSignerGens(content, null); + } } for (Iterator it = signerGens.iterator(); it.hasNext();) { - SignerInfoGenerator sGen = (SignerInfoGenerator)it.next(); - SignerInfo inf = sGen.generate(contentTypeOID); - - digestAlgs.add(inf.getDigestAlgorithm()); - signerInfos.add(inf); - - byte[] calcDigest = sGen.getCalculatedDigest(); - - if (calcDigest != null) - { - digests.put(inf.getDigestAlgorithm().getAlgorithm().getId(), calcDigest); - } + SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next(); + SignerInfo signerInfo = generateSignerInfo(signerGen, encapContentType); + digestAlgs.add(signerInfo.getDigestAlgorithm()); + signerInfos.add(signerInfo); } - ASN1Set certificates = createSetFromList(certs, isDefiniteLength); + ASN1Set certificates = createSetFromList(this.certs, isDefiniteLength); - ASN1Set certrevlist = createSetFromList(crls, isDefiniteLength); + ASN1Set crls = createSetFromList(this.crls, isDefiniteLength); - ContentInfo encInfo = new ContentInfo(contentTypeOID, octs); + ContentInfo encapContentInfo = new ContentInfo(encapContentType, encapContent); - SignedData sd = new SignedData( - CMSUtils.convertToDlSet(digestAlgs), - encInfo, - certificates, - certrevlist, - new DERSet(signerInfos)); + SignedData signedData = new SignedData( + CMSUtils.convertToDlSet(digestAlgs), + encapContentInfo, + certificates, + crls, + new DERSet(signerInfos)); - ContentInfo contentInfo = new ContentInfo( - CMSObjectIdentifiers.signedData, sd); + ContentInfo contentInfo = new ContentInfo(CMSObjectIdentifiers.signedData, signedData); return new CMSSignedData(content, contentInfo); } - private static ASN1Set createSetFromList(List list, boolean isDefiniteLength) - { - if(list.size()!=0) - { - return isDefiniteLength ? CMSUtils.createDlSetFromList(list) : CMSUtils.createBerSetFromList(list); - } - return null; - } - /** * generate a set of one or more SignerInformation objects representing counter signatures on * the passed in SignerInformation object. @@ -255,7 +216,71 @@ private static ASN1Set createSetFromList(List list, boolean isDefiniteLength) public SignerInformationStore generateCounterSigners(SignerInformation signer) throws CMSException { - return this.generate(new CMSProcessableByteArray(null, signer.getSignature()), false).getSignerInfos(); + digests.clear(); + + CMSTypedData content = new CMSProcessableByteArray(null, signer.getSignature()); + + ArrayList signerInformations = new ArrayList(); + + for (Iterator it = _signers.iterator(); it.hasNext();) + { + SignerInformation _signer = (SignerInformation)it.next(); + SignerInfo signerInfo = _signer.toASN1Structure(); + signerInformations.add(new SignerInformation(signerInfo, null, content, null)); + } + + writeContentViaSignerGens(content, null); + + for (Iterator it = signerGens.iterator(); it.hasNext();) + { + SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next(); + SignerInfo signerInfo = generateSignerInfo(signerGen, null); + signerInformations.add(new SignerInformation(signerInfo, null, content, null)); + } + + return new SignerInformationStore(signerInformations); + } + + private SignerInfo generateSignerInfo(SignerInfoGenerator signerGen, ASN1ObjectIdentifier contentType) + throws CMSException + { + SignerInfo signerInfo = signerGen.generate(contentType); + + byte[] calcDigest = signerGen.getCalculatedDigest(); + if (calcDigest != null) + { + digests.put(signerInfo.getDigestAlgorithm().getAlgorithm().getId(), calcDigest); + } + + return signerInfo; + } + + private void writeContentViaSignerGens(CMSTypedData content, OutputStream s) + throws CMSException + { + OutputStream cOut = CMSUtils.attachSignersToOutputStream(signerGens, s); + + // Just in case it's unencapsulated and there are no signers! + cOut = CMSUtils.getSafeOutputStream(cOut); + + try + { + content.write(cOut); + + cOut.close(); + } + catch (IOException e) + { + throw new CMSException("data processing exception: " + e.getMessage(), e); + } + } + + private static ASN1Set createSetFromList(List list, boolean isDefiniteLength) + { + return list.size() < 1 + ? null + : isDefiniteLength + ? CMSUtils.createDlSetFromList(list) + : CMSUtils.createBerSetFromList(list); } } - diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java index f35c844977..53c9347311 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java @@ -71,7 +71,7 @@ public static ContentInfo getInstance( ASN1TaggedObject obj, boolean explicit) { - return getInstance(ASN1Sequence.getInstance(obj, explicit)); + return new ContentInfo(ASN1Sequence.getInstance(obj, explicit)); } private ContentInfo( @@ -104,11 +104,10 @@ public ContentInfo( ASN1ObjectIdentifier contentType, ASN1Encodable content) { - // TODO[cms] Blocked by CMSSignedDataGenerator.generateCounterSigners transient usage of null here -// if (contentType == null) -// { -// throw new NullPointerException("'contentType' cannot be null"); -// } + if (contentType == null) + { + throw new NullPointerException("'contentType' cannot be null"); + } this.contentType = contentType; this.content = content;