summary refs log tree commit diff
path: root/crypto/src/asn1
diff options
context:
space:
mode:
authorOren Novotny <oren@novotny.org>2018-09-30 08:49:27 -0400
committerOren Novotny <oren@novotny.org>2018-09-30 08:49:27 -0400
commit22dcb7ce12fcd9142116aea0e36dffc3ce32b889 (patch)
tree4dd606ea73cd53f42d11f4f219575fb07ceb0f88 /crypto/src/asn1
parentfix filter (diff)
parentRFC 8032: Avoid unnecessary doublings in precomputation (diff)
downloadBouncyCastle.NET-ed25519-22dcb7ce12fcd9142116aea0e36dffc3ce32b889.tar.xz
merge from master
Diffstat (limited to 'crypto/src/asn1')
-rw-r--r--crypto/src/asn1/DerApplicationSpecific.cs33
-rw-r--r--crypto/src/asn1/edec/EdECObjectIdentifiers.cs17
-rw-r--r--crypto/src/asn1/pkcs/EncryptionScheme.cs8
-rw-r--r--crypto/src/asn1/pkcs/PrivateKeyInfo.cs193
-rw-r--r--crypto/src/asn1/x509/TBSCertificateStructure.cs8
5 files changed, 172 insertions, 87 deletions
diff --git a/crypto/src/asn1/DerApplicationSpecific.cs b/crypto/src/asn1/DerApplicationSpecific.cs
index 52467fabe..a2d57bf9d 100644
--- a/crypto/src/asn1/DerApplicationSpecific.cs
+++ b/crypto/src/asn1/DerApplicationSpecific.cs
@@ -199,38 +199,27 @@ namespace Org.BouncyCastle.Asn1
 		{
 			int tagNo = input[0] & 0x1f;
 			int index = 1;
-			//
-			// with tagged object tag number is bottom 5 bits, or stored at the start of the content
-			//
+
+            // with tagged object tag number is bottom 5 bits, or stored at the start of the content
 			if (tagNo == 0x1f)
 			{
-				tagNo = 0;
-
-				int b = input[index++] & 0xff;
+				int b = input[index++];
 
-				// X.690-0207 8.1.2.4.2
+                // X.690-0207 8.1.2.4.2
 				// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
 				if ((b & 0x7f) == 0) // Note: -1 will pass
-				{
-					throw new InvalidOperationException("corrupted stream - invalid high tag number found");
-				}
+					throw new IOException("corrupted stream - invalid high tag number found");
 
-				while ((b >= 0) && ((b & 0x80) != 0))
+                while ((b & 0x80) != 0)
 				{
-					tagNo |= (b & 0x7f);
-					tagNo <<= 7;
-					b = input[index++] & 0xff;
+					b = input[index++];
 				}
-
-				tagNo |= (b & 0x7f);
 			}
 
-			byte[] tmp = new byte[input.Length - index + 1];
-
-			Array.Copy(input, index, tmp, 1, tmp.Length - 1);
-
-			tmp[0] = (byte)newTag;
-
+            int remaining = input.Length - index;
+            byte[] tmp = new byte[1 + remaining];
+            tmp[0] = (byte)newTag;
+			Array.Copy(input, index, tmp, 1, remaining);
 			return tmp;
 		}
     }
diff --git a/crypto/src/asn1/edec/EdECObjectIdentifiers.cs b/crypto/src/asn1/edec/EdECObjectIdentifiers.cs
new file mode 100644
index 000000000..f8c5713d8
--- /dev/null
+++ b/crypto/src/asn1/edec/EdECObjectIdentifiers.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.EdEC
+{
+    /**
+     * Edwards Elliptic Curve Object Identifiers (RFC 8410)
+     */
+    public abstract class EdECObjectIdentifiers
+    {
+        public static readonly DerObjectIdentifier id_edwards_curve_algs = new DerObjectIdentifier("1.3.101");
+
+        public static readonly DerObjectIdentifier id_X25519 = id_edwards_curve_algs.Branch("110");
+        public static readonly DerObjectIdentifier id_X448 = id_edwards_curve_algs.Branch("111");
+        public static readonly DerObjectIdentifier id_Ed25519 = id_edwards_curve_algs.Branch("112");
+        public static readonly DerObjectIdentifier id_Ed448 = id_edwards_curve_algs.Branch("113");
+    }
+}
diff --git a/crypto/src/asn1/pkcs/EncryptionScheme.cs b/crypto/src/asn1/pkcs/EncryptionScheme.cs
index 7b90ece53..34d26e172 100644
--- a/crypto/src/asn1/pkcs/EncryptionScheme.cs
+++ b/crypto/src/asn1/pkcs/EncryptionScheme.cs
@@ -8,7 +8,13 @@ namespace Org.BouncyCastle.Asn1.Pkcs
     public class EncryptionScheme
         : AlgorithmIdentifier
     {
-		public EncryptionScheme(
+        public EncryptionScheme(
+            DerObjectIdentifier	objectID)
+            : base(objectID)
+        {
+        }
+
+        public EncryptionScheme(
             DerObjectIdentifier	objectID,
             Asn1Encodable		parameters)
 			: base(objectID, parameters)
diff --git a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
index c5be7a315..dfb332fdd 100644
--- a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
+++ b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
@@ -4,15 +4,55 @@ using System.IO;
 
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Collections;
 
 namespace Org.BouncyCastle.Asn1.Pkcs
 {
+    /**
+     *  RFC 5958
+     *
+     *  <pre>
+     *  [IMPLICIT TAGS]
+     *
+     *  OneAsymmetricKey ::= SEQUENCE {
+     *      version                   Version,
+     *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
+     *      privateKey                PrivateKey,
+     *      attributes            [0] Attributes OPTIONAL,
+     *      ...,
+     *      [[2: publicKey        [1] PublicKey OPTIONAL ]],
+     *      ...
+     *  }
+     *
+     *  PrivateKeyInfo ::= OneAsymmetricKey
+     *
+     *  Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2)
+     *
+     *  PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+     *                                     { PUBLIC-KEY,
+     *                                       { PrivateKeyAlgorithms } }
+     *
+     *  PrivateKey ::= OCTET STRING
+     *                     -- Content varies based on type of key.  The
+     *                     -- algorithm identifier dictates the format of
+     *                     -- the key.
+     *
+     *  PublicKey ::= BIT STRING
+     *                     -- Content varies based on type of key.  The
+     *                     -- algorithm identifier dictates the format of
+     *                     -- the key.
+     *
+     *  Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
+     *  </pre>
+     */
     public class PrivateKeyInfo
         : Asn1Encodable
     {
-        private readonly Asn1OctetString        privKey;
-        private readonly AlgorithmIdentifier	algID;
-        private readonly Asn1Set				attributes;
+        private readonly DerInteger version;
+        private readonly AlgorithmIdentifier privateKeyAlgorithm;
+        private readonly Asn1OctetString privateKey;
+        private readonly Asn1Set attributes;
+        private readonly DerBitString publicKey;
 
         public static PrivateKeyInfo GetInstance(Asn1TaggedObject obj, bool explicitly)
         {
@@ -25,110 +65,139 @@ namespace Org.BouncyCastle.Asn1.Pkcs
             if (obj == null)
                 return null;
             if (obj is PrivateKeyInfo)
-                return (PrivateKeyInfo) obj;
+                return (PrivateKeyInfo)obj;
             return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj));
         }
 
-        public PrivateKeyInfo(AlgorithmIdentifier algID, Asn1Encodable privateKey)
-            : this(algID, privateKey, null)
+        private static int GetVersionValue(DerInteger version)
+        {
+            BigInteger bigValue = version.Value;
+            if (bigValue.CompareTo(BigInteger.Zero) < 0 || bigValue.CompareTo(BigInteger.One) > 0)
+                throw new ArgumentException("invalid version for private key info", "version");
+
+            return bigValue.IntValue;
+        }
+
+        public PrivateKeyInfo(
+            AlgorithmIdentifier privateKeyAlgorithm,
+            Asn1Encodable privateKey)
+            : this(privateKeyAlgorithm, privateKey, null, null)
         {
         }
 
         public PrivateKeyInfo(
-            AlgorithmIdentifier	algID,
-            Asn1Encodable       privateKey,
-            Asn1Set				attributes)
+            AlgorithmIdentifier privateKeyAlgorithm,
+            Asn1Encodable privateKey,
+            Asn1Set attributes)
+            : this(privateKeyAlgorithm, privateKey, attributes, null)
         {
-            this.algID = algID;
-            this.privKey = new DerOctetString(privateKey.GetEncoded(Asn1Encodable.Der));
+        }
+
+        public PrivateKeyInfo(
+            AlgorithmIdentifier privateKeyAlgorithm,
+            Asn1Encodable privateKey,
+            Asn1Set attributes,
+            byte[] publicKey)
+        {
+            this.version = new DerInteger(publicKey != null ? BigInteger.One : BigInteger.Zero);
+            this.privateKeyAlgorithm = privateKeyAlgorithm;
+            this.privateKey = new DerOctetString(privateKey);
             this.attributes = attributes;
+            this.publicKey = publicKey == null ? null : new DerBitString(publicKey);
         }
 
         private PrivateKeyInfo(Asn1Sequence seq)
         {
             IEnumerator e = seq.GetEnumerator();
 
-            e.MoveNext();
-            BigInteger version = ((DerInteger)e.Current).Value;
-            if (version.IntValue != 0)
-            {
-                throw new ArgumentException("wrong version for private key info: " + version.IntValue);
-            }
+            this.version = DerInteger.GetInstance(CollectionUtilities.RequireNext(e));
 
-            e.MoveNext();
-            algID = AlgorithmIdentifier.GetInstance(e.Current);
-            e.MoveNext();
-            privKey = Asn1OctetString.GetInstance(e.Current);
+            int versionValue = GetVersionValue(version);
 
-            if (e.MoveNext())
+            this.privateKeyAlgorithm = AlgorithmIdentifier.GetInstance(CollectionUtilities.RequireNext(e));
+            this.privateKey = Asn1OctetString.GetInstance(CollectionUtilities.RequireNext(e));
+
+            int lastTag = -1;
+            while (e.MoveNext())
             {
-                attributes = Asn1Set.GetInstance((Asn1TaggedObject)e.Current, false);
+                Asn1TaggedObject tagged = (Asn1TaggedObject)e.Current;
+
+                int tag = tagged.TagNo;
+                if (tag <= lastTag)
+                    throw new ArgumentException("invalid optional field in private key info", "seq");
+
+                lastTag = tag;
+
+                switch (tag)
+                {
+                case 0:
+                {
+                    this.attributes = Asn1Set.GetInstance(tagged, false);
+                    break;
+                }
+                case 1:
+                {
+                    if (versionValue < 1)
+                        throw new ArgumentException("'publicKey' requires version v2(1) or later", "seq");
+
+                    this.publicKey = DerBitString.GetInstance(tagged, false);
+                    break;
+                }
+                default:
+                {
+                    throw new ArgumentException("unknown optional field in private key info", "seq");
+                }
+                }
             }
         }
 
-        public virtual AlgorithmIdentifier PrivateKeyAlgorithm
+        public virtual Asn1Set Attributes
         {
-            get { return algID; }
+            get { return attributes; }
         }
 
-        [Obsolete("Use 'PrivateKeyAlgorithm' property instead")]
-        public virtual AlgorithmIdentifier AlgorithmID
+        /// <summary>Return true if a public key is present, false otherwise.</summary>
+        public virtual bool HasPublicKey
         {
-            get { return algID; }
+            get { return publicKey != null; }
+        }
+
+        public virtual AlgorithmIdentifier PrivateKeyAlgorithm
+        {
+            get { return privateKeyAlgorithm; }
         }
 
         public virtual Asn1Object ParsePrivateKey()
         {
-            return Asn1Object.FromByteArray(privKey.GetOctets());
+            return Asn1Object.FromByteArray(privateKey.GetOctets());
         }
 
-        [Obsolete("Use 'ParsePrivateKey' instead")]
-        public virtual Asn1Object PrivateKey
+        /// <summary>For when the public key is an ASN.1 encoding.</summary>
+        public virtual Asn1Object ParsePublicKey()
         {
-            get
-            {
-                try
-                {
-                    return ParsePrivateKey();
-                }
-                catch (IOException)
-                {
-                    throw new InvalidOperationException("unable to parse private key");
-                }
-            }
+            return publicKey == null ? null : Asn1Object.FromByteArray(publicKey.GetOctets());
         }
 
-        public virtual Asn1Set Attributes
+        /// <summary>Return the public key as a raw bit string.</summary>
+        public virtual DerBitString PublicKeyData
         {
-            get { return attributes; }
+            get { return publicKey; }
         }
 
-        /**
-         * write out an RSA private key with its associated information
-         * as described in Pkcs8.
-         * <pre>
-         *      PrivateKeyInfo ::= Sequence {
-         *                              version Version,
-         *                              privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
-         *                              privateKey PrivateKey,
-         *                              attributes [0] IMPLICIT Attributes OPTIONAL
-         *                          }
-         *      Version ::= Integer {v1(0)} (v1,...)
-         *
-         *      PrivateKey ::= OCTET STRING
-         *
-         *      Attributes ::= Set OF Attr
-         * </pre>
-         */
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector(new DerInteger(0), algID, privKey);
+            Asn1EncodableVector v = new Asn1EncodableVector(version, privateKeyAlgorithm, privateKey);
 
             if (attributes != null)
             {
                 v.Add(new DerTaggedObject(false, 0, attributes));
             }
 
+            if (publicKey != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, publicKey));
+            }
+
             return new DerSequence(v);
         }
     }
diff --git a/crypto/src/asn1/x509/TBSCertificateStructure.cs b/crypto/src/asn1/x509/TBSCertificateStructure.cs
index 9df078539..e69e985f5 100644
--- a/crypto/src/asn1/x509/TBSCertificateStructure.cs
+++ b/crypto/src/asn1/x509/TBSCertificateStructure.cs
@@ -121,7 +121,7 @@ namespace Org.BouncyCastle.Asn1.X509
 
             while (extras > 0)
 			{
-				DerTaggedObject extra = (DerTaggedObject) seq[seqStart + 6 + extras];
+				DerTaggedObject extra = (DerTaggedObject)seq[seqStart + 6 + extras];
 
 				switch (extra.TagNo)
 				{
@@ -140,9 +140,13 @@ namespace Org.BouncyCastle.Asn1.X509
                     if (isV2)
                         throw new ArgumentException("version 2 certificate cannot contain extensions");
 
-                    extensions = X509Extensions.GetInstance(extra);
+                    extensions = X509Extensions.GetInstance(Asn1Sequence.GetInstance(extra, true));
 					break;
                 }
+                default:
+                {
+                    throw new ArgumentException("Unknown tag encountered in structure: " + extra.TagNo);
+                }
                 }
                 extras--;
 			}