Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/java/org/spongycastle/asn1/cms')
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/Attribute.java110
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/AttributeTable.java240
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/Attributes.java85
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/AuthEnvelopedData.java248
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/AuthEnvelopedDataParser.java157
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/AuthenticatedData.java312
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/AuthenticatedDataParser.java206
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/CCMParameters.java102
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/CMSAttributes.java30
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/CMSObjectIdentifiers.java43
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/CompressedData.java117
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/CompressedDataParser.java49
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/ContentInfo.java130
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/ContentInfoParser.java48
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/DigestedData.java128
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/EncryptedContentInfo.java120
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/EncryptedContentInfoParser.java53
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/EncryptedData.java111
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/EnvelopedData.java215
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/EnvelopedDataParser.java120
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/Evidence.java80
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/GCMParameters.java102
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/IssuerAndSerialNumber.java138
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/KEKIdentifier.java151
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/KEKRecipientInfo.java133
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/KeyAgreeRecipientIdentifier.java116
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/KeyAgreeRecipientInfo.java166
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/KeyTransRecipientInfo.java127
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/MetaData.java135
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/OriginatorIdentifierOrKey.java179
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/OriginatorInfo.java159
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/OriginatorPublicKey.java114
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/OtherKeyAttribute.java96
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/OtherRecipientInfo.java112
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/OtherRevocationInfoFormat.java109
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/PasswordRecipientInfo.java157
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/RecipientEncryptedKey.java109
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/RecipientIdentifier.java111
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/RecipientInfo.java173
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/RecipientKeyIdentifier.java171
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/SCVPReqRes.java108
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/SignedData.java330
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/SignedDataParser.java141
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/SignerIdentifier.java114
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/SignerInfo.java282
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/Time.java198
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/TimeStampAndCRL.java96
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/TimeStampTokenEvidence.java98
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/TimeStampedData.java131
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/TimeStampedDataParser.java141
-rw-r--r--core/src/main/java/org/spongycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java122
51 files changed, 7023 insertions, 0 deletions
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/Attribute.java b/core/src/main/java/org/spongycastle/asn1/cms/Attribute.java
new file mode 100644
index 00000000..59b8772c
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/Attribute.java
@@ -0,0 +1,110 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.DERSequence;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#page-14">RFC 5652</a>:
+ * Attribute is a pair of OID (as type identifier) + set of values.
+ * <p>
+ * <pre>
+ * Attribute ::= SEQUENCE {
+ * attrType OBJECT IDENTIFIER,
+ * attrValues SET OF AttributeValue
+ * }
+ *
+ * AttributeValue ::= ANY
+ * </pre>
+ * <p>
+ * General rule on values is that same AttributeValue must not be included
+ * multiple times into the set. That is, if the value is a SET OF INTEGERs,
+ * then having same value repeated is wrong: (1, 1), but different values is OK: (1, 2).
+ * Normally the AttributeValue syntaxes are more complicated than that.
+ * <p>
+ * General rule of Attribute usage is that the {@link Attributes} containers
+ * must not have multiple Attribute:s with same attrType (OID) there.
+ */
+public class Attribute
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier attrType;
+ private ASN1Set attrValues;
+
+ /**
+ * Return an Attribute object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link Attribute} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with Attribute structure inside
+ * </ul>
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static Attribute getInstance(
+ Object o)
+ {
+ if (o instanceof Attribute)
+ {
+ return (Attribute)o;
+ }
+
+ if (o != null)
+ {
+ return new Attribute(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ private Attribute(
+ ASN1Sequence seq)
+ {
+ attrType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+ attrValues = (ASN1Set)seq.getObjectAt(1);
+ }
+
+ public Attribute(
+ ASN1ObjectIdentifier attrType,
+ ASN1Set attrValues)
+ {
+ this.attrType = attrType;
+ this.attrValues = attrValues;
+ }
+
+ public ASN1ObjectIdentifier getAttrType()
+ {
+ return attrType;
+ }
+
+ public ASN1Set getAttrValues()
+ {
+ return attrValues;
+ }
+
+ public ASN1Encodable[] getAttributeValues()
+ {
+ return attrValues.toArray();
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attrType);
+ v.add(attrValues);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/AttributeTable.java b/core/src/main/java/org/spongycastle/asn1/cms/AttributeTable.java
new file mode 100644
index 00000000..69e0988d
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/AttributeTable.java
@@ -0,0 +1,240 @@
+package org.spongycastle.asn1.cms;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.DERSet;
+
+/**
+ * This is helper tool to construct {@link Attributes} sets.
+ */
+public class AttributeTable
+{
+ private Hashtable attributes = new Hashtable();
+
+ public AttributeTable(
+ Hashtable attrs)
+ {
+ attributes = copyTable(attrs);
+ }
+
+ public AttributeTable(
+ ASN1EncodableVector v)
+ {
+ for (int i = 0; i != v.size(); i++)
+ {
+ Attribute a = Attribute.getInstance(v.get(i));
+
+ addAttribute(a.getAttrType(), a);
+ }
+ }
+
+ public AttributeTable(
+ ASN1Set s)
+ {
+ for (int i = 0; i != s.size(); i++)
+ {
+ Attribute a = Attribute.getInstance(s.getObjectAt(i));
+
+ addAttribute(a.getAttrType(), a);
+ }
+ }
+
+ public AttributeTable(
+ Attribute attr)
+ {
+ addAttribute(attr.getAttrType(), attr);
+ }
+
+ public AttributeTable(
+ Attributes attrs)
+ {
+ this(ASN1Set.getInstance(attrs.toASN1Primitive()));
+ }
+
+ private void addAttribute(
+ ASN1ObjectIdentifier oid,
+ Attribute a)
+ {
+ Object value = attributes.get(oid);
+
+ if (value == null)
+ {
+ attributes.put(oid, a);
+ }
+ else
+ {
+ Vector v;
+
+ if (value instanceof Attribute)
+ {
+ v = new Vector();
+
+ v.addElement(value);
+ v.addElement(a);
+ }
+ else
+ {
+ v = (Vector)value;
+
+ v.addElement(a);
+ }
+
+ attributes.put(oid, v);
+ }
+ }
+
+ /**
+ * Return the first attribute matching the OBJECT IDENTIFIER oid.
+ *
+ * @param oid type of attribute required.
+ * @return first attribute found of type oid.
+ */
+ public Attribute get(
+ ASN1ObjectIdentifier oid)
+ {
+ Object value = attributes.get(oid);
+
+ if (value instanceof Vector)
+ {
+ return (Attribute)((Vector)value).elementAt(0);
+ }
+
+ return (Attribute)value;
+ }
+
+ /**
+ * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be
+ * empty if there are no attributes of the required type present.
+ *
+ * @param oid type of attribute required.
+ * @return a vector of all the attributes found of type oid.
+ */
+ public ASN1EncodableVector getAll(
+ ASN1ObjectIdentifier oid)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ Object value = attributes.get(oid);
+
+ if (value instanceof Vector)
+ {
+ Enumeration e = ((Vector)value).elements();
+
+ while (e.hasMoreElements())
+ {
+ v.add((Attribute)e.nextElement());
+ }
+ }
+ else if (value != null)
+ {
+ v.add((Attribute)value);
+ }
+
+ return v;
+ }
+
+ public int size()
+ {
+ int size = 0;
+
+ for (Enumeration en = attributes.elements(); en.hasMoreElements();)
+ {
+ Object o = en.nextElement();
+
+ if (o instanceof Vector)
+ {
+ size += ((Vector)o).size();
+ }
+ else
+ {
+ size++;
+ }
+ }
+
+ return size;
+ }
+
+ public Hashtable toHashtable()
+ {
+ return copyTable(attributes);
+ }
+
+ public ASN1EncodableVector toASN1EncodableVector()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ Enumeration e = attributes.elements();
+
+ while (e.hasMoreElements())
+ {
+ Object value = e.nextElement();
+
+ if (value instanceof Vector)
+ {
+ Enumeration en = ((Vector)value).elements();
+
+ while (en.hasMoreElements())
+ {
+ v.add(Attribute.getInstance(en.nextElement()));
+ }
+ }
+ else
+ {
+ v.add(Attribute.getInstance(value));
+ }
+ }
+
+ return v;
+ }
+
+ public Attributes toASN1Structure()
+ {
+ return new Attributes(this.toASN1EncodableVector());
+ }
+
+ private Hashtable copyTable(
+ Hashtable in)
+ {
+ Hashtable out = new Hashtable();
+ Enumeration e = in.keys();
+
+ while (e.hasMoreElements())
+ {
+ Object key = e.nextElement();
+
+ out.put(key, in.get(key));
+ }
+
+ return out;
+ }
+
+ /**
+ * Return a new table with the passed in attribute added.
+ *
+ * @param attrType
+ * @param attrValue
+ * @return
+ */
+ public AttributeTable add(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue)
+ {
+ AttributeTable newTable = new AttributeTable(attributes);
+
+ newTable.addAttribute(attrType, new Attribute(attrType, new DERSet(attrValue)));
+
+ return newTable;
+ }
+
+ public AttributeTable remove(ASN1ObjectIdentifier attrType)
+ {
+ AttributeTable newTable = new AttributeTable(attributes);
+
+ newTable.attributes.remove(attrType);
+
+ return newTable;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/Attributes.java b/core/src/main/java/org/spongycastle/asn1/cms/Attributes.java
new file mode 100644
index 00000000..55ac61e9
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/Attributes.java
@@ -0,0 +1,85 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.DLSet;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652">RFC 5652</a> defines
+ * 5 "SET OF Attribute" entities with 5 different names.
+ * This is common implementation for them all:
+ * <pre>
+ * SignedAttributes ::= SET SIZE (1..MAX) OF Attribute
+ * UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute
+ * UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute
+ * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
+ * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * Attributes ::=
+ * SET SIZE(1..MAX) OF Attribute
+ * </pre>
+ */
+public class Attributes
+ extends ASN1Object
+{
+ private ASN1Set attributes;
+
+ private Attributes(ASN1Set set)
+ {
+ attributes = set;
+ }
+
+ public Attributes(ASN1EncodableVector v)
+ {
+ attributes = new DLSet(v);
+ }
+
+ /**
+ * Return an Attribute set object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link Attributes} object
+ * <li> {@link org.spongycastle.asn1.ASN1Set#getInstance(java.lang.Object) ASN1Set} input formats with Attributes structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static Attributes getInstance(Object obj)
+ {
+ if (obj instanceof Attributes)
+ {
+ return (Attributes)obj;
+ }
+ else if (obj != null)
+ {
+ return new Attributes(ASN1Set.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public Attribute[] getAttributes()
+ {
+ Attribute[] rv = new Attribute[attributes.size()];
+
+ for (int i = 0; i != rv.length; i++)
+ {
+ rv[i] = Attribute.getInstance(attributes.getObjectAt(i));
+ }
+
+ return rv;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return attributes;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/AuthEnvelopedData.java b/core/src/main/java/org/spongycastle/asn1/cms/AuthEnvelopedData.java
new file mode 100644
index 00000000..df691133
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/AuthEnvelopedData.java
@@ -0,0 +1,248 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5083">RFC 5083</a>:
+ *
+ * CMS AuthEnveloped Data object.
+ * <p>
+ * ASN.1:
+ * <pre>
+ * id-ct-authEnvelopedData OBJECT IDENTIFIER ::= { iso(1)
+ * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)
+ * smime(16) ct(1) 23 }
+ *
+ * AuthEnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * authEncryptedContentInfo EncryptedContentInfo,
+ * authAttrs [1] IMPLICIT AuthAttributes OPTIONAL,
+ * mac MessageAuthenticationCode,
+ * unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL }
+ * </pre>
+ */
+public class AuthEnvelopedData
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private OriginatorInfo originatorInfo;
+ private ASN1Set recipientInfos;
+ private EncryptedContentInfo authEncryptedContentInfo;
+ private ASN1Set authAttrs;
+ private ASN1OctetString mac;
+ private ASN1Set unauthAttrs;
+
+ public AuthEnvelopedData(
+ OriginatorInfo originatorInfo,
+ ASN1Set recipientInfos,
+ EncryptedContentInfo authEncryptedContentInfo,
+ ASN1Set authAttrs,
+ ASN1OctetString mac,
+ ASN1Set unauthAttrs)
+ {
+ // "It MUST be set to 0."
+ this.version = new ASN1Integer(0);
+
+ this.originatorInfo = originatorInfo;
+
+ // TODO
+ // "There MUST be at least one element in the collection."
+ this.recipientInfos = recipientInfos;
+
+ this.authEncryptedContentInfo = authEncryptedContentInfo;
+
+ // TODO
+ // "The authAttrs MUST be present if the content type carried in
+ // EncryptedContentInfo is not id-data."
+ this.authAttrs = authAttrs;
+
+ this.mac = mac;
+
+ this.unauthAttrs = unauthAttrs;
+ }
+
+ /**
+ * Constructs AuthEnvelopedData by parsing supplied ASN1Sequence
+ * <p>
+ * @param seq An ASN1Sequence with AuthEnvelopedData
+ * @deprecated use getInstance().
+ */
+ public AuthEnvelopedData(
+ ASN1Sequence seq)
+ {
+ int index = 0;
+
+ // TODO
+ // "It MUST be set to 0."
+ ASN1Primitive tmp = seq.getObjectAt(index++).toASN1Primitive();
+ version = (ASN1Integer)tmp;
+
+ tmp = seq.getObjectAt(index++).toASN1Primitive();
+ if (tmp instanceof ASN1TaggedObject)
+ {
+ originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false);
+ tmp = seq.getObjectAt(index++).toASN1Primitive();
+ }
+
+ // TODO
+ // "There MUST be at least one element in the collection."
+ recipientInfos = ASN1Set.getInstance(tmp);
+
+ tmp = seq.getObjectAt(index++).toASN1Primitive();
+ authEncryptedContentInfo = EncryptedContentInfo.getInstance(tmp);
+
+ tmp = seq.getObjectAt(index++).toASN1Primitive();
+ if (tmp instanceof ASN1TaggedObject)
+ {
+ authAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false);
+ tmp = seq.getObjectAt(index++).toASN1Primitive();
+ }
+ else
+ {
+ // TODO
+ // "The authAttrs MUST be present if the content type carried in
+ // EncryptedContentInfo is not id-data."
+ }
+
+ mac = ASN1OctetString.getInstance(tmp);
+
+ if (seq.size() > index)
+ {
+ tmp = seq.getObjectAt(index++).toASN1Primitive();
+ unauthAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false);
+ }
+ }
+
+ /**
+ * Return an AuthEnvelopedData object from a tagged object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats
+ * </ul>
+ *
+
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static AuthEnvelopedData getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return an AuthEnvelopedData object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link AuthEnvelopedData} object
+ * <li> {@link ASN1Sequence org.spongycastle.asn1.ASN1Sequence} input formats with AuthEnvelopedData structure inside
+ * </ul>
+ *
+ * @param obj The object we want converted.
+ * @throws IllegalArgumentException if the object cannot be converted, or was null.
+ */
+ public static AuthEnvelopedData getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof AuthEnvelopedData)
+ {
+ return (AuthEnvelopedData)obj;
+ }
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new AuthEnvelopedData((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("Invalid AuthEnvelopedData: " + obj.getClass().getName());
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public OriginatorInfo getOriginatorInfo()
+ {
+ return originatorInfo;
+ }
+
+ public ASN1Set getRecipientInfos()
+ {
+ return recipientInfos;
+ }
+
+ public EncryptedContentInfo getAuthEncryptedContentInfo()
+ {
+ return authEncryptedContentInfo;
+ }
+
+ public ASN1Set getAuthAttrs()
+ {
+ return authAttrs;
+ }
+
+ public ASN1OctetString getMac()
+ {
+ return mac;
+ }
+
+ public ASN1Set getUnauthAttrs()
+ {
+ return unauthAttrs;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+
+ if (originatorInfo != null)
+ {
+ v.add(new DERTaggedObject(false, 0, originatorInfo));
+ }
+
+ v.add(recipientInfos);
+ v.add(authEncryptedContentInfo);
+
+ // "authAttrs optionally contains the authenticated attributes."
+ if (authAttrs != null)
+ {
+ // "AuthAttributes MUST be DER encoded, even if the rest of the
+ // AuthEnvelopedData structure is BER encoded."
+ v.add(new DERTaggedObject(false, 1, authAttrs));
+ }
+
+ v.add(mac);
+
+ // "unauthAttrs optionally contains the unauthenticated attributes."
+ if (unauthAttrs != null)
+ {
+ v.add(new DERTaggedObject(false, 2, unauthAttrs));
+ }
+
+ return new BERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/AuthEnvelopedDataParser.java b/core/src/main/java/org/spongycastle/asn1/cms/AuthEnvelopedDataParser.java
new file mode 100644
index 00000000..99b238c0
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/AuthEnvelopedDataParser.java
@@ -0,0 +1,157 @@
+package org.spongycastle.asn1.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.ASN1SetParser;
+import org.spongycastle.asn1.ASN1TaggedObjectParser;
+import org.spongycastle.asn1.BERTags;
+
+/**
+ * Parse {@link AuthEnvelopedData} input stream.
+ *
+ * <pre>
+ * AuthEnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * authEncryptedContentInfo EncryptedContentInfo,
+ * authAttrs [1] IMPLICIT AuthAttributes OPTIONAL,
+ * mac MessageAuthenticationCode,
+ * unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL }
+ * </pre>
+ */
+public class AuthEnvelopedDataParser
+{
+ private ASN1SequenceParser seq;
+ private ASN1Integer version;
+ private ASN1Encodable nextObject;
+ private boolean originatorInfoCalled;
+
+ public AuthEnvelopedDataParser(ASN1SequenceParser seq) throws IOException
+ {
+ this.seq = seq;
+
+ // TODO
+ // "It MUST be set to 0."
+ this.version = ASN1Integer.getInstance(seq.readObject());
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public OriginatorInfo getOriginatorInfo()
+ throws IOException
+ {
+ originatorInfoCalled = true;
+
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ if (nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)nextObject).getTagNo() == 0)
+ {
+ ASN1SequenceParser originatorInfo = (ASN1SequenceParser) ((ASN1TaggedObjectParser)nextObject).getObjectParser(BERTags.SEQUENCE, false);
+ nextObject = null;
+ return OriginatorInfo.getInstance(originatorInfo.toASN1Primitive());
+ }
+
+ return null;
+ }
+
+ public ASN1SetParser getRecipientInfos()
+ throws IOException
+ {
+ if (!originatorInfoCalled)
+ {
+ getOriginatorInfo();
+ }
+
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ ASN1SetParser recipientInfos = (ASN1SetParser)nextObject;
+ nextObject = null;
+ return recipientInfos;
+ }
+
+ public EncryptedContentInfoParser getAuthEncryptedContentInfo()
+ throws IOException
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ if (nextObject != null)
+ {
+ ASN1SequenceParser o = (ASN1SequenceParser) nextObject;
+ nextObject = null;
+ return new EncryptedContentInfoParser(o);
+ }
+
+ return null;
+ }
+
+ public ASN1SetParser getAuthAttrs()
+ throws IOException
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ if (nextObject instanceof ASN1TaggedObjectParser)
+ {
+ ASN1Encodable o = nextObject;
+ nextObject = null;
+ return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false);
+ }
+
+ // TODO
+ // "The authAttrs MUST be present if the content type carried in
+ // EncryptedContentInfo is not id-data."
+
+ return null;
+ }
+
+ public ASN1OctetString getMac()
+ throws IOException
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ ASN1Encodable o = nextObject;
+ nextObject = null;
+
+ return ASN1OctetString.getInstance(o.toASN1Primitive());
+ }
+
+ public ASN1SetParser getUnauthAttrs()
+ throws IOException
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ if (nextObject != null)
+ {
+ ASN1Encodable o = nextObject;
+ nextObject = null;
+ return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false);
+ }
+
+ return null;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/AuthenticatedData.java b/core/src/main/java/org/spongycastle/asn1/cms/AuthenticatedData.java
new file mode 100644
index 00000000..474e5216
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/AuthenticatedData.java
@@ -0,0 +1,312 @@
+package org.spongycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-9.1">RFC 5652</a> section 9.1:
+ * The AuthenticatedData carries AuthAttributes and other data
+ * which define what really is being signed.
+ * <p>
+ * <pre>
+ * AuthenticatedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * macAlgorithm MessageAuthenticationCodeAlgorithm,
+ * digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
+ * encapContentInfo EncapsulatedContentInfo,
+ * authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
+ * mac MessageAuthenticationCode,
+ * unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
+ *
+ * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * MessageAuthenticationCode ::= OCTET STRING
+ * </pre>
+ */
+public class AuthenticatedData
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private OriginatorInfo originatorInfo;
+ private ASN1Set recipientInfos;
+ private AlgorithmIdentifier macAlgorithm;
+ private AlgorithmIdentifier digestAlgorithm;
+ private ContentInfo encapsulatedContentInfo;
+ private ASN1Set authAttrs;
+ private ASN1OctetString mac;
+ private ASN1Set unauthAttrs;
+
+ public AuthenticatedData(
+ OriginatorInfo originatorInfo,
+ ASN1Set recipientInfos,
+ AlgorithmIdentifier macAlgorithm,
+ AlgorithmIdentifier digestAlgorithm,
+ ContentInfo encapsulatedContent,
+ ASN1Set authAttrs,
+ ASN1OctetString mac,
+ ASN1Set unauthAttrs)
+ {
+ if (digestAlgorithm != null || authAttrs != null)
+ {
+ if (digestAlgorithm == null || authAttrs == null)
+ {
+ throw new IllegalArgumentException("digestAlgorithm and authAttrs must be set together");
+ }
+ }
+
+ version = new ASN1Integer(calculateVersion(originatorInfo));
+
+ this.originatorInfo = originatorInfo;
+ this.macAlgorithm = macAlgorithm;
+ this.digestAlgorithm = digestAlgorithm;
+ this.recipientInfos = recipientInfos;
+ this.encapsulatedContentInfo = encapsulatedContent;
+ this.authAttrs = authAttrs;
+ this.mac = mac;
+ this.unauthAttrs = unauthAttrs;
+ }
+
+ /**
+ * @deprecated use getInstance()
+ */
+ public AuthenticatedData(
+ ASN1Sequence seq)
+ {
+ int index = 0;
+
+ version = (ASN1Integer)seq.getObjectAt(index++);
+
+ Object tmp = seq.getObjectAt(index++);
+
+ if (tmp instanceof ASN1TaggedObject)
+ {
+ originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false);
+ tmp = seq.getObjectAt(index++);
+ }
+
+ recipientInfos = ASN1Set.getInstance(tmp);
+ macAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(index++));
+
+ tmp = seq.getObjectAt(index++);
+
+ if (tmp instanceof ASN1TaggedObject)
+ {
+ digestAlgorithm = AlgorithmIdentifier.getInstance((ASN1TaggedObject)tmp, false);
+ tmp = seq.getObjectAt(index++);
+ }
+
+ encapsulatedContentInfo = ContentInfo.getInstance(tmp);
+
+ tmp = seq.getObjectAt(index++);
+
+ if (tmp instanceof ASN1TaggedObject)
+ {
+ authAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false);
+ tmp = seq.getObjectAt(index++);
+ }
+
+ mac = ASN1OctetString.getInstance(tmp);
+
+ if (seq.size() > index)
+ {
+ unauthAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false);
+ }
+ }
+
+ /**
+ * Return an AuthenticatedData object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static AuthenticatedData getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return an AuthenticatedData object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link AuthenticatedData} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with AuthenticatedData structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static AuthenticatedData getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof AuthenticatedData)
+ {
+ return (AuthenticatedData)obj;
+ }
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new AuthenticatedData((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("Invalid AuthenticatedData: " + obj.getClass().getName());
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public OriginatorInfo getOriginatorInfo()
+ {
+ return originatorInfo;
+ }
+
+ public ASN1Set getRecipientInfos()
+ {
+ return recipientInfos;
+ }
+
+ public AlgorithmIdentifier getMacAlgorithm()
+ {
+ return macAlgorithm;
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithm()
+ {
+ return digestAlgorithm;
+ }
+
+ public ContentInfo getEncapsulatedContentInfo()
+ {
+ return encapsulatedContentInfo;
+ }
+
+ public ASN1Set getAuthAttrs()
+ {
+ return authAttrs;
+ }
+
+ public ASN1OctetString getMac()
+ {
+ return mac;
+ }
+
+ public ASN1Set getUnauthAttrs()
+ {
+ return unauthAttrs;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+
+ if (originatorInfo != null)
+ {
+ v.add(new DERTaggedObject(false, 0, originatorInfo));
+ }
+
+ v.add(recipientInfos);
+ v.add(macAlgorithm);
+
+ if (digestAlgorithm != null)
+ {
+ v.add(new DERTaggedObject(false, 1, digestAlgorithm));
+ }
+
+ v.add(encapsulatedContentInfo);
+
+ if (authAttrs != null)
+ {
+ v.add(new DERTaggedObject(false, 2, authAttrs));
+ }
+
+ v.add(mac);
+
+ if (unauthAttrs != null)
+ {
+ v.add(new DERTaggedObject(false, 3, unauthAttrs));
+ }
+
+ return new BERSequence(v);
+ }
+
+ public static int calculateVersion(OriginatorInfo origInfo)
+ {
+ if (origInfo == null)
+ {
+ return 0;
+ }
+ else
+ {
+ int ver = 0;
+
+ for (Enumeration e = origInfo.getCertificates().getObjects(); e.hasMoreElements();)
+ {
+ Object obj = e.nextElement();
+
+ if (obj instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tag = (ASN1TaggedObject)obj;
+
+ if (tag.getTagNo() == 2)
+ {
+ ver = 1;
+ }
+ else if (tag.getTagNo() == 3)
+ {
+ ver = 3;
+ break;
+ }
+ }
+ }
+
+ if (origInfo.getCRLs() != null)
+ {
+ for (Enumeration e = origInfo.getCRLs().getObjects(); e.hasMoreElements();)
+ {
+ Object obj = e.nextElement();
+
+ if (obj instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tag = (ASN1TaggedObject)obj;
+
+ if (tag.getTagNo() == 1)
+ {
+ ver = 3;
+ break;
+ }
+ }
+ }
+ }
+
+ return ver;
+ }
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/AuthenticatedDataParser.java b/core/src/main/java/org/spongycastle/asn1/cms/AuthenticatedDataParser.java
new file mode 100644
index 00000000..ea1d4028
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/AuthenticatedDataParser.java
@@ -0,0 +1,206 @@
+package org.spongycastle.asn1.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.ASN1SetParser;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.ASN1TaggedObjectParser;
+import org.spongycastle.asn1.BERTags;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * Parse {@link AuthenticatedData} stream.
+ * <pre>
+ * AuthenticatedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * macAlgorithm MessageAuthenticationCodeAlgorithm,
+ * digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
+ * encapContentInfo EncapsulatedContentInfo,
+ * authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
+ * mac MessageAuthenticationCode,
+ * unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
+ *
+ * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * MessageAuthenticationCode ::= OCTET STRING
+ * </pre>
+ */
+public class AuthenticatedDataParser
+{
+ private ASN1SequenceParser seq;
+ private ASN1Integer version;
+ private ASN1Encodable nextObject;
+ private boolean originatorInfoCalled;
+
+ public AuthenticatedDataParser(
+ ASN1SequenceParser seq)
+ throws IOException
+ {
+ this.seq = seq;
+ this.version = ASN1Integer.getInstance(seq.readObject());
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public OriginatorInfo getOriginatorInfo()
+ throws IOException
+ {
+ originatorInfoCalled = true;
+
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ if (nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)nextObject).getTagNo() == 0)
+ {
+ ASN1SequenceParser originatorInfo = (ASN1SequenceParser) ((ASN1TaggedObjectParser)nextObject).getObjectParser(BERTags.SEQUENCE, false);
+ nextObject = null;
+ return OriginatorInfo.getInstance(originatorInfo.toASN1Primitive());
+ }
+
+ return null;
+ }
+
+ public ASN1SetParser getRecipientInfos()
+ throws IOException
+ {
+ if (!originatorInfoCalled)
+ {
+ getOriginatorInfo();
+ }
+
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ ASN1SetParser recipientInfos = (ASN1SetParser)nextObject;
+ nextObject = null;
+ return recipientInfos;
+ }
+
+ public AlgorithmIdentifier getMacAlgorithm()
+ throws IOException
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ if (nextObject != null)
+ {
+ ASN1SequenceParser o = (ASN1SequenceParser)nextObject;
+ nextObject = null;
+ return AlgorithmIdentifier.getInstance(o.toASN1Primitive());
+ }
+
+ return null;
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithm()
+ throws IOException
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ if (nextObject instanceof ASN1TaggedObjectParser)
+ {
+ AlgorithmIdentifier obj = AlgorithmIdentifier.getInstance((ASN1TaggedObject)nextObject.toASN1Primitive(), false);
+ nextObject = null;
+ return obj;
+ }
+
+ return null;
+ }
+
+ /**
+ * @deprecated use getEncapsulatedContentInfo()
+ */
+ public ContentInfoParser getEnapsulatedContentInfo()
+ throws IOException
+ {
+ return getEncapsulatedContentInfo();
+ }
+
+ public ContentInfoParser getEncapsulatedContentInfo()
+ throws IOException
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ if (nextObject != null)
+ {
+ ASN1SequenceParser o = (ASN1SequenceParser)nextObject;
+ nextObject = null;
+ return new ContentInfoParser(o);
+ }
+
+ return null;
+ }
+
+ public ASN1SetParser getAuthAttrs()
+ throws IOException
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ if (nextObject instanceof ASN1TaggedObjectParser)
+ {
+ ASN1Encodable o = nextObject;
+ nextObject = null;
+ return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false);
+ }
+
+ return null;
+ }
+
+ public ASN1OctetString getMac()
+ throws IOException
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ ASN1Encodable o = nextObject;
+ nextObject = null;
+
+ return ASN1OctetString.getInstance(o.toASN1Primitive());
+ }
+
+ public ASN1SetParser getUnauthAttrs()
+ throws IOException
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.readObject();
+ }
+
+ if (nextObject != null)
+ {
+ ASN1Encodable o = nextObject;
+ nextObject = null;
+ return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false);
+ }
+
+ return null;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/CCMParameters.java b/core/src/main/java/org/spongycastle/asn1/cms/CCMParameters.java
new file mode 100644
index 00000000..1c505449
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/CCMParameters.java
@@ -0,0 +1,102 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.util.Arrays;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5084">RFC 5084</a>: CCMParameters object.
+ * <p>
+ * <pre>
+ CCMParameters ::= SEQUENCE {
+ aes-nonce OCTET STRING, -- recommended size is 12 octets
+ aes-ICVlen AES-CCM-ICVlen DEFAULT 12 }
+ * </pre>
+ */
+public class CCMParameters
+ extends ASN1Object
+{
+ private byte[] nonce;
+ private int icvLen;
+
+ /**
+ * Return an CCMParameters object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link org.spongycastle.asn1.cms.CCMParameters} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(Object) ASN1Sequence} input formats with CCMParameters structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static CCMParameters getInstance(
+ Object obj)
+ {
+ if (obj instanceof CCMParameters)
+ {
+ return (CCMParameters)obj;
+ }
+ else if (obj != null)
+ {
+ return new CCMParameters(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private CCMParameters(
+ ASN1Sequence seq)
+ {
+ this.nonce = ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets();
+
+ if (seq.size() == 2)
+ {
+ this.icvLen = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().intValue();
+ }
+ else
+ {
+ this.icvLen = 12;
+ }
+ }
+
+ public CCMParameters(
+ byte[] nonce,
+ int icvLen)
+ {
+ this.nonce = Arrays.clone(nonce);
+ this.icvLen = icvLen;
+ }
+
+ public byte[] getNonce()
+ {
+ return Arrays.clone(nonce);
+ }
+
+ public int getIcvLen()
+ {
+ return icvLen;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DEROctetString(nonce));
+
+ if (icvLen != 12)
+ {
+ v.add(new ASN1Integer(icvLen));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/CMSAttributes.java b/core/src/main/java/org/spongycastle/asn1/cms/CMSAttributes.java
new file mode 100644
index 00000000..f1b85b59
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/CMSAttributes.java
@@ -0,0 +1,30 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652">RFC 5652</a> CMS attribute OID constants.
+ * <pre>
+ * contentType ::= 1.2.840.113549.1.9.3
+ * messageDigest ::= 1.2.840.113549.1.9.4
+ * signingTime ::= 1.2.840.113549.1.9.5
+ * counterSignature ::= 1.2.840.113549.1.9.6
+ *
+ * contentHint ::= 1.2.840.113549.1.9.16.2.4
+ * </pre>
+ */
+
+public interface CMSAttributes
+{
+ /** PKCS#9: 1.2.840.113549.1.9.3 */
+ public static final ASN1ObjectIdentifier contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType;
+ /** PKCS#9: 1.2.840.113549.1.9.4 */
+ public static final ASN1ObjectIdentifier messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest;
+ /** PKCS#9: 1.2.840.113549.1.9.5 */
+ public static final ASN1ObjectIdentifier signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime;
+ /** PKCS#9: 1.2.840.113549.1.9.6 */
+ public static final ASN1ObjectIdentifier counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature;
+ /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */
+ public static final ASN1ObjectIdentifier contentHint = PKCSObjectIdentifiers.id_aa_contentHint;
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/CMSObjectIdentifiers.java b/core/src/main/java/org/spongycastle/asn1/cms/CMSObjectIdentifiers.java
new file mode 100644
index 00000000..9e38740f
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/CMSObjectIdentifiers.java
@@ -0,0 +1,43 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+public interface CMSObjectIdentifiers
+{
+ /** PKCS#7: 1.2.840.113549.1.7.1 */
+ static final ASN1ObjectIdentifier data = PKCSObjectIdentifiers.data;
+ /** PKCS#7: 1.2.840.113549.1.7.2 */
+ static final ASN1ObjectIdentifier signedData = PKCSObjectIdentifiers.signedData;
+ /** PKCS#7: 1.2.840.113549.1.7.3 */
+ static final ASN1ObjectIdentifier envelopedData = PKCSObjectIdentifiers.envelopedData;
+ /** PKCS#7: 1.2.840.113549.1.7.4 */
+ static final ASN1ObjectIdentifier signedAndEnvelopedData = PKCSObjectIdentifiers.signedAndEnvelopedData;
+ /** PKCS#7: 1.2.840.113549.1.7.5 */
+ static final ASN1ObjectIdentifier digestedData = PKCSObjectIdentifiers.digestedData;
+ /** PKCS#7: 1.2.840.113549.1.7.6 */
+ static final ASN1ObjectIdentifier encryptedData = PKCSObjectIdentifiers.encryptedData;
+ /** PKCS#9: 1.2.840.113549.1.9.16.1.2 -- smime ct authData */
+ static final ASN1ObjectIdentifier authenticatedData = PKCSObjectIdentifiers.id_ct_authData;
+ /** PKCS#9: 1.2.840.113549.1.9.16.1.9 -- smime ct compressedData */
+ static final ASN1ObjectIdentifier compressedData = PKCSObjectIdentifiers.id_ct_compressedData;
+ /** PKCS#9: 1.2.840.113549.1.9.16.1.23 -- smime ct authEnvelopedData */
+ static final ASN1ObjectIdentifier authEnvelopedData = PKCSObjectIdentifiers.id_ct_authEnvelopedData;
+ /** PKCS#9: 1.2.840.113549.1.9.16.1.31 -- smime ct timestampedData*/
+ static final ASN1ObjectIdentifier timestampedData = PKCSObjectIdentifiers.id_ct_timestampedData;
+
+ /**
+ * The other Revocation Info arc
+ * <p>
+ * <pre>
+ * id-ri OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+ * dod(6) internet(1) security(5) mechanisms(5) pkix(7) ri(16) }
+ * </pre>
+ */
+ static final ASN1ObjectIdentifier id_ri = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.16");
+
+ /** 1.3.6.1.5.5.7.16.2 */
+ static final ASN1ObjectIdentifier id_ri_ocsp_response = id_ri.branch("2");
+ /** 1.3.6.1.5.5.7.16.4 */
+ static final ASN1ObjectIdentifier id_ri_scvp = id_ri.branch("4");
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/CompressedData.java b/core/src/main/java/org/spongycastle/asn1/cms/CompressedData.java
new file mode 100644
index 00000000..88d3c458
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/CompressedData.java
@@ -0,0 +1,117 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc3274">RFC 3274</a>: CMS Compressed Data.
+ *
+ * <pre>
+ * CompressedData ::= SEQUENCE {
+ * version CMSVersion,
+ * compressionAlgorithm CompressionAlgorithmIdentifier,
+ * encapContentInfo EncapsulatedContentInfo
+ * }
+ * </pre>
+ */
+public class CompressedData
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private AlgorithmIdentifier compressionAlgorithm;
+ private ContentInfo encapContentInfo;
+
+ public CompressedData(
+ AlgorithmIdentifier compressionAlgorithm,
+ ContentInfo encapContentInfo)
+ {
+ this.version = new ASN1Integer(0);
+ this.compressionAlgorithm = compressionAlgorithm;
+ this.encapContentInfo = encapContentInfo;
+ }
+
+ private CompressedData(
+ ASN1Sequence seq)
+ {
+ this.version = (ASN1Integer)seq.getObjectAt(0);
+ this.compressionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+ this.encapContentInfo = ContentInfo.getInstance(seq.getObjectAt(2));
+ }
+
+ /**
+ * Return a CompressedData object from a tagged object.
+ *
+ * @param ato the tagged object holding the object we want.
+ * @param isExplicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static CompressedData getInstance(
+ ASN1TaggedObject ato,
+ boolean isExplicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(ato, isExplicit));
+ }
+
+ /**
+ * Return a CompressedData object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link CompressedData} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with CompressedData structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static CompressedData getInstance(
+ Object obj)
+ {
+ if (obj instanceof CompressedData)
+ {
+ return (CompressedData)obj;
+ }
+
+ if (obj != null)
+ {
+ return new CompressedData(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public AlgorithmIdentifier getCompressionAlgorithmIdentifier()
+ {
+ return compressionAlgorithm;
+ }
+
+ public ContentInfo getEncapContentInfo()
+ {
+ return encapContentInfo;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(compressionAlgorithm);
+ v.add(encapContentInfo);
+
+ return new BERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/CompressedDataParser.java b/core/src/main/java/org/spongycastle/asn1/cms/CompressedDataParser.java
new file mode 100644
index 00000000..913cecb8
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/CompressedDataParser.java
@@ -0,0 +1,49 @@
+package org.spongycastle.asn1.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * Parser of <a href="http://tools.ietf.org/html/rfc3274">RFC 3274</a> {@link CompressedData} object.
+ * <p>
+ * <pre>
+ * CompressedData ::= SEQUENCE {
+ * version CMSVersion,
+ * compressionAlgorithm CompressionAlgorithmIdentifier,
+ * encapContentInfo EncapsulatedContentInfo
+ * }
+ * </pre>
+ */
+public class CompressedDataParser
+{
+ private ASN1Integer _version;
+ private AlgorithmIdentifier _compressionAlgorithm;
+ private ContentInfoParser _encapContentInfo;
+
+ public CompressedDataParser(
+ ASN1SequenceParser seq)
+ throws IOException
+ {
+ this._version = (ASN1Integer)seq.readObject();
+ this._compressionAlgorithm = AlgorithmIdentifier.getInstance(seq.readObject().toASN1Primitive());
+ this._encapContentInfo = new ContentInfoParser((ASN1SequenceParser)seq.readObject());
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return _version;
+ }
+
+ public AlgorithmIdentifier getCompressionAlgorithmIdentifier()
+ {
+ return _compressionAlgorithm;
+ }
+
+ public ContentInfoParser getEncapContentInfo()
+ {
+ return _encapContentInfo;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/ContentInfo.java b/core/src/main/java/org/spongycastle/asn1/cms/ContentInfo.java
new file mode 100644
index 00000000..7616a7e5
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/ContentInfo.java
@@ -0,0 +1,130 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.BERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-3">RFC 5652</a> ContentInfo, and
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.2">RFC 5652</a> EncapsulatedContentInfo objects.
+ *
+ * <pre>
+ * ContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
+ * }
+ *
+ * EncapsulatedContentInfo ::= SEQUENCE {
+ * eContentType ContentType,
+ * eContent [0] EXPLICIT OCTET STRING OPTIONAL
+ * }
+ * </pre>
+ */
+public class ContentInfo
+ extends ASN1Object
+ implements CMSObjectIdentifiers
+{
+ private ASN1ObjectIdentifier contentType;
+ private ASN1Encodable content;
+
+ /**
+ * Return an ContentInfo object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link ContentInfo} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with ContentInfo structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static ContentInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof ContentInfo)
+ {
+ return (ContentInfo)obj;
+ }
+ else if (obj != null)
+ {
+ return new ContentInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public static ContentInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * @deprecated use getInstance()
+ */
+ public ContentInfo(
+ ASN1Sequence seq)
+ {
+ if (seq.size() < 1 || seq.size() > 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+ }
+
+ contentType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+
+ if (seq.size() > 1)
+ {
+ ASN1TaggedObject tagged = (ASN1TaggedObject)seq.getObjectAt(1);
+ if (!tagged.isExplicit() || tagged.getTagNo() != 0)
+ {
+ throw new IllegalArgumentException("Bad tag for 'content'");
+ }
+
+ content = tagged.getObject();
+ }
+ }
+
+ public ContentInfo(
+ ASN1ObjectIdentifier contentType,
+ ASN1Encodable content)
+ {
+ this.contentType = contentType;
+ this.content = content;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return contentType;
+ }
+
+ public ASN1Encodable getContent()
+ {
+ return content;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(contentType);
+
+ if (content != null)
+ {
+ v.add(new BERTaggedObject(0, content));
+ }
+
+ return new BERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/ContentInfoParser.java b/core/src/main/java/org/spongycastle/asn1/cms/ContentInfoParser.java
new file mode 100644
index 00000000..3951a4ed
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/ContentInfoParser.java
@@ -0,0 +1,48 @@
+package org.spongycastle.asn1.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.ASN1TaggedObjectParser;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-3">RFC 5652</a> {@link ContentInfo} object parser.
+ *
+ * <pre>
+ * ContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+ * </pre>
+ */
+public class ContentInfoParser
+{
+ private ASN1ObjectIdentifier contentType;
+ private ASN1TaggedObjectParser content;
+
+ public ContentInfoParser(
+ ASN1SequenceParser seq)
+ throws IOException
+ {
+ contentType = (ASN1ObjectIdentifier)seq.readObject();
+ content = (ASN1TaggedObjectParser)seq.readObject();
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return contentType;
+ }
+
+ public ASN1Encodable getContent(
+ int tag)
+ throws IOException
+ {
+ if (content != null)
+ {
+ return content.getObjectParser(tag, true);
+ }
+
+ return null;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/DigestedData.java b/core/src/main/java/org/spongycastle/asn1/cms/DigestedData.java
new file mode 100644
index 00000000..e20a4178
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/DigestedData.java
@@ -0,0 +1,128 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-7">RFC 5652</a> DigestedData object.
+ * <pre>
+ * DigestedData ::= SEQUENCE {
+ * version CMSVersion,
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * encapContentInfo EncapsulatedContentInfo,
+ * digest Digest }
+ * </pre>
+ */
+public class DigestedData
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private AlgorithmIdentifier digestAlgorithm;
+ private ContentInfo encapContentInfo;
+ private ASN1OctetString digest;
+
+ public DigestedData(
+ AlgorithmIdentifier digestAlgorithm,
+ ContentInfo encapContentInfo,
+ byte[] digest)
+ {
+ this.version = new ASN1Integer(0);
+ this.digestAlgorithm = digestAlgorithm;
+ this.encapContentInfo = encapContentInfo;
+ this.digest = new DEROctetString(digest);
+ }
+
+ private DigestedData(
+ ASN1Sequence seq)
+ {
+ this.version = (ASN1Integer)seq.getObjectAt(0);
+ this.digestAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+ this.encapContentInfo = ContentInfo.getInstance(seq.getObjectAt(2));
+ this.digest = ASN1OctetString.getInstance(seq.getObjectAt(3));
+ }
+
+ /**
+ * Return a DigestedData object from a tagged object.
+ *
+ * @param ato the tagged object holding the object we want.
+ * @param isExplicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static DigestedData getInstance(
+ ASN1TaggedObject ato,
+ boolean isExplicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(ato, isExplicit));
+ }
+
+ /**
+ * Return a DigestedData object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link DigestedData} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static DigestedData getInstance(
+ Object obj)
+ {
+ if (obj instanceof DigestedData)
+ {
+ return (DigestedData)obj;
+ }
+
+ if (obj != null)
+ {
+ return new DigestedData(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithm()
+ {
+ return digestAlgorithm;
+ }
+
+ public ContentInfo getEncapContentInfo()
+ {
+ return encapContentInfo;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(digestAlgorithm);
+ v.add(encapContentInfo);
+ v.add(digest);
+
+ return new BERSequence(v);
+ }
+
+ public byte[] getDigest()
+ {
+ return digest.getOctets();
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/EncryptedContentInfo.java b/core/src/main/java/org/spongycastle/asn1/cms/EncryptedContentInfo.java
new file mode 100644
index 00000000..9fcd591c
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/EncryptedContentInfo.java
@@ -0,0 +1,120 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.BERTaggedObject;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.1">RFC 5652</a> EncryptedContentInfo object.
+ *
+ * <pre>
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * }
+ * </pre>
+ */
+public class EncryptedContentInfo
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier contentType;
+ private AlgorithmIdentifier contentEncryptionAlgorithm;
+ private ASN1OctetString encryptedContent;
+
+ public EncryptedContentInfo(
+ ASN1ObjectIdentifier contentType,
+ AlgorithmIdentifier contentEncryptionAlgorithm,
+ ASN1OctetString encryptedContent)
+ {
+ this.contentType = contentType;
+ this.contentEncryptionAlgorithm = contentEncryptionAlgorithm;
+ this.encryptedContent = encryptedContent;
+ }
+
+ private EncryptedContentInfo(
+ ASN1Sequence seq)
+ {
+ if (seq.size() < 2)
+ {
+ throw new IllegalArgumentException("Truncated Sequence Found");
+ }
+
+ contentType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+ contentEncryptionAlgorithm = AlgorithmIdentifier.getInstance(
+ seq.getObjectAt(1));
+ if (seq.size() > 2)
+ {
+ encryptedContent = ASN1OctetString.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(2), false);
+ }
+ }
+
+ /**
+ * Return an EncryptedContentInfo object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link EncryptedContentInfo} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static EncryptedContentInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof EncryptedContentInfo)
+ {
+ return (EncryptedContentInfo)obj;
+ }
+ if (obj != null)
+ {
+ return new EncryptedContentInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return contentType;
+ }
+
+ public AlgorithmIdentifier getContentEncryptionAlgorithm()
+ {
+ return contentEncryptionAlgorithm;
+ }
+
+ public ASN1OctetString getEncryptedContent()
+ {
+ return encryptedContent;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(contentType);
+ v.add(contentEncryptionAlgorithm);
+
+ if (encryptedContent != null)
+ {
+ v.add(new BERTaggedObject(false, 0, encryptedContent));
+ }
+
+ return new BERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/EncryptedContentInfoParser.java b/core/src/main/java/org/spongycastle/asn1/cms/EncryptedContentInfoParser.java
new file mode 100644
index 00000000..9c5f38d2
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/EncryptedContentInfoParser.java
@@ -0,0 +1,53 @@
+package org.spongycastle.asn1.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.ASN1TaggedObjectParser;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * Parser for <a href="http://tools.ietf.org/html/rfc5652#section-6.1">RFC 5652</a> EncryptedContentInfo object.
+ * <p>
+ * <pre>
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * }
+ * </pre>
+ */
+public class EncryptedContentInfoParser
+{
+ private ASN1ObjectIdentifier _contentType;
+ private AlgorithmIdentifier _contentEncryptionAlgorithm;
+ private ASN1TaggedObjectParser _encryptedContent;
+
+ public EncryptedContentInfoParser(
+ ASN1SequenceParser seq)
+ throws IOException
+ {
+ _contentType = (ASN1ObjectIdentifier)seq.readObject();
+ _contentEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.readObject().toASN1Primitive());
+ _encryptedContent = (ASN1TaggedObjectParser)seq.readObject();
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return _contentType;
+ }
+
+ public AlgorithmIdentifier getContentEncryptionAlgorithm()
+ {
+ return _contentEncryptionAlgorithm;
+ }
+
+ public ASN1Encodable getEncryptedContent(
+ int tag)
+ throws IOException
+ {
+ return _encryptedContent.getObjectParser(tag, false);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/EncryptedData.java b/core/src/main/java/org/spongycastle/asn1/cms/EncryptedData.java
new file mode 100644
index 00000000..69b86781
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/EncryptedData.java
@@ -0,0 +1,111 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.BERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-8">RFC 5652</a> EncryptedData object.
+ * <p>
+ * <pre>
+ * EncryptedData ::= SEQUENCE {
+ * version CMSVersion,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }
+ * </pre>
+ */
+public class EncryptedData
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private EncryptedContentInfo encryptedContentInfo;
+ private ASN1Set unprotectedAttrs;
+
+ /**
+ * Return an EncryptedData object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link EncryptedData} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats
+ * </ul>
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static EncryptedData getInstance(Object o)
+ {
+ if (o instanceof EncryptedData)
+ {
+ return (EncryptedData)o;
+ }
+
+ if (o != null)
+ {
+ return new EncryptedData(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public EncryptedData(EncryptedContentInfo encInfo)
+ {
+ this(encInfo, null);
+ }
+
+ public EncryptedData(EncryptedContentInfo encInfo, ASN1Set unprotectedAttrs)
+ {
+ this.version = new ASN1Integer((unprotectedAttrs == null) ? 0 : 2);
+ this.encryptedContentInfo = encInfo;
+ this.unprotectedAttrs = unprotectedAttrs;
+ }
+
+ private EncryptedData(ASN1Sequence seq)
+ {
+ this.version = ASN1Integer.getInstance(seq.getObjectAt(0));
+ this.encryptedContentInfo = EncryptedContentInfo.getInstance(seq.getObjectAt(1));
+
+ if (seq.size() == 3)
+ {
+ this.unprotectedAttrs = ASN1Set.getInstance(seq.getObjectAt(2));
+ }
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public EncryptedContentInfo getEncryptedContentInfo()
+ {
+ return encryptedContentInfo;
+ }
+
+ public ASN1Set getUnprotectedAttrs()
+ {
+ return unprotectedAttrs;
+ }
+
+ /**
+ * @return a basic ASN.1 object representation.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(encryptedContentInfo);
+ if (unprotectedAttrs != null)
+ {
+ v.add(new BERTaggedObject(false, 1, unprotectedAttrs));
+ }
+
+ return new BERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/EnvelopedData.java b/core/src/main/java/org/spongycastle/asn1/cms/EnvelopedData.java
new file mode 100644
index 00000000..ac9b483f
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/EnvelopedData.java
@@ -0,0 +1,215 @@
+package org.spongycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.1">RFC 5652</a> EnvelopedData object.
+ * <pre>
+ * EnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
+ * }
+ * </pre>
+ */
+public class EnvelopedData
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private OriginatorInfo originatorInfo;
+ private ASN1Set recipientInfos;
+ private EncryptedContentInfo encryptedContentInfo;
+ private ASN1Set unprotectedAttrs;
+
+ public EnvelopedData(
+ OriginatorInfo originatorInfo,
+ ASN1Set recipientInfos,
+ EncryptedContentInfo encryptedContentInfo,
+ ASN1Set unprotectedAttrs)
+ {
+ version = new ASN1Integer(calculateVersion(originatorInfo, recipientInfos, unprotectedAttrs));
+
+ this.originatorInfo = originatorInfo;
+ this.recipientInfos = recipientInfos;
+ this.encryptedContentInfo = encryptedContentInfo;
+ this.unprotectedAttrs = unprotectedAttrs;
+ }
+
+ public EnvelopedData(
+ OriginatorInfo originatorInfo,
+ ASN1Set recipientInfos,
+ EncryptedContentInfo encryptedContentInfo,
+ Attributes unprotectedAttrs)
+ {
+ version = new ASN1Integer(calculateVersion(originatorInfo, recipientInfos, ASN1Set.getInstance(unprotectedAttrs)));
+
+ this.originatorInfo = originatorInfo;
+ this.recipientInfos = recipientInfos;
+ this.encryptedContentInfo = encryptedContentInfo;
+ this.unprotectedAttrs = ASN1Set.getInstance(unprotectedAttrs);
+ }
+
+ /**
+ * @deprecated use getInstance()
+ */
+ public EnvelopedData(
+ ASN1Sequence seq)
+ {
+ int index = 0;
+
+ version = (ASN1Integer)seq.getObjectAt(index++);
+
+ Object tmp = seq.getObjectAt(index++);
+
+ if (tmp instanceof ASN1TaggedObject)
+ {
+ originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false);
+ tmp = seq.getObjectAt(index++);
+ }
+
+ recipientInfos = ASN1Set.getInstance(tmp);
+
+ encryptedContentInfo = EncryptedContentInfo.getInstance(seq.getObjectAt(index++));
+
+ if(seq.size() > index)
+ {
+ unprotectedAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false);
+ }
+ }
+
+ /**
+ * Return an EnvelopedData object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static EnvelopedData getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return an EnvelopedData object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link EnvelopedData} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with EnvelopedData structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static EnvelopedData getInstance(
+ Object obj)
+ {
+ if (obj instanceof EnvelopedData)
+ {
+ return (EnvelopedData)obj;
+ }
+
+ if (obj != null)
+ {
+ return new EnvelopedData(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public OriginatorInfo getOriginatorInfo()
+ {
+ return originatorInfo;
+ }
+
+ public ASN1Set getRecipientInfos()
+ {
+ return recipientInfos;
+ }
+
+ public EncryptedContentInfo getEncryptedContentInfo()
+ {
+ return encryptedContentInfo;
+ }
+
+ public ASN1Set getUnprotectedAttrs()
+ {
+ return unprotectedAttrs;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+
+ if (originatorInfo != null)
+ {
+ v.add(new DERTaggedObject(false, 0, originatorInfo));
+ }
+
+ v.add(recipientInfos);
+ v.add(encryptedContentInfo);
+
+ if (unprotectedAttrs != null)
+ {
+ v.add(new DERTaggedObject(false, 1, unprotectedAttrs));
+ }
+
+ return new BERSequence(v);
+ }
+
+ public static int calculateVersion(OriginatorInfo originatorInfo, ASN1Set recipientInfos, ASN1Set unprotectedAttrs)
+ {
+ int version;
+
+ if (originatorInfo != null || unprotectedAttrs != null)
+ {
+ version = 2;
+ }
+ else
+ {
+ version = 0;
+
+ Enumeration e = recipientInfos.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ RecipientInfo ri = RecipientInfo.getInstance(e.nextElement());
+
+ if (ri.getVersion().getValue().intValue() != version)
+ {
+ version = 2;
+ break;
+ }
+ }
+ }
+
+ return version;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/EnvelopedDataParser.java b/core/src/main/java/org/spongycastle/asn1/cms/EnvelopedDataParser.java
new file mode 100644
index 00000000..534a27c0
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/EnvelopedDataParser.java
@@ -0,0 +1,120 @@
+package org.spongycastle.asn1.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.ASN1SetParser;
+import org.spongycastle.asn1.ASN1TaggedObjectParser;
+import org.spongycastle.asn1.BERTags;
+
+/**
+ * Parser of <a href="http://tools.ietf.org/html/rfc5652#section-6.1">RFC 5652</a> {@link EnvelopedData} object.
+ * <p>
+ * <pre>
+ * EnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
+ * }
+ * </pre>
+ */
+public class EnvelopedDataParser
+{
+ private ASN1SequenceParser _seq;
+ private ASN1Integer _version;
+ private ASN1Encodable _nextObject;
+ private boolean _originatorInfoCalled;
+
+ public EnvelopedDataParser(
+ ASN1SequenceParser seq)
+ throws IOException
+ {
+ this._seq = seq;
+ this._version = ASN1Integer.getInstance(seq.readObject());
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return _version;
+ }
+
+ public OriginatorInfo getOriginatorInfo()
+ throws IOException
+ {
+ _originatorInfoCalled = true;
+
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.readObject();
+ }
+
+ if (_nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)_nextObject).getTagNo() == 0)
+ {
+ ASN1SequenceParser originatorInfo = (ASN1SequenceParser) ((ASN1TaggedObjectParser)_nextObject).getObjectParser(BERTags.SEQUENCE, false);
+ _nextObject = null;
+ return OriginatorInfo.getInstance(originatorInfo.toASN1Primitive());
+ }
+
+ return null;
+ }
+
+ public ASN1SetParser getRecipientInfos()
+ throws IOException
+ {
+ if (!_originatorInfoCalled)
+ {
+ getOriginatorInfo();
+ }
+
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.readObject();
+ }
+
+ ASN1SetParser recipientInfos = (ASN1SetParser)_nextObject;
+ _nextObject = null;
+ return recipientInfos;
+ }
+
+ public EncryptedContentInfoParser getEncryptedContentInfo()
+ throws IOException
+ {
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.readObject();
+ }
+
+
+ if (_nextObject != null)
+ {
+ ASN1SequenceParser o = (ASN1SequenceParser) _nextObject;
+ _nextObject = null;
+ return new EncryptedContentInfoParser(o);
+ }
+
+ return null;
+ }
+
+ public ASN1SetParser getUnprotectedAttrs()
+ throws IOException
+ {
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.readObject();
+ }
+
+
+ if (_nextObject != null)
+ {
+ ASN1Encodable o = _nextObject;
+ _nextObject = null;
+ return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false);
+ }
+
+ return null;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/Evidence.java b/core/src/main/java/org/spongycastle/asn1/cms/Evidence.java
new file mode 100644
index 00000000..a8b173f9
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/Evidence.java
@@ -0,0 +1,80 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Choice;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5544">RFC 5544</a>:
+ * Binding Documents with Time-Stamps; Evidence object.
+ * <p>
+ * <pre>
+ * Evidence ::= CHOICE {
+ * tstEvidence [0] TimeStampTokenEvidence, -- see RFC 3161
+ * ersEvidence [1] EvidenceRecord, -- see RFC 4998
+ * otherEvidence [2] OtherEvidence
+ * }
+ * </pre>
+ */
+public class Evidence
+ extends ASN1Object
+ implements ASN1Choice
+{
+ private TimeStampTokenEvidence tstEvidence;
+
+ public Evidence(TimeStampTokenEvidence tstEvidence)
+ {
+ this.tstEvidence = tstEvidence;
+ }
+
+ private Evidence(ASN1TaggedObject tagged)
+ {
+ if (tagged.getTagNo() == 0)
+ {
+ this.tstEvidence = TimeStampTokenEvidence.getInstance(tagged, false);
+ }
+ }
+
+ /**
+ * Return an Evidence object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> {@link Evidence} object
+ * <li> {@link org.spongycastle.asn1.ASN1TaggedObject#getInstance(java.lang.Object) ASN1TaggedObject} input formats with Evidence data inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static Evidence getInstance(Object obj)
+ {
+ if (obj == null || obj instanceof Evidence)
+ {
+ return (Evidence)obj;
+ }
+ else if (obj instanceof ASN1TaggedObject)
+ {
+ return new Evidence(ASN1TaggedObject.getInstance(obj));
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance");
+ }
+
+ public TimeStampTokenEvidence getTstEvidence()
+ {
+ return tstEvidence;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ if (tstEvidence != null)
+ {
+ return new DERTaggedObject(false, 0, tstEvidence);
+ }
+
+ return null;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/GCMParameters.java b/core/src/main/java/org/spongycastle/asn1/cms/GCMParameters.java
new file mode 100644
index 00000000..131b1899
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/GCMParameters.java
@@ -0,0 +1,102 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.util.Arrays;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5084">RFC 5084</a>: GCMParameters object.
+ * <p>
+ * <pre>
+ GCMParameters ::= SEQUENCE {
+ aes-nonce OCTET STRING, -- recommended size is 12 octets
+ aes-ICVlen AES-GCM-ICVlen DEFAULT 12 }
+ * </pre>
+ */
+public class GCMParameters
+ extends ASN1Object
+{
+ private byte[] nonce;
+ private int icvLen;
+
+ /**
+ * Return an GCMParameters object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link org.spongycastle.asn1.cms.GCMParameters} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(Object) ASN1Sequence} input formats with GCMParameters structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static GCMParameters getInstance(
+ Object obj)
+ {
+ if (obj instanceof GCMParameters)
+ {
+ return (GCMParameters)obj;
+ }
+ else if (obj != null)
+ {
+ return new GCMParameters(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private GCMParameters(
+ ASN1Sequence seq)
+ {
+ this.nonce = ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets();
+
+ if (seq.size() == 2)
+ {
+ this.icvLen = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().intValue();
+ }
+ else
+ {
+ this.icvLen = 12;
+ }
+ }
+
+ public GCMParameters(
+ byte[] nonce,
+ int icvLen)
+ {
+ this.nonce = Arrays.clone(nonce);
+ this.icvLen = icvLen;
+ }
+
+ public byte[] getNonce()
+ {
+ return Arrays.clone(nonce);
+ }
+
+ public int getIcvLen()
+ {
+ return icvLen;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DEROctetString(nonce));
+
+ if (icvLen != 12)
+ {
+ v.add(new ASN1Integer(icvLen));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/IssuerAndSerialNumber.java b/core/src/main/java/org/spongycastle/asn1/cms/IssuerAndSerialNumber.java
new file mode 100644
index 00000000..2b32efbe
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/IssuerAndSerialNumber.java
@@ -0,0 +1,138 @@
+package org.spongycastle.asn1.cms;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.X509CertificateStructure;
+import org.spongycastle.asn1.x509.X509Name;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-10.2.4">RFC 5652</a>: IssuerAndSerialNumber object.
+ * <p>
+ * <pre>
+ * IssuerAndSerialNumber ::= SEQUENCE {
+ * issuer Name,
+ * serialNumber CertificateSerialNumber
+ * }
+ *
+ * CertificateSerialNumber ::= INTEGER -- See RFC 5280
+ * </pre>
+ */
+public class IssuerAndSerialNumber
+ extends ASN1Object
+{
+ private X500Name name;
+ private ASN1Integer serialNumber;
+
+ /**
+ * Return an IssuerAndSerialNumber object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link IssuerAndSerialNumber} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with IssuerAndSerialNumber structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static IssuerAndSerialNumber getInstance(
+ Object obj)
+ {
+ if (obj instanceof IssuerAndSerialNumber)
+ {
+ return (IssuerAndSerialNumber)obj;
+ }
+ else if (obj != null)
+ {
+ return new IssuerAndSerialNumber(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * @deprecated use getInstance() method.
+ */
+ public IssuerAndSerialNumber(
+ ASN1Sequence seq)
+ {
+ this.name = X500Name.getInstance(seq.getObjectAt(0));
+ this.serialNumber = (ASN1Integer)seq.getObjectAt(1);
+ }
+
+ public IssuerAndSerialNumber(
+ Certificate certificate)
+ {
+ this.name = certificate.getIssuer();
+ this.serialNumber = certificate.getSerialNumber();
+ }
+
+ /**
+ * @deprecated use constructor taking Certificate
+ */
+ public IssuerAndSerialNumber(
+ X509CertificateStructure certificate)
+ {
+ this.name = certificate.getIssuer();
+ this.serialNumber = certificate.getSerialNumber();
+ }
+
+ public IssuerAndSerialNumber(
+ X500Name name,
+ BigInteger serialNumber)
+ {
+ this.name = name;
+ this.serialNumber = new ASN1Integer(serialNumber);
+ }
+
+ /**
+ * @deprecated use X500Name constructor
+ */
+ public IssuerAndSerialNumber(
+ X509Name name,
+ BigInteger serialNumber)
+ {
+ this.name = X500Name.getInstance(name);
+ this.serialNumber = new ASN1Integer(serialNumber);
+ }
+
+ /**
+ * @deprecated use X500Name constructor
+ */
+ public IssuerAndSerialNumber(
+ X509Name name,
+ ASN1Integer serialNumber)
+ {
+ this.name = X500Name.getInstance(name);
+ this.serialNumber = serialNumber;
+ }
+
+ public X500Name getName()
+ {
+ return name;
+ }
+
+ public ASN1Integer getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(name);
+ v.add(serialNumber);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/KEKIdentifier.java b/core/src/main/java/org/spongycastle/asn1/cms/KEKIdentifier.java
new file mode 100644
index 00000000..951c3ce7
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/KEKIdentifier.java
@@ -0,0 +1,151 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.3">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <p>
+ * <pre>
+ * KEKIdentifier ::= SEQUENCE {
+ * keyIdentifier OCTET STRING,
+ * date GeneralizedTime OPTIONAL,
+ * other OtherKeyAttribute OPTIONAL
+ * }
+ * </pre>
+ */
+public class KEKIdentifier
+ extends ASN1Object
+{
+ private ASN1OctetString keyIdentifier;
+ private ASN1GeneralizedTime date;
+ private OtherKeyAttribute other;
+
+ public KEKIdentifier(
+ byte[] keyIdentifier,
+ ASN1GeneralizedTime date,
+ OtherKeyAttribute other)
+ {
+ this.keyIdentifier = new DEROctetString(keyIdentifier);
+ this.date = date;
+ this.other = other;
+ }
+
+ private KEKIdentifier(
+ ASN1Sequence seq)
+ {
+ keyIdentifier = (ASN1OctetString)seq.getObjectAt(0);
+
+ switch (seq.size())
+ {
+ case 1:
+ break;
+ case 2:
+ if (seq.getObjectAt(1) instanceof ASN1GeneralizedTime)
+ {
+ date = (ASN1GeneralizedTime)seq.getObjectAt(1);
+ }
+ else
+ {
+ other = OtherKeyAttribute.getInstance(seq.getObjectAt(1));
+ }
+ break;
+ case 3:
+ date = (ASN1GeneralizedTime)seq.getObjectAt(1);
+ other = OtherKeyAttribute.getInstance(seq.getObjectAt(2));
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid KEKIdentifier");
+ }
+ }
+
+ /**
+ * Return a KEKIdentifier object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static KEKIdentifier getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return a KEKIdentifier object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link KEKIdentifier} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with KEKIdentifier structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static KEKIdentifier getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof KEKIdentifier)
+ {
+ return (KEKIdentifier)obj;
+ }
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new KEKIdentifier((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("Invalid KEKIdentifier: " + obj.getClass().getName());
+ }
+
+ public ASN1OctetString getKeyIdentifier()
+ {
+ return keyIdentifier;
+ }
+
+ public ASN1GeneralizedTime getDate()
+ {
+ return date;
+ }
+
+ public OtherKeyAttribute getOther()
+ {
+ return other;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(keyIdentifier);
+
+ if (date != null)
+ {
+ v.add(date);
+ }
+
+ if (other != null)
+ {
+ v.add(other);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/KEKRecipientInfo.java b/core/src/main/java/org/spongycastle/asn1/cms/KEKRecipientInfo.java
new file mode 100644
index 00000000..42151ce4
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/KEKRecipientInfo.java
@@ -0,0 +1,133 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.3">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <p>
+ * <pre>
+ * KEKRecipientInfo ::= SEQUENCE {
+ * version CMSVersion, -- always set to 4
+ * kekid KEKIdentifier,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey
+ * }
+ * </pre>
+ */
+public class KEKRecipientInfo
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private KEKIdentifier kekid;
+ private AlgorithmIdentifier keyEncryptionAlgorithm;
+ private ASN1OctetString encryptedKey;
+
+ public KEKRecipientInfo(
+ KEKIdentifier kekid,
+ AlgorithmIdentifier keyEncryptionAlgorithm,
+ ASN1OctetString encryptedKey)
+ {
+ this.version = new ASN1Integer(4);
+ this.kekid = kekid;
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.encryptedKey = encryptedKey;
+ }
+
+ public KEKRecipientInfo(
+ ASN1Sequence seq)
+ {
+ version = (ASN1Integer)seq.getObjectAt(0);
+ kekid = KEKIdentifier.getInstance(seq.getObjectAt(1));
+ keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2));
+ encryptedKey = (ASN1OctetString)seq.getObjectAt(3);
+ }
+
+ /**
+ * Return a KEKRecipientInfo object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static KEKRecipientInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return a KEKRecipientInfo object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link KEKRecipientInfo} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with KEKRecipientInfo structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static KEKRecipientInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof KEKRecipientInfo)
+ {
+ return (KEKRecipientInfo)obj;
+ }
+
+ if (obj != null)
+ {
+ return new KEKRecipientInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public KEKIdentifier getKekid()
+ {
+ return kekid;
+ }
+
+ public AlgorithmIdentifier getKeyEncryptionAlgorithm()
+ {
+ return keyEncryptionAlgorithm;
+ }
+
+ public ASN1OctetString getEncryptedKey()
+ {
+ return encryptedKey;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(kekid);
+ v.add(keyEncryptionAlgorithm);
+ v.add(encryptedKey);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/KeyAgreeRecipientIdentifier.java b/core/src/main/java/org/spongycastle/asn1/cms/KeyAgreeRecipientIdentifier.java
new file mode 100644
index 00000000..f3de2bc1
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/KeyAgreeRecipientIdentifier.java
@@ -0,0 +1,116 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Choice;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.2">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <p>
+ * <pre>
+ * KeyAgreeRecipientIdentifier ::= CHOICE {
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * rKeyId [0] IMPLICIT RecipientKeyIdentifier }
+ * </pre>
+ */
+public class KeyAgreeRecipientIdentifier
+ extends ASN1Object
+ implements ASN1Choice
+{
+ private IssuerAndSerialNumber issuerSerial;
+ private RecipientKeyIdentifier rKeyID;
+
+ /**
+ * Return an KeyAgreeRecipientIdentifier object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static KeyAgreeRecipientIdentifier getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return an KeyAgreeRecipientIdentifier object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> {@link KeyAgreeRecipientIdentifier} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with IssuerAndSerialNumber structure inside
+ * <li> {@link org.spongycastle.asn1.ASN1TaggedObject#getInstance(java.lang.Object) ASN1TaggedObject} with tag value 0: a KeyAgreeRecipientIdentifier data structure
+ * </ul>
+ * <p>
+ * Note: no byte[] input!
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static KeyAgreeRecipientIdentifier getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof KeyAgreeRecipientIdentifier)
+ {
+ return (KeyAgreeRecipientIdentifier)obj;
+ }
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new KeyAgreeRecipientIdentifier(IssuerAndSerialNumber.getInstance(obj));
+ }
+
+ if (obj instanceof ASN1TaggedObject && ((ASN1TaggedObject)obj).getTagNo() == 0)
+ {
+ return new KeyAgreeRecipientIdentifier(RecipientKeyIdentifier.getInstance(
+ (ASN1TaggedObject)obj, false));
+ }
+
+ throw new IllegalArgumentException("Invalid KeyAgreeRecipientIdentifier: " + obj.getClass().getName());
+ }
+
+ public KeyAgreeRecipientIdentifier(
+ IssuerAndSerialNumber issuerSerial)
+ {
+ this.issuerSerial = issuerSerial;
+ this.rKeyID = null;
+ }
+
+ public KeyAgreeRecipientIdentifier(
+ RecipientKeyIdentifier rKeyID)
+ {
+ this.issuerSerial = null;
+ this.rKeyID = rKeyID;
+ }
+
+ public IssuerAndSerialNumber getIssuerAndSerialNumber()
+ {
+ return issuerSerial;
+ }
+
+ public RecipientKeyIdentifier getRKeyID()
+ {
+ return rKeyID;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ if (issuerSerial != null)
+ {
+ return issuerSerial.toASN1Primitive();
+ }
+
+ return new DERTaggedObject(false, 0, rKeyID);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/KeyAgreeRecipientInfo.java b/core/src/main/java/org/spongycastle/asn1/cms/KeyAgreeRecipientInfo.java
new file mode 100644
index 00000000..28a1edc2
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/KeyAgreeRecipientInfo.java
@@ -0,0 +1,166 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.2">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <p>
+ * <pre>
+ * KeyAgreeRecipientInfo ::= SEQUENCE {
+ * version CMSVersion, -- always set to 3
+ * originator [0] EXPLICIT OriginatorIdentifierOrKey,
+ * ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * recipientEncryptedKeys RecipientEncryptedKeys
+ * }
+ *
+ * UserKeyingMaterial ::= OCTET STRING
+ * </pre>
+ */
+public class KeyAgreeRecipientInfo
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private OriginatorIdentifierOrKey originator;
+ private ASN1OctetString ukm;
+ private AlgorithmIdentifier keyEncryptionAlgorithm;
+ private ASN1Sequence recipientEncryptedKeys;
+
+ public KeyAgreeRecipientInfo(
+ OriginatorIdentifierOrKey originator,
+ ASN1OctetString ukm,
+ AlgorithmIdentifier keyEncryptionAlgorithm,
+ ASN1Sequence recipientEncryptedKeys)
+ {
+ this.version = new ASN1Integer(3);
+ this.originator = originator;
+ this.ukm = ukm;
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.recipientEncryptedKeys = recipientEncryptedKeys;
+ }
+
+ /**
+ * @deprecated use getInstance()
+ */
+ public KeyAgreeRecipientInfo(
+ ASN1Sequence seq)
+ {
+ int index = 0;
+
+ version = (ASN1Integer)seq.getObjectAt(index++);
+ originator = OriginatorIdentifierOrKey.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(index++), true);
+
+ if (seq.getObjectAt(index) instanceof ASN1TaggedObject)
+ {
+ ukm = ASN1OctetString.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(index++), true);
+ }
+
+ keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(
+ seq.getObjectAt(index++));
+
+ recipientEncryptedKeys = (ASN1Sequence)seq.getObjectAt(index++);
+ }
+
+ /**
+ * Return a KeyAgreeRecipientInfo object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static KeyAgreeRecipientInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return a KeyAgreeRecipientInfo object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link KeyAgreeRecipientInfo} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with KeyAgreeRecipientInfo structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static KeyAgreeRecipientInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof KeyAgreeRecipientInfo)
+ {
+ return (KeyAgreeRecipientInfo)obj;
+ }
+
+ if (obj != null)
+ {
+ return new KeyAgreeRecipientInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public OriginatorIdentifierOrKey getOriginator()
+ {
+ return originator;
+ }
+
+ public ASN1OctetString getUserKeyingMaterial()
+ {
+ return ukm;
+ }
+
+ public AlgorithmIdentifier getKeyEncryptionAlgorithm()
+ {
+ return keyEncryptionAlgorithm;
+ }
+
+ public ASN1Sequence getRecipientEncryptedKeys()
+ {
+ return recipientEncryptedKeys;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(new DERTaggedObject(true, 0, originator));
+
+ if (ukm != null)
+ {
+ v.add(new DERTaggedObject(true, 1, ukm));
+ }
+
+ v.add(keyEncryptionAlgorithm);
+ v.add(recipientEncryptedKeys);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/KeyTransRecipientInfo.java b/core/src/main/java/org/spongycastle/asn1/cms/KeyTransRecipientInfo.java
new file mode 100644
index 00000000..e031dce5
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/KeyTransRecipientInfo.java
@@ -0,0 +1,127 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.1">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <pre>
+ * KeyTransRecipientInfo ::= SEQUENCE {
+ * version CMSVersion, -- always set to 0 or 2
+ * rid RecipientIdentifier,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey
+ * }
+ * </pre>
+ */
+public class KeyTransRecipientInfo
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private RecipientIdentifier rid;
+ private AlgorithmIdentifier keyEncryptionAlgorithm;
+ private ASN1OctetString encryptedKey;
+
+ public KeyTransRecipientInfo(
+ RecipientIdentifier rid,
+ AlgorithmIdentifier keyEncryptionAlgorithm,
+ ASN1OctetString encryptedKey)
+ {
+ if (rid.toASN1Primitive() instanceof ASN1TaggedObject)
+ {
+ this.version = new ASN1Integer(2);
+ }
+ else
+ {
+ this.version = new ASN1Integer(0);
+ }
+
+ this.rid = rid;
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.encryptedKey = encryptedKey;
+ }
+
+ /**
+ * @deprecated use getInstance()
+ */
+ public KeyTransRecipientInfo(
+ ASN1Sequence seq)
+ {
+ this.version = (ASN1Integer)seq.getObjectAt(0);
+ this.rid = RecipientIdentifier.getInstance(seq.getObjectAt(1));
+ this.keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2));
+ this.encryptedKey = (ASN1OctetString)seq.getObjectAt(3);
+ }
+
+ /**
+ * Return a KeyTransRecipientInfo object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link KeyTransRecipientInfo} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with KeyTransRecipientInfo structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static KeyTransRecipientInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof KeyTransRecipientInfo)
+ {
+ return (KeyTransRecipientInfo)obj;
+ }
+
+ if(obj != null)
+ {
+ return new KeyTransRecipientInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public RecipientIdentifier getRecipientIdentifier()
+ {
+ return rid;
+ }
+
+ public AlgorithmIdentifier getKeyEncryptionAlgorithm()
+ {
+ return keyEncryptionAlgorithm;
+ }
+
+ public ASN1OctetString getEncryptedKey()
+ {
+ return encryptedKey;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(rid);
+ v.add(keyEncryptionAlgorithm);
+ v.add(encryptedKey);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/MetaData.java b/core/src/main/java/org/spongycastle/asn1/cms/MetaData.java
new file mode 100644
index 00000000..92cf468d
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/MetaData.java
@@ -0,0 +1,135 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Boolean;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERUTF8String;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5544">RFC 5544</a>:
+ * Binding Documents with Time-Stamps; MetaData object.
+ * <p>
+ * <pre>
+ * MetaData ::= SEQUENCE {
+ * hashProtected BOOLEAN,
+ * fileName UTF8String OPTIONAL,
+ * mediaType IA5String OPTIONAL,
+ * otherMetaData Attributes OPTIONAL
+ * }
+ * </pre>
+ */
+public class MetaData
+ extends ASN1Object
+{
+ private ASN1Boolean hashProtected;
+ private DERUTF8String fileName;
+ private DERIA5String mediaType;
+ private Attributes otherMetaData;
+
+ public MetaData(
+ ASN1Boolean hashProtected,
+ DERUTF8String fileName,
+ DERIA5String mediaType,
+ Attributes otherMetaData)
+ {
+ this.hashProtected = hashProtected;
+ this.fileName = fileName;
+ this.mediaType = mediaType;
+ this.otherMetaData = otherMetaData;
+ }
+
+ private MetaData(ASN1Sequence seq)
+ {
+ this.hashProtected = ASN1Boolean.getInstance(seq.getObjectAt(0));
+
+ int index = 1;
+
+ if (index < seq.size() && seq.getObjectAt(index) instanceof DERUTF8String)
+ {
+ this.fileName = DERUTF8String.getInstance(seq.getObjectAt(index++));
+ }
+ if (index < seq.size() && seq.getObjectAt(index) instanceof DERIA5String)
+ {
+ this.mediaType = DERIA5String.getInstance(seq.getObjectAt(index++));
+ }
+ if (index < seq.size())
+ {
+ this.otherMetaData = Attributes.getInstance(seq.getObjectAt(index++));
+ }
+ }
+
+ /**
+ * Return a MetaData object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link MetaData} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with MetaData structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static MetaData getInstance(Object obj)
+ {
+ if (obj instanceof MetaData)
+ {
+ return (MetaData)obj;
+ }
+ else if (obj != null)
+ {
+ return new MetaData(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(hashProtected);
+
+ if (fileName != null)
+ {
+ v.add(fileName);
+ }
+
+ if (mediaType != null)
+ {
+ v.add(mediaType);
+ }
+
+ if (otherMetaData != null)
+ {
+ v.add(otherMetaData);
+ }
+
+ return new DERSequence(v);
+ }
+
+ public boolean isHashProtected()
+ {
+ return hashProtected.isTrue();
+ }
+
+ public DERUTF8String getFileName()
+ {
+ return this.fileName;
+ }
+
+ public DERIA5String getMediaType()
+ {
+ return this.mediaType;
+ }
+
+ public Attributes getOtherMetaData()
+ {
+ return otherMetaData;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/OriginatorIdentifierOrKey.java b/core/src/main/java/org/spongycastle/asn1/cms/OriginatorIdentifierOrKey.java
new file mode 100644
index 00000000..042daff8
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/OriginatorIdentifierOrKey.java
@@ -0,0 +1,179 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Choice;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.2">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <pre>
+ * OriginatorIdentifierOrKey ::= CHOICE {
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * subjectKeyIdentifier [0] SubjectKeyIdentifier,
+ * originatorKey [1] OriginatorPublicKey
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ * </pre>
+ */
+public class OriginatorIdentifierOrKey
+ extends ASN1Object
+ implements ASN1Choice
+{
+ private ASN1Encodable id;
+
+ public OriginatorIdentifierOrKey(
+ IssuerAndSerialNumber id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * @deprecated use version taking a SubjectKeyIdentifier
+ */
+ public OriginatorIdentifierOrKey(
+ ASN1OctetString id)
+ {
+ this(new SubjectKeyIdentifier(id.getOctets()));
+ }
+
+ public OriginatorIdentifierOrKey(
+ SubjectKeyIdentifier id)
+ {
+ this.id = new DERTaggedObject(false, 0, id);
+ }
+
+ public OriginatorIdentifierOrKey(
+ OriginatorPublicKey id)
+ {
+ this.id = new DERTaggedObject(false, 1, id);
+ }
+
+ /**
+ * @deprecated use more specific version
+ */
+ public OriginatorIdentifierOrKey(
+ ASN1Primitive id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * Return an OriginatorIdentifierOrKey object from a tagged object.
+ *
+ * @param o the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static OriginatorIdentifierOrKey getInstance(
+ ASN1TaggedObject o,
+ boolean explicit)
+ {
+ if (!explicit)
+ {
+ throw new IllegalArgumentException(
+ "Can't implicitly tag OriginatorIdentifierOrKey");
+ }
+
+ return getInstance(o.getObject());
+ }
+
+ /**
+ * Return an OriginatorIdentifierOrKey object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link OriginatorIdentifierOrKey} object
+ * <li> {@link IssuerAndSerialNumber} object
+ * <li> {@link SubjectKeyIdentifier} object
+ * <li> {@link OriginatorPublicKey} object
+ * <li> {@link org.spongycastle.asn1.ASN1TaggedObject#getInstance(java.lang.Object) ASN1TaggedObject} input formats with IssuerAndSerialNumber structure inside
+ * </ul>
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static OriginatorIdentifierOrKey getInstance(
+ Object o)
+ {
+ if (o == null || o instanceof OriginatorIdentifierOrKey)
+ {
+ return (OriginatorIdentifierOrKey)o;
+ }
+
+ if (o instanceof IssuerAndSerialNumber)
+ {
+ return new OriginatorIdentifierOrKey((IssuerAndSerialNumber)o);
+ }
+
+ if (o instanceof SubjectKeyIdentifier)
+ {
+ return new OriginatorIdentifierOrKey((SubjectKeyIdentifier)o);
+ }
+
+ if (o instanceof OriginatorPublicKey)
+ {
+ return new OriginatorIdentifierOrKey((OriginatorPublicKey)o);
+ }
+
+ if (o instanceof ASN1TaggedObject)
+ {
+ // TODO Add validation
+ return new OriginatorIdentifierOrKey((ASN1TaggedObject)o);
+ }
+
+ throw new IllegalArgumentException("Invalid OriginatorIdentifierOrKey: " + o.getClass().getName());
+ }
+
+ public ASN1Encodable getId()
+ {
+ return id;
+ }
+
+ public IssuerAndSerialNumber getIssuerAndSerialNumber()
+ {
+ if (id instanceof IssuerAndSerialNumber)
+ {
+ return (IssuerAndSerialNumber)id;
+ }
+
+ return null;
+ }
+
+ public SubjectKeyIdentifier getSubjectKeyIdentifier()
+ {
+ if (id instanceof ASN1TaggedObject && ((ASN1TaggedObject)id).getTagNo() == 0)
+ {
+ return SubjectKeyIdentifier.getInstance((ASN1TaggedObject)id, false);
+ }
+
+ return null;
+ }
+
+ public OriginatorPublicKey getOriginatorKey()
+ {
+ if (id instanceof ASN1TaggedObject && ((ASN1TaggedObject)id).getTagNo() == 1)
+ {
+ return OriginatorPublicKey.getInstance((ASN1TaggedObject)id, false);
+ }
+
+ return null;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return id.toASN1Primitive();
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/OriginatorInfo.java b/core/src/main/java/org/spongycastle/asn1/cms/OriginatorInfo.java
new file mode 100644
index 00000000..88d2e630
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/OriginatorInfo.java
@@ -0,0 +1,159 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.1">RFC 5652</a>: OriginatorInfo object.
+ * <pre>
+ * RFC 3369:
+ *
+ * OriginatorInfo ::= SEQUENCE {
+ * certs [0] IMPLICIT CertificateSet OPTIONAL,
+ * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL
+ * }
+ * CertificateRevocationLists ::= SET OF CertificateList (from X.509)
+ *
+ * RFC 3582 / 5652:
+ *
+ * OriginatorInfo ::= SEQUENCE {
+ * certs [0] IMPLICIT CertificateSet OPTIONAL,
+ * crls [1] IMPLICIT RevocationInfoChoices OPTIONAL
+ * }
+ * RevocationInfoChoices ::= SET OF RevocationInfoChoice
+ * RevocationInfoChoice ::= CHOICE {
+ * crl CertificateList,
+ * other [1] IMPLICIT OtherRevocationInfoFormat }
+ *
+ * OtherRevocationInfoFormat ::= SEQUENCE {
+ * otherRevInfoFormat OBJECT IDENTIFIER,
+ * otherRevInfo ANY DEFINED BY otherRevInfoFormat }
+ * </pre>
+ * <p>
+ * TODO: RevocationInfoChoices / RevocationInfoChoice.
+ * Constructor using CertificateSet, CertificationInfoChoices
+ */
+public class OriginatorInfo
+ extends ASN1Object
+{
+ private ASN1Set certs;
+ private ASN1Set crls;
+
+ public OriginatorInfo(
+ ASN1Set certs,
+ ASN1Set crls)
+ {
+ this.certs = certs;
+ this.crls = crls;
+ }
+
+ private OriginatorInfo(
+ ASN1Sequence seq)
+ {
+ switch (seq.size())
+ {
+ case 0: // empty
+ break;
+ case 1:
+ ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0);
+ switch (o.getTagNo())
+ {
+ case 0 :
+ certs = ASN1Set.getInstance(o, false);
+ break;
+ case 1 :
+ crls = ASN1Set.getInstance(o, false);
+ break;
+ default:
+ throw new IllegalArgumentException("Bad tag in OriginatorInfo: " + o.getTagNo());
+ }
+ break;
+ case 2:
+ certs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(0), false);
+ crls = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(1), false);
+ break;
+ default:
+ throw new IllegalArgumentException("OriginatorInfo too big");
+ }
+ }
+
+ /**
+ * Return an OriginatorInfo object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static OriginatorInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return an OriginatorInfo object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link OriginatorInfo} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with OriginatorInfo structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static OriginatorInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof OriginatorInfo)
+ {
+ return (OriginatorInfo)obj;
+ }
+ else if (obj != null)
+ {
+ return new OriginatorInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Set getCertificates()
+ {
+ return certs;
+ }
+
+ public ASN1Set getCRLs()
+ {
+ return crls;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (certs != null)
+ {
+ v.add(new DERTaggedObject(false, 0, certs));
+ }
+
+ if (crls != null)
+ {
+ v.add(new DERTaggedObject(false, 1, crls));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/OriginatorPublicKey.java b/core/src/main/java/org/spongycastle/asn1/cms/OriginatorPublicKey.java
new file mode 100644
index 00000000..e5edcf3e
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/OriginatorPublicKey.java
@@ -0,0 +1,114 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.2">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <p>
+ * <pre>
+ * OriginatorPublicKey ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * publicKey BIT STRING
+ * }
+ * </pre>
+ */
+public class OriginatorPublicKey
+ extends ASN1Object
+{
+ private AlgorithmIdentifier algorithm;
+ private DERBitString publicKey;
+
+ public OriginatorPublicKey(
+ AlgorithmIdentifier algorithm,
+ byte[] publicKey)
+ {
+ this.algorithm = algorithm;
+ this.publicKey = new DERBitString(publicKey);
+ }
+
+ /**
+ * @deprecated use getInstance()
+ */
+ public OriginatorPublicKey(
+ ASN1Sequence seq)
+ {
+ algorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
+ publicKey = (DERBitString)seq.getObjectAt(1);
+ }
+
+ /**
+ * Return an OriginatorPublicKey object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static OriginatorPublicKey getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return an OriginatorPublicKey object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link OriginatorPublicKey} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with OriginatorPublicKey structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static OriginatorPublicKey getInstance(
+ Object obj)
+ {
+ if (obj instanceof OriginatorPublicKey)
+ {
+ return (OriginatorPublicKey)obj;
+ }
+
+ if (obj != null)
+ {
+ return new OriginatorPublicKey(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public AlgorithmIdentifier getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public DERBitString getPublicKey()
+ {
+ return publicKey;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(algorithm);
+ v.add(publicKey);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/OtherKeyAttribute.java b/core/src/main/java/org/spongycastle/asn1/cms/OtherKeyAttribute.java
new file mode 100644
index 00000000..cc9db1c7
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/OtherKeyAttribute.java
@@ -0,0 +1,96 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-10.2.7">RFC 5652</a>: OtherKeyAttribute object.
+ * <p>
+ * <pre>
+ * OtherKeyAttribute ::= SEQUENCE {
+ * keyAttrId OBJECT IDENTIFIER,
+ * keyAttr ANY DEFINED BY keyAttrId OPTIONAL
+ * }
+ * </pre>
+ */
+public class OtherKeyAttribute
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier keyAttrId;
+ private ASN1Encodable keyAttr;
+
+ /**
+ * Return an OtherKeyAttribute object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link OtherKeyAttribute} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with OtherKeyAttribute structure inside
+ * </ul>
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static OtherKeyAttribute getInstance(
+ Object o)
+ {
+ if (o instanceof OtherKeyAttribute)
+ {
+ return (OtherKeyAttribute)o;
+ }
+
+ if (o != null)
+ {
+ return new OtherKeyAttribute(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ /**
+ * @deprecated use getInstance()
+ */
+ public OtherKeyAttribute(
+ ASN1Sequence seq)
+ {
+ keyAttrId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+ keyAttr = seq.getObjectAt(1);
+ }
+
+ public OtherKeyAttribute(
+ ASN1ObjectIdentifier keyAttrId,
+ ASN1Encodable keyAttr)
+ {
+ this.keyAttrId = keyAttrId;
+ this.keyAttr = keyAttr;
+ }
+
+ public ASN1ObjectIdentifier getKeyAttrId()
+ {
+ return keyAttrId;
+ }
+
+ public ASN1Encodable getKeyAttr()
+ {
+ return keyAttr;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(keyAttrId);
+ v.add(keyAttr);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/OtherRecipientInfo.java b/core/src/main/java/org/spongycastle/asn1/cms/OtherRecipientInfo.java
new file mode 100644
index 00000000..2f95e85c
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/OtherRecipientInfo.java
@@ -0,0 +1,112 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.5">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <pre>
+ * OtherRecipientInfo ::= SEQUENCE {
+ * oriType OBJECT IDENTIFIER,
+ * oriValue ANY DEFINED BY oriType }
+ * </pre>
+ */
+public class OtherRecipientInfo
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier oriType;
+ private ASN1Encodable oriValue;
+
+ public OtherRecipientInfo(
+ ASN1ObjectIdentifier oriType,
+ ASN1Encodable oriValue)
+ {
+ this.oriType = oriType;
+ this.oriValue = oriValue;
+ }
+
+ /**
+ * @deprecated use getInstance().
+ */
+ public OtherRecipientInfo(
+ ASN1Sequence seq)
+ {
+ oriType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+ oriValue = seq.getObjectAt(1);
+ }
+
+ /**
+ * Return a OtherRecipientInfo object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static OtherRecipientInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return a OtherRecipientInfo object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link PasswordRecipientInfo} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with OtherRecipientInfo structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static OtherRecipientInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof OtherRecipientInfo)
+ {
+ return (OtherRecipientInfo)obj;
+ }
+
+ if (obj != null)
+ {
+ return new OtherRecipientInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1ObjectIdentifier getType()
+ {
+ return oriType;
+ }
+
+ public ASN1Encodable getValue()
+ {
+ return oriValue;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(oriType);
+ v.add(oriValue);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/OtherRevocationInfoFormat.java b/core/src/main/java/org/spongycastle/asn1/cms/OtherRevocationInfoFormat.java
new file mode 100644
index 00000000..178fd991
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/OtherRevocationInfoFormat.java
@@ -0,0 +1,109 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-10.2.1">RFC 5652</a>: OtherRevocationInfoFormat object.
+ * <p>
+ * <pre>
+ * OtherRevocationInfoFormat ::= SEQUENCE {
+ * otherRevInfoFormat OBJECT IDENTIFIER,
+ * otherRevInfo ANY DEFINED BY otherRevInfoFormat }
+ * </pre>
+ */
+public class OtherRevocationInfoFormat
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier otherRevInfoFormat;
+ private ASN1Encodable otherRevInfo;
+
+ public OtherRevocationInfoFormat(
+ ASN1ObjectIdentifier otherRevInfoFormat,
+ ASN1Encodable otherRevInfo)
+ {
+ this.otherRevInfoFormat = otherRevInfoFormat;
+ this.otherRevInfo = otherRevInfo;
+ }
+
+ private OtherRevocationInfoFormat(
+ ASN1Sequence seq)
+ {
+ otherRevInfoFormat = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+ otherRevInfo = seq.getObjectAt(1);
+ }
+
+ /**
+ * Return a OtherRevocationInfoFormat object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static OtherRevocationInfoFormat getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return a OtherRevocationInfoFormat object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link OtherRevocationInfoFormat} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with OtherRevocationInfoFormat structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static OtherRevocationInfoFormat getInstance(
+ Object obj)
+ {
+ if (obj instanceof OtherRevocationInfoFormat)
+ {
+ return (OtherRevocationInfoFormat)obj;
+ }
+
+ if (obj != null)
+ {
+ return new OtherRevocationInfoFormat(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1ObjectIdentifier getInfoFormat()
+ {
+ return otherRevInfoFormat;
+ }
+
+ public ASN1Encodable getInfo()
+ {
+ return otherRevInfo;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(otherRevInfoFormat);
+ v.add(otherRevInfo);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/PasswordRecipientInfo.java b/core/src/main/java/org/spongycastle/asn1/cms/PasswordRecipientInfo.java
new file mode 100644
index 00000000..26dd78f5
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/PasswordRecipientInfo.java
@@ -0,0 +1,157 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-10.2.7">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <pre>
+ * PasswordRecipientInfo ::= SEQUENCE {
+ * version CMSVersion, -- Always set to 0
+ * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier
+ * OPTIONAL,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey }
+ * </pre>
+ */
+public class PasswordRecipientInfo
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private AlgorithmIdentifier keyDerivationAlgorithm;
+ private AlgorithmIdentifier keyEncryptionAlgorithm;
+ private ASN1OctetString encryptedKey;
+
+ public PasswordRecipientInfo(
+ AlgorithmIdentifier keyEncryptionAlgorithm,
+ ASN1OctetString encryptedKey)
+ {
+ this.version = new ASN1Integer(0);
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.encryptedKey = encryptedKey;
+ }
+
+ public PasswordRecipientInfo(
+ AlgorithmIdentifier keyDerivationAlgorithm,
+ AlgorithmIdentifier keyEncryptionAlgorithm,
+ ASN1OctetString encryptedKey)
+ {
+ this.version = new ASN1Integer(0);
+ this.keyDerivationAlgorithm = keyDerivationAlgorithm;
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.encryptedKey = encryptedKey;
+ }
+
+ /**
+ * @deprecated use getInstance() method.
+ */
+ public PasswordRecipientInfo(
+ ASN1Sequence seq)
+ {
+ version = (ASN1Integer)seq.getObjectAt(0);
+ if (seq.getObjectAt(1) instanceof ASN1TaggedObject)
+ {
+ keyDerivationAlgorithm = AlgorithmIdentifier.getInstance((ASN1TaggedObject)seq.getObjectAt(1), false);
+ keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2));
+ encryptedKey = (ASN1OctetString)seq.getObjectAt(3);
+ }
+ else
+ {
+ keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+ encryptedKey = (ASN1OctetString)seq.getObjectAt(2);
+ }
+ }
+
+ /**
+ * Return a PasswordRecipientInfo object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static PasswordRecipientInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return a PasswordRecipientInfo object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link PasswordRecipientInfo} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with PasswordRecipientInfo structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static PasswordRecipientInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof PasswordRecipientInfo)
+ {
+ return (PasswordRecipientInfo)obj;
+ }
+
+ if (obj != null)
+ {
+ return new PasswordRecipientInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public AlgorithmIdentifier getKeyDerivationAlgorithm()
+ {
+ return keyDerivationAlgorithm;
+ }
+
+ public AlgorithmIdentifier getKeyEncryptionAlgorithm()
+ {
+ return keyEncryptionAlgorithm;
+ }
+
+ public ASN1OctetString getEncryptedKey()
+ {
+ return encryptedKey;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+
+ if (keyDerivationAlgorithm != null)
+ {
+ v.add(new DERTaggedObject(false, 0, keyDerivationAlgorithm));
+ }
+ v.add(keyEncryptionAlgorithm);
+ v.add(encryptedKey);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/RecipientEncryptedKey.java b/core/src/main/java/org/spongycastle/asn1/cms/RecipientEncryptedKey.java
new file mode 100644
index 00000000..a51a13a5
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/RecipientEncryptedKey.java
@@ -0,0 +1,109 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.2">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <pre>
+ * RecipientEncryptedKey ::= SEQUENCE {
+ * rid KeyAgreeRecipientIdentifier,
+ * encryptedKey EncryptedKey
+ * }
+ * </pre>
+ */
+public class RecipientEncryptedKey
+ extends ASN1Object
+{
+ private KeyAgreeRecipientIdentifier identifier;
+ private ASN1OctetString encryptedKey;
+
+ private RecipientEncryptedKey(
+ ASN1Sequence seq)
+ {
+ identifier = KeyAgreeRecipientIdentifier.getInstance(seq.getObjectAt(0));
+ encryptedKey = (ASN1OctetString)seq.getObjectAt(1);
+ }
+
+ /**
+ * Return an RecipientEncryptedKey object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static RecipientEncryptedKey getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return a RecipientEncryptedKey object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link RecipientEncryptedKey} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with RecipientEncryptedKey structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static RecipientEncryptedKey getInstance(
+ Object obj)
+ {
+ if (obj instanceof RecipientEncryptedKey)
+ {
+ return (RecipientEncryptedKey)obj;
+ }
+
+ if (obj != null)
+ {
+ return new RecipientEncryptedKey(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public RecipientEncryptedKey(
+ KeyAgreeRecipientIdentifier id,
+ ASN1OctetString encryptedKey)
+ {
+ this.identifier = id;
+ this.encryptedKey = encryptedKey;
+ }
+
+ public KeyAgreeRecipientIdentifier getIdentifier()
+ {
+ return identifier;
+ }
+
+ public ASN1OctetString getEncryptedKey()
+ {
+ return encryptedKey;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(identifier);
+ v.add(encryptedKey);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/RecipientIdentifier.java b/core/src/main/java/org/spongycastle/asn1/cms/RecipientIdentifier.java
new file mode 100644
index 00000000..cbf52625
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/RecipientIdentifier.java
@@ -0,0 +1,111 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Choice;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.1">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <pre>
+ * RecipientIdentifier ::= CHOICE {
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * subjectKeyIdentifier [0] SubjectKeyIdentifier
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ * </pre>
+ */
+public class RecipientIdentifier
+ extends ASN1Object
+ implements ASN1Choice
+{
+ private ASN1Encodable id;
+
+ public RecipientIdentifier(
+ IssuerAndSerialNumber id)
+ {
+ this.id = id;
+ }
+
+ public RecipientIdentifier(
+ ASN1OctetString id)
+ {
+ this.id = new DERTaggedObject(false, 0, id);
+ }
+
+ public RecipientIdentifier(
+ ASN1Primitive id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * Return a RecipientIdentifier object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link RecipientIdentifier} object
+ * <li> {@link IssuerAndSerialNumber} object
+ * <li> {@link org.spongycastle.asn1.ASN1OctetString#getInstance(java.lang.Object) ASN1OctetString} input formats (OctetString, byte[]) with value of KeyIdentifier in DER form
+ * <li> {@link org.spongycastle.asn1.ASN1Primitive ASN1Primitive} for RecipientIdentifier constructor
+ * </ul>
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static RecipientIdentifier getInstance(
+ Object o)
+ {
+ if (o == null || o instanceof RecipientIdentifier)
+ {
+ return (RecipientIdentifier)o;
+ }
+
+ if (o instanceof IssuerAndSerialNumber)
+ {
+ return new RecipientIdentifier((IssuerAndSerialNumber)o);
+ }
+
+ if (o instanceof ASN1OctetString)
+ {
+ return new RecipientIdentifier((ASN1OctetString)o);
+ }
+
+ if (o instanceof ASN1Primitive)
+ {
+ return new RecipientIdentifier((ASN1Primitive)o);
+ }
+
+ throw new IllegalArgumentException(
+ "Illegal object in RecipientIdentifier: " + o.getClass().getName());
+ }
+
+ public boolean isTagged()
+ {
+ return (id instanceof ASN1TaggedObject);
+ }
+
+ public ASN1Encodable getId()
+ {
+ if (id instanceof ASN1TaggedObject)
+ {
+ return ASN1OctetString.getInstance((ASN1TaggedObject)id, false);
+ }
+
+ return IssuerAndSerialNumber.getInstance(id);
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return id.toASN1Primitive();
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/RecipientInfo.java b/core/src/main/java/org/spongycastle/asn1/cms/RecipientInfo.java
new file mode 100644
index 00000000..d6b5c802
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/RecipientInfo.java
@@ -0,0 +1,173 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Choice;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <p>
+ * <pre>
+ * RecipientInfo ::= CHOICE {
+ * ktri KeyTransRecipientInfo,
+ * kari [1] KeyAgreeRecipientInfo,
+ * kekri [2] KEKRecipientInfo,
+ * pwri [3] PasswordRecipientInfo,
+ * ori [4] OtherRecipientInfo }
+ * </pre>
+ */
+public class RecipientInfo
+ extends ASN1Object
+ implements ASN1Choice
+{
+ ASN1Encodable info;
+
+ public RecipientInfo(
+ KeyTransRecipientInfo info)
+ {
+ this.info = info;
+ }
+
+ public RecipientInfo(
+ KeyAgreeRecipientInfo info)
+ {
+ this.info = new DERTaggedObject(false, 1, info);
+ }
+
+ public RecipientInfo(
+ KEKRecipientInfo info)
+ {
+ this.info = new DERTaggedObject(false, 2, info);
+ }
+
+ public RecipientInfo(
+ PasswordRecipientInfo info)
+ {
+ this.info = new DERTaggedObject(false, 3, info);
+ }
+
+ public RecipientInfo(
+ OtherRecipientInfo info)
+ {
+ this.info = new DERTaggedObject(false, 4, info);
+ }
+
+ public RecipientInfo(
+ ASN1Primitive info)
+ {
+ this.info = info;
+ }
+
+ /**
+ * Return a RecipientInfo object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link RecipientInfo} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with RecipientInfo structure inside
+ * <li> {@link org.spongycastle.asn1.ASN1TaggedObject#getInstance(java.lang.Object) ASN1TaggedObject} input formats with RecipientInfo structure inside
+ * </ul>
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static RecipientInfo getInstance(
+ Object o)
+ {
+ if (o == null || o instanceof RecipientInfo)
+ {
+ return (RecipientInfo)o;
+ }
+ else if (o instanceof ASN1Sequence)
+ {
+ return new RecipientInfo((ASN1Sequence)o);
+ }
+ else if (o instanceof ASN1TaggedObject)
+ {
+ return new RecipientInfo((ASN1TaggedObject)o);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: "
+ + o.getClass().getName());
+ }
+
+ public ASN1Integer getVersion()
+ {
+ if (info instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject o = (ASN1TaggedObject)info;
+
+ switch (o.getTagNo())
+ {
+ case 1:
+ return KeyAgreeRecipientInfo.getInstance(o, false).getVersion();
+ case 2:
+ return getKEKInfo(o).getVersion();
+ case 3:
+ return PasswordRecipientInfo.getInstance(o, false).getVersion();
+ case 4:
+ return new ASN1Integer(0); // no syntax version for OtherRecipientInfo
+ default:
+ throw new IllegalStateException("unknown tag");
+ }
+ }
+
+ return KeyTransRecipientInfo.getInstance(info).getVersion();
+ }
+
+ public boolean isTagged()
+ {
+ return (info instanceof ASN1TaggedObject);
+ }
+
+ public ASN1Encodable getInfo()
+ {
+ if (info instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject o = (ASN1TaggedObject)info;
+
+ switch (o.getTagNo())
+ {
+ case 1:
+ return KeyAgreeRecipientInfo.getInstance(o, false);
+ case 2:
+ return getKEKInfo(o);
+ case 3:
+ return PasswordRecipientInfo.getInstance(o, false);
+ case 4:
+ return OtherRecipientInfo.getInstance(o, false);
+ default:
+ throw new IllegalStateException("unknown tag");
+ }
+ }
+
+ return KeyTransRecipientInfo.getInstance(info);
+ }
+
+ private KEKRecipientInfo getKEKInfo(ASN1TaggedObject o)
+ {
+ if (o.isExplicit())
+ { // compatibilty with erroneous version
+ return KEKRecipientInfo.getInstance(o, true);
+ }
+ else
+ {
+ return KEKRecipientInfo.getInstance(o, false);
+ }
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return info.toASN1Primitive();
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/RecipientKeyIdentifier.java b/core/src/main/java/org/spongycastle/asn1/cms/RecipientKeyIdentifier.java
new file mode 100644
index 00000000..16d9312f
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/RecipientKeyIdentifier.java
@@ -0,0 +1,171 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-6.2.2">RFC 5652</a>:
+ * Content encryption key delivery mechanisms.
+ * <p>
+ * <pre>
+ * RecipientKeyIdentifier ::= SEQUENCE {
+ * subjectKeyIdentifier SubjectKeyIdentifier,
+ * date GeneralizedTime OPTIONAL,
+ * other OtherKeyAttribute OPTIONAL
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ * </pre>
+ */
+public class RecipientKeyIdentifier
+ extends ASN1Object
+{
+ private ASN1OctetString subjectKeyIdentifier;
+ private ASN1GeneralizedTime date;
+ private OtherKeyAttribute other;
+
+ public RecipientKeyIdentifier(
+ ASN1OctetString subjectKeyIdentifier,
+ ASN1GeneralizedTime date,
+ OtherKeyAttribute other)
+ {
+ this.subjectKeyIdentifier = subjectKeyIdentifier;
+ this.date = date;
+ this.other = other;
+ }
+
+ public RecipientKeyIdentifier(
+ byte[] subjectKeyIdentifier,
+ ASN1GeneralizedTime date,
+ OtherKeyAttribute other)
+ {
+ this.subjectKeyIdentifier = new DEROctetString(subjectKeyIdentifier);
+ this.date = date;
+ this.other = other;
+ }
+
+ public RecipientKeyIdentifier(
+ byte[] subjectKeyIdentifier)
+ {
+ this(subjectKeyIdentifier, null, null);
+ }
+
+ /**
+ * @deprecated use getInstance()
+ */
+ public RecipientKeyIdentifier(
+ ASN1Sequence seq)
+ {
+ subjectKeyIdentifier = ASN1OctetString.getInstance(
+ seq.getObjectAt(0));
+
+ switch(seq.size())
+ {
+ case 1:
+ break;
+ case 2:
+ if (seq.getObjectAt(1) instanceof ASN1GeneralizedTime)
+ {
+ date = ASN1GeneralizedTime.getInstance(seq.getObjectAt(1));
+ }
+ else
+ {
+ other = OtherKeyAttribute.getInstance(seq.getObjectAt(2));
+ }
+ break;
+ case 3:
+ date = ASN1GeneralizedTime.getInstance(seq.getObjectAt(1));
+ other = OtherKeyAttribute.getInstance(seq.getObjectAt(2));
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid RecipientKeyIdentifier");
+ }
+ }
+
+ /**
+ * Return a RecipientKeyIdentifier object from a tagged object.
+ *
+ * @param ato the tagged object holding the object we want.
+ * @param isExplicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static RecipientKeyIdentifier getInstance(ASN1TaggedObject ato, boolean isExplicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(ato, isExplicit));
+ }
+
+ /**
+ * Return a RecipientKeyIdentifier object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link RecipientKeyIdentifier} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with RecipientKeyIdentifier structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static RecipientKeyIdentifier getInstance(Object obj)
+ {
+ if (obj instanceof RecipientKeyIdentifier)
+ {
+ return (RecipientKeyIdentifier)obj;
+ }
+
+ if(obj != null)
+ {
+ return new RecipientKeyIdentifier(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ASN1OctetString getSubjectKeyIdentifier()
+ {
+ return subjectKeyIdentifier;
+ }
+
+ public ASN1GeneralizedTime getDate()
+ {
+ return date;
+ }
+
+ public OtherKeyAttribute getOtherKeyAttribute()
+ {
+ return other;
+ }
+
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(subjectKeyIdentifier);
+
+ if (date != null)
+ {
+ v.add(date);
+ }
+
+ if (other != null)
+ {
+ v.add(other);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/SCVPReqRes.java b/core/src/main/java/org/spongycastle/asn1/cms/SCVPReqRes.java
new file mode 100644
index 00000000..0b702e8c
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/SCVPReqRes.java
@@ -0,0 +1,108 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5940">RFC 5940</a>:
+ * Additional Cryptographic Message Syntax (CMS) Revocation Information Choices.
+ * <p>
+ * <pre>
+ * SCVPReqRes ::= SEQUENCE {
+ * request [0] EXPLICIT ContentInfo OPTIONAL,
+ * response ContentInfo }
+ * </pre>
+ */
+public class SCVPReqRes
+ extends ASN1Object
+{
+ private final ContentInfo request;
+ private final ContentInfo response;
+
+ /**
+ * Return a SCVPReqRes object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link SCVPReqRes} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SCVPReqRes structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static SCVPReqRes getInstance(
+ Object obj)
+ {
+ if (obj instanceof SCVPReqRes)
+ {
+ return (SCVPReqRes)obj;
+ }
+ else if (obj != null)
+ {
+ return new SCVPReqRes(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private SCVPReqRes(
+ ASN1Sequence seq)
+ {
+ if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
+ {
+ this.request = ContentInfo.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(0)), true);
+ this.response = ContentInfo.getInstance(seq.getObjectAt(1));
+ }
+ else
+ {
+ this.request = null;
+ this.response = ContentInfo.getInstance(seq.getObjectAt(0));
+ }
+ }
+
+ public SCVPReqRes(ContentInfo response)
+ {
+ this.request = null; // use of this confuses earlier JDKs
+ this.response = response;
+ }
+
+ public SCVPReqRes(ContentInfo request, ContentInfo response)
+ {
+ this.request = request;
+ this.response = response;
+ }
+
+ public ContentInfo getRequest()
+ {
+ return request;
+ }
+
+ public ContentInfo getResponse()
+ {
+ return response;
+ }
+
+ /**
+ * @return the ASN.1 primitive representation.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (request != null)
+ {
+ v.add(new DERTaggedObject(true, 0, request));
+ }
+
+ v.add(response);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/SignedData.java b/core/src/main/java/org/spongycastle/asn1/cms/SignedData.java
new file mode 100644
index 00000000..c564b391
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/SignedData.java
@@ -0,0 +1,330 @@
+package org.spongycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.BERSet;
+import org.spongycastle.asn1.BERTaggedObject;
+import org.spongycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.1">RFC 5652</a>:
+ * <p>
+ * A signed data object containing multitude of {@link SignerInfo}s.
+ * <pre>
+ * SignedData ::= SEQUENCE {
+ * version CMSVersion,
+ * digestAlgorithms DigestAlgorithmIdentifiers,
+ * encapContentInfo EncapsulatedContentInfo,
+ * certificates [0] IMPLICIT CertificateSet OPTIONAL,
+ * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ * signerInfos SignerInfos
+ * }
+ *
+ * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
+ *
+ * SignerInfos ::= SET OF SignerInfo
+ * </pre>
+ * <p>
+ * The version calculation uses following ruleset from RFC 3852 section 5.1:
+ * <pre>
+ * IF ((certificates is present) AND
+ * (any certificates with a type of other are present)) OR
+ * ((crls is present) AND
+ * (any crls with a type of other are present))
+ * THEN version MUST be 5
+ * ELSE
+ * IF (certificates is present) AND
+ * (any version 2 attribute certificates are present)
+ * THEN version MUST be 4
+ * ELSE
+ * IF ((certificates is present) AND
+ * (any version 1 attribute certificates are present)) OR
+ * (any SignerInfo structures are version 3) OR
+ * (encapContentInfo eContentType is other than id-data)
+ * THEN version MUST be 3
+ * ELSE version MUST be 1
+ * </pre>
+ * <p>
+ * @todo Check possible update for this to RFC 5652 level
+ */
+public class SignedData
+ extends ASN1Object
+{
+ private static final ASN1Integer VERSION_1 = new ASN1Integer(1);
+ private static final ASN1Integer VERSION_3 = new ASN1Integer(3);
+ private static final ASN1Integer VERSION_4 = new ASN1Integer(4);
+ private static final ASN1Integer VERSION_5 = new ASN1Integer(5);
+
+ private ASN1Integer version;
+ private ASN1Set digestAlgorithms;
+ private ContentInfo contentInfo;
+ private ASN1Set certificates;
+ private ASN1Set crls;
+ private ASN1Set signerInfos;
+ private boolean certsBer;
+ private boolean crlsBer;
+
+ /**
+ * Return a SignedData object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link SignedData} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignedData structure inside
+ * </ul>
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static SignedData getInstance(
+ Object o)
+ {
+ if (o instanceof SignedData)
+ {
+ return (SignedData)o;
+ }
+ else if (o != null)
+ {
+ return new SignedData(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public SignedData(
+ ASN1Set digestAlgorithms,
+ ContentInfo contentInfo,
+ ASN1Set certificates,
+ ASN1Set crls,
+ ASN1Set signerInfos)
+ {
+ this.version = calculateVersion(contentInfo.getContentType(), certificates, crls, signerInfos);
+ this.digestAlgorithms = digestAlgorithms;
+ this.contentInfo = contentInfo;
+ this.certificates = certificates;
+ this.crls = crls;
+ this.signerInfos = signerInfos;
+ this.crlsBer = crls instanceof BERSet;
+ this.certsBer = certificates instanceof BERSet;
+ }
+
+
+ private ASN1Integer calculateVersion(
+ ASN1ObjectIdentifier contentOid,
+ ASN1Set certs,
+ ASN1Set crls,
+ ASN1Set signerInfs)
+ {
+ boolean otherCert = false;
+ boolean otherCrl = false;
+ boolean attrCertV1Found = false;
+ boolean attrCertV2Found = false;
+
+ if (certs != null)
+ {
+ for (Enumeration en = certs.getObjects(); en.hasMoreElements();)
+ {
+ Object obj = en.nextElement();
+ if (obj instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj);
+
+ if (tagged.getTagNo() == 1)
+ {
+ attrCertV1Found = true;
+ }
+ else if (tagged.getTagNo() == 2)
+ {
+ attrCertV2Found = true;
+ }
+ else if (tagged.getTagNo() == 3)
+ {
+ otherCert = true;
+ }
+ }
+ }
+ }
+
+ if (otherCert)
+ {
+ return new ASN1Integer(5);
+ }
+
+ if (crls != null) // no need to check if otherCert is true
+ {
+ for (Enumeration en = crls.getObjects(); en.hasMoreElements();)
+ {
+ Object obj = en.nextElement();
+ if (obj instanceof ASN1TaggedObject)
+ {
+ otherCrl = true;
+ }
+ }
+ }
+
+ if (otherCrl)
+ {
+ return VERSION_5;
+ }
+
+ if (attrCertV2Found)
+ {
+ return VERSION_4;
+ }
+
+ if (attrCertV1Found)
+ {
+ return VERSION_3;
+ }
+
+ if (checkForVersion3(signerInfs))
+ {
+ return VERSION_3;
+ }
+
+ if (!CMSObjectIdentifiers.data.equals(contentOid))
+ {
+ return VERSION_3;
+ }
+
+ return VERSION_1;
+ }
+
+ private boolean checkForVersion3(ASN1Set signerInfs)
+ {
+ for (Enumeration e = signerInfs.getObjects(); e.hasMoreElements();)
+ {
+ SignerInfo s = SignerInfo.getInstance(e.nextElement());
+
+ if (s.getVersion().getValue().intValue() == 3)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private SignedData(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ version = ASN1Integer.getInstance(e.nextElement());
+ digestAlgorithms = ((ASN1Set)e.nextElement());
+ contentInfo = ContentInfo.getInstance(e.nextElement());
+
+ while (e.hasMoreElements())
+ {
+ ASN1Primitive o = (ASN1Primitive)e.nextElement();
+
+ //
+ // an interesting feature of SignedData is that there appear
+ // to be varying implementations...
+ // for the moment we ignore anything which doesn't fit.
+ //
+ if (o instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tagged = (ASN1TaggedObject)o;
+
+ switch (tagged.getTagNo())
+ {
+ case 0:
+ certsBer = tagged instanceof BERTaggedObject;
+ certificates = ASN1Set.getInstance(tagged, false);
+ break;
+ case 1:
+ crlsBer = tagged instanceof BERTaggedObject;
+ crls = ASN1Set.getInstance(tagged, false);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo());
+ }
+ }
+ else
+ {
+ signerInfos = (ASN1Set)o;
+ }
+ }
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public ASN1Set getDigestAlgorithms()
+ {
+ return digestAlgorithms;
+ }
+
+ public ContentInfo getEncapContentInfo()
+ {
+ return contentInfo;
+ }
+
+ public ASN1Set getCertificates()
+ {
+ return certificates;
+ }
+
+ public ASN1Set getCRLs()
+ {
+ return crls;
+ }
+
+ public ASN1Set getSignerInfos()
+ {
+ return signerInfos;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(digestAlgorithms);
+ v.add(contentInfo);
+
+ if (certificates != null)
+ {
+ if (certsBer)
+ {
+ v.add(new BERTaggedObject(false, 0, certificates));
+ }
+ else
+ {
+ v.add(new DERTaggedObject(false, 0, certificates));
+ }
+ }
+
+ if (crls != null)
+ {
+ if (crlsBer)
+ {
+ v.add(new BERTaggedObject(false, 1, crls));
+ }
+ else
+ {
+ v.add(new DERTaggedObject(false, 1, crls));
+ }
+ }
+
+ v.add(signerInfos);
+
+ return new BERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/SignedDataParser.java b/core/src/main/java/org/spongycastle/asn1/cms/SignedDataParser.java
new file mode 100644
index 00000000..7e79a7bf
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/SignedDataParser.java
@@ -0,0 +1,141 @@
+package org.spongycastle.asn1.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1SetParser;
+import org.spongycastle.asn1.ASN1TaggedObjectParser;
+import org.spongycastle.asn1.BERTags;
+
+/**
+ * Parser for <a href="http://tools.ietf.org/html/rfc5652#section-5.1">RFC 5652</a>: {@link SignedData} object.
+ * <p>
+ * <pre>
+ * SignedData ::= SEQUENCE {
+ * version CMSVersion,
+ * digestAlgorithms DigestAlgorithmIdentifiers,
+ * encapContentInfo EncapsulatedContentInfo,
+ * certificates [0] IMPLICIT CertificateSet OPTIONAL,
+ * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ * signerInfos SignerInfos
+ * }
+ * </pre>
+ */
+public class SignedDataParser
+{
+ private ASN1SequenceParser _seq;
+ private ASN1Integer _version;
+ private Object _nextObject;
+ private boolean _certsCalled;
+ private boolean _crlsCalled;
+
+ public static SignedDataParser getInstance(
+ Object o)
+ throws IOException
+ {
+ if (o instanceof ASN1Sequence)
+ {
+ return new SignedDataParser(((ASN1Sequence)o).parser());
+ }
+ if (o instanceof ASN1SequenceParser)
+ {
+ return new SignedDataParser((ASN1SequenceParser)o);
+ }
+
+ throw new IOException("unknown object encountered: " + o.getClass().getName());
+ }
+
+ private SignedDataParser(
+ ASN1SequenceParser seq)
+ throws IOException
+ {
+ this._seq = seq;
+ this._version = (ASN1Integer)seq.readObject();
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return _version;
+ }
+
+ public ASN1SetParser getDigestAlgorithms()
+ throws IOException
+ {
+ Object o = _seq.readObject();
+
+ if (o instanceof ASN1Set)
+ {
+ return ((ASN1Set)o).parser();
+ }
+
+ return (ASN1SetParser)o;
+ }
+
+ public ContentInfoParser getEncapContentInfo()
+ throws IOException
+ {
+ return new ContentInfoParser((ASN1SequenceParser)_seq.readObject());
+ }
+
+ public ASN1SetParser getCertificates()
+ throws IOException
+ {
+ _certsCalled = true;
+ _nextObject = _seq.readObject();
+
+ if (_nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)_nextObject).getTagNo() == 0)
+ {
+ ASN1SetParser certs = (ASN1SetParser)((ASN1TaggedObjectParser)_nextObject).getObjectParser(BERTags.SET, false);
+ _nextObject = null;
+
+ return certs;
+ }
+
+ return null;
+ }
+
+ public ASN1SetParser getCrls()
+ throws IOException
+ {
+ if (!_certsCalled)
+ {
+ throw new IOException("getCerts() has not been called.");
+ }
+
+ _crlsCalled = true;
+
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.readObject();
+ }
+
+ if (_nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)_nextObject).getTagNo() == 1)
+ {
+ ASN1SetParser crls = (ASN1SetParser)((ASN1TaggedObjectParser)_nextObject).getObjectParser(BERTags.SET, false);
+ _nextObject = null;
+
+ return crls;
+ }
+
+ return null;
+ }
+
+ public ASN1SetParser getSignerInfos()
+ throws IOException
+ {
+ if (!_certsCalled || !_crlsCalled)
+ {
+ throw new IOException("getCerts() and/or getCrls() has not been called.");
+ }
+
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.readObject();
+ }
+
+ return (ASN1SetParser)_nextObject;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/SignerIdentifier.java b/core/src/main/java/org/spongycastle/asn1/cms/SignerIdentifier.java
new file mode 100644
index 00000000..a2ab088b
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/SignerIdentifier.java
@@ -0,0 +1,114 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1Choice;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.3">RFC 5652</a>:
+ * Identify who signed the containing {@link SignerInfo} object.
+ * <p>
+ * The certificates referred to by this are at containing {@link SignedData} structure.
+ * <p>
+ * <pre>
+ * SignerIdentifier ::= CHOICE {
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * subjectKeyIdentifier [0] SubjectKeyIdentifier
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ * </pre>
+ */
+public class SignerIdentifier
+ extends ASN1Object
+ implements ASN1Choice
+{
+ private ASN1Encodable id;
+
+ public SignerIdentifier(
+ IssuerAndSerialNumber id)
+ {
+ this.id = id;
+ }
+
+ public SignerIdentifier(
+ ASN1OctetString id)
+ {
+ this.id = new DERTaggedObject(false, 0, id);
+ }
+
+ public SignerIdentifier(
+ ASN1Primitive id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * Return a SignerIdentifier object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link SignerIdentifier} object
+ * <li> {@link IssuerAndSerialNumber} object
+ * <li> {@link org.spongycastle.asn1.ASN1OctetString#getInstance(java.lang.Object) ASN1OctetString} input formats with SignerIdentifier structure inside
+ * <li> {@link org.spongycastle.asn1.ASN1Primitive ASN1Primitive} for SignerIdentifier constructor.
+ * </ul>
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static SignerIdentifier getInstance(
+ Object o)
+ {
+ if (o == null || o instanceof SignerIdentifier)
+ {
+ return (SignerIdentifier)o;
+ }
+
+ if (o instanceof IssuerAndSerialNumber)
+ {
+ return new SignerIdentifier((IssuerAndSerialNumber)o);
+ }
+
+ if (o instanceof ASN1OctetString)
+ {
+ return new SignerIdentifier((ASN1OctetString)o);
+ }
+
+ if (o instanceof ASN1Primitive)
+ {
+ return new SignerIdentifier((ASN1Primitive)o);
+ }
+
+ throw new IllegalArgumentException(
+ "Illegal object in SignerIdentifier: " + o.getClass().getName());
+ }
+
+ public boolean isTagged()
+ {
+ return (id instanceof ASN1TaggedObject);
+ }
+
+ public ASN1Encodable getId()
+ {
+ if (id instanceof ASN1TaggedObject)
+ {
+ return ASN1OctetString.getInstance((ASN1TaggedObject)id, false);
+ }
+
+ return id;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return id.toASN1Primitive();
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/SignerInfo.java b/core/src/main/java/org/spongycastle/asn1/cms/SignerInfo.java
new file mode 100644
index 00000000..301f26e3
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/SignerInfo.java
@@ -0,0 +1,282 @@
+package org.spongycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.3">RFC 5652</a>:
+ * Signature container per Signer, see {@link SignerIdentifier}.
+ * <pre>
+ * PKCS#7:
+ *
+ * SignerInfo ::= SEQUENCE {
+ * version Version,
+ * sid SignerIdentifier,
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+ * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ * encryptedDigest EncryptedDigest,
+ * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+ * }
+ *
+ * EncryptedDigest ::= OCTET STRING
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * -----------------------------------------
+ *
+ * RFC 5256:
+ *
+ * SignerInfo ::= SEQUENCE {
+ * version CMSVersion,
+ * sid SignerIdentifier,
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
+ * signatureAlgorithm SignatureAlgorithmIdentifier,
+ * signature SignatureValue,
+ * unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL
+ * }
+ *
+ * -- {@link SignerIdentifier} referenced certificates are at containing
+ * -- {@link SignedData} certificates element.
+ *
+ * SignerIdentifier ::= CHOICE {
+ * issuerAndSerialNumber {@link IssuerAndSerialNumber},
+ * subjectKeyIdentifier [0] SubjectKeyIdentifier }
+ *
+ * -- See {@link Attributes} for generalized SET OF {@link Attribute}
+ *
+ * SignedAttributes ::= SET SIZE (1..MAX) OF Attribute
+ * UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * {@link Attribute} ::= SEQUENCE {
+ * attrType OBJECT IDENTIFIER,
+ * attrValues SET OF AttributeValue }
+ *
+ * AttributeValue ::= ANY
+ *
+ * SignatureValue ::= OCTET STRING
+ * </pre>
+ */
+public class SignerInfo
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private SignerIdentifier sid;
+ private AlgorithmIdentifier digAlgorithm;
+ private ASN1Set authenticatedAttributes;
+ private AlgorithmIdentifier digEncryptionAlgorithm;
+ private ASN1OctetString encryptedDigest;
+ private ASN1Set unauthenticatedAttributes;
+
+ /**
+ * Return a SignerInfo object from the given input
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link SignerInfo} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignerInfo structure inside
+ * </ul>
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static SignerInfo getInstance(
+ Object o)
+ throws IllegalArgumentException
+ {
+ if (o instanceof SignerInfo)
+ {
+ return (SignerInfo)o;
+ }
+ else if (o != null)
+ {
+ return new SignerInfo(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ /**
+ *
+ * @param sid
+ * @param digAlgorithm CMS knows as 'digestAlgorithm'
+ * @param authenticatedAttributes CMS knows as 'signedAttrs'
+ * @param digEncryptionAlgorithm CMS knows as 'signatureAlgorithm'
+ * @param encryptedDigest CMS knows as 'signature'
+ * @param unauthenticatedAttributes CMS knows as 'unsignedAttrs'
+ */
+ public SignerInfo(
+ SignerIdentifier sid,
+ AlgorithmIdentifier digAlgorithm,
+ ASN1Set authenticatedAttributes,
+ AlgorithmIdentifier digEncryptionAlgorithm,
+ ASN1OctetString encryptedDigest,
+ ASN1Set unauthenticatedAttributes)
+ {
+ if (sid.isTagged())
+ {
+ this.version = new ASN1Integer(3);
+ }
+ else
+ {
+ this.version = new ASN1Integer(1);
+ }
+
+ this.sid = sid;
+ this.digAlgorithm = digAlgorithm;
+ this.authenticatedAttributes = authenticatedAttributes;
+ this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+ this.encryptedDigest = encryptedDigest;
+ this.unauthenticatedAttributes = unauthenticatedAttributes;
+ }
+
+ /**
+ *
+ * @param sid
+ * @param digAlgorithm CMS knows as 'digestAlgorithm'
+ * @param authenticatedAttributes CMS knows as 'signedAttrs'
+ * @param digEncryptionAlgorithm CMS knows as 'signatureAlgorithm'
+ * @param encryptedDigest CMS knows as 'signature'
+ * @param unauthenticatedAttributes CMS knows as 'unsignedAttrs'
+ */
+ public SignerInfo(
+ SignerIdentifier sid,
+ AlgorithmIdentifier digAlgorithm,
+ Attributes authenticatedAttributes,
+ AlgorithmIdentifier digEncryptionAlgorithm,
+ ASN1OctetString encryptedDigest,
+ Attributes unauthenticatedAttributes)
+ {
+ if (sid.isTagged())
+ {
+ this.version = new ASN1Integer(3);
+ }
+ else
+ {
+ this.version = new ASN1Integer(1);
+ }
+
+ this.sid = sid;
+ this.digAlgorithm = digAlgorithm;
+ this.authenticatedAttributes = ASN1Set.getInstance(authenticatedAttributes);
+ this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+ this.encryptedDigest = encryptedDigest;
+ this.unauthenticatedAttributes = ASN1Set.getInstance(unauthenticatedAttributes);
+ }
+
+ /**
+ * @deprecated use getInstance() method.
+ */
+ public SignerInfo(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ version = (ASN1Integer)e.nextElement();
+ sid = SignerIdentifier.getInstance(e.nextElement());
+ digAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+
+ Object obj = e.nextElement();
+
+ if (obj instanceof ASN1TaggedObject)
+ {
+ authenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)obj, false);
+
+ digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+ }
+ else
+ {
+ authenticatedAttributes = null;
+ digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(obj);
+ }
+
+ encryptedDigest = DEROctetString.getInstance(e.nextElement());
+
+ if (e.hasMoreElements())
+ {
+ unauthenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false);
+ }
+ else
+ {
+ unauthenticatedAttributes = null;
+ }
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public SignerIdentifier getSID()
+ {
+ return sid;
+ }
+
+ public ASN1Set getAuthenticatedAttributes()
+ {
+ return authenticatedAttributes;
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithm()
+ {
+ return digAlgorithm;
+ }
+
+ public ASN1OctetString getEncryptedDigest()
+ {
+ return encryptedDigest;
+ }
+
+ public AlgorithmIdentifier getDigestEncryptionAlgorithm()
+ {
+ return digEncryptionAlgorithm;
+ }
+
+ public ASN1Set getUnauthenticatedAttributes()
+ {
+ return unauthenticatedAttributes;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(sid);
+ v.add(digAlgorithm);
+
+ if (authenticatedAttributes != null)
+ {
+ v.add(new DERTaggedObject(false, 0, authenticatedAttributes));
+ }
+
+ v.add(digEncryptionAlgorithm);
+ v.add(encryptedDigest);
+
+ if (unauthenticatedAttributes != null)
+ {
+ v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/Time.java b/core/src/main/java/org/spongycastle/asn1/cms/Time.java
new file mode 100644
index 00000000..1dccff36
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/Time.java
@@ -0,0 +1,198 @@
+package org.spongycastle.asn1.cms;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.SimpleTimeZone;
+
+import org.spongycastle.asn1.ASN1Choice;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.ASN1UTCTime;
+import org.spongycastle.asn1.DERGeneralizedTime;
+import org.spongycastle.asn1.DERUTCTime;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-11.3">RFC 5652</a>:
+ * Dual-mode timestamp format producing either UTCTIme or GeneralizedTime.
+ * <p>
+ * <pre>
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime }
+ * </pre>
+ * <p>
+ * This has a constructor using java.util.Date for input which generates
+ * a {@link org.spongycastle.asn1.DERUTCTime DERUTCTime} object if the
+ * supplied datetime is in range 1950-01-01-00:00:00 UTC until 2049-12-31-23:59:60 UTC.
+ * If the datetime value is outside that range, the generated object will be
+ * {@link org.spongycastle.asn1.DERGeneralizedTime DERGeneralizedTime}.
+ */
+public class Time
+ extends ASN1Object
+ implements ASN1Choice
+{
+ ASN1Primitive time;
+
+ public static Time getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(obj.getObject());
+ }
+
+ /**
+ * @deprecated use getInstance()
+ */
+ public Time(
+ ASN1Primitive time)
+ {
+ if (!(time instanceof ASN1UTCTime)
+ && !(time instanceof ASN1GeneralizedTime))
+ {
+ throw new IllegalArgumentException("unknown object passed to Time");
+ }
+
+ this.time = time;
+ }
+
+ /**
+ * Creates a time object from a given date - if the date is between 1950
+ * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
+ * is used.
+ *
+ * @param time a date object representing the time of interest.
+ */
+ public Time(
+ Date time)
+ {
+ SimpleTimeZone tz = new SimpleTimeZone(0, "Z");
+ SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss");
+
+ dateF.setTimeZone(tz);
+
+ String d = dateF.format(time) + "Z";
+ int year = Integer.parseInt(d.substring(0, 4));
+
+ if (year < 1950 || year > 2049)
+ {
+ this.time = new DERGeneralizedTime(d);
+ }
+ else
+ {
+ this.time = new DERUTCTime(d.substring(2));
+ }
+ }
+
+ /**
+ * Creates a time object from a given date and locale - if the date is between 1950
+ * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
+ * is used. You may need to use this constructor if the default locale
+ * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations.
+ *
+ * @param time a date object representing the time of interest.
+ * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value.
+ */
+ public Time(
+ Date time,
+ Locale locale)
+ {
+ SimpleTimeZone tz = new SimpleTimeZone(0, "Z");
+ SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", locale);
+
+ dateF.setTimeZone(tz);
+
+ String d = dateF.format(time) + "Z";
+ int year = Integer.parseInt(d.substring(0, 4));
+
+ if (year < 1950 || year > 2049)
+ {
+ this.time = new DERGeneralizedTime(d);
+ }
+ else
+ {
+ this.time = new DERUTCTime(d.substring(2));
+ }
+ }
+
+ /**
+ * Return a Time object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link Time} object
+ * <li> {@link org.spongycastle.asn1.DERUTCTime DERUTCTime} object
+ * <li> {@link org.spongycastle.asn1.DERGeneralizedTime DERGeneralizedTime} object
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static Time getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof Time)
+ {
+ return (Time)obj;
+ }
+ else if (obj instanceof ASN1UTCTime)
+ {
+ return new Time((ASN1UTCTime)obj);
+ }
+ else if (obj instanceof ASN1GeneralizedTime)
+ {
+ return new Time((ASN1GeneralizedTime)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ /**
+ * Get the date+tine as a String in full form century format.
+ */
+ public String getTime()
+ {
+ if (time instanceof ASN1UTCTime)
+ {
+ return ((ASN1UTCTime)time).getAdjustedTime();
+ }
+ else
+ {
+ return ((ASN1GeneralizedTime)time).getTime();
+ }
+ }
+
+ /**
+ * Get java.util.Date version of date+time.
+ */
+ public Date getDate()
+ {
+ try
+ {
+ if (time instanceof ASN1UTCTime)
+ {
+ return ((ASN1UTCTime)time).getAdjustedDate();
+ }
+ else
+ {
+ return ((ASN1GeneralizedTime)time).getDate();
+ }
+ }
+ catch (ParseException e)
+ { // this should never happen
+ throw new IllegalStateException("invalid date string: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return time;
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/TimeStampAndCRL.java b/core/src/main/java/org/spongycastle/asn1/cms/TimeStampAndCRL.java
new file mode 100644
index 00000000..af5d3bef
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/TimeStampAndCRL.java
@@ -0,0 +1,96 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.CertificateList;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5544">RFC 5544</a>
+ * Binding Documents with Time-Stamps; TimeStampAndCRL object.
+ * <pre>
+ * TimeStampAndCRL ::= SEQUENCE {
+ * timeStamp TimeStampToken, -- according to RFC 3161
+ * crl CertificateList OPTIONAL -- according to RFC 5280
+ * }
+ * </pre>
+ */
+public class TimeStampAndCRL
+ extends ASN1Object
+{
+ private ContentInfo timeStamp;
+ private CertificateList crl;
+
+ public TimeStampAndCRL(ContentInfo timeStamp)
+ {
+ this.timeStamp = timeStamp;
+ }
+
+ private TimeStampAndCRL(ASN1Sequence seq)
+ {
+ this.timeStamp = ContentInfo.getInstance(seq.getObjectAt(0));
+ if (seq.size() == 2)
+ {
+ this.crl = CertificateList.getInstance(seq.getObjectAt(1));
+ }
+ }
+
+ /**
+ * Return a TimeStampAndCRL object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link TimeStampAndCRL} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with TimeStampAndCRL structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static TimeStampAndCRL getInstance(Object obj)
+ {
+ if (obj instanceof TimeStampAndCRL)
+ {
+ return (TimeStampAndCRL)obj;
+ }
+ else if (obj != null)
+ {
+ return new TimeStampAndCRL(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ContentInfo getTimeStampToken()
+ {
+ return this.timeStamp;
+ }
+
+ /** @deprecated use getCRL() */
+ public CertificateList getCertificateList()
+ {
+ return this.crl;
+ }
+
+ public CertificateList getCRL()
+ {
+ return this.crl;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(timeStamp);
+
+ if (crl != null)
+ {
+ v.add(crl);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/TimeStampTokenEvidence.java b/core/src/main/java/org/spongycastle/asn1/cms/TimeStampTokenEvidence.java
new file mode 100644
index 00000000..1a2e622d
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/TimeStampTokenEvidence.java
@@ -0,0 +1,98 @@
+package org.spongycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5544">RFC 5544</a>
+ * Binding Documents with Time-Stamps; TimeStampTokenEvidence object.
+ * <pre>
+ * TimeStampTokenEvidence ::=
+ * SEQUENCE SIZE(1..MAX) OF TimeStampAndCRL
+ * </pre>
+ */
+public class TimeStampTokenEvidence
+ extends ASN1Object
+{
+ private TimeStampAndCRL[] timeStampAndCRLs;
+
+ public TimeStampTokenEvidence(TimeStampAndCRL[] timeStampAndCRLs)
+ {
+ this.timeStampAndCRLs = timeStampAndCRLs;
+ }
+
+ public TimeStampTokenEvidence(TimeStampAndCRL timeStampAndCRL)
+ {
+ this.timeStampAndCRLs = new TimeStampAndCRL[1];
+
+ timeStampAndCRLs[0] = timeStampAndCRL;
+ }
+
+ private TimeStampTokenEvidence(ASN1Sequence seq)
+ {
+ this.timeStampAndCRLs = new TimeStampAndCRL[seq.size()];
+
+ int count = 0;
+
+ for (Enumeration en = seq.getObjects(); en.hasMoreElements();)
+ {
+ timeStampAndCRLs[count++] = TimeStampAndCRL.getInstance(en.nextElement());
+ }
+ }
+
+ public static TimeStampTokenEvidence getInstance(ASN1TaggedObject tagged, boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(tagged, explicit));
+ }
+
+ /**
+ * Return a TimeStampTokenEvidence object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link TimeStampTokenEvidence} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with TimeStampTokenEvidence structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static TimeStampTokenEvidence getInstance(Object obj)
+ {
+ if (obj instanceof TimeStampTokenEvidence)
+ {
+ return (TimeStampTokenEvidence)obj;
+ }
+ else if (obj != null)
+ {
+ return new TimeStampTokenEvidence(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public TimeStampAndCRL[] toTimeStampAndCRLArray()
+ {
+ return timeStampAndCRLs;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (int i = 0; i != timeStampAndCRLs.length; i++)
+ {
+ v.add(timeStampAndCRLs[i]);
+ }
+
+ return new DERSequence(v);
+ }
+
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/TimeStampedData.java b/core/src/main/java/org/spongycastle/asn1/cms/TimeStampedData.java
new file mode 100644
index 00000000..ab201dca
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/TimeStampedData.java
@@ -0,0 +1,131 @@
+package org.spongycastle.asn1.cms;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.DERIA5String;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5544">RFC 5544</a>:
+ * Binding Documents with Time-Stamps; TimeStampedData object.
+ * <p>
+ * <pre>
+ * TimeStampedData ::= SEQUENCE {
+ * version INTEGER { v1(1) },
+ * dataUri IA5String OPTIONAL,
+ * metaData MetaData OPTIONAL,
+ * content OCTET STRING OPTIONAL,
+ * temporalEvidence Evidence
+ * }
+ * </pre>
+ */
+public class TimeStampedData
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private DERIA5String dataUri;
+ private MetaData metaData;
+ private ASN1OctetString content;
+ private Evidence temporalEvidence;
+
+ public TimeStampedData(DERIA5String dataUri, MetaData metaData, ASN1OctetString content, Evidence temporalEvidence)
+ {
+ this.version = new ASN1Integer(1);
+ this.dataUri = dataUri;
+ this.metaData = metaData;
+ this.content = content;
+ this.temporalEvidence = temporalEvidence;
+ }
+
+ private TimeStampedData(ASN1Sequence seq)
+ {
+ this.version = ASN1Integer.getInstance(seq.getObjectAt(0));
+
+ int index = 1;
+ if (seq.getObjectAt(index) instanceof DERIA5String)
+ {
+ this.dataUri = DERIA5String.getInstance(seq.getObjectAt(index++));
+ }
+ if (seq.getObjectAt(index) instanceof MetaData || seq.getObjectAt(index) instanceof ASN1Sequence)
+ {
+ this.metaData = MetaData.getInstance(seq.getObjectAt(index++));
+ }
+ if (seq.getObjectAt(index) instanceof ASN1OctetString)
+ {
+ this.content = ASN1OctetString.getInstance(seq.getObjectAt(index++));
+ }
+ this.temporalEvidence = Evidence.getInstance(seq.getObjectAt(index));
+ }
+
+ /**
+ * Return a TimeStampedData object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link RecipientKeyIdentifier} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with TimeStampedData structure inside
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static TimeStampedData getInstance(Object obj)
+ {
+ if (obj == null || obj instanceof TimeStampedData)
+ {
+ return (TimeStampedData)obj;
+ }
+ return new TimeStampedData(ASN1Sequence.getInstance(obj));
+ }
+
+ public DERIA5String getDataUri()
+ {
+ return dataUri;
+ }
+
+ public MetaData getMetaData()
+ {
+ return metaData;
+ }
+
+ public ASN1OctetString getContent()
+ {
+ return content;
+ }
+
+ public Evidence getTemporalEvidence()
+ {
+ return temporalEvidence;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+
+ if (dataUri != null)
+ {
+ v.add(dataUri);
+ }
+
+ if (metaData != null)
+ {
+ v.add(metaData);
+ }
+
+ if (content != null)
+ {
+ v.add(content);
+ }
+
+ v.add(temporalEvidence);
+
+ return new BERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/TimeStampedDataParser.java b/core/src/main/java/org/spongycastle/asn1/cms/TimeStampedDataParser.java
new file mode 100644
index 00000000..bf5d288a
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/TimeStampedDataParser.java
@@ -0,0 +1,141 @@
+package org.spongycastle.asn1.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1OctetStringParser;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.DERIA5String;
+
+/**
+ * Parser for <a href="http://tools.ietf.org/html/rfc5544">RFC 5544</a>:
+ * {@link TimeStampedData} object.
+ * <p>
+ * <pre>
+ * TimeStampedData ::= SEQUENCE {
+ * version INTEGER { v1(1) },
+ * dataUri IA5String OPTIONAL,
+ * metaData MetaData OPTIONAL,
+ * content OCTET STRING OPTIONAL,
+ * temporalEvidence Evidence
+ * }
+ * </pre>
+ */
+public class TimeStampedDataParser
+{
+ private ASN1Integer version;
+ private DERIA5String dataUri;
+ private MetaData metaData;
+ private ASN1OctetStringParser content;
+ private Evidence temporalEvidence;
+ private ASN1SequenceParser parser;
+
+ private TimeStampedDataParser(ASN1SequenceParser parser)
+ throws IOException
+ {
+ this.parser = parser;
+ this.version = ASN1Integer.getInstance(parser.readObject());
+
+ ASN1Encodable obj = parser.readObject();
+
+ if (obj instanceof DERIA5String)
+ {
+ this.dataUri = DERIA5String.getInstance(obj);
+ obj = parser.readObject();
+ }
+ if (obj instanceof MetaData || obj instanceof ASN1SequenceParser)
+ {
+ this.metaData = MetaData.getInstance(obj.toASN1Primitive());
+ obj = parser.readObject();
+ }
+ if (obj instanceof ASN1OctetStringParser)
+ {
+ this.content = (ASN1OctetStringParser)obj;
+ }
+ }
+
+ public static TimeStampedDataParser getInstance(Object obj)
+ throws IOException
+ {
+ if (obj instanceof ASN1Sequence)
+ {
+ return new TimeStampedDataParser(((ASN1Sequence)obj).parser());
+ }
+ if (obj instanceof ASN1SequenceParser)
+ {
+ return new TimeStampedDataParser((ASN1SequenceParser)obj);
+ }
+
+ return null;
+ }
+
+ public DERIA5String getDataUri()
+ {
+ return dataUri;
+ }
+
+ public MetaData getMetaData()
+ {
+ return metaData;
+ }
+
+ public ASN1OctetStringParser getContent()
+ {
+ return content;
+ }
+
+ public Evidence getTemporalEvidence()
+ throws IOException
+ {
+ if (temporalEvidence == null)
+ {
+ temporalEvidence = Evidence.getInstance(parser.readObject().toASN1Primitive());
+ }
+
+ return temporalEvidence;
+ }
+
+ /**
+ * <pre>
+ * TimeStampedData ::= SEQUENCE {
+ * version INTEGER { v1(1) },
+ * dataUri IA5String OPTIONAL,
+ * metaData MetaData OPTIONAL,
+ * content OCTET STRING OPTIONAL,
+ * temporalEvidence Evidence
+ * }
+ * </pre>
+ * @return
+ * @deprecated will be removed
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+
+ if (dataUri != null)
+ {
+ v.add(dataUri);
+ }
+
+ if (metaData != null)
+ {
+ v.add(metaData);
+ }
+
+ if (content != null)
+ {
+ v.add(content);
+ }
+
+ v.add(temporalEvidence);
+
+ return new BERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/spongycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java b/core/src/main/java/org/spongycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java
new file mode 100644
index 00000000..ae95a3d9
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java
@@ -0,0 +1,122 @@
+package org.spongycastle.asn1.cms.ecc;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.cms.OriginatorPublicKey;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5753">RFC 5753/3278</a>: MQVuserKeyingMaterial object.
+ * <pre>
+ * MQVuserKeyingMaterial ::= SEQUENCE {
+ * ephemeralPublicKey OriginatorPublicKey,
+ * addedukm [0] EXPLICIT UserKeyingMaterial OPTIONAL }
+ * </pre>
+ */
+public class MQVuserKeyingMaterial
+ extends ASN1Object
+{
+ private OriginatorPublicKey ephemeralPublicKey;
+ private ASN1OctetString addedukm;
+
+ public MQVuserKeyingMaterial(
+ OriginatorPublicKey ephemeralPublicKey,
+ ASN1OctetString addedukm)
+ {
+ // TODO Check ephemeralPublicKey not null
+
+ this.ephemeralPublicKey = ephemeralPublicKey;
+ this.addedukm = addedukm;
+ }
+
+ private MQVuserKeyingMaterial(
+ ASN1Sequence seq)
+ {
+ // TODO Check seq has either 1 or 2 elements
+
+ this.ephemeralPublicKey = OriginatorPublicKey.getInstance(
+ seq.getObjectAt(0));
+
+ if (seq.size() > 1)
+ {
+ this.addedukm = ASN1OctetString.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true);
+ }
+ }
+
+ /**
+ * Return an MQVuserKeyingMaterial object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static MQVuserKeyingMaterial getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Return an MQVuserKeyingMaterial object from the given object.
+ * <p>
+ * Accepted inputs:
+ * <ul>
+ * <li> null &rarr; null
+ * <li> {@link MQVuserKeyingMaterial} object
+ * <li> {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence} with MQVuserKeyingMaterial inside it.
+ * </ul>
+ *
+ * @param obj the object we want converted.
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static MQVuserKeyingMaterial getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof MQVuserKeyingMaterial)
+ {
+ return (MQVuserKeyingMaterial)obj;
+ }
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new MQVuserKeyingMaterial((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("Invalid MQVuserKeyingMaterial: " + obj.getClass().getName());
+ }
+
+ public OriginatorPublicKey getEphemeralPublicKey()
+ {
+ return ephemeralPublicKey;
+ }
+
+ public ASN1OctetString getAddedukm()
+ {
+ return addedukm;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ v.add(ephemeralPublicKey);
+
+ if (addedukm != null)
+ {
+ v.add(new DERTaggedObject(true, 0, addedukm));
+ }
+
+ return new DERSequence(v);
+ }
+}