summary refs log tree commit diff
path: root/crypto/src/asn1
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2019-06-01 19:11:34 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2019-06-01 19:11:34 +0700
commit5cc0a46f4dbaafd9e3104643ec1fa5bf69ac5a6c (patch)
tree0ac8a1bd4557e3682c2fb2cbf889bd992402b1db /crypto/src/asn1
parentRemove extraneous output (diff)
downloadBouncyCastle.NET-ed25519-5cc0a46f4dbaafd9e3104643ec1fa5bf69ac5a6c.tar.xz
Name constraint validation updates from bc-java
Diffstat (limited to 'crypto/src/asn1')
-rw-r--r--crypto/src/asn1/x500/AttributeTypeAndValue.cs60
-rw-r--r--crypto/src/asn1/x500/Rdn.cs104
-rw-r--r--crypto/src/asn1/x500/style/IetfUtilities.cs214
3 files changed, 378 insertions, 0 deletions
diff --git a/crypto/src/asn1/x500/AttributeTypeAndValue.cs b/crypto/src/asn1/x500/AttributeTypeAndValue.cs
new file mode 100644
index 000000000..eb6b3ca30
--- /dev/null
+++ b/crypto/src/asn1/x500/AttributeTypeAndValue.cs
@@ -0,0 +1,60 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X500
+{
+    /**
+     * Holding class for the AttributeTypeAndValue structures that make up an RDN.
+     */
+    public class AttributeTypeAndValue
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier type;
+        private readonly Asn1Encodable value;
+
+        private AttributeTypeAndValue(Asn1Sequence seq)
+        {
+            type = (DerObjectIdentifier)seq[0];
+            value = seq[1];
+        }
+
+        public static AttributeTypeAndValue GetInstance(object obj)
+        {
+            if (obj is AttributeTypeAndValue)
+                return (AttributeTypeAndValue)obj;
+            if (null != obj)
+                return new AttributeTypeAndValue(Asn1Sequence.GetInstance(obj));
+            throw new ArgumentNullException("obj");
+        }
+
+        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/x500/Rdn.cs b/crypto/src/asn1/x500/Rdn.cs
new file mode 100644
index 000000000..4881d0890
--- /dev/null
+++ b/crypto/src/asn1/x500/Rdn.cs
@@ -0,0 +1,104 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X500
+{
+    /**
+     * Holding class for a single Relative Distinguished Name (RDN).
+     */
+    public class Rdn
+        : Asn1Encodable
+    {
+        private readonly Asn1Set values;
+
+        private Rdn(Asn1Set values)
+        {
+            this.values = values;
+        }
+
+        public static Rdn GetInstance(object obj)
+        {
+            if (obj is Rdn)
+                return (Rdn)obj;
+            if (null != obj)
+                return new Rdn(Asn1Set.GetInstance(obj));
+            return null;
+        }
+
+        /**
+         * Create a single valued RDN.
+         *
+         * @param oid RDN type.
+         * @param value RDN value.
+         */
+        public Rdn(DerObjectIdentifier oid, Asn1Encodable value)
+        {
+            this.values = new DerSet(new DerSequence(oid, value));
+        }
+
+        public Rdn(AttributeTypeAndValue attrTAndV)
+        {
+            this.values = new DerSet(attrTAndV);
+        }
+
+        /**
+         * Create a multi-valued RDN.
+         *
+         * @param aAndVs attribute type/value pairs making up the RDN
+         */
+        public Rdn(AttributeTypeAndValue[] aAndVs)
+        {
+            this.values = new DerSet(aAndVs);
+        }
+
+        public virtual bool IsMultiValued
+        {
+            get { return this.values.Count > 1; }
+        }
+
+        /**
+         * Return the number of AttributeTypeAndValue objects in this RDN,
+         *
+         * @return size of RDN, greater than 1 if multi-valued.
+         */
+        public virtual int Count
+        {
+            get { return this.values.Count; }
+        }
+
+        public virtual AttributeTypeAndValue GetFirst()
+        {
+            if (this.values.Count == 0)
+                return null;
+
+            return AttributeTypeAndValue.GetInstance(this.values[0]);
+        }
+
+        public virtual AttributeTypeAndValue[] GetTypesAndValues()
+        {
+            AttributeTypeAndValue[] tmp = new AttributeTypeAndValue[values.Count];
+
+            for (int i = 0; i < tmp.Length; ++i)
+            {
+                tmp[i] = AttributeTypeAndValue.GetInstance(values[i]);
+            }
+
+            return tmp;
+        }
+
+        /**
+         * <pre>
+         * RelativeDistinguishedName ::=
+         *                     SET OF AttributeTypeAndValue
+
+         * AttributeTypeAndValue ::= SEQUENCE {
+         *        type     AttributeType,
+         *        value    AttributeValue }
+         * </pre>
+         * @return this object as its ASN1Primitive type
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return values;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x500/style/IetfUtilities.cs b/crypto/src/asn1/x500/style/IetfUtilities.cs
new file mode 100644
index 000000000..e3236aaec
--- /dev/null
+++ b/crypto/src/asn1/x500/style/IetfUtilities.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X500.Style
+{
+    public abstract class IetfUtilities
+    {
+        public static string ValueToString(Asn1Encodable value)
+        {
+            StringBuilder vBuf = new StringBuilder();
+
+            if (value is IAsn1String && !(value is DerUniversalString))
+            {
+                string v = ((IAsn1String)value).GetString();
+                if (v.Length > 0 && v[0] == '#')
+                {
+                    vBuf.Append('\\');
+                }
+
+                vBuf.Append(v);
+            }
+            else
+            {
+                try
+                {
+                    vBuf.Append('#');
+                    vBuf.Append(Hex.ToHexString(value.ToAsn1Object().GetEncoded(Asn1Encodable.Der)));
+                }
+                catch (IOException e)
+                {
+                    throw new ArgumentException("Other value has no encoded form", "value", e);
+                }
+            }
+
+            int end = vBuf.Length;
+            int index = 0;
+
+            if (vBuf.Length >= 2 && vBuf[0] == '\\' && vBuf[1] == '#')
+            {
+                index += 2;
+            }
+
+            while (index != end)
+            {
+                switch (vBuf[index])
+                {
+                    case ',':
+                    case '"':
+                    case '\\':
+                    case '+':
+                    case '=':
+                    case '<':
+                    case '>':
+                    case ';':
+                    {
+                        vBuf.Insert(index, "\\");
+                        index += 2;
+                        ++end;
+                        break;
+                    }
+                    default:
+                    {
+                        ++index;
+                        break;
+                    }
+                }
+            }
+
+            int start = 0;
+            if (vBuf.Length > 0)
+            {
+                while (vBuf.Length > start && vBuf[start] == ' ')
+                {
+                    vBuf.Insert(start, "\\");
+                    start += 2;
+                }
+            }
+
+            int endBuf = vBuf.Length - 1;
+
+            while (endBuf >= 0 && vBuf[endBuf] == ' ')
+            {
+                vBuf.Insert(endBuf, '\\');
+                endBuf--;
+            }
+
+            return vBuf.ToString();
+        }
+
+        public static string Canonicalize(string s)
+        {
+            string value = Platform.ToLowerInvariant(s);
+
+            if (value.Length > 0 && value[0] == '#')
+            {
+                Asn1Object obj = DecodeObject(value);
+
+                if (obj is IAsn1String)
+                {
+                    value = Platform.ToLowerInvariant(((IAsn1String)obj).GetString());
+                }
+            }
+
+            if (value.Length > 1)
+            {
+                int start = 0;
+                while (start + 1 < value.Length && value[start] == '\\' && value[start + 1] == ' ')
+                {
+                    start += 2;
+                }
+
+                int end = value.Length - 1;
+                while (end - 1 > 0 && value[end - 1] == '\\' && value[end] == ' ')
+                {
+                    end -= 2;
+                }
+
+                if (start > 0 || end < value.Length - 1)
+                {
+                    value = value.Substring(start, end + 1 - start);
+                }
+            }
+
+            return StripInternalSpaces(value);
+        }
+
+        public static string CanonicalString(Asn1Encodable value)
+        {
+            return Canonicalize(ValueToString(value));
+        }
+
+        private static Asn1Object DecodeObject(string oValue)
+        {
+            try
+            {
+                return Asn1Object.FromByteArray(Hex.Decode(oValue.Substring(1)));
+            }
+            catch (IOException e)
+            {
+                throw new InvalidOperationException("unknown encoding in name: " + e);
+            }
+        }
+
+        public static string StripInternalSpaces(string str)
+        {
+            if (str.IndexOf("  ") < 0)
+                return str;
+
+            StringBuilder res = new StringBuilder();
+
+            char c1 = str[0];
+            res.Append(c1);
+
+            for (int k = 1; k < str.Length; k++)
+            {
+                char c2 = str[k];
+                if (!(' ' == c1 && ' ' == c2))
+                {
+                    res.Append(c2);
+                    c1 = c2;
+                }
+            }
+
+            return res.ToString();
+        }
+
+        public static bool RdnAreEqual(Rdn rdn1, Rdn rdn2)
+        {
+            if (rdn1.Count != rdn2.Count)
+                return false;
+
+            AttributeTypeAndValue[] atvs1 = rdn1.GetTypesAndValues();
+            AttributeTypeAndValue[] atvs2 = rdn2.GetTypesAndValues();
+
+            if (atvs1.Length != atvs2.Length)
+                return false;
+
+            for (int i = 0; i != atvs1.Length; i++)
+            {
+                if (!AtvAreEqual(atvs1[i], atvs2[i]))
+                    return false;
+            }
+
+            return true;
+        }
+
+        private static bool AtvAreEqual(AttributeTypeAndValue atv1, AttributeTypeAndValue atv2)
+        {
+            if (atv1 == atv2)
+                return true;
+            if (null == atv1 || null == atv2)
+                return false;
+
+            DerObjectIdentifier o1 = atv1.Type;
+            DerObjectIdentifier o2 = atv2.Type;
+
+            if (!o1.Equals(o2))
+                return false;
+
+            string v1 = CanonicalString(atv1.Value);
+            string v2 = CanonicalString(atv2.Value);
+
+            if (!v1.Equals(v2))
+                return false;
+
+            return true;
+        }
+    }
+}