Skip to content

Commit 5a4ccfd

Browse files
committed
minor refactoring
added editor class for signed data streams with digest editing capability - relates to github #1965
1 parent 3c31f1f commit 5a4ccfd

File tree

2 files changed

+133
-22
lines changed

2 files changed

+133
-22
lines changed

pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataParser.java

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -449,17 +449,7 @@ public static OutputStream replaceSigners(
449449
AlgorithmIdentifier[] newDigestAlgIds = (AlgorithmIdentifier[])digestAlgs.toArray(new AlgorithmIdentifier[digestAlgs.size()]);
450450
sigGen.getRawOutputStream().write(new DLSet(newDigestAlgIds).getEncoded());
451451

452-
// encap content info
453-
ContentInfoParser encapContentInfo = signedData.getEncapContentInfo();
454-
455-
BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream());
456-
457-
eiGen.addObject(encapContentInfo.getContentType());
458-
459-
pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream());
460-
461-
eiGen.close();
462-
452+
writeEncapContentInfoToGenerator(signedData, sigGen);
463453

464454
writeSetToGeneratorTagged(sigGen, signedData.getCertificates(), 0);
465455
writeSetToGeneratorTagged(sigGen, signedData.getCrls(), 1);
@@ -520,16 +510,7 @@ public static OutputStream replaceCertificatesAndCRLs(
520510
// digests
521511
sigGen.getRawOutputStream().write(signedData.getDigestAlgorithms().toASN1Primitive().getEncoded());
522512

523-
// encap content info
524-
ContentInfoParser encapContentInfo = signedData.getEncapContentInfo();
525-
526-
BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream());
527-
528-
eiGen.addObject(encapContentInfo.getContentType());
529-
530-
pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream());
531-
532-
eiGen.close();
513+
writeEncapContentInfoToGenerator(signedData, sigGen);
533514

534515
//
535516
// skip existing certs and CRLs
@@ -580,7 +561,7 @@ public static OutputStream replaceCertificatesAndCRLs(
580561
return out;
581562
}
582563

583-
private static void writeSetToGeneratorTagged(
564+
static void writeSetToGeneratorTagged(
584565
ASN1Generator asn1Gen,
585566
ASN1SetParser asn1SetParser,
586567
int tagNo)
@@ -662,4 +643,18 @@ private static void pipeOctetString(
662643
// ASN1OctetStringParser octs = (ASN1OctetStringParser)sp.readObject();
663644
// Streams.drain(octs.getOctetStream());
664645
// }
646+
647+
static void writeEncapContentInfoToGenerator(SignedDataParser signedData, BERSequenceGenerator sigGen)
648+
throws IOException
649+
{
650+
// encap content info
651+
ContentInfoParser encapContentInfo = signedData.getEncapContentInfo();
652+
653+
BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream());
654+
eiGen.addObject(encapContentInfo.getContentType());
655+
656+
pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream());
657+
658+
eiGen.close();
659+
}
665660
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package org.bouncycastle.cms;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.io.OutputStream;
6+
import java.util.Iterator;
7+
import java.util.LinkedHashMap;
8+
import java.util.Map;
9+
10+
import org.bouncycastle.asn1.ASN1EncodableVector;
11+
import org.bouncycastle.asn1.ASN1SequenceParser;
12+
import org.bouncycastle.asn1.ASN1StreamParser;
13+
import org.bouncycastle.asn1.BERSequenceGenerator;
14+
import org.bouncycastle.asn1.BERTags;
15+
import org.bouncycastle.asn1.DERSet;
16+
import org.bouncycastle.asn1.DLSet;
17+
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
18+
import org.bouncycastle.asn1.cms.ContentInfoParser;
19+
import org.bouncycastle.asn1.cms.SignedDataParser;
20+
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
21+
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
22+
import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder;
23+
import org.bouncycastle.operator.DigestCalculator;
24+
import org.bouncycastle.operator.DigestCalculatorProvider;
25+
import org.bouncycastle.operator.OperatorCreationException;
26+
27+
public class CMSSignedDataStreamEditor
28+
{
29+
private static final CMSSignedHelper HELPER = CMSSignedHelper.INSTANCE;
30+
private static final DefaultDigestAlgorithmIdentifierFinder dgstAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
31+
/**
32+
* Add the specified digest algorithm to the signed data contained in the input stream and write
33+
* the updated signed data to the provided output stream. This ensures that the output signed data
34+
* includes the specified digest algorithm. Uses the provided DigestAlgorithmIdentifierFinder to
35+
* create the digest sets and the DigestCalculatorProvider for computing the required digests.
36+
* <p>
37+
* The output stream is returned unclosed.
38+
* </p>
39+
*
40+
* @param out the output stream where the updated signed data object will be written.
41+
* @param original the input stream containing the original signed data to be modified.
42+
* @param digestAlgorithm the digest algorithm to be added to the signed data.
43+
* @param digestAlgIdFinder the DigestAlgorithmIdentifierFinder used to create the digest sets.
44+
* @param digestCalculatorProvider the DigestCalculatorProvider used to compute the digests.
45+
* @return the output stream containing the updated signed data.
46+
*/
47+
public static OutputStream addDigestAlgorithm(OutputStream out, InputStream original,
48+
AlgorithmIdentifier digestAlgorithm,
49+
DigestAlgorithmIdentifierFinder digestAlgIdFinder,
50+
DigestCalculatorProvider digestCalculatorProvider)
51+
throws IOException, CMSException
52+
{
53+
ContentInfoParser contentInfo = new ContentInfoParser((ASN1SequenceParser)new ASN1StreamParser(original).readObject());
54+
SignedDataParser signedData = SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE));
55+
BERSequenceGenerator sGen = new BERSequenceGenerator(out);
56+
57+
sGen.addObject(CMSObjectIdentifiers.signedData);
58+
59+
BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true);
60+
61+
// version number
62+
sigGen.addObject(signedData.getVersion());
63+
// digests
64+
ASN1EncodableVector digestAlgs = new ASN1EncodableVector();
65+
Map<AlgorithmIdentifier, DigestCalculator> digests = new LinkedHashMap<AlgorithmIdentifier, DigestCalculator>();
66+
try
67+
{
68+
for (Iterator it = ((DLSet)signedData.getDigestAlgorithms().toASN1Primitive()).iterator(); it.hasNext(); )
69+
{
70+
AlgorithmIdentifier oid = AlgorithmIdentifier.getInstance(it.next());
71+
digestAlgs.add(HELPER.fixDigestAlgID(oid, digestAlgIdFinder));
72+
digests.put(oid, digestCalculatorProvider.get(oid));
73+
}
74+
if (!digests.containsKey(digestAlgorithm))
75+
{
76+
digestAlgs.add(HELPER.fixDigestAlgID(digestAlgorithm, digestAlgIdFinder));
77+
digests.put(digestAlgorithm, digestCalculatorProvider.get(digestAlgorithm));
78+
}
79+
}
80+
catch (OperatorCreationException e)
81+
{
82+
throw new CMSException("unable to find digest algorithm");
83+
}
84+
sigGen.getRawOutputStream().write(new DERSet(digestAlgs).getEncoded());
85+
86+
CMSSignedDataParser.writeEncapContentInfoToGenerator(signedData, sigGen);
87+
88+
CMSSignedDataParser.writeSetToGeneratorTagged(sigGen, signedData.getCertificates(), 0);
89+
CMSSignedDataParser.writeSetToGeneratorTagged(sigGen, signedData.getCrls(), 1);
90+
sigGen.getRawOutputStream().write(signedData.getSignerInfos().toASN1Primitive().getEncoded());
91+
92+
sigGen.close();
93+
sGen.close();
94+
95+
return out;
96+
}
97+
98+
/**
99+
* Add the specified digest algorithm to the signed data contained in the input stream and write
100+
* the updated signed data to the provided output stream. This ensures that the output signed data
101+
* includes the specified digest algorithm.
102+
* <p>
103+
* The output stream is returned unclosed.
104+
* </p>
105+
*
106+
* @param out the output stream where the updated signed data object will be written.
107+
* @param original the input stream containing the original signed data to be modified.
108+
* @param digestAlgorithm the digest algorithm to be added to the signed data.
109+
* @return the output stream containing the updated signed data.
110+
*/
111+
public static OutputStream addDigestAlgorithm(OutputStream out, InputStream original, AlgorithmIdentifier digestAlgorithm, DigestCalculatorProvider digestCalculatorProvider)
112+
throws IOException, CMSException
113+
{
114+
return addDigestAlgorithm(out, original, digestAlgorithm, dgstAlgFinder, digestCalculatorProvider);
115+
}
116+
}

0 commit comments

Comments
 (0)