summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2019-06-04 13:53:00 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2019-06-04 13:53:00 +0700
commit6c7a86e0b73074b2a42ea129acc831ace01d41a5 (patch)
treec0bb41783442ef197d0f10bcb56f6e015fc687ec
parentName constraint validation updates from bc-java (diff)
downloadBouncyCastle.NET-ed25519-6c7a86e0b73074b2a42ea129acc831ace01d41a5.tar.xz
Port LinkedCertificate from bc-java
-rw-r--r--crypto/BouncyCastle.Android.csproj1
-rw-r--r--crypto/BouncyCastle.csproj1
-rw-r--r--crypto/BouncyCastle.iOS.csproj1
-rw-r--r--crypto/crypto.csproj10
-rw-r--r--crypto/src/asn1/Asn1EncodableVector.cs8
-rw-r--r--crypto/src/asn1/bc/BCObjectIdentifiers.cs11
-rw-r--r--crypto/src/asn1/bc/LinkedCertificate.cs100
-rw-r--r--crypto/test/UnitTests.csproj1
-rw-r--r--crypto/test/src/asn1/test/LinkedCertificateTest.cs97
-rw-r--r--crypto/test/src/asn1/test/RegressionTest.cs1
10 files changed, 230 insertions, 1 deletions
diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj
index a356bce2c..41ad0c236 100644
--- a/crypto/BouncyCastle.Android.csproj
+++ b/crypto/BouncyCastle.Android.csproj
@@ -142,6 +142,7 @@
     <Compile Include="src\asn1\anssi\ANSSINamedCurves.cs" />
     <Compile Include="src\asn1\anssi\ANSSIObjectIdentifiers.cs" />
     <Compile Include="src\asn1\bc\BCObjectIdentifiers.cs" />
+    <Compile Include="src\asn1\bc\LinkedCertificate.cs" />
     <Compile Include="src\asn1\bsi\BsiObjectIdentifiers.cs" />
     <Compile Include="src\asn1\cmp\CAKeyUpdAnnContent.cs" />
     <Compile Include="src\asn1\cmp\CertConfirmContent.cs" />
diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj
index c79463f7c..8c7f342d2 100644
--- a/crypto/BouncyCastle.csproj
+++ b/crypto/BouncyCastle.csproj
@@ -136,6 +136,7 @@
     <Compile Include="src\asn1\anssi\ANSSINamedCurves.cs" />
     <Compile Include="src\asn1\anssi\ANSSIObjectIdentifiers.cs" />
     <Compile Include="src\asn1\bc\BCObjectIdentifiers.cs" />
+    <Compile Include="src\asn1\bc\LinkedCertificate.cs" />
     <Compile Include="src\asn1\bsi\BsiObjectIdentifiers.cs" />
     <Compile Include="src\asn1\cmp\CAKeyUpdAnnContent.cs" />
     <Compile Include="src\asn1\cmp\CertConfirmContent.cs" />
diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj
index 630df8a1f..f3ffb3b66 100644
--- a/crypto/BouncyCastle.iOS.csproj
+++ b/crypto/BouncyCastle.iOS.csproj
@@ -137,6 +137,7 @@
     <Compile Include="src\asn1\anssi\ANSSINamedCurves.cs" />
     <Compile Include="src\asn1\anssi\ANSSIObjectIdentifiers.cs" />
     <Compile Include="src\asn1\bc\BCObjectIdentifiers.cs" />
+    <Compile Include="src\asn1\bc\LinkedCertificate.cs" />
     <Compile Include="src\asn1\bsi\BsiObjectIdentifiers.cs" />
     <Compile Include="src\asn1\cmp\CAKeyUpdAnnContent.cs" />
     <Compile Include="src\asn1\cmp\CertConfirmContent.cs" />
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 38f4544d8..55fcf1704 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -569,6 +569,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\asn1\bc\LinkedCertificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\asn1\bsi\BsiObjectIdentifiers.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -11668,6 +11673,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\asn1\test\LinkedCertificateTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\asn1\test\MiscTest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/asn1/Asn1EncodableVector.cs b/crypto/src/asn1/Asn1EncodableVector.cs
index 49532fe57..8a97e8b4f 100644
--- a/crypto/src/asn1/Asn1EncodableVector.cs
+++ b/crypto/src/asn1/Asn1EncodableVector.cs
@@ -61,6 +61,14 @@ namespace Org.BouncyCastle.Asn1
 			}
 		}
 
+        public void AddOptionalTagged(bool isExplicit, int tagNo, Asn1Encodable obj)
+        {
+            if (null != obj)
+            {
+                v.Add(new DerTaggedObject(isExplicit, tagNo, obj));
+            }
+        }
+
 		public Asn1Encodable this[
 			int index]
 		{
diff --git a/crypto/src/asn1/bc/BCObjectIdentifiers.cs b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
index 1e2448853..0ffd65dfc 100644
--- a/crypto/src/asn1/bc/BCObjectIdentifiers.cs
+++ b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
@@ -101,5 +101,14 @@ namespace Org.BouncyCastle.Asn1.BC
          * NewHope
          */
         public static readonly DerObjectIdentifier newHope = bc_exch.Branch("1");
+
+        /**
+         * X.509 extension(4) values
+         * <p>
+         * 1.3.6.1.4.1.22554.4
+         */
+        public static readonly DerObjectIdentifier bc_ext = bc.Branch("4");
+
+        public static readonly DerObjectIdentifier linkedCertificate = bc_ext.Branch("1");
 	}
-}
\ No newline at end of file
+}
diff --git a/crypto/src/asn1/bc/LinkedCertificate.cs b/crypto/src/asn1/bc/LinkedCertificate.cs
new file mode 100644
index 000000000..c8d05d8f5
--- /dev/null
+++ b/crypto/src/asn1/bc/LinkedCertificate.cs
@@ -0,0 +1,100 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.BC
+{
+    /**
+     * Extension to tie an alternate certificate to the containing certificate.
+     * <pre>
+     *     LinkedCertificate := SEQUENCE {
+     *         digest        DigestInfo,                   -- digest of PQC certificate
+     *         certLocation  GeneralName,                  -- location of PQC certificate
+     *         certIssuer    [0] Name OPTIONAL,            -- issuer of PQC cert (if different from current certificate)
+     *         cACerts       [1] GeneralNames OPTIONAL,    -- CA certificates for PQC cert (one of more locations)
+     * }
+     * </pre>
+     */
+    public class LinkedCertificate
+        : Asn1Encodable
+    {
+        private readonly DigestInfo mDigest;
+        private readonly GeneralName mCertLocation;
+
+        private X509Name mCertIssuer;
+        private GeneralNames mCACerts;
+
+        public LinkedCertificate(DigestInfo digest, GeneralName certLocation)
+            : this(digest, certLocation, null, null)
+        {
+        }
+
+        public LinkedCertificate(DigestInfo digest, GeneralName certLocation, X509Name certIssuer, GeneralNames caCerts)
+        {
+            this.mDigest = digest;
+            this.mCertLocation = certLocation;
+            this.mCertIssuer = certIssuer;
+            this.mCACerts = caCerts;
+        }
+
+        private LinkedCertificate(Asn1Sequence seq)
+        {
+            this.mDigest = DigestInfo.GetInstance(seq[0]);
+            this.mCertLocation = GeneralName.GetInstance(seq[1]);
+
+            for (int i = 2; i < seq.Count; ++i)
+            {
+                Asn1TaggedObject tagged =  Asn1TaggedObject.GetInstance(seq[i]);
+
+                switch (tagged.TagNo)
+                {
+                case 0:
+                    this.mCertIssuer = X509Name.GetInstance(tagged, false);
+                    break;
+                case 1:
+                    this.mCACerts = GeneralNames.GetInstance(tagged, false);
+                    break;
+                default:
+                    throw new ArgumentException("unknown tag in tagged field");
+                }
+            }
+        }
+
+        public static LinkedCertificate GetInstance(object obj)
+        {
+            if (obj is LinkedCertificate)
+                return (LinkedCertificate)obj;
+            if (obj != null)
+                return new LinkedCertificate(Asn1Sequence.GetInstance(obj));
+            return null;
+        }
+
+        public virtual DigestInfo Digest
+        {
+            get { return mDigest; }
+        }
+
+        public virtual GeneralName CertLocation
+        {
+            get { return mCertLocation; }
+        }
+
+        public virtual X509Name CertIssuer
+        {
+            get { return mCertIssuer; }
+        }
+
+        public virtual GeneralNames CACerts
+        {
+            get { return mCACerts; }
+        }
+
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(mDigest, mCertLocation);
+            v.AddOptionalTagged(false, 0, mCertIssuer);
+            v.AddOptionalTagged(false, 1, mCACerts);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj
index 9420cc832..1378034a6 100644
--- a/crypto/test/UnitTests.csproj
+++ b/crypto/test/UnitTests.csproj
@@ -85,6 +85,7 @@
     <Compile Include="src\asn1\test\IssuingDistributionPointTest.cs" />
     <Compile Include="src\asn1\test\KeyUsageTest.cs" />
     <Compile Include="src\asn1\test\LDSSecurityObjectUnitTest.cs" />
+    <Compile Include="src\asn1\test\LinkedCertificateTest.cs" />
     <Compile Include="src\asn1\test\MiscTest.cs" />
     <Compile Include="src\asn1\test\MonetaryLimitUnitTest.cs" />
     <Compile Include="src\asn1\test\MonetaryValueUnitTest.cs" />
diff --git a/crypto/test/src/asn1/test/LinkedCertificateTest.cs b/crypto/test/src/asn1/test/LinkedCertificateTest.cs
new file mode 100644
index 000000000..416c048c0
--- /dev/null
+++ b/crypto/test/src/asn1/test/LinkedCertificateTest.cs
@@ -0,0 +1,97 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.BC;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+    public class LinkedCertificateTest
+        : Asn1UnitTest
+    {
+        public override string Name
+        {
+            get { return "LinkedCertificate"; }
+        }
+
+        public override void PerformTest()
+        {
+            DigestInfo digInfo = new DigestInfo(new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256), new byte[32]);
+            GeneralName certLocation = new GeneralName(GeneralName.UniformResourceIdentifier, "https://www.bouncycastle.org/certs");
+            X509Name certIssuer = null;
+            GeneralNames cACerts = null;
+
+            LinkedCertificate linked = new LinkedCertificate(digInfo, certLocation);
+
+            CheckConstruction(linked, digInfo, certLocation, certIssuer, cACerts);
+
+            certIssuer = new X509Name("CN=Test");
+            cACerts = new GeneralNames(new GeneralName(new X509Name("CN=CA Test")));
+
+            linked = new LinkedCertificate(digInfo, certLocation, certIssuer, cACerts);
+
+            CheckConstruction(linked, digInfo, certLocation, certIssuer, cACerts);
+
+            linked = LinkedCertificate.GetInstance(null);
+
+            if (linked != null)
+            {
+                Fail("null getInstance() failed.");
+            }
+
+            try
+            {
+                LinkedCertificate.GetInstance(new object());
+
+                Fail("getInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException e)
+            {
+                // expected
+            }
+        }
+
+        private void CheckConstruction(LinkedCertificate linked, DigestInfo digestInfo, GeneralName certLocation,
+            X509Name certIssuer, GeneralNames caCerts)
+        {
+            CheckValues(linked, digestInfo, certLocation, certIssuer, caCerts);
+
+            linked = LinkedCertificate.GetInstance(linked);
+
+            CheckValues(linked, digestInfo, certLocation, certIssuer, caCerts);
+
+            Asn1InputStream aIn = new Asn1InputStream(linked.ToAsn1Object().GetEncoded());
+
+            Asn1Sequence seq = (Asn1Sequence)aIn.ReadObject();
+
+            linked = LinkedCertificate.GetInstance(seq);
+
+            CheckValues(linked, digestInfo, certLocation, certIssuer, caCerts);
+        }
+
+        private void CheckValues(LinkedCertificate linked, DigestInfo digestInfo, GeneralName certLocation,
+            X509Name certIssuer, GeneralNames caCerts)
+        {
+            checkMandatoryField("digest", digestInfo, linked.Digest);
+            checkMandatoryField("certLocatin", certLocation, linked.CertLocation);
+            checkOptionalField("certIssuer", certIssuer, linked.CertIssuer);
+            checkOptionalField("caCerts", caCerts, linked.CACerts);
+        }
+
+        public static void Main(string[] args)
+        {
+            RunTest(new LinkedCertificateTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/RegressionTest.cs b/crypto/test/src/asn1/test/RegressionTest.cs
index 4534f2c75..67860ccd7 100644
--- a/crypto/test/src/asn1/test/RegressionTest.cs
+++ b/crypto/test/src/asn1/test/RegressionTest.cs
@@ -37,6 +37,7 @@ namespace Org.BouncyCastle.Asn1.Tests
 			new IssuingDistributionPointUnitTest(),
 			new KeyUsageTest(),
             new LDSSecurityObjectUnitTest(),
+            new LinkedCertificateTest(),
             new MiscTest(),
 			new MonetaryLimitUnitTest(),
 			new MonetaryValueUnitTest(),