001: package org.bouncycastle.asn1.cms;
002:
003: import org.bouncycastle.asn1.ASN1Encodable;
004: import org.bouncycastle.asn1.ASN1EncodableVector;
005: import org.bouncycastle.asn1.ASN1Sequence;
006: import org.bouncycastle.asn1.ASN1Set;
007: import org.bouncycastle.asn1.ASN1TaggedObject;
008: import org.bouncycastle.asn1.BERSequence;
009: import org.bouncycastle.asn1.BERSet;
010: import org.bouncycastle.asn1.BERTaggedObject;
011: import org.bouncycastle.asn1.DERInteger;
012: import org.bouncycastle.asn1.DERObject;
013: import org.bouncycastle.asn1.DERObjectIdentifier;
014: import org.bouncycastle.asn1.DERTaggedObject;
015:
016: import java.util.Enumeration;
017:
018: /**
019: * a signed data object.
020: */
021: public class SignedData extends ASN1Encodable {
022: private DERInteger version;
023: private ASN1Set digestAlgorithms;
024: private ContentInfo contentInfo;
025: private ASN1Set certificates;
026: private ASN1Set crls;
027: private ASN1Set signerInfos;
028: private boolean certsBer;
029: private boolean crlsBer;
030:
031: public static SignedData getInstance(Object o) {
032: if (o instanceof SignedData) {
033: return (SignedData) o;
034: } else if (o instanceof ASN1Sequence) {
035: return new SignedData((ASN1Sequence) o);
036: }
037:
038: throw new IllegalArgumentException("unknown object in factory");
039: }
040:
041: public SignedData(ASN1Set digestAlgorithms,
042: ContentInfo contentInfo, ASN1Set certificates,
043: ASN1Set crls, ASN1Set signerInfos) {
044: this .version = calculateVersion(contentInfo.getContentType(),
045: certificates, crls, signerInfos);
046: this .digestAlgorithms = digestAlgorithms;
047: this .contentInfo = contentInfo;
048: this .certificates = certificates;
049: this .crls = crls;
050: this .signerInfos = signerInfos;
051: this .crlsBer = crls instanceof BERSet;
052: this .certsBer = certificates instanceof BERSet;
053: }
054:
055: // RFC3852, section 5.1:
056: // IF ((certificates is present) AND
057: // (any certificates with a type of other are present)) OR
058: // ((crls is present) AND
059: // (any crls with a type of other are present))
060: // THEN version MUST be 5
061: // ELSE
062: // IF (certificates is present) AND
063: // (any version 2 attribute certificates are present)
064: // THEN version MUST be 4
065: // ELSE
066: // IF ((certificates is present) AND
067: // (any version 1 attribute certificates are present)) OR
068: // (any SignerInfo structures are version 3) OR
069: // (encapContentInfo eContentType is other than id-data)
070: // THEN version MUST be 3
071: // ELSE version MUST be 1
072: //
073: private DERInteger calculateVersion(DERObjectIdentifier contentOid,
074: ASN1Set certs, ASN1Set crls, ASN1Set signerInfs) {
075: boolean otherCert = false;
076: boolean otherCrl = false;
077: boolean attrCertV1Found = false;
078: boolean attrCertV2Found = false;
079:
080: if (certs != null) {
081: for (Enumeration en = certs.getObjects(); en
082: .hasMoreElements();) {
083: Object obj = en.nextElement();
084: if (obj instanceof ASN1TaggedObject) {
085: ASN1TaggedObject tagged = (ASN1TaggedObject) obj;
086:
087: if (tagged.getTagNo() == 1) {
088: attrCertV1Found = true;
089: } else if (tagged.getTagNo() == 2) {
090: attrCertV2Found = true;
091: } else if (tagged.getTagNo() == 3) {
092: otherCert = true;
093: }
094: }
095: }
096: }
097:
098: if (otherCert) {
099: return new DERInteger(5);
100: }
101:
102: if (crls != null) // no need to check if otherCert is true
103: {
104: for (Enumeration en = crls.getObjects(); en
105: .hasMoreElements();) {
106: Object obj = en.nextElement();
107: if (obj instanceof ASN1TaggedObject) {
108: otherCrl = true;
109: }
110: }
111: }
112:
113: if (otherCrl) {
114: return new DERInteger(5);
115: }
116:
117: if (attrCertV2Found) {
118: return new DERInteger(4);
119: }
120:
121: if (attrCertV1Found) {
122: return new DERInteger(3);
123: }
124:
125: if (contentOid.equals(CMSObjectIdentifiers.data)) {
126: if (checkForVersion3(signerInfs)) {
127: return new DERInteger(3);
128: } else {
129: return new DERInteger(1);
130: }
131: } else {
132: return new DERInteger(3);
133: }
134: }
135:
136: private boolean checkForVersion3(ASN1Set signerInfs) {
137: for (Enumeration e = signerInfs.getObjects(); e
138: .hasMoreElements();) {
139: SignerInfo s = SignerInfo.getInstance(e.nextElement());
140:
141: if (s.getVersion().getValue().intValue() == 3) {
142: return true;
143: }
144: }
145:
146: return false;
147: }
148:
149: public SignedData(ASN1Sequence seq) {
150: Enumeration e = seq.getObjects();
151:
152: version = (DERInteger) e.nextElement();
153: digestAlgorithms = ((ASN1Set) e.nextElement());
154: contentInfo = ContentInfo.getInstance(e.nextElement());
155:
156: while (e.hasMoreElements()) {
157: DERObject o = (DERObject) e.nextElement();
158:
159: //
160: // an interesting feature of SignedData is that there appear
161: // to be varying implementations...
162: // for the moment we ignore anything which doesn't fit.
163: //
164: if (o instanceof ASN1TaggedObject) {
165: ASN1TaggedObject tagged = (ASN1TaggedObject) o;
166:
167: switch (tagged.getTagNo()) {
168: case 0:
169: certsBer = tagged instanceof BERTaggedObject;
170: certificates = ASN1Set.getInstance(tagged, false);
171: break;
172: case 1:
173: crlsBer = tagged instanceof BERTaggedObject;
174: crls = ASN1Set.getInstance(tagged, false);
175: break;
176: default:
177: throw new IllegalArgumentException(
178: "unknown tag value " + tagged.getTagNo());
179: }
180: } else {
181: signerInfos = (ASN1Set) o;
182: }
183: }
184: }
185:
186: public DERInteger getVersion() {
187: return version;
188: }
189:
190: public ASN1Set getDigestAlgorithms() {
191: return digestAlgorithms;
192: }
193:
194: public ContentInfo getEncapContentInfo() {
195: return contentInfo;
196: }
197:
198: public ASN1Set getCertificates() {
199: return certificates;
200: }
201:
202: public ASN1Set getCRLs() {
203: return crls;
204: }
205:
206: public ASN1Set getSignerInfos() {
207: return signerInfos;
208: }
209:
210: /**
211: * Produce an object suitable for an ASN1OutputStream.
212: * <pre>
213: * SignedData ::= SEQUENCE {
214: * version CMSVersion,
215: * digestAlgorithms DigestAlgorithmIdentifiers,
216: * encapContentInfo EncapsulatedContentInfo,
217: * certificates [0] IMPLICIT CertificateSet OPTIONAL,
218: * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
219: * signerInfos SignerInfos
220: * }
221: * </pre>
222: */
223: public DERObject toASN1Object() {
224: ASN1EncodableVector v = new ASN1EncodableVector();
225:
226: v.add(version);
227: v.add(digestAlgorithms);
228: v.add(contentInfo);
229:
230: if (certificates != null) {
231: if (certsBer) {
232: v.add(new BERTaggedObject(false, 0, certificates));
233: } else {
234: v.add(new DERTaggedObject(false, 0, certificates));
235: }
236: }
237:
238: if (crls != null) {
239: if (crlsBer) {
240: v.add(new BERTaggedObject(false, 1, crls));
241: } else {
242: v.add(new DERTaggedObject(false, 1, crls));
243: }
244: }
245:
246: v.add(signerInfos);
247:
248: return new BERSequence(v);
249: }
250: }
|