summary refs log tree commit diff
path: root/crypto/src/asn1/cmp
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/cmp
parentminor tweaks (diff)
downloadBouncyCastle.NET-ed25519-ecc8edb622f0f42d43f72ae388fa4c4274e51c5f.tar.xz
Initial CMP
Diffstat (limited to 'crypto/src/asn1/cmp')
-rw-r--r--crypto/src/asn1/cmp/CertificateConfirmationContent.cs44
-rw-r--r--crypto/src/asn1/cmp/CertificateConfirmationContentBuilder.cs71
-rw-r--r--crypto/src/asn1/cmp/CertificateStatus.cs54
-rw-r--r--crypto/src/asn1/cmp/CmpException.cs26
-rw-r--r--crypto/src/asn1/cmp/GeneralPKIMessage.cs49
-rw-r--r--crypto/src/asn1/cmp/ProtectedPkiMessage.cs107
-rw-r--r--crypto/src/asn1/cmp/ProtectedPkiMessageBuilder.cs174
7 files changed, 525 insertions, 0 deletions
diff --git a/crypto/src/asn1/cmp/CertificateConfirmationContent.cs b/crypto/src/asn1/cmp/CertificateConfirmationContent.cs
new file mode 100644
index 000000000..9f2f3e038
--- /dev/null
+++ b/crypto/src/asn1/cmp/CertificateConfirmationContent.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Org.BouncyCastle.Cms;
+
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class CertificateConfirmationContent
+    {
+        private DefaultDigestAlgorithmIdentifierFinder digestAlgFinder;
+        private CertConfirmContent content;
+
+
+        public CertificateConfirmationContent(CertConfirmContent content)
+        {
+            this.content = content;
+        }
+
+        public CertificateConfirmationContent(CertConfirmContent content,
+            DefaultDigestAlgorithmIdentifierFinder digestAlgFinder)
+        {
+            this.content = content;
+            this.digestAlgFinder = digestAlgFinder;
+        }
+
+        public CertConfirmContent ToAsn1Structure()
+        {
+            return content;
+        }
+
+        public CertificateStatus[] GetStatusMessages()
+        {
+            CertStatus[] statusArray = content.ToCertStatusArray();
+            CertificateStatus[] ret = new CertificateStatus[statusArray.Length];
+            for (int i = 0; i != ret.Length; i++)
+            {
+                ret[i] = new CertificateStatus(digestAlgFinder, statusArray[i]);
+            }
+
+            return ret;
+        } 
+    }
+}
diff --git a/crypto/src/asn1/cmp/CertificateConfirmationContentBuilder.cs b/crypto/src/asn1/cmp/CertificateConfirmationContentBuilder.cs
new file mode 100644
index 000000000..b8c306f81
--- /dev/null
+++ b/crypto/src/asn1/cmp/CertificateConfirmationContentBuilder.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class CertificateConfirmationContentBuilder
+    {
+        DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+        private DefaultDigestAlgorithmIdentifierFinder digestAlgFinder;
+        private ArrayList acceptedCerts = new ArrayList();
+        private ArrayList acceptedReqIds = new ArrayList();
+
+        public CertificateConfirmationContentBuilder() : this(new DefaultDigestAlgorithmIdentifierFinder())
+        {
+
+        }
+    
+        public CertificateConfirmationContentBuilder(DefaultDigestAlgorithmIdentifierFinder digestAlgFinder)
+        {
+            this.digestAlgFinder = digestAlgFinder;
+        }
+
+        public CertificateConfirmationContentBuilder AddAcceptedCertificate(X509Certificate certHolder,
+            BigInteger certReqId)
+        {
+            acceptedCerts.Add(certHolder);
+            acceptedReqIds.Add(certReqId);
+            return this;
+        }
+
+        public CertificateConfirmationContent Build()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+            for (int i = 0; i != acceptedCerts.Count; i++)
+            {
+                X509Certificate cert = (X509Certificate) acceptedCerts[i];
+                BigInteger reqId = (BigInteger) acceptedReqIds[i];
+
+
+                
+                AlgorithmIdentifier algorithmIdentifier =  sigAlgFinder.Find(cert.SigAlgName);
+
+                AlgorithmIdentifier digAlg = digestAlgFinder.find(algorithmIdentifier);
+                if (digAlg == null)
+                {
+                    throw new CmpException("cannot find algorithm for digest from signature");
+                }
+
+                DigestSink sink = new DigestSink(DigestUtilities.GetDigest(digAlg.Algorithm));
+
+                sink.Write(cert.GetEncoded());
+
+                byte[] dig = new byte[sink.Digest.GetDigestSize()];
+                sink.Digest.DoFinal(dig, 0);
+
+                v.Add(new CertStatus(dig,reqId));
+            }
+
+            return new CertificateConfirmationContent(CertConfirmContent.GetInstance(new DerSequence(v)),
+                digestAlgFinder);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/CertificateStatus.cs b/crypto/src/asn1/cmp/CertificateStatus.cs
new file mode 100644
index 000000000..d16c8e006
--- /dev/null
+++ b/crypto/src/asn1/cmp/CertificateStatus.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class CertificateStatus
+    {
+        private DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+        private DefaultDigestAlgorithmIdentifierFinder digestAlgFinder;
+        private CertStatus certStatus;
+
+        public CertificateStatus(DefaultDigestAlgorithmIdentifierFinder digestAlgFinder, CertStatus certStatus)
+        {
+            this.digestAlgFinder = digestAlgFinder;
+            this.certStatus = certStatus;
+        }
+
+         public PkiStatusInfo PkiStatusInfo
+         {
+             get { return certStatus.StatusInfo; }
+         }
+
+        public BigInteger CertRequestId
+        {
+            get { return certStatus.CertReqID.Value; }
+        }
+
+        public bool IsVerified(X509Certificate cert)
+        {
+
+            AlgorithmIdentifier digAlg = digestAlgFinder.find( sigAlgFinder.Find(cert.SigAlgName));
+            if (digAlg == null)
+            {
+                throw new CmpException("cannot find algorithm for digest from signature "+cert.SigAlgName);
+            }
+
+            DigestSink digestSink = new DigestSink(DigestUtilities.GetDigest(digAlg.Algorithm));
+
+            digestSink.Write(cert.GetEncoded());
+
+            byte[] digest = new byte[digestSink.Digest.GetDigestSize()];
+            digestSink.Digest.DoFinal(digest, 0);
+            return Arrays.ConstantTimeAreEqual(certStatus.CertHash.GetOctets(), digest);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/CmpException.cs b/crypto/src/asn1/cmp/CmpException.cs
new file mode 100644
index 000000000..0500b7d3e
--- /dev/null
+++ b/crypto/src/asn1/cmp/CmpException.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class CmpException : Exception
+    {
+        public CmpException()
+        {
+        }
+
+        public CmpException(string message) : base(message)
+        {
+        }
+
+        public CmpException(string message, Exception innerException) : base(message, innerException)
+        {
+        }
+
+        protected CmpException(SerializationInfo info, StreamingContext context) : base(info, context)
+        {
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/GeneralPKIMessage.cs b/crypto/src/asn1/cmp/GeneralPKIMessage.cs
new file mode 100644
index 000000000..d91b8ef7e
--- /dev/null
+++ b/crypto/src/asn1/cmp/GeneralPKIMessage.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class GeneralPKIMessage
+    {
+        private readonly PkiMessage pkiMessage;
+
+        private static PkiMessage parseBytes(byte[] encoding)
+        {
+            return PkiMessage.GetInstance(Asn1Object.FromByteArray(encoding));
+        }
+
+        public GeneralPKIMessage(PkiMessage pkiMessage)
+        {
+            this.pkiMessage = pkiMessage;
+        }
+
+        public GeneralPKIMessage(byte[] encoding) : this(parseBytes(encoding))
+        {
+        }
+
+        public PkiHeader Header {
+            get {
+                return pkiMessage.Header;
+            }
+        }
+
+        public PkiBody Body
+        {
+            get
+            {
+                return pkiMessage.Body;
+            }
+        }
+
+        public bool HasProtection
+        {
+            get { return pkiMessage.Protection != null; }
+        }
+
+        public PkiMessage ToAsn1Structure()
+        {
+            return pkiMessage;
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/ProtectedPkiMessage.cs b/crypto/src/asn1/cmp/ProtectedPkiMessage.cs
new file mode 100644
index 000000000..c39f06ad0
--- /dev/null
+++ b/crypto/src/asn1/cmp/ProtectedPkiMessage.cs
@@ -0,0 +1,107 @@
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.X509;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+   
+    public class ProtectedPkiMessage
+    {
+        private PkiMessage pkiMessage;
+        
+
+        public ProtectedPkiMessage(GeneralPKIMessage pkiMessage)
+        {
+            
+            if (!pkiMessage.HasProtection)
+            {
+                throw new ArgumentException("pki message not protected");
+            }
+
+            this.pkiMessage = pkiMessage.ToAsn1Structure();
+        }
+           
+        public ProtectedPkiMessage(PkiMessage pkiMessage)
+        {
+            if (pkiMessage.Header.ProtectionAlg == null)
+            {
+                throw new ArgumentException("pki message not protected");
+            }
+
+            this.pkiMessage = pkiMessage;
+        }
+
+        public PkiHeader Header { get { return pkiMessage.Header; } }
+        public PkiBody Body { get { return pkiMessage.Body; } }
+
+        public PkiMessage ToAsn1Message() { return pkiMessage; }
+
+        public bool HasPasswordBasedMacProtected { get { return Header.ProtectionAlg.Algorithm.Equals(CmpObjectIdentifiers.passwordBasedMac); } }
+
+        public X509Certificate[] GetCertificates()
+        {
+            CmpCertificate[] certs = pkiMessage.GetExtraCerts();
+
+            if (certs == null)
+            {
+                return new X509Certificate[0];
+            }
+
+            X509Certificate[] res = new X509Certificate[certs.Length];
+           for (int t=0; t<certs.Length;t++)
+            {
+                res[t] = new X509Certificate(X509CertificateStructure.GetInstance(certs[t].GetEncoded()));
+            }
+
+            return res;
+        }
+        
+
+        
+
+        public bool Verify(IVerifierFactory verifier)
+        {
+           Asn1EncodableVector avec = new Asn1EncodableVector();
+           avec.Add(pkiMessage.Header);
+           avec.Add(pkiMessage.Body);
+           byte[] enc =   new DerSequence(avec).GetDerEncoded();
+
+           IStreamCalculator streamCalculator = verifier.CreateCalculator();
+
+           streamCalculator.Stream.Write(enc,0,enc.Length);
+           streamCalculator.Stream.Flush();
+           streamCalculator.Stream.Close();
+          
+           IVerifier result = (IVerifier) streamCalculator.GetResult();     
+           return result.IsVerified(pkiMessage.Protection.GetBytes());          
+        }
+
+
+        public bool Verify(Asn1MacFactoryProvider asn1Factory, byte[] password)
+        {
+            if (!CmpObjectIdentifiers.passwordBasedMac.Equals(pkiMessage.Header.ProtectionAlg.Algorithm))
+            {
+                throw new InvalidOperationException("protection algorithm is not mac based");
+            }
+
+            PbmParameter parameter = PbmParameter.GetInstance(pkiMessage.Header.ProtectionAlg.Parameters);
+
+            PkMacFactory macFactory = (PkMacFactory)asn1Factory.CreateMacFactory(parameter);
+                            
+            macFactory.Password = password;
+            MacVerifierFactory macVerifierFactory = new MacVerifierFactory(macFactory);
+
+            return Verify(macVerifierFactory);       
+        }
+
+    }
+}
diff --git a/crypto/src/asn1/cmp/ProtectedPkiMessageBuilder.cs b/crypto/src/asn1/cmp/ProtectedPkiMessageBuilder.cs
new file mode 100644
index 000000000..a6a98d753
--- /dev/null
+++ b/crypto/src/asn1/cmp/ProtectedPkiMessageBuilder.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class ProtectedPkiMessageBuilder
+    {
+        private PkiHeaderBuilder hdrBuilBuilder;
+        private PkiBody body;
+        private ArrayList generalInfos = new ArrayList();
+        private ArrayList extraCerts = new ArrayList();
+
+        public ProtectedPkiMessageBuilder(GeneralName sender, GeneralName recipient) : this(PkiHeader.CMP_2000, sender,
+            recipient)
+        {
+        }
+
+
+        public ProtectedPkiMessageBuilder(int pvno, GeneralName sender, GeneralName recipient)
+        {
+            hdrBuilBuilder = new PkiHeaderBuilder(pvno, sender, recipient);
+        }
+
+        public ProtectedPkiMessageBuilder SetTransactionId(byte[] tid)
+        {
+            hdrBuilBuilder.SetTransactionID(tid);
+            return this;
+        }
+
+        public ProtectedPkiMessageBuilder SetFreeText(PkiFreeText freeText)
+        {
+            hdrBuilBuilder.SetFreeText(freeText);
+            return this;
+        }
+
+        public ProtectedPkiMessageBuilder AddGeneralInfo(InfoTypeAndValue genInfo)
+        {
+            generalInfos.Add(genInfo);
+            return this;
+        }
+
+        public ProtectedPkiMessageBuilder SetRecipKID(byte[] id)
+        {
+            hdrBuilBuilder.SetRecipKID(id);
+            return this;
+        }
+
+        public ProtectedPkiMessageBuilder SetRecipNonce(byte[] nonce)
+        {
+            hdrBuilBuilder.SetRecipNonce(nonce);
+            return this;
+        }
+
+        public ProtectedPkiMessageBuilder SetSenderKID(byte[] id)
+        {
+            hdrBuilBuilder.SetSenderKID(id);
+            return this;
+        }
+
+        public ProtectedPkiMessageBuilder SetSenderNonce(byte[] nonce)
+        {
+            hdrBuilBuilder.SetSenderNonce(nonce);
+            return this;
+        }
+
+        public ProtectedPkiMessageBuilder SetBody(PkiBody body)
+        {
+            this.body = body;
+            return this;
+        }
+
+        public ProtectedPkiMessageBuilder AddCmpCertificate(X509Certificate certificate)
+        {
+            extraCerts.Add(certificate);
+            return this;
+        }
+
+        public ProtectedPkiMessage Build(ISignatureFactory signatureFactory)
+        {
+            IStreamCalculator calculator = signatureFactory.CreateCalculator();
+
+            if (!(signatureFactory.AlgorithmDetails is AlgorithmIdentifier))
+            {
+                throw new ArgumentException("AlgorithmDetails is not AlgorithmIdentifier");
+            }
+
+            FinalizeHeader((AlgorithmIdentifier) signatureFactory.AlgorithmDetails);
+            PkiHeader header = hdrBuilBuilder.Build();
+            DerBitString protection = new DerBitString(CalculateSignature(calculator, header, body));
+            return FinalizeMessage(header, protection);
+        }
+
+        public ProtectedPkiMessage Build(IMacFactory factory)
+        {           
+                IStreamCalculator calculator = factory.CreateCalculator();                
+                FinalizeHeader((AlgorithmIdentifier)factory.AlgorithmDetails);
+                PkiHeader header = hdrBuilBuilder.Build();
+                DerBitString protection = new DerBitString(CalculateSignature(calculator, header, body));
+                return FinalizeMessage(header, protection);        
+        }
+
+
+        private void FinalizeHeader(AlgorithmIdentifier algorithmIdentifier)
+        {
+            hdrBuilBuilder.SetProtectionAlg(algorithmIdentifier);
+            if (generalInfos.Count > 0)
+            {
+                InfoTypeAndValue[] genInfos = new InfoTypeAndValue[generalInfos.Count];
+                for (int t = 0; t < genInfos.Length; t++)
+                {
+                    genInfos[t] = (InfoTypeAndValue) generalInfos[t];
+                }
+
+                hdrBuilBuilder.SetGeneralInfo(genInfos);
+            }
+        }
+
+        private ProtectedPkiMessage FinalizeMessage(PkiHeader header, DerBitString protection)
+        {
+            if (extraCerts.Count > 0)
+            {
+                CmpCertificate[] cmpCertificates = new CmpCertificate[extraCerts.Count];
+                for (int i = 0; i < cmpCertificates.Length; i++)
+                {
+                    byte[] cert = ((X509Certificate) extraCerts[i]).GetEncoded();
+                    cmpCertificates[i] = CmpCertificate.GetInstance((Asn1Sequence.FromByteArray(cert)));
+                }
+
+                return new ProtectedPkiMessage(new PkiMessage(header, body, protection, cmpCertificates));
+            }
+
+            return new ProtectedPkiMessage(new PkiMessage(header, body, protection));
+        }
+
+        private byte[] CalculateSignature(IStreamCalculator signer, PkiHeader header, PkiBody body)
+        {
+            Asn1EncodableVector avec = new Asn1EncodableVector();
+            avec.Add(header);
+            avec.Add(body);
+            byte[] encoded = new DerSequence(avec).GetEncoded();
+            signer.Stream.Write(encoded, 0, encoded.Length);
+            Object result = signer.GetResult();
+
+
+            if (result is DefaultSignatureResult)
+            {
+                return ((DefaultSignatureResult) result).Collect();
+            }
+            else if (result is DefaultMacAndDigestResult)
+            {
+                return ((DefaultMacAndDigestResult) result).MacResult;
+            }
+            else if (result is byte[])
+            {
+                return (byte[]) result;
+            }
+
+            throw new InvalidOperationException("result is not byte[] or DefaultSignatureResult");
+        }
+    }
+}
\ No newline at end of file