summary refs log tree commit diff
path: root/crypto/src/asn1/crmf
diff options
context:
space:
mode:
authorMegan Woods <megan@flygfisk.com>2019-01-14 17:07:22 +1100
committerMegan Woods <megan@flygfisk.com>2019-01-14 17:07:22 +1100
commitecc8edb622f0f42d43f72ae388fa4c4274e51c5f (patch)
tree9091e5bf1fe54dde31ee786956139b0fb54b0ba3 /crypto/src/asn1/crmf
parentminor tweaks (diff)
downloadBouncyCastle.NET-ed25519-ecc8edb622f0f42d43f72ae388fa4c4274e51c5f.tar.xz
Initial CMP
Diffstat (limited to 'crypto/src/asn1/crmf')
-rw-r--r--crypto/src/asn1/crmf/AuthenticatorControl.cs33
-rw-r--r--crypto/src/asn1/crmf/CertificateRequestMessage.cs182
-rw-r--r--crypto/src/asn1/crmf/CertificateRequestMessageBuilder.cs261
-rw-r--r--crypto/src/asn1/crmf/Controls.cs9
-rw-r--r--crypto/src/asn1/crmf/CrmfException.cs26
-rw-r--r--crypto/src/asn1/crmf/EncryptedValueBuilder.cs53
-rw-r--r--crypto/src/asn1/crmf/OptionalValidity.cs6
-rw-r--r--crypto/src/asn1/crmf/PkiArchiveControl.cs68
-rw-r--r--crypto/src/asn1/crmf/ProofOfPossessionSigningKeyBuilder.cs90
-rw-r--r--crypto/src/asn1/crmf/RegTokenControl.cs32
10 files changed, 760 insertions, 0 deletions
diff --git a/crypto/src/asn1/crmf/AuthenticatorControl.cs b/crypto/src/asn1/crmf/AuthenticatorControl.cs
new file mode 100644
index 000000000..060088b1f
--- /dev/null
+++ b/crypto/src/asn1/crmf/AuthenticatorControl.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class AuthenticatorControl:IControl
+    {
+
+        private static readonly DerObjectIdentifier type = CrmfObjectIdentifiers.id_regCtrl_authenticator;
+
+        private readonly DerUtf8String token;
+
+        public AuthenticatorControl(DerUtf8String token)
+        {
+            this.token = token;
+        }
+
+        public AuthenticatorControl(String token)
+        {
+            this.token = new DerUtf8String(token);
+        }
+
+        public DerObjectIdentifier Type
+        {
+            get { return type; }
+        }
+
+        public Asn1Encodable Value {
+            get { return token; }
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertificateRequestMessage.cs b/crypto/src/asn1/crmf/CertificateRequestMessage.cs
new file mode 100644
index 000000000..b80c2a3fd
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertificateRequestMessage.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertificateRequestMessage
+    {
+        public static readonly int popRaVerified = Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.TYPE_RA_VERIFIED;
+        public static readonly int popSigningKey = Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.TYPE_SIGNING_KEY;
+        public static readonly int popKeyEncipherment = Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
+        public static readonly int popKeyAgreement = Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.TYPE_KEY_AGREEMENT;
+
+        private readonly CertReqMsg certReqMsg;
+        private readonly Controls controls;
+
+        private static CertReqMsg ParseBytes(byte[] encoding)
+       
+        {        
+                return CertReqMsg.GetInstance(encoding);
+        }
+
+        public CertificateRequestMessage(CertReqMsg certReqMsg)
+        {
+            this.certReqMsg = certReqMsg;
+            this.controls = certReqMsg.CertReq.Controls;
+        }
+
+        public CertReqMsg ToAsn1Structure()
+        {
+            return certReqMsg; 
+        }
+
+        public CertTemplate GetCertTemplate()
+        {
+            return this.certReqMsg.CertReq.CertTemplate;
+        }
+
+        public bool HasControls
+        {
+            get { return controls != null; }
+        }
+
+
+        public bool HasControl(DerObjectIdentifier objectIdentifier)
+        {
+            return findControl(objectIdentifier) != null;
+        }
+
+        public IControl GetControl(DerObjectIdentifier type)
+        {
+            AttributeTypeAndValue found = findControl(type);
+            if (found != null)
+            {
+                if (found.Type.Equals(CrmfObjectIdentifiers.id_regCtrl_pkiArchiveOptions))
+                {
+                    return new PkiArchiveControl(PkiArchiveOptions.GetInstance(found.Value));
+                }
+
+                if (found.Type.Equals(CrmfObjectIdentifiers.id_regCtrl_regToken))
+                {
+                    return new RegTokenControl(DerUtf8String.GetInstance(found.Value));
+                }
+
+                if (found.Type.Equals(CrmfObjectIdentifiers.id_regCtrl_authenticator))
+                {
+                    return new AuthenticatorControl(DerUtf8String.GetInstance(found.Value));
+                }
+            }        
+            return null;
+        }
+
+
+
+
+        public AttributeTypeAndValue findControl(DerObjectIdentifier type)
+        {
+            if (controls == null)
+            {
+                return null;
+            }
+
+            AttributeTypeAndValue[] tAndV = controls.ToAttributeTypeAndValueArray();
+            AttributeTypeAndValue found = null;
+
+            for (int i = 0; i < tAndV.Length; i++)
+            {
+                if (tAndV[i].Type.Equals(type))
+                {
+                    found = tAndV[i];
+                    break;
+                }
+            }
+
+            return found;
+        }
+
+        public bool HasProofOfPossession
+        {
+            get { return certReqMsg.Popo != null; }
+        }
+
+        public int ProofOfPossession
+        {
+            get { return certReqMsg.Popo.Type; }
+        }
+
+        public bool HasSigningKeyProofOfPossessionWithPkMac
+        {
+            get
+            {
+                ProofOfPossession pop = certReqMsg.Popo;
+
+                if (pop.Type == popSigningKey)
+                {
+                    PopoSigningKey popoSign = PopoSigningKey.GetInstance(pop.Object);
+
+                    return popoSign.PoposkInput.PublicKeyMac != null;
+                }
+
+                return false;
+
+            }
+        }
+   
+        public bool IsValidSigningKeyPop(IVerifierFactoryProvider verifierProvider)
+        {
+            ProofOfPossession pop = certReqMsg.Popo;
+            if (pop.Type == popSigningKey)
+            {
+                PopoSigningKey popoSign = PopoSigningKey.GetInstance(pop.Object);
+                if (popoSign.PoposkInput != null && popoSign.PoposkInput.PublicKeyMac != null)
+                {
+                    throw new InvalidOperationException("verification requires password check");
+                }
+                return verifySignature(verifierProvider, popoSign);
+            }
+
+            throw new InvalidOperationException("not Signing Key type of proof of possession");
+        }
+
+
+
+        private bool verifySignature(IVerifierFactoryProvider verifierFactoryProvider, PopoSigningKey signKey)
+        {
+            IVerifierFactory verifer;
+            IStreamCalculator calculator;
+            try
+            {
+                verifer = verifierFactoryProvider.CreateVerifierFactory(signKey.AlgorithmIdentifier);
+                calculator = verifer.CreateCalculator();
+            }
+            catch (Exception ex)
+            {
+                throw new CrmfException("unable to create verifier: "+ex.Message, ex);
+            }
+
+            if (signKey.PoposkInput != null)
+            {
+                byte[] b = signKey.GetDerEncoded();
+              calculator.Stream.Write(b,0,b.Length);
+            }
+            else
+            {
+                byte[] b = certReqMsg.GetDerEncoded();
+                calculator.Stream.Write(b,0,b.Length);
+            }
+
+            DefaultVerifierResult result = (DefaultVerifierResult) calculator.GetResult();
+      
+            return result.IsVerified(signKey.Signature.GetBytes());
+        }
+
+        public byte[] GetEncoded()
+        {
+            return certReqMsg.GetEncoded();
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertificateRequestMessageBuilder.cs b/crypto/src/asn1/crmf/CertificateRequestMessageBuilder.cs
new file mode 100644
index 000000000..df604f4f5
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertificateRequestMessageBuilder.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertificateRequestMessageBuilder
+    {
+        private readonly BigInteger _certReqId;
+        private X509ExtensionsGenerator _extGenerator;
+        private CertTemplateBuilder _templateBuilder;
+        private ArrayList _controls= new ArrayList();
+        private ISignatureFactory _popSigner;
+        private PkMacFactory _pkMacBuilder;
+        private char[] _password;
+        private GeneralName _sender;
+        private int _popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
+        private PopoPrivKey _popoPrivKey;
+        private Asn1Null _popRaVerified;
+        private PKMacValue _agreeMac;
+
+        public CertificateRequestMessageBuilder(BigInteger certReqId)
+        {
+            this._certReqId = certReqId;
+            this._extGenerator = new X509ExtensionsGenerator();
+            this._templateBuilder = new CertTemplateBuilder();
+        }
+
+        public CertificateRequestMessageBuilder SetPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+        {
+            if (publicKeyInfo != null)
+            {
+                _templateBuilder.SetPublicKey(publicKeyInfo);
+            }
+
+            return this;
+        }
+
+
+        public CertificateRequestMessageBuilder SetIssuer(X509Name issuer)
+        {
+            if (issuer != null)
+            {
+                _templateBuilder.SetIssuer(issuer);
+            }
+
+            return this;
+        }
+
+        public CertificateRequestMessageBuilder SetSubject(X509Name subject)
+        {
+            if (subject != null)
+            {
+                _templateBuilder.SetSubject(subject);
+            }
+
+            return this;
+        }
+
+        public CertificateRequestMessageBuilder SetSerialNumber(BigInteger serialNumber)
+        {
+            if (serialNumber != null)
+            {
+                _templateBuilder.SetSerialNumber(new DerInteger(serialNumber));
+            }
+
+            return this;
+        }
+
+        public CertificateRequestMessageBuilder SetValidity(Time notBefore, Time notAfter)
+        {
+            _templateBuilder.SetValidity(new OptionalValidity(notBefore, notAfter));
+            return this;                
+        }
+
+        public CertificateRequestMessageBuilder AddExtension(DerObjectIdentifier oid, bool critical,
+            Asn1Encodable value)
+        {
+           _extGenerator.AddExtension(oid,critical, value);
+            return this;
+        }
+
+        public CertificateRequestMessageBuilder AddExtension(DerObjectIdentifier oid, bool critical,
+            byte[] value)
+        {
+            _extGenerator.AddExtension(oid, critical, value);
+            return this;
+        }
+
+        public CertificateRequestMessageBuilder SetProofOfPossessionSignKeySigner(ISignatureFactory popoSignatureFactory)
+        {
+            if (_popoPrivKey != null || _popRaVerified != null || _agreeMac != null)
+            {
+                throw new InvalidOperationException("only one proof of possession is allowed.");
+            }
+
+            this._popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
+            return this;
+        }
+
+        public CertificateRequestMessageBuilder SetProofOfPossessionSubsequentMessage(SubsequentMessage msg)
+        {
+            if (_popoPrivKey != null || _popRaVerified != null || _agreeMac != null)
+            {
+                throw new InvalidOperationException("only one proof of possession is allowed.");
+            }
+
+            this._popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
+            this._popoPrivKey = new PopoPrivKey(msg);
+
+        
+            return this;
+        }
+
+
+        public CertificateRequestMessageBuilder SetProofOfPossessionSubsequentMessage(int type, SubsequentMessage msg)
+        {
+            if (_popoPrivKey != null || _popRaVerified != null || _agreeMac != null)
+            {
+                throw new InvalidOperationException("only one proof of possession is allowed.");
+            }
+
+            if (type != ProofOfPossession.TYPE_KEY_ENCIPHERMENT && type != ProofOfPossession.TYPE_KEY_AGREEMENT)
+            {
+                throw new ArgumentException("type must be ProofOfPossession.TYPE_KEY_ENCIPHERMENT || ProofOfPossession.TYPE_KEY_AGREEMENT");
+            }
+
+            this._popoType = type;
+            this._popoPrivKey = new PopoPrivKey(msg);
+            return this;        
+        }
+
+        public CertificateRequestMessageBuilder SetProofOfPossessionAgreeMac(PKMacValue macValue)
+        {
+            if (_popSigner != null || _popRaVerified != null || _popoPrivKey != null)
+            {
+                throw new InvalidOperationException("only one proof of possession allowed");
+            }
+
+            this._agreeMac = macValue;        
+            return this;
+        }
+
+        public CertificateRequestMessageBuilder SetProofOfPossessionRaVerified()
+        {
+            if (_popSigner != null || _popoPrivKey != null)
+            {
+                throw new InvalidOperationException("only one proof of possession allowed");
+            }
+
+            this._popRaVerified = DerNull.Instance;
+
+            return this;
+        }
+
+        public CertificateRequestMessageBuilder SetAuthInfoPKMAC(PkMacFactory pkmacFactory, char[] password)
+        {
+            this._pkMacBuilder = pkmacFactory;
+            this._password = password;
+
+            return this;
+        }
+
+        public CertificateRequestMessageBuilder SetAuthInfoSender(X509Name sender)
+        {
+            return SetAuthInfoSender(new GeneralName(sender));
+        }
+
+        public CertificateRequestMessageBuilder SetAuthInfoSender(GeneralName sender)
+        {
+            this._sender = sender;
+            return this;
+        }
+
+        public CertificateRequestMessage Build()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            v.Add(new DerInteger(this._certReqId));
+
+            if (!this._extGenerator.IsEmpty)
+            {
+               this._templateBuilder.SetExtensions(_extGenerator.Generate());
+            }
+
+            v.Add(_templateBuilder.Build());
+
+            if (_controls.Count>0)
+            {
+                Asn1EncodableVector controlV = new Asn1EncodableVector();
+
+                foreach (Object item  in _controls)
+                {
+                    IControl control = (IControl) item;
+                    controlV.Add(new AttributeTypeAndValue(control.Type, control.Value));
+                }
+                    
+                v.Add(new DerSequence(controlV));
+            }
+
+            CertRequest request = CertRequest.GetInstance(new DerSequence(v));
+
+            v = new Asn1EncodableVector();
+
+            v.Add(request);
+
+            if (_popSigner != null)
+            {
+                CertTemplate template = request.CertTemplate;
+
+                if (template.Subject == null || template.PublicKey == null)
+                {
+                    SubjectPublicKeyInfo pubKeyInfo = request.CertTemplate.PublicKey;
+                  
+                    ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(pubKeyInfo);
+
+                    if (_sender != null)
+                    {
+                        builder.setSender(_sender);
+                    }
+                    else
+                    {
+                       // PkMa pkmacGenerator = new PKMACValueGenerator(_pkmacBuilder);
+
+                        builder.setPublicKeyMac(_pkMacBuilder, _password);
+                    }
+
+                    v.Add(new ProofOfPossession(builder.build(_popSigner)));
+                }
+                else
+                {
+                    ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(request);
+
+                    v.Add(new ProofOfPossession(builder.build(_popSigner)));
+                }
+            }
+            else if (_popoPrivKey != null)
+            {
+                v.Add(new ProofOfPossession(_popoType, _popoPrivKey));
+            }
+            else if (_agreeMac != null)
+            {
+                v.Add(new ProofOfPossession(ProofOfPossession.TYPE_KEY_AGREEMENT,
+                        PopoPrivKey.GetInstance(new DerTaggedObject(false, PopoPrivKey.agreeMAC, _agreeMac),true )));
+
+            }
+            else if (_popRaVerified != null)
+            {
+                v.Add(new ProofOfPossession());
+            }
+
+            return new CertificateRequestMessage(CertReqMsg.GetInstance(new DerSequence(v)));
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/Controls.cs b/crypto/src/asn1/crmf/Controls.cs
index e8b9f3db0..8f986168c 100644
--- a/crypto/src/asn1/crmf/Controls.cs
+++ b/crypto/src/asn1/crmf/Controls.cs
@@ -4,6 +4,15 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Crmf
 {
+
+    public interface IControl
+    {
+        DerObjectIdentifier Type { get; }
+
+        Asn1Encodable Value { get; }
+    }
+
+
     public class Controls
         : Asn1Encodable
     {
diff --git a/crypto/src/asn1/crmf/CrmfException.cs b/crypto/src/asn1/crmf/CrmfException.cs
new file mode 100644
index 000000000..7043ccd73
--- /dev/null
+++ b/crypto/src/asn1/crmf/CrmfException.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CrmfException : Exception
+    {
+        public CrmfException()
+        {
+        }
+
+        public CrmfException(string message) : base(message)
+        {
+        }
+
+        public CrmfException(string message, Exception innerException) : base(message, innerException)
+        {
+        }
+
+        protected CrmfException(SerializationInfo info, StreamingContext context) : base(info, context)
+        {
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/EncryptedValueBuilder.cs b/crypto/src/asn1/crmf/EncryptedValueBuilder.cs
new file mode 100644
index 000000000..4b57156d4
--- /dev/null
+++ b/crypto/src/asn1/crmf/EncryptedValueBuilder.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+
+//    public delegate IBlockCipher BlockCipherCreator(ICipherParameters);
+//
+//    public class EncryptedValueBuilder
+//    {
+//        private readonly IBlockCipher _cipher;
+//        private static readonly IDictionary algToDelegate = Platform.CreateHashtable();
+//        static EncryptedValueBuilder()
+//        {
+//            algToDelegate[NistObjectIdentifiers.IdAes128Cbc] = new CipherCreator()
+//                {Creator = delegate(ICipherParameters param) { return new AesEngine(); }};
+//
+//        }
+//
+//
+//        public EncryptedValueBuilder(DerObjectIdentifier alg)
+//        {
+//            
+//        }
+//
+//
+//        private static IBlockCipher AesCBC(ICipherParameters param)
+//        {
+//            if (param is ParametersWithIV ivParam) {
+//                return new 
+//            }
+//            else
+//            {
+//                throw new ArgumentException("expecting param to be ParametersWithIv");
+//            }
+//        }
+//
+//
+//
+//        private class CipherCreator
+//        {
+//            public BlockCipherCreator Creator { get; set; }
+//        }
+//
+//    }
+}
diff --git a/crypto/src/asn1/crmf/OptionalValidity.cs b/crypto/src/asn1/crmf/OptionalValidity.cs
index d1a0f7ffb..46fd1f860 100644
--- a/crypto/src/asn1/crmf/OptionalValidity.cs
+++ b/crypto/src/asn1/crmf/OptionalValidity.cs
@@ -33,6 +33,12 @@ namespace Org.BouncyCastle.Asn1.Crmf
             return new OptionalValidity(Asn1Sequence.GetInstance(obj));
         }
 
+        public OptionalValidity(Time notBefore, Time notAfter)
+        {
+            this.notBefore = notBefore;
+            this.notAfter = notAfter;
+        }
+
         public virtual Time NotBefore
         {
             get { return notBefore; }
diff --git a/crypto/src/asn1/crmf/PkiArchiveControl.cs b/crypto/src/asn1/crmf/PkiArchiveControl.cs
new file mode 100644
index 000000000..0290fdfe6
--- /dev/null
+++ b/crypto/src/asn1/crmf/PkiArchiveControl.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Cms;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PkiArchiveControl:IControl
+    {
+        public static readonly int encryptedPrivKey = PkiArchiveOptions.encryptedPrivKey;
+        public static readonly int keyGenParameters = PkiArchiveOptions.keyGenParameters;
+        public static readonly int archiveRemGenPrivKey = PkiArchiveOptions.archiveRemGenPrivKey;
+
+        private static readonly DerObjectIdentifier type = CrmfObjectIdentifiers.id_regCtrl_pkiArchiveOptions;
+
+        private readonly PkiArchiveOptions pkiArchiveOptions;
+
+        public PkiArchiveControl(PkiArchiveOptions pkiArchiveOptions)
+        {
+            this.pkiArchiveOptions = pkiArchiveOptions;
+        }
+
+        public DerObjectIdentifier Type
+        {
+            get { return type; }
+        }
+
+        public Asn1Encodable Value
+        {
+            get { return pkiArchiveOptions; }
+        }
+
+        public int ArchiveType
+        {
+            get { return pkiArchiveOptions.Type; }
+        }
+
+        public bool EnvelopedData
+        {
+            get
+            {
+                EncryptedKey encKey = EncryptedKey.GetInstance(pkiArchiveOptions.Value);
+                return !encKey.IsEncryptedValue;
+            }
+        }
+
+        public CmsEnvelopedData GetEnvelopedData()
+        {
+            try
+            {
+                EncryptedKey encKey = EncryptedKey.GetInstance(pkiArchiveOptions.Value);
+                EnvelopedData data = Org.BouncyCastle.Asn1.Cms.EnvelopedData.GetInstance(encKey.Value);
+
+                return new CmsEnvelopedData(new ContentInfo(CmsObjectIdentifiers.EnvelopedData, data));
+            }
+            catch (CmsException e)
+            {
+                throw new CrmfException("CMS parsing error: " + e.Message, e);
+            }
+            catch (Exception e)
+            {
+                throw  new CrmfException("CRMF parsing error: "+e.Message, e);
+            }
+        }
+
+    }
+}
diff --git a/crypto/src/asn1/crmf/ProofOfPossessionSigningKeyBuilder.cs b/crypto/src/asn1/crmf/ProofOfPossessionSigningKeyBuilder.cs
new file mode 100644
index 000000000..cbaf834a1
--- /dev/null
+++ b/crypto/src/asn1/crmf/ProofOfPossessionSigningKeyBuilder.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Crypto.Paddings;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class ProofOfPossessionSigningKeyBuilder
+    {
+        private CertRequest _certRequest;
+        private SubjectPublicKeyInfo _pubKeyInfo;
+        private GeneralName _name;
+        private PKMacValue _publicKeyMAC;
+
+        public ProofOfPossessionSigningKeyBuilder(CertRequest certRequest)
+        {
+            this._certRequest = certRequest;
+        }
+
+
+        public ProofOfPossessionSigningKeyBuilder(SubjectPublicKeyInfo pubKeyInfo)
+        {
+            this._pubKeyInfo = pubKeyInfo;
+        }
+
+        public ProofOfPossessionSigningKeyBuilder setSender(GeneralName name)
+        {
+            this._name = name;
+
+            return this;
+        }
+
+        public ProofOfPossessionSigningKeyBuilder setPublicKeyMac(PkMacFactory generator, char[] password)
+        {
+            IStreamCalculator calc = generator.CreateCalculator();
+            byte[] d = _pubKeyInfo.GetDerEncoded();
+            calc.Stream.Write(d, 0, d.Length);
+            calc.Stream.Flush();
+            calc.Stream.Close();
+
+
+            this._publicKeyMAC = new PKMacValue(
+                (AlgorithmIdentifier)generator.AlgorithmDetails,
+                new DerBitString(((DefaultMacAndDigestResult)calc.GetResult()).MacResult));
+
+            return this;
+        }
+
+        public PopoSigningKey build(ISignatureFactory signer)
+        {
+            if (_name != null && _publicKeyMAC != null)
+            {
+                throw new InvalidOperationException("name and publicKeyMAC cannot both be set.");
+            }
+
+            PopoSigningKeyInput popo;
+            byte[] b;
+            IStreamCalculator calc = signer.CreateCalculator();
+            if (_certRequest != null)
+            {
+                popo = null;
+                b = _certRequest.GetDerEncoded();
+                calc.Stream.Write(b, 0, b.Length);
+
+            }
+            else if (_name != null)
+            {
+                popo = new PopoSigningKeyInput(_name, _pubKeyInfo);
+                b = popo.GetDerEncoded();
+                calc.Stream.Write(b, 0, b.Length);
+            }
+            else
+            {
+                popo = new PopoSigningKeyInput(_publicKeyMAC, _pubKeyInfo);
+                b = popo.GetDerEncoded();
+                calc.Stream.Write(b, 0, b.Length);
+            }
+
+            calc.Stream.Flush();
+            calc.Stream.Close();
+            DefaultSignatureResult res = (DefaultSignatureResult)calc.GetResult();
+            return new PopoSigningKey(popo, (AlgorithmIdentifier)signer.AlgorithmDetails, new DerBitString(res.Collect()));
+        }
+
+
+    }
+}
diff --git a/crypto/src/asn1/crmf/RegTokenControl.cs b/crypto/src/asn1/crmf/RegTokenControl.cs
new file mode 100644
index 000000000..77bf32557
--- /dev/null
+++ b/crypto/src/asn1/crmf/RegTokenControl.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class RegTokenControl:IControl
+    {
+        private static readonly DerObjectIdentifier type = CrmfObjectIdentifiers.id_regCtrl_regToken;
+    
+        private readonly DerUtf8String token;
+
+        public RegTokenControl(DerUtf8String token)
+        {
+            this.token = token;
+        }
+
+        public RegTokenControl(String token)
+        {
+            this.token = new DerUtf8String(token);
+        }
+
+        public DerObjectIdentifier Type
+        {
+            get { return type; }
+        }
+        public Asn1Encodable Value
+        {
+            get { return token; }
+        }
+    }
+}