summary refs log tree commit diff
path: root/crypto/src/asn1/crmf
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/asn1/crmf')
-rw-r--r--crypto/src/asn1/crmf/AttributeTypeAndValue.cs66
-rw-r--r--crypto/src/asn1/crmf/CertId.cs58
-rw-r--r--crypto/src/asn1/crmf/CertReqMessages.cs52
-rw-r--r--crypto/src/asn1/crmf/CertReqMsg.cs106
-rw-r--r--crypto/src/asn1/crmf/CertRequest.cs82
-rw-r--r--crypto/src/asn1/crmf/CertTemplate.cs149
-rw-r--r--crypto/src/asn1/crmf/CertTemplateBuilder.cs125
-rw-r--r--crypto/src/asn1/crmf/Controls.cs52
-rw-r--r--crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs23
-rw-r--r--crypto/src/asn1/crmf/EncKeyWithID.cs103
-rw-r--r--crypto/src/asn1/crmf/EncryptedKey.cs78
-rw-r--r--crypto/src/asn1/crmf/EncryptedValue.cs154
-rw-r--r--crypto/src/asn1/crmf/OptionalValidity.cs71
-rw-r--r--crypto/src/asn1/crmf/PKIArchiveOptions.cs105
-rw-r--r--crypto/src/asn1/crmf/PKIPublicationInfo.cs64
-rw-r--r--crypto/src/asn1/crmf/PKMacValue.cs89
-rw-r--r--crypto/src/asn1/crmf/PopoPrivKey.cs84
-rw-r--r--crypto/src/asn1/crmf/PopoSigningKey.cs115
-rw-r--r--crypto/src/asn1/crmf/PopoSigningKeyInput.cs115
-rw-r--r--crypto/src/asn1/crmf/ProofOfPossession.cs98
-rw-r--r--crypto/src/asn1/crmf/SinglePubInfo.cs58
-rw-r--r--crypto/src/asn1/crmf/SubsequentMessage.cs27
22 files changed, 1874 insertions, 0 deletions
diff --git a/crypto/src/asn1/crmf/AttributeTypeAndValue.cs b/crypto/src/asn1/crmf/AttributeTypeAndValue.cs
new file mode 100644
index 000000000..823668992
--- /dev/null
+++ b/crypto/src/asn1/crmf/AttributeTypeAndValue.cs
@@ -0,0 +1,66 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class AttributeTypeAndValue
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier type;
+        private readonly Asn1Encodable value;
+
+        private AttributeTypeAndValue(Asn1Sequence seq)
+        {
+            type = (DerObjectIdentifier)seq[0];
+            value = (Asn1Encodable)seq[1];
+        }
+
+        public static AttributeTypeAndValue GetInstance(object obj)
+        {
+            if (obj is AttributeTypeAndValue)
+                return (AttributeTypeAndValue)obj;
+
+            if (obj is Asn1Sequence)
+                return new AttributeTypeAndValue((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public AttributeTypeAndValue(
+            String oid,
+            Asn1Encodable value)
+            : this(new DerObjectIdentifier(oid), value)
+        {
+        }
+
+        public AttributeTypeAndValue(
+            DerObjectIdentifier type,
+            Asn1Encodable value)
+        {
+            this.type = type;
+            this.value = value;
+        }
+
+        public virtual DerObjectIdentifier Type
+        {
+            get { return type; }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get { return value; }
+        }
+
+        /**
+         * <pre>
+         * AttributeTypeAndValue ::= SEQUENCE {
+         *           type         OBJECT IDENTIFIER,
+         *           value        ANY DEFINED BY type }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(type, value);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertId.cs b/crypto/src/asn1/crmf/CertId.cs
new file mode 100644
index 000000000..10c2cc8b4
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertId.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertId
+        : Asn1Encodable
+    {
+        private readonly GeneralName issuer;
+        private readonly DerInteger serialNumber;
+
+        private CertId(Asn1Sequence seq)
+        {
+            issuer = GeneralName.GetInstance(seq[0]);
+            serialNumber = DerInteger.GetInstance(seq[1]);
+        }
+
+        public static CertId GetInstance(object obj)
+        {
+            if (obj is CertId)
+                return (CertId)obj;
+
+            if (obj is Asn1Sequence)
+                return new CertId((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public static CertId GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        public virtual GeneralName Issuer
+        {
+            get { return issuer; }
+        }
+
+        public virtual DerInteger SerialNumber
+        {
+            get { return serialNumber; }
+        }
+
+        /**
+         * <pre>
+         * CertId ::= SEQUENCE {
+         *                 issuer           GeneralName,
+         *                 serialNumber     INTEGER }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(issuer, serialNumber);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertReqMessages.cs b/crypto/src/asn1/crmf/CertReqMessages.cs
new file mode 100644
index 000000000..9247281e8
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertReqMessages.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertReqMessages
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence content;
+
+        private CertReqMessages(Asn1Sequence seq)
+        {
+            content = seq;
+        }
+
+        public static CertReqMessages GetInstance(object obj)
+        {
+            if (obj is CertReqMessages)
+                return (CertReqMessages)obj;
+
+            if (obj is Asn1Sequence)
+                return new CertReqMessages((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+		public CertReqMessages(params CertReqMsg[] msgs)
+        {
+            content = new DerSequence(msgs);
+        }
+
+        public virtual CertReqMsg[] ToCertReqMsgArray()
+        {
+            CertReqMsg[] result = new CertReqMsg[content.Count];
+            for (int i = 0; i != result.Length; ++i)
+            {
+                result[i] = CertReqMsg.GetInstance(content[i]);
+            }
+            return result;
+        }
+
+        /**
+         * <pre>
+         * CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return content;
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertReqMsg.cs b/crypto/src/asn1/crmf/CertReqMsg.cs
new file mode 100644
index 000000000..2ca319a57
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertReqMsg.cs
@@ -0,0 +1,106 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertReqMsg
+        : Asn1Encodable
+    {
+        private readonly CertRequest certReq;
+        private readonly ProofOfPossession popo;
+        private readonly Asn1Sequence regInfo;
+
+        private CertReqMsg(Asn1Sequence seq)
+        {
+            certReq = CertRequest.GetInstance(seq[0]);
+
+            for (int pos = 1; pos < seq.Count; ++pos)
+            {
+                object o = seq[pos];
+
+                if (o is Asn1TaggedObject || o is ProofOfPossession)
+                {
+                    popo = ProofOfPossession.GetInstance(o);
+                }
+                else
+                {
+                    regInfo = Asn1Sequence.GetInstance(o);
+                }
+            }
+        }
+
+        public static CertReqMsg GetInstance(object obj)
+        {
+            if (obj is CertReqMsg)
+                return (CertReqMsg)obj;
+
+            if (obj != null)
+                return new CertReqMsg(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        /**
+         * Creates a new CertReqMsg.
+         * @param certReq CertRequest
+         * @param popo may be null
+         * @param regInfo may be null
+         */
+        public CertReqMsg(
+            CertRequest				certReq,
+            ProofOfPossession		popo,
+            AttributeTypeAndValue[]	regInfo)
+        {
+            if (certReq == null)
+                throw new ArgumentNullException("certReq");
+
+            this.certReq = certReq;
+            this.popo = popo;
+
+            if (regInfo != null)
+            {
+                this.regInfo = new DerSequence(regInfo);
+            }
+        }
+
+        public virtual CertRequest CertReq
+        {
+            get { return certReq; }
+        }
+
+        public virtual ProofOfPossession Popo
+        {
+            get { return popo; }
+        }
+
+        public virtual AttributeTypeAndValue[] GetRegInfo()
+        {
+            if (regInfo == null)
+                return null;
+
+            AttributeTypeAndValue[] results = new AttributeTypeAndValue[regInfo.Count];
+            for (int i = 0; i != results.Length; ++i)
+            {
+                results[i] = AttributeTypeAndValue.GetInstance(regInfo[i]);
+            }
+            return results;
+        }
+
+        /**
+         * <pre>
+         * CertReqMsg ::= SEQUENCE {
+         *                    certReq   CertRequest,
+         *                    pop       ProofOfPossession  OPTIONAL,
+         *                    -- content depends upon key type
+         *                    regInfo   SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(certReq);
+            v.AddOptional(popo);
+            v.AddOptional(regInfo);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertRequest.cs b/crypto/src/asn1/crmf/CertRequest.cs
new file mode 100644
index 000000000..625a9b519
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertRequest.cs
@@ -0,0 +1,82 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertRequest
+        : Asn1Encodable
+    {
+        private readonly DerInteger certReqId;
+        private readonly CertTemplate certTemplate;
+        private readonly Controls controls;
+
+        private CertRequest(Asn1Sequence seq)
+        {
+            certReqId = DerInteger.GetInstance(seq[0]);
+            certTemplate = CertTemplate.GetInstance(seq[1]);
+            if (seq.Count > 2)
+            {
+                controls = Controls.GetInstance(seq[2]);
+            }
+        }
+
+        public static CertRequest GetInstance(object obj)
+        {
+            if (obj is CertRequest)
+                return (CertRequest)obj;
+
+            if (obj != null)
+                return new CertRequest(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        public CertRequest(
+            int certReqId,
+            CertTemplate certTemplate,
+            Controls controls)
+            : this(new DerInteger(certReqId), certTemplate, controls)
+        {
+        }
+
+        public CertRequest(
+            DerInteger certReqId,
+            CertTemplate certTemplate,
+            Controls controls)
+        {
+            this.certReqId = certReqId;
+            this.certTemplate = certTemplate;
+            this.controls = controls;
+        }
+
+        public virtual DerInteger CertReqID
+        {
+            get { return certReqId; }
+        }
+
+        public virtual CertTemplate CertTemplate
+        {
+            get { return certTemplate; }
+        }
+
+        public virtual Controls Controls
+        {
+            get { return controls; }
+        }
+
+        /**
+         * <pre>
+         * CertRequest ::= SEQUENCE {
+         *                      certReqId     INTEGER,          -- ID for matching request and reply
+         *                      certTemplate  CertTemplate,  -- Selected fields of cert to be issued
+         *                      controls      Controls OPTIONAL }   -- Attributes affecting issuance
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(certReqId, certTemplate);
+            v.AddOptional(controls);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertTemplate.cs b/crypto/src/asn1/crmf/CertTemplate.cs
new file mode 100644
index 000000000..3de9f1d5a
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertTemplate.cs
@@ -0,0 +1,149 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertTemplate
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence seq;
+
+        private readonly DerInteger version;
+        private readonly DerInteger serialNumber;
+        private readonly AlgorithmIdentifier signingAlg;
+        private readonly X509Name issuer;
+        private readonly OptionalValidity validity;
+        private readonly X509Name subject;
+        private readonly SubjectPublicKeyInfo publicKey;
+        private readonly DerBitString issuerUID;
+        private readonly DerBitString subjectUID;
+        private readonly X509Extensions extensions;
+
+        private CertTemplate(Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+            foreach (Asn1TaggedObject tObj in seq)
+            {
+                switch (tObj.TagNo)
+                {
+                case 0:
+                    version = DerInteger.GetInstance(tObj, false);
+                    break;
+                case 1:
+                    serialNumber = DerInteger.GetInstance(tObj, false);
+                    break;
+                case 2:
+                    signingAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                    break;
+                case 3:
+                    issuer = X509Name.GetInstance(tObj, true); // CHOICE
+                    break;
+                case 4:
+                    validity = OptionalValidity.GetInstance(Asn1Sequence.GetInstance(tObj, false));
+                    break;
+                case 5:
+                    subject = X509Name.GetInstance(tObj, true); // CHOICE
+                    break;
+                case 6:
+                    publicKey = SubjectPublicKeyInfo.GetInstance(tObj, false);
+                    break;
+                case 7:
+                    issuerUID = DerBitString.GetInstance(tObj, false);
+                    break;
+                case 8:
+                    subjectUID = DerBitString.GetInstance(tObj, false);
+                    break;
+                case 9:
+                    extensions = X509Extensions.GetInstance(tObj, false);
+                    break;
+                default:
+                    throw new ArgumentException("unknown tag: " + tObj.TagNo, "seq");
+                }
+            }
+        }
+
+        public static CertTemplate GetInstance(object obj)
+        {
+            if (obj is CertTemplate)
+                return (CertTemplate)obj;
+
+            if (obj != null)
+                return new CertTemplate(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        public virtual int Version
+        {
+            get { return version.Value.IntValue; }
+        }
+
+        public virtual DerInteger SerialNumber
+        {
+            get { return serialNumber; }
+        }
+
+        public virtual AlgorithmIdentifier SigningAlg
+        {
+            get { return signingAlg; }
+        }
+
+        public virtual X509Name Issuer
+        {
+            get { return issuer; }
+        }
+
+        public virtual OptionalValidity Validity
+        {
+            get { return validity; }
+        }
+
+        public virtual X509Name Subject
+        {
+            get { return subject; }
+        }
+
+        public virtual SubjectPublicKeyInfo PublicKey
+        {
+            get { return publicKey; }
+        }
+
+        public virtual DerBitString IssuerUID
+        {
+            get { return issuerUID; }
+        }
+
+        public virtual DerBitString SubjectUID
+        {
+            get { return subjectUID; }
+        }
+
+        public virtual X509Extensions Extensions
+        {
+            get { return extensions; }
+        }
+
+        /**
+         * <pre>
+         *  CertTemplate ::= SEQUENCE {
+         *      version      [0] Version               OPTIONAL,
+         *      serialNumber [1] INTEGER               OPTIONAL,
+         *      signingAlg   [2] AlgorithmIdentifier   OPTIONAL,
+         *      issuer       [3] Name                  OPTIONAL,
+         *      validity     [4] OptionalValidity      OPTIONAL,
+         *      subject      [5] Name                  OPTIONAL,
+         *      publicKey    [6] SubjectPublicKeyInfo  OPTIONAL,
+         *      issuerUID    [7] UniqueIdentifier      OPTIONAL,
+         *      subjectUID   [8] UniqueIdentifier      OPTIONAL,
+         *      extensions   [9] Extensions            OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertTemplateBuilder.cs b/crypto/src/asn1/crmf/CertTemplateBuilder.cs
new file mode 100644
index 000000000..51c73c4e1
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertTemplateBuilder.cs
@@ -0,0 +1,125 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertTemplateBuilder
+    {
+        private DerInteger version;
+        private DerInteger serialNumber;
+        private AlgorithmIdentifier signingAlg;
+        private X509Name issuer;
+        private OptionalValidity validity;
+        private X509Name subject;
+        private SubjectPublicKeyInfo publicKey;
+        private DerBitString issuerUID;
+        private DerBitString subjectUID;
+        private X509Extensions extensions;
+
+        /** Sets the X.509 version. Note: for X509v3, use 2 here. */
+        public virtual CertTemplateBuilder SetVersion(int ver)
+        {
+            version = new DerInteger(ver);
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetSerialNumber(DerInteger ser)
+        {
+            serialNumber = ser;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetSigningAlg(AlgorithmIdentifier aid)
+        {
+            signingAlg = aid;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetIssuer(X509Name name)
+        {
+            issuer = name;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetValidity(OptionalValidity v)
+        {
+            validity = v;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetSubject(X509Name name)
+        {
+            subject = name;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetPublicKey(SubjectPublicKeyInfo spki)
+        {
+            publicKey = spki;
+            return this;
+        }
+
+        /** Sets the issuer unique ID (deprecated in X.509v3) */
+        public virtual CertTemplateBuilder SetIssuerUID(DerBitString uid)
+        {
+            issuerUID = uid;
+            return this;
+        }
+
+        /** Sets the subject unique ID (deprecated in X.509v3) */
+        public virtual CertTemplateBuilder SetSubjectUID(DerBitString uid)
+        {
+            subjectUID = uid;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetExtensions(X509Extensions extens)
+        {
+            extensions = extens;
+            return this;
+        }
+
+        /**
+         * <pre>
+         *  CertTemplate ::= SEQUENCE {
+         *      version      [0] Version               OPTIONAL,
+         *      serialNumber [1] INTEGER               OPTIONAL,
+         *      signingAlg   [2] AlgorithmIdentifier   OPTIONAL,
+         *      issuer       [3] Name                  OPTIONAL,
+         *      validity     [4] OptionalValidity      OPTIONAL,
+         *      subject      [5] Name                  OPTIONAL,
+         *      publicKey    [6] SubjectPublicKeyInfo  OPTIONAL,
+         *      issuerUID    [7] UniqueIdentifier      OPTIONAL,
+         *      subjectUID   [8] UniqueIdentifier      OPTIONAL,
+         *      extensions   [9] Extensions            OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public virtual CertTemplate Build()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            AddOptional(v, 0, false, version);
+            AddOptional(v, 1, false, serialNumber);
+            AddOptional(v, 2, false, signingAlg);
+            AddOptional(v, 3, true, issuer); // CHOICE
+            AddOptional(v, 4, false, validity);
+            AddOptional(v, 5, true, subject); // CHOICE
+            AddOptional(v, 6, false, publicKey);
+            AddOptional(v, 7, false, issuerUID);
+            AddOptional(v, 8, false, subjectUID);
+            AddOptional(v, 9, false, extensions);
+
+            return CertTemplate.GetInstance(new DerSequence(v));
+        }
+
+        private void AddOptional(Asn1EncodableVector v, int tagNo, bool isExplicit, Asn1Encodable obj)
+        {
+            if (obj != null)
+            {
+                v.Add(new DerTaggedObject(isExplicit, tagNo, obj));
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/Controls.cs b/crypto/src/asn1/crmf/Controls.cs
new file mode 100644
index 000000000..cc52ea4bb
--- /dev/null
+++ b/crypto/src/asn1/crmf/Controls.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class Controls
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence content;
+
+        private Controls(Asn1Sequence seq)
+        {
+            content = seq;
+        }
+
+        public static Controls GetInstance(object obj)
+        {
+            if (obj is Controls)
+                return (Controls)obj;
+
+            if (obj is Asn1Sequence)
+                return new Controls((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+		public Controls(params AttributeTypeAndValue[] atvs)
+        {
+            content = new DerSequence(atvs);
+        }
+
+        public virtual AttributeTypeAndValue[] ToAttributeTypeAndValueArray()
+        {
+            AttributeTypeAndValue[] result = new AttributeTypeAndValue[content.Count];
+            for (int i = 0; i != result.Length; ++i)
+            {
+                result[i] = AttributeTypeAndValue.GetInstance(content[i]);
+            }
+            return result;
+        }
+
+        /**
+         * <pre>
+         * Controls  ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return content;
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs b/crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs
new file mode 100644
index 000000000..eaa1f7ba4
--- /dev/null
+++ b/crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs
@@ -0,0 +1,23 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public abstract class CrmfObjectIdentifiers
+    {
+        public static readonly DerObjectIdentifier id_pkix = new DerObjectIdentifier("1.3.6.1.5.5.7");
+
+        // arc for Internet X.509 PKI protocols and their components
+
+        public static readonly DerObjectIdentifier id_pkip  = id_pkix.Branch("5");
+
+        public static readonly DerObjectIdentifier id_regCtrl = id_pkip.Branch("1");
+        public static readonly DerObjectIdentifier id_regCtrl_regToken = id_regCtrl.Branch("1");
+        public static readonly DerObjectIdentifier id_regCtrl_authenticator = id_regCtrl.Branch("2");
+        public static readonly DerObjectIdentifier id_regCtrl_pkiPublicationInfo = id_regCtrl.Branch("3");
+        public static readonly DerObjectIdentifier id_regCtrl_pkiArchiveOptions = id_regCtrl.Branch("4");
+
+        public static readonly DerObjectIdentifier id_ct_encKeyWithID = new DerObjectIdentifier(PkcsObjectIdentifiers.IdCT + ".21");
+    }
+}
diff --git a/crypto/src/asn1/crmf/EncKeyWithID.cs b/crypto/src/asn1/crmf/EncKeyWithID.cs
new file mode 100644
index 000000000..6de56fa0b
--- /dev/null
+++ b/crypto/src/asn1/crmf/EncKeyWithID.cs
@@ -0,0 +1,103 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class EncKeyWithID
+        : Asn1Encodable
+    {
+        private readonly PrivateKeyInfo privKeyInfo;
+        private readonly Asn1Encodable identifier;
+
+        public static EncKeyWithID GetInstance(object obj)
+        {
+            if (obj is EncKeyWithID)
+                return (EncKeyWithID)obj;
+
+            if (obj != null)
+                return new EncKeyWithID(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        private EncKeyWithID(Asn1Sequence seq)
+        {
+            this.privKeyInfo = PrivateKeyInfo.GetInstance(seq[0]);
+
+            if (seq.Count > 1)
+            {
+                if (!(seq[1] is DerUtf8String))
+                {
+                    this.identifier = GeneralName.GetInstance(seq[1]);
+                }
+                else
+                {
+                    this.identifier = (Asn1Encodable)seq[1];
+                }
+            }
+            else
+            {
+                this.identifier = null;
+            }
+        }
+
+        public EncKeyWithID(PrivateKeyInfo privKeyInfo)
+        {
+            this.privKeyInfo = privKeyInfo;
+            this.identifier = null;
+        }
+
+        public EncKeyWithID(PrivateKeyInfo privKeyInfo, DerUtf8String str)
+        {
+            this.privKeyInfo = privKeyInfo;
+            this.identifier = str;
+        }
+
+        public EncKeyWithID(PrivateKeyInfo privKeyInfo, GeneralName generalName)
+        {
+            this.privKeyInfo = privKeyInfo;
+            this.identifier = generalName;
+        }
+
+        public virtual PrivateKeyInfo PrivateKey
+        {
+            get { return privKeyInfo; }
+        }
+
+        public virtual bool HasIdentifier
+        {
+            get { return identifier != null; }
+        }
+
+        public virtual bool IsIdentifierUtf8String
+        {
+            get { return identifier is DerUtf8String; }
+        }
+
+        public virtual Asn1Encodable Identifier
+        {
+            get { return identifier; }
+        }
+
+        /**
+         * <pre>
+         * EncKeyWithID ::= SEQUENCE {
+         *      privateKey           PrivateKeyInfo,
+         *      identifier CHOICE {
+         *         string               UTF8String,
+         *         generalName          GeneralName
+         *     } OPTIONAL
+         * }
+         * </pre>
+         * @return
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(privKeyInfo);
+            v.AddOptional(identifier);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/EncryptedKey.cs b/crypto/src/asn1/crmf/EncryptedKey.cs
new file mode 100644
index 000000000..850fbd219
--- /dev/null
+++ b/crypto/src/asn1/crmf/EncryptedKey.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class EncryptedKey
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly EnvelopedData envelopedData;
+        private readonly EncryptedValue encryptedValue;
+
+        public static EncryptedKey GetInstance(object o)
+        {
+            if (o is EncryptedKey)
+            {
+                return (EncryptedKey)o;
+            }
+            else if (o is Asn1TaggedObject)
+            {
+                return new EncryptedKey(EnvelopedData.GetInstance((Asn1TaggedObject)o, false));
+            }
+            else if (o is EncryptedValue)
+            {
+                return new EncryptedKey((EncryptedValue)o);
+            }
+            else
+            {
+                return new EncryptedKey(EncryptedValue.GetInstance(o));
+            }
+        }
+
+        public EncryptedKey(EnvelopedData envelopedData)
+        {
+            this.envelopedData = envelopedData;
+        }
+
+        public EncryptedKey(EncryptedValue encryptedValue)
+        {
+            this.encryptedValue = encryptedValue;
+        }
+
+        public virtual bool IsEncryptedValue
+        {
+            get { return encryptedValue != null; }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get
+            {
+                if (encryptedValue != null)
+                    return encryptedValue;
+
+                return envelopedData;
+            }
+        }
+
+        /**
+         * <pre>
+         *    EncryptedKey ::= CHOICE {
+         *        encryptedValue        EncryptedValue, -- deprecated
+         *        envelopedData     [0] EnvelopedData }
+         *        -- The encrypted private key MUST be placed in the envelopedData
+         *        -- encryptedContentInfo encryptedContent OCTET STRING.
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            if (encryptedValue != null)
+            {
+                return encryptedValue.ToAsn1Object();
+            }
+
+            return new DerTaggedObject(false, 0, envelopedData);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/EncryptedValue.cs b/crypto/src/asn1/crmf/EncryptedValue.cs
new file mode 100644
index 000000000..83122e220
--- /dev/null
+++ b/crypto/src/asn1/crmf/EncryptedValue.cs
@@ -0,0 +1,154 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class EncryptedValue
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier intendedAlg;
+        private readonly AlgorithmIdentifier symmAlg;
+        private readonly DerBitString encSymmKey;
+        private readonly AlgorithmIdentifier keyAlg;
+        private readonly Asn1OctetString valueHint;
+        private readonly DerBitString encValue;
+
+        private EncryptedValue(Asn1Sequence seq)
+        {
+            int index = 0;
+            while (seq[index] is Asn1TaggedObject)
+            {
+                Asn1TaggedObject tObj = (Asn1TaggedObject)seq[index];
+
+                switch (tObj.TagNo)
+                {
+                    case 0:
+                        intendedAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                        break;
+                    case 1:
+                        symmAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                        break;
+                    case 2:
+                        encSymmKey = DerBitString.GetInstance(tObj, false);
+                        break;
+                    case 3:
+                        keyAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                        break;
+                    case 4:
+                        valueHint = Asn1OctetString.GetInstance(tObj, false);
+                        break;
+                }
+                ++index;
+            }
+
+            encValue = DerBitString.GetInstance(seq[index]);
+        }
+
+        public static EncryptedValue GetInstance(object obj)
+        {
+            if (obj is EncryptedValue)
+                return (EncryptedValue)obj;
+
+            if (obj != null)
+                return new EncryptedValue(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        public EncryptedValue(
+            AlgorithmIdentifier intendedAlg,
+            AlgorithmIdentifier symmAlg,
+            DerBitString encSymmKey,
+            AlgorithmIdentifier keyAlg,
+            Asn1OctetString valueHint,
+            DerBitString encValue)
+        {
+            if (encValue == null)
+            {
+                throw new ArgumentNullException("encValue");
+            }
+
+            this.intendedAlg = intendedAlg;
+            this.symmAlg = symmAlg;
+            this.encSymmKey = encSymmKey;
+            this.keyAlg = keyAlg;
+            this.valueHint = valueHint;
+            this.encValue = encValue;
+        }
+
+        public virtual AlgorithmIdentifier IntendedAlg
+        {
+            get { return intendedAlg; }
+        }
+
+        public virtual AlgorithmIdentifier SymmAlg
+        {
+            get { return symmAlg; }
+        }
+
+        public virtual DerBitString EncSymmKey
+        {
+            get { return encSymmKey; }
+        }
+
+        public virtual AlgorithmIdentifier KeyAlg
+        {
+            get { return keyAlg; }
+        }
+
+        public virtual Asn1OctetString ValueHint
+        {
+            get { return valueHint; }
+        }
+
+        public virtual DerBitString EncValue
+        {
+            get { return encValue; }
+        }
+
+        /**
+         * <pre>
+         * EncryptedValue ::= SEQUENCE {
+         *                     intendedAlg   [0] AlgorithmIdentifier  OPTIONAL,
+         *                     -- the intended algorithm for which the value will be used
+         *                     symmAlg       [1] AlgorithmIdentifier  OPTIONAL,
+         *                     -- the symmetric algorithm used to encrypt the value
+         *                     encSymmKey    [2] BIT STRING           OPTIONAL,
+         *                     -- the (encrypted) symmetric key used to encrypt the value
+         *                     keyAlg        [3] AlgorithmIdentifier  OPTIONAL,
+         *                     -- algorithm used to encrypt the symmetric key
+         *                     valueHint     [4] OCTET STRING         OPTIONAL,
+         *                     -- a brief description or identifier of the encValue content
+         *                     -- (may be meaningful only to the sending entity, and used only
+         *                     -- if EncryptedValue might be re-examined by the sending entity
+         *                     -- in the future)
+         *                     encValue       BIT STRING }
+         *                     -- the encrypted value itself
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            AddOptional(v, 0, intendedAlg);
+            AddOptional(v, 1, symmAlg);
+            AddOptional(v, 2, encSymmKey);
+            AddOptional(v, 3, keyAlg);
+            AddOptional(v, 4, valueHint);
+
+            v.Add(encValue);
+
+            return new DerSequence(v);
+        }
+
+        private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+        {
+            if (obj != null)
+            {
+                v.Add(new DerTaggedObject(false, tagNo, obj));
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/OptionalValidity.cs b/crypto/src/asn1/crmf/OptionalValidity.cs
new file mode 100644
index 000000000..d1a0f7ffb
--- /dev/null
+++ b/crypto/src/asn1/crmf/OptionalValidity.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class OptionalValidity
+        : Asn1Encodable
+    {
+        private readonly Time notBefore;
+        private readonly Time notAfter;
+
+        private OptionalValidity(Asn1Sequence seq)
+        {
+            foreach (Asn1TaggedObject tObj in seq)
+            {
+                if (tObj.TagNo == 0)
+                {
+                    notBefore = Time.GetInstance(tObj, true);
+                }
+                else
+                {
+                    notAfter = Time.GetInstance(tObj, true);
+                }
+            }
+        }
+
+        public static OptionalValidity GetInstance(object obj)
+        {
+            if (obj == null || obj is OptionalValidity)
+                return (OptionalValidity)obj;
+
+            return new OptionalValidity(Asn1Sequence.GetInstance(obj));
+        }
+
+        public virtual Time NotBefore
+        {
+            get { return notBefore; }
+        }
+
+        public virtual Time NotAfter
+        {
+            get { return notAfter; }
+        }
+
+        /**
+         * <pre>
+         * OptionalValidity ::= SEQUENCE {
+         *                        notBefore  [0] Time OPTIONAL,
+         *                        notAfter   [1] Time OPTIONAL } --at least one MUST be present
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (notBefore != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, notBefore));
+            }
+
+            if (notAfter != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, notAfter));
+            }
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PKIArchiveOptions.cs b/crypto/src/asn1/crmf/PKIArchiveOptions.cs
new file mode 100644
index 000000000..910f73b22
--- /dev/null
+++ b/crypto/src/asn1/crmf/PKIArchiveOptions.cs
@@ -0,0 +1,105 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PkiArchiveOptions
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int encryptedPrivKey = 0;
+        public const int keyGenParameters = 1;
+        public const int archiveRemGenPrivKey = 2;
+
+        private readonly Asn1Encodable value;
+
+        public static PkiArchiveOptions GetInstance(object obj)
+        {
+            if (obj is PkiArchiveOptions)
+                return (PkiArchiveOptions)obj;
+
+            if (obj is Asn1TaggedObject)
+                return new PkiArchiveOptions((Asn1TaggedObject)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        private PkiArchiveOptions(Asn1TaggedObject tagged)
+        {
+            switch (tagged.TagNo)
+            {
+                case encryptedPrivKey:
+                    value = EncryptedKey.GetInstance(tagged.GetObject());
+                    break;
+                case keyGenParameters:
+                    value = Asn1OctetString.GetInstance(tagged, false);
+                    break;
+                case archiveRemGenPrivKey:
+                    value = DerBoolean.GetInstance(tagged, false);
+                    break;
+                default:
+                    throw new ArgumentException("unknown tag number: " + tagged.TagNo, "tagged");
+            }
+        }
+
+        public PkiArchiveOptions(EncryptedKey encKey)
+        {
+            this.value = encKey;
+        }
+
+        public PkiArchiveOptions(Asn1OctetString keyGenParameters)
+        {
+            this.value = keyGenParameters;
+        }
+
+        public PkiArchiveOptions(bool archiveRemGenPrivKey)
+        {
+            this.value = DerBoolean.GetInstance(archiveRemGenPrivKey);
+        }
+
+        public virtual int Type
+        {
+            get
+            {
+                if (value is EncryptedKey)
+                    return encryptedPrivKey;
+
+                if (value is Asn1OctetString)
+                    return keyGenParameters;
+
+                return archiveRemGenPrivKey;
+            }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get { return value; }
+        }
+
+        /**
+         * <pre>
+         *  PkiArchiveOptions ::= CHOICE {
+         *      encryptedPrivKey     [0] EncryptedKey,
+         *      -- the actual value of the private key
+         *      keyGenParameters     [1] KeyGenParameters,
+         *      -- parameters which allow the private key to be re-generated
+         *      archiveRemGenPrivKey [2] BOOLEAN }
+         *      -- set to TRUE if sender wishes receiver to archive the private
+         *      -- key of a key pair that the receiver generates in response to
+         *      -- this request; set to FALSE if no archival is desired.
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            if (value is EncryptedKey)
+            {
+                return new DerTaggedObject(true, encryptedPrivKey, value);  // choice
+            }
+
+            if (value is Asn1OctetString)
+            {
+                return new DerTaggedObject(false, keyGenParameters, value);
+            }
+
+            return new DerTaggedObject(false, archiveRemGenPrivKey, value);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PKIPublicationInfo.cs b/crypto/src/asn1/crmf/PKIPublicationInfo.cs
new file mode 100644
index 000000000..c8bc1403e
--- /dev/null
+++ b/crypto/src/asn1/crmf/PKIPublicationInfo.cs
@@ -0,0 +1,64 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PkiPublicationInfo
+        : Asn1Encodable
+    {
+        private readonly DerInteger action;
+        private readonly Asn1Sequence pubInfos;
+
+        private PkiPublicationInfo(Asn1Sequence seq)
+        {
+            action = DerInteger.GetInstance(seq[0]);
+            pubInfos = Asn1Sequence.GetInstance(seq[1]);
+        }
+
+        public static PkiPublicationInfo GetInstance(object obj)
+        {
+            if (obj is PkiPublicationInfo)
+                return (PkiPublicationInfo)obj;
+
+            if (obj is Asn1Sequence)
+                return new PkiPublicationInfo((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public virtual DerInteger Action
+        {
+            get { return action; }
+        }
+
+        public virtual SinglePubInfo[] GetPubInfos()
+        {
+            if (pubInfos == null)
+                return null;
+
+            SinglePubInfo[] results = new SinglePubInfo[pubInfos.Count];
+            for (int i = 0; i != results.Length; ++i)
+            {
+                results[i] = SinglePubInfo.GetInstance(pubInfos[i]);
+            }
+            return results;
+        }
+
+        /**
+         * <pre>
+         * PkiPublicationInfo ::= SEQUENCE {
+         *                  action     INTEGER {
+         *                                 dontPublish (0),
+         *                                 pleasePublish (1) },
+         *                  pubInfos  SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL }
+         * -- pubInfos MUST NOT be present if action is "dontPublish"
+         * -- (if action is "pleasePublish" and pubInfos is omitted,
+         * -- "dontCare" is assumed)
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(action, pubInfos);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PKMacValue.cs b/crypto/src/asn1/crmf/PKMacValue.cs
new file mode 100644
index 000000000..20a08fd1d
--- /dev/null
+++ b/crypto/src/asn1/crmf/PKMacValue.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    /**
+     * Password-based MAC value for use with POPOSigningKeyInput.
+     */
+    public class PKMacValue
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier  algID;
+        private readonly DerBitString         macValue;
+
+        private PKMacValue(Asn1Sequence seq)
+        {
+            this.algID = AlgorithmIdentifier.GetInstance(seq[0]);
+            this.macValue = DerBitString.GetInstance(seq[1]);
+        }
+
+        public static PKMacValue GetInstance(object obj)
+        {
+            if (obj is PKMacValue)
+                return (PKMacValue)obj;
+
+            if (obj is Asn1Sequence)
+                return new PKMacValue((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public static PKMacValue GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        /**
+         * Creates a new PKMACValue.
+         * @param params parameters for password-based MAC
+         * @param value MAC of the DER-encoded SubjectPublicKeyInfo
+         */
+        public PKMacValue(
+            PbmParameter pbmParams,
+            DerBitString macValue)
+            : this(new AlgorithmIdentifier(CmpObjectIdentifiers.passwordBasedMac, pbmParams), macValue)
+        {
+        }
+
+        /**
+         * Creates a new PKMACValue.
+         * @param aid CMPObjectIdentifiers.passwordBasedMAC, with PBMParameter
+         * @param value MAC of the DER-encoded SubjectPublicKeyInfo
+         */
+        public PKMacValue(
+            AlgorithmIdentifier algID,
+            DerBitString        macValue)
+        {
+            this.algID = algID;
+            this.macValue = macValue;
+        }
+
+        public virtual AlgorithmIdentifier AlgID
+        {
+            get { return algID; }
+        }
+
+        public virtual DerBitString MacValue
+        {
+            get { return macValue; }
+        }
+
+        /**
+         * <pre>
+         * PKMACValue ::= SEQUENCE {
+         *      algId  AlgorithmIdentifier,
+         *      -- algorithm value shall be PasswordBasedMac 1.2.840.113533.7.66.13
+         *      -- parameter value is PBMParameter
+         *      value  BIT STRING }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(algID, macValue);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PopoPrivKey.cs b/crypto/src/asn1/crmf/PopoPrivKey.cs
new file mode 100644
index 000000000..0cedc5127
--- /dev/null
+++ b/crypto/src/asn1/crmf/PopoPrivKey.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PopoPrivKey
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int thisMessage = 0;
+        public const int subsequentMessage = 1;
+        public const int dhMAC = 2;
+        public const int agreeMAC = 3;
+        public const int encryptedKey = 4;
+
+        private readonly int tagNo;
+        private readonly Asn1Encodable obj;
+
+        private PopoPrivKey(Asn1TaggedObject obj)
+        {
+            this.tagNo = obj.TagNo;
+
+            switch (tagNo)
+            {
+            case thisMessage:
+                this.obj = DerBitString.GetInstance(obj, false);
+                break;
+            case subsequentMessage:
+                this.obj = SubsequentMessage.ValueOf(DerInteger.GetInstance(obj, false).Value.IntValue);
+                break;
+            case dhMAC:
+                this.obj = DerBitString.GetInstance(obj, false);
+                break;
+            case agreeMAC:
+                this.obj = PKMacValue.GetInstance(obj, false);
+                break;
+            case encryptedKey:
+                this.obj = EnvelopedData.GetInstance(obj, false);
+                break;
+            default:
+                throw new ArgumentException("unknown tag in PopoPrivKey", "obj");
+            }
+        }
+
+        public static PopoPrivKey GetInstance(Asn1TaggedObject tagged, bool isExplicit)
+        {
+            return new PopoPrivKey(Asn1TaggedObject.GetInstance(tagged.GetObject()));
+        }
+
+        public PopoPrivKey(SubsequentMessage msg)
+        {
+            this.tagNo = subsequentMessage;
+            this.obj = msg;
+        }
+
+        public virtual int Type
+        {
+            get { return tagNo; }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get { return obj; }
+        }
+
+        /**
+         * <pre>
+         * PopoPrivKey ::= CHOICE {
+         *        thisMessage       [0] BIT STRING,         -- Deprecated
+         *         -- possession is proven in this message (which contains the private
+         *         -- key itself (encrypted for the CA))
+         *        subsequentMessage [1] SubsequentMessage,
+         *         -- possession will be proven in a subsequent message
+         *        dhMAC             [2] BIT STRING,         -- Deprecated
+         *        agreeMAC          [3] PKMACValue,
+         *        encryptedKey      [4] EnvelopedData }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, tagNo, obj);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PopoSigningKey.cs b/crypto/src/asn1/crmf/PopoSigningKey.cs
new file mode 100644
index 000000000..614278eda
--- /dev/null
+++ b/crypto/src/asn1/crmf/PopoSigningKey.cs
@@ -0,0 +1,115 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PopoSigningKey
+        : Asn1Encodable
+    {
+        private readonly PopoSigningKeyInput poposkInput;
+        private readonly AlgorithmIdentifier algorithmIdentifier;
+        private readonly DerBitString signature;
+
+        private PopoSigningKey(Asn1Sequence seq)
+        {
+            int index = 0;
+
+            if (seq[index] is Asn1TaggedObject)
+            {
+                Asn1TaggedObject tagObj
+                    = (Asn1TaggedObject) seq[index++];
+                if (tagObj.TagNo != 0)
+                {
+                    throw new ArgumentException( "Unknown PopoSigningKeyInput tag: " + tagObj.TagNo, "seq");
+                }
+                poposkInput = PopoSigningKeyInput.GetInstance(tagObj.GetObject());
+            }
+            algorithmIdentifier = AlgorithmIdentifier.GetInstance(seq[index++]);
+            signature = DerBitString.GetInstance(seq[index]);
+        }
+
+        public static PopoSigningKey GetInstance(object obj)
+        {
+            if (obj is PopoSigningKey)
+                return (PopoSigningKey)obj;
+
+            if (obj is Asn1Sequence)
+                return new PopoSigningKey((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public static PopoSigningKey GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        /**
+         * Creates a new Proof of Possession object for a signing key.
+         * @param poposkIn the PopoSigningKeyInput structure, or null if the
+         *     CertTemplate includes both subject and publicKey values.
+         * @param aid the AlgorithmIdentifier used to sign the proof of possession.
+         * @param signature a signature over the DER-encoded value of poposkIn,
+         *     or the DER-encoded value of certReq if poposkIn is null.
+         */
+        public PopoSigningKey(
+            PopoSigningKeyInput poposkIn,
+            AlgorithmIdentifier aid,
+            DerBitString signature)
+        {
+            this.poposkInput = poposkIn;
+            this.algorithmIdentifier = aid;
+            this.signature = signature;
+        }
+
+        public virtual PopoSigningKeyInput PoposkInput
+        {
+            get { return poposkInput; }
+        }
+
+        public virtual AlgorithmIdentifier AlgorithmIdentifier
+        {
+            get { return algorithmIdentifier; }
+        }
+
+        public virtual DerBitString Signature
+        {
+            get { return signature; }
+        }
+
+        /**
+         * <pre>
+         * PopoSigningKey ::= SEQUENCE {
+         *                      poposkInput           [0] PopoSigningKeyInput OPTIONAL,
+         *                      algorithmIdentifier   AlgorithmIdentifier,
+         *                      signature             BIT STRING }
+         *  -- The signature (using "algorithmIdentifier") is on the
+         *  -- DER-encoded value of poposkInput.  NOTE: If the CertReqMsg
+         *  -- certReq CertTemplate contains the subject and publicKey values,
+         *  -- then poposkInput MUST be omitted and the signature MUST be
+         *  -- computed on the DER-encoded value of CertReqMsg certReq.  If
+         *  -- the CertReqMsg certReq CertTemplate does not contain the public
+         *  -- key and subject values, then poposkInput MUST be present and
+         *  -- MUST be signed.  This strategy ensures that the public key is
+         *  -- not present in both the poposkInput and CertReqMsg certReq
+         *  -- CertTemplate fields.
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (poposkInput != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, poposkInput));
+            }
+
+            v.Add(algorithmIdentifier);
+            v.Add(signature);
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PopoSigningKeyInput.cs b/crypto/src/asn1/crmf/PopoSigningKeyInput.cs
new file mode 100644
index 000000000..63695262f
--- /dev/null
+++ b/crypto/src/asn1/crmf/PopoSigningKeyInput.cs
@@ -0,0 +1,115 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PopoSigningKeyInput
+        : Asn1Encodable
+    {
+        private readonly GeneralName            sender;
+        private readonly PKMacValue             publicKeyMac;
+        private readonly SubjectPublicKeyInfo   publicKey;
+
+        private PopoSigningKeyInput(Asn1Sequence seq)
+        {
+            Asn1Encodable authInfo = (Asn1Encodable)seq[0];
+
+            if (authInfo is Asn1TaggedObject)
+            {
+                Asn1TaggedObject tagObj = (Asn1TaggedObject)authInfo;
+                if (tagObj.TagNo != 0)
+                {
+                    throw new ArgumentException("Unknown authInfo tag: " + tagObj.TagNo, "seq");
+                }
+                sender = GeneralName.GetInstance(tagObj.GetObject());
+            }
+            else
+            {
+                publicKeyMac = PKMacValue.GetInstance(authInfo);
+            }
+
+            publicKey = SubjectPublicKeyInfo.GetInstance(seq[1]);
+        }
+
+        public static PopoSigningKeyInput GetInstance(object obj)
+        {
+            if (obj is PopoSigningKeyInput)
+                return (PopoSigningKeyInput)obj;
+
+            if (obj is Asn1Sequence)
+                return new PopoSigningKeyInput((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        /** Creates a new PopoSigningKeyInput with sender name as authInfo. */
+        public PopoSigningKeyInput(
+            GeneralName sender,
+            SubjectPublicKeyInfo spki)
+        {
+            this.sender = sender;
+            this.publicKey = spki;
+        }
+
+        /** Creates a new PopoSigningKeyInput using password-based MAC. */
+        public PopoSigningKeyInput(
+            PKMacValue pkmac,
+            SubjectPublicKeyInfo spki)
+        {
+            this.publicKeyMac = pkmac;
+            this.publicKey = spki;
+        }
+
+        /** Returns the sender field, or null if authInfo is publicKeyMac */
+        public virtual GeneralName Sender
+        {
+            get { return sender; }
+        }
+
+        /** Returns the publicKeyMac field, or null if authInfo is sender */
+        public virtual PKMacValue PublicKeyMac
+        {
+            get { return publicKeyMac; }
+        }
+
+        public virtual SubjectPublicKeyInfo PublicKey
+        {
+            get { return publicKey; }
+        }
+
+        /**
+         * <pre>
+         * PopoSigningKeyInput ::= SEQUENCE {
+         *        authInfo             CHOICE {
+         *                                 sender              [0] GeneralName,
+         *                                 -- used only if an authenticated identity has been
+         *                                 -- established for the sender (e.g., a DN from a
+         *                                 -- previously-issued and currently-valid certificate
+         *                                 publicKeyMac        PKMacValue },
+         *                                 -- used if no authenticated GeneralName currently exists for
+         *                                 -- the sender; publicKeyMac contains a password-based MAC
+         *                                 -- on the DER-encoded value of publicKey
+         *        publicKey           SubjectPublicKeyInfo }  -- from CertTemplate
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (sender != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, sender));
+            }
+            else
+            {
+                v.Add(publicKeyMac);
+            }
+
+            v.Add(publicKey);
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/ProofOfPossession.cs b/crypto/src/asn1/crmf/ProofOfPossession.cs
new file mode 100644
index 000000000..fc00edb32
--- /dev/null
+++ b/crypto/src/asn1/crmf/ProofOfPossession.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class ProofOfPossession
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int TYPE_RA_VERIFIED = 0;
+        public const int TYPE_SIGNING_KEY = 1;
+        public const int TYPE_KEY_ENCIPHERMENT = 2;
+        public const int TYPE_KEY_AGREEMENT = 3;
+
+        private readonly int tagNo;
+        private readonly Asn1Encodable obj;
+
+        private ProofOfPossession(Asn1TaggedObject tagged)
+        {
+            tagNo = tagged.TagNo;
+            switch (tagNo)
+            {
+            case 0:
+                obj = DerNull.Instance;
+                break;
+            case 1:
+                obj = PopoSigningKey.GetInstance(tagged, false);
+                break;
+            case 2:
+            case 3:
+                obj = PopoPrivKey.GetInstance(tagged, false);
+                break;
+            default:
+                throw new ArgumentException("unknown tag: " + tagNo, "tagged");
+            }
+        }
+
+        public static ProofOfPossession GetInstance(object obj)
+        {
+            if (obj is ProofOfPossession)
+                return (ProofOfPossession)obj;
+
+            if (obj is Asn1TaggedObject)
+                return new ProofOfPossession((Asn1TaggedObject)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        /** Creates a ProofOfPossession with type raVerified. */
+        public ProofOfPossession()
+        {
+            tagNo = TYPE_RA_VERIFIED;
+            obj = DerNull.Instance;
+        }
+
+        /** Creates a ProofOfPossession for a signing key. */
+        public ProofOfPossession(PopoSigningKey Poposk)
+        {
+            tagNo = TYPE_SIGNING_KEY;
+            obj = Poposk;
+        }
+
+        /**
+         * Creates a ProofOfPossession for key encipherment or agreement.
+         * @param type one of TYPE_KEY_ENCIPHERMENT or TYPE_KEY_AGREEMENT
+         */
+        public ProofOfPossession(int type, PopoPrivKey privkey)
+        {
+            tagNo = type;
+            obj = privkey;
+        }
+
+        public virtual int Type
+        {
+            get { return tagNo; }
+        }
+
+        public virtual Asn1Encodable Object
+        {
+            get { return obj; }
+        }
+
+        /**
+         * <pre>
+         * ProofOfPossession ::= CHOICE {
+         *                           raVerified        [0] NULL,
+         *                           -- used if the RA has already verified that the requester is in
+         *                           -- possession of the private key
+         *                           signature         [1] PopoSigningKey,
+         *                           keyEncipherment   [2] PopoPrivKey,
+         *                           keyAgreement      [3] PopoPrivKey }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, tagNo, obj);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/SinglePubInfo.cs b/crypto/src/asn1/crmf/SinglePubInfo.cs
new file mode 100644
index 000000000..eaf8a3efd
--- /dev/null
+++ b/crypto/src/asn1/crmf/SinglePubInfo.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class SinglePubInfo
+        : Asn1Encodable
+    {
+        private readonly DerInteger pubMethod;
+        private readonly GeneralName pubLocation;
+
+        private SinglePubInfo(Asn1Sequence seq)
+        {
+            pubMethod = DerInteger.GetInstance(seq[0]);
+
+            if (seq.Count == 2)
+            {
+                pubLocation = GeneralName.GetInstance(seq[1]);
+            }
+        }
+
+        public static SinglePubInfo GetInstance(object obj)
+        {
+            if (obj is SinglePubInfo)
+                return (SinglePubInfo)obj;
+
+            if (obj is Asn1Sequence)
+                return new SinglePubInfo((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public virtual GeneralName PubLocation
+        {
+            get { return pubLocation; }
+        }
+
+        /**
+         * <pre>
+         * SinglePubInfo ::= SEQUENCE {
+         *        pubMethod    INTEGER {
+         *           dontCare    (0),
+         *           x500        (1),
+         *           web         (2),
+         *           ldap        (3) },
+         *       pubLocation  GeneralName OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(pubMethod);
+            v.AddOptional(pubLocation);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/SubsequentMessage.cs b/crypto/src/asn1/crmf/SubsequentMessage.cs
new file mode 100644
index 000000000..cc1c16492
--- /dev/null
+++ b/crypto/src/asn1/crmf/SubsequentMessage.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class SubsequentMessage
+        : DerInteger
+    {
+        public static readonly SubsequentMessage encrCert = new SubsequentMessage(0);
+        public static readonly SubsequentMessage challengeResp = new SubsequentMessage(1);
+    
+        private SubsequentMessage(int value)
+            : base(value)
+        {
+        }
+
+        public static SubsequentMessage ValueOf(int value)
+        {
+            if (value == 0)
+                return encrCert;
+
+            if (value == 1)
+                return challengeResp;
+
+            throw new ArgumentException("unknown value: " + value, "value");
+        }
+    }
+}