summary refs log tree commit diff
path: root/crypto/src/asn1/x509
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/asn1/x509')
-rw-r--r--crypto/src/asn1/x509/AuthorityInformationAccess.cs20
-rw-r--r--crypto/src/asn1/x509/AuthorityKeyIdentifier.cs105
-rw-r--r--crypto/src/asn1/x509/BasicConstraints.cs43
-rw-r--r--crypto/src/asn1/x509/CRLDistPoint.cs32
-rw-r--r--crypto/src/asn1/x509/CertificatePolicies.cs34
-rw-r--r--crypto/src/asn1/x509/ExtendedKeyUsage.cs41
-rw-r--r--crypto/src/asn1/x509/GeneralNames.cs41
-rw-r--r--crypto/src/asn1/x509/KeyUsage.cs22
-rw-r--r--crypto/src/asn1/x509/SubjectKeyIdentifier.cs56
-rw-r--r--crypto/src/asn1/x509/X509Extensions.cs25
10 files changed, 222 insertions, 197 deletions
diff --git a/crypto/src/asn1/x509/AuthorityInformationAccess.cs b/crypto/src/asn1/x509/AuthorityInformationAccess.cs
index 9329e2b98..f4b694cf0 100644
--- a/crypto/src/asn1/x509/AuthorityInformationAccess.cs
+++ b/crypto/src/asn1/x509/AuthorityInformationAccess.cs
@@ -26,7 +26,10 @@ namespace Org.BouncyCastle.Asn1.X509
     public class AuthorityInformationAccess
         : Asn1Encodable
     {
-        private readonly AccessDescription[] descriptions;
+        private static AccessDescription[] Copy(AccessDescription[] descriptions)
+        {
+            return (AccessDescription[])descriptions.Clone();
+        }
 
         public static AuthorityInformationAccess GetInstance(object obj)
         {
@@ -37,6 +40,13 @@ namespace Org.BouncyCastle.Asn1.X509
             return new AuthorityInformationAccess(Asn1Sequence.GetInstance(obj));
         }
 
+        public static AuthorityInformationAccess FromExtensions(X509Extensions extensions)
+        {
+            return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.AuthorityInfoAccess));
+        }
+
+        private readonly AccessDescription[] descriptions;
+
         private AuthorityInformationAccess(
             Asn1Sequence seq)
         {
@@ -57,6 +67,12 @@ namespace Org.BouncyCastle.Asn1.X509
             this.descriptions = new AccessDescription[]{ description };
         }
 
+        public AuthorityInformationAccess(
+            AccessDescription[] descriptions)
+        {
+            this.descriptions = Copy(descriptions);
+        }
+
         /**
          * create an AuthorityInformationAccess with the oid and location provided.
          */
@@ -67,7 +83,7 @@ namespace Org.BouncyCastle.Asn1.X509
 
         public AccessDescription[] GetAccessDescriptions()
         {
-            return (AccessDescription[])descriptions.Clone();
+            return Copy(descriptions);
         }
 
         public override Asn1Object ToAsn1Object()
diff --git a/crypto/src/asn1/x509/AuthorityKeyIdentifier.cs b/crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
index aca1dc330..e7f12016a 100644
--- a/crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
+++ b/crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
@@ -5,6 +5,7 @@ using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
 
 namespace Org.BouncyCastle.Asn1.X509
 {
@@ -25,56 +26,51 @@ namespace Org.BouncyCastle.Asn1.X509
     public class AuthorityKeyIdentifier
         : Asn1Encodable
     {
-        internal readonly Asn1OctetString	keyidentifier;
-        internal readonly GeneralNames		certissuer;
-        internal readonly DerInteger		certserno;
-
-		public static AuthorityKeyIdentifier GetInstance(
-            Asn1TaggedObject	obj,
-            bool				explicitly)
+        public static AuthorityKeyIdentifier GetInstance(Asn1TaggedObject obj, bool explicitly)
         {
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		public static AuthorityKeyIdentifier GetInstance(
-            object obj)
+		public static AuthorityKeyIdentifier GetInstance(object obj)
         {
             if (obj is AuthorityKeyIdentifier)
-            {
-                return (AuthorityKeyIdentifier) obj;
-            }
-
-			if (obj is Asn1Sequence)
-            {
-                return new AuthorityKeyIdentifier((Asn1Sequence) obj);
-            }
+                return (AuthorityKeyIdentifier)obj;
+            if (obj is X509Extension)
+                return GetInstance(X509Extension.ConvertValueToObject((X509Extension)obj));
+            if (obj == null)
+                return null;
+            return new AuthorityKeyIdentifier(Asn1Sequence.GetInstance(obj));
+		}
 
-	        if (obj is X509Extension)
-			{
-				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
-			}
+        public static AuthorityKeyIdentifier FromExtensions(X509Extensions extensions)
+        {
+            return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.AuthorityKeyIdentifier));
+        }
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+        private readonly Asn1OctetString keyidentifier;
+        private readonly GeneralNames certissuer;
+        private readonly DerInteger certserno;
 
-		protected internal AuthorityKeyIdentifier(
+        protected internal AuthorityKeyIdentifier(
             Asn1Sequence seq)
         {
-			foreach (Asn1TaggedObject o in seq)
+            foreach (Asn1Encodable element in seq)
 			{
-				switch (o.TagNo)
+                Asn1TaggedObject obj = Asn1TaggedObject.GetInstance(element);
+
+				switch (obj.TagNo)
                 {
-					case 0:
-						this.keyidentifier = Asn1OctetString.GetInstance(o, false);
-						break;
-					case 1:
-						this.certissuer = GeneralNames.GetInstance(o, false);
-						break;
-					case 2:
-						this.certserno = DerInteger.GetInstance(o, false);
-						break;
-					default:
-						throw new ArgumentException("illegal tag");
+				case 0:
+					this.keyidentifier = Asn1OctetString.GetInstance(obj, false);
+					break;
+				case 1:
+					this.certissuer = GeneralNames.GetInstance(obj, false);
+					break;
+				case 2:
+					this.certserno = DerInteger.GetInstance(obj, false);
+					break;
+				default:
+					throw new ArgumentException("illegal tag");
                 }
             }
         }
@@ -94,14 +90,8 @@ namespace Org.BouncyCastle.Asn1.X509
          **/
         public AuthorityKeyIdentifier(
             SubjectPublicKeyInfo spki)
+            : this(spki, null, null)
         {
-            IDigest digest = new Sha1Digest();
-            byte[] resBuf = new byte[digest.GetDigestSize()];
-
-			byte[] bytes = spki.PublicKeyData.GetBytes();
-            digest.BlockUpdate(bytes, 0, bytes.Length);
-            digest.DoFinal(resBuf, 0);
-            this.keyidentifier = new DerOctetString(resBuf);
         }
 
         /**
@@ -115,27 +105,24 @@ namespace Org.BouncyCastle.Asn1.X509
         {
             IDigest digest = new Sha1Digest();
             byte[] resBuf = new byte[digest.GetDigestSize()];
-
 			byte[] bytes = spki.PublicKeyData.GetBytes();
             digest.BlockUpdate(bytes, 0, bytes.Length);
             digest.DoFinal(resBuf, 0);
 
 			this.keyidentifier = new DerOctetString(resBuf);
             this.certissuer = name;
-            this.certserno = new DerInteger(serialNumber);
+            this.certserno = serialNumber == null ? null : new DerInteger(serialNumber);
         }
 
-		/**
+        /**
 		 * create an AuthorityKeyIdentifier with the GeneralNames tag and
 		 * the serial number provided.
 		 */
 		public AuthorityKeyIdentifier(
 			GeneralNames	name,
 			BigInteger		serialNumber)
+            : this((byte[])null, name, serialNumber)
 		{
-			this.keyidentifier = null;
-			this.certissuer = GeneralNames.GetInstance(name.ToAsn1Object());
-			this.certserno = new DerInteger(serialNumber);
 		}
 
 		/**
@@ -143,13 +130,11 @@ namespace Org.BouncyCastle.Asn1.X509
 		 */
 		public AuthorityKeyIdentifier(
 			byte[] keyIdentifier)
+            : this(keyIdentifier, null, null)
 		{
-			this.keyidentifier = new DerOctetString(keyIdentifier);
-			this.certissuer = null;
-			this.certserno = null;
 		}
 
-		/**
+        /**
 		 * create an AuthorityKeyIdentifier with a precomupted key identifier
 		 * and the GeneralNames tag and the serial number provided as well.
 		 */
@@ -158,9 +143,9 @@ namespace Org.BouncyCastle.Asn1.X509
 			GeneralNames	name,
 			BigInteger		serialNumber)
 		{
-			this.keyidentifier = new DerOctetString(keyIdentifier);
-			this.certissuer = GeneralNames.GetInstance(name.ToAsn1Object());
-			this.certserno = new DerInteger(serialNumber);
+			this.keyidentifier = keyIdentifier == null ? null : new DerOctetString(keyIdentifier);
+			this.certissuer = name;
+			this.certserno = serialNumber == null ? null : new DerInteger(serialNumber);
 		}
 
 		public byte[] GetKeyIdentifier()
@@ -178,7 +163,7 @@ namespace Org.BouncyCastle.Asn1.X509
             get { return certserno == null ? null : certserno.Value; }
         }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          */
         public override Asn1Object ToAsn1Object()
@@ -192,7 +177,9 @@ namespace Org.BouncyCastle.Asn1.X509
 
 		public override string ToString()
         {
-            return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.GetOctets() + ")");
+            string keyID = (keyidentifier != null) ? Hex.ToHexString(keyidentifier.GetOctets()) : "null";
+
+            return "AuthorityKeyIdentifier: KeyID(" + keyID + ")";
         }
     }
 }
diff --git a/crypto/src/asn1/x509/BasicConstraints.cs b/crypto/src/asn1/x509/BasicConstraints.cs
index 079294d1b..deecae241 100644
--- a/crypto/src/asn1/x509/BasicConstraints.cs
+++ b/crypto/src/asn1/x509/BasicConstraints.cs
@@ -8,38 +8,31 @@ namespace Org.BouncyCastle.Asn1.X509
     public class BasicConstraints
         : Asn1Encodable
     {
-        private readonly DerBoolean	cA;
-        private readonly DerInteger	pathLenConstraint;
-
-		public static BasicConstraints GetInstance(
-            Asn1TaggedObject	obj,
-            bool				explicitly)
+		public static BasicConstraints GetInstance(Asn1TaggedObject obj, bool explicitly)
         {
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		public static BasicConstraints GetInstance(
-            object obj)
+		public static BasicConstraints GetInstance(object obj)
         {
-            if (obj == null || obj is BasicConstraints)
-            {
-                return (BasicConstraints) obj;
-            }
-
-			if (obj is Asn1Sequence)
-            {
-                return new BasicConstraints((Asn1Sequence) obj);
-            }
+            if (obj is BasicConstraints)
+                return (BasicConstraints)obj;
+            if (obj is X509Extension)
+                return GetInstance(X509Extension.ConvertValueToObject((X509Extension)obj));
+            if (obj == null)
+                return null;
+            return new BasicConstraints(Asn1Sequence.GetInstance(obj));
+		}
 
-			if (obj is X509Extension)
-			{
-				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
-			}
+        public static BasicConstraints FromExtensions(X509Extensions extensions)
+        {
+            return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.BasicConstraints));
+        }
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+        private readonly DerBoolean cA;
+        private readonly DerInteger pathLenConstraint;
 
-		private BasicConstraints(
+        private BasicConstraints(
             Asn1Sequence seq)
         {
 			if (seq.Count > 0)
@@ -105,7 +98,7 @@ namespace Org.BouncyCastle.Asn1.X509
          */
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector();
+            Asn1EncodableVector v = new Asn1EncodableVector(2);
             v.AddOptional(cA,
                 pathLenConstraint); // yes some people actually do this when cA is false...
             return new DerSequence(v);
diff --git a/crypto/src/asn1/x509/CRLDistPoint.cs b/crypto/src/asn1/x509/CRLDistPoint.cs
index 56ba79ca5..446bb19db 100644
--- a/crypto/src/asn1/x509/CRLDistPoint.cs
+++ b/crypto/src/asn1/x509/CRLDistPoint.cs
@@ -8,32 +8,28 @@ namespace Org.BouncyCastle.Asn1.X509
     public class CrlDistPoint
         : Asn1Encodable
     {
-        internal readonly Asn1Sequence seq;
-
-		public static CrlDistPoint GetInstance(
-            Asn1TaggedObject	obj,
-            bool				explicitly)
+		public static CrlDistPoint GetInstance(Asn1TaggedObject obj, bool explicitly)
         {
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		public static CrlDistPoint GetInstance(
-            object obj)
+		public static CrlDistPoint GetInstance(object obj)
         {
-            if (obj is CrlDistPoint || obj == null)
-            {
-                return (CrlDistPoint) obj;
-            }
+            if (obj is CrlDistPoint)
+                return (CrlDistPoint)obj;
+            if (obj == null)
+                return null;
+            return new CrlDistPoint(Asn1Sequence.GetInstance(obj));
+		}
 
-			if (obj is Asn1Sequence)
-            {
-                return new CrlDistPoint((Asn1Sequence) obj);
-            }
+        public static CrlDistPoint FromExtensions(X509Extensions extensions)
+        {
+            return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.CrlDistributionPoints));
+        }
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+        internal readonly Asn1Sequence seq;
 
-		private CrlDistPoint(
+        private CrlDistPoint(
             Asn1Sequence seq)
         {
             this.seq = seq;
diff --git a/crypto/src/asn1/x509/CertificatePolicies.cs b/crypto/src/asn1/x509/CertificatePolicies.cs
index a83565bb2..97214bd3f 100644
--- a/crypto/src/asn1/x509/CertificatePolicies.cs
+++ b/crypto/src/asn1/x509/CertificatePolicies.cs
@@ -6,13 +6,17 @@ namespace Org.BouncyCastle.Asn1.X509
     public class CertificatePolicies
         : Asn1Encodable
     {
-        private readonly PolicyInformation[] policyInformation;
+        private static PolicyInformation[] Copy(PolicyInformation[] policyInfo)
+        {
+            return (PolicyInformation[])policyInfo.Clone();
+        }
 
         public static CertificatePolicies GetInstance(object obj)
         {
-            if (obj == null || obj is CertificatePolicies)
+            if (obj is CertificatePolicies)
                 return (CertificatePolicies)obj;
-
+            if (obj == null)
+                return null;
             return new CertificatePolicies(Asn1Sequence.GetInstance(obj));
         }
 
@@ -21,6 +25,13 @@ namespace Org.BouncyCastle.Asn1.X509
             return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
         }
 
+        public static CertificatePolicies FromExtensions(X509Extensions extensions)
+        {
+            return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.CertificatePolicies));
+        }
+
+        private readonly PolicyInformation[] policyInformation;
+
         /**
          * Construct a CertificatePolicies object containing one PolicyInformation.
          * 
@@ -33,7 +44,7 @@ namespace Org.BouncyCastle.Asn1.X509
 
         public CertificatePolicies(PolicyInformation[] policyInformation)
         {
-            this.policyInformation = policyInformation;
+            this.policyInformation = Copy(policyInformation);
         }
 
         private CertificatePolicies(Asn1Sequence seq)
@@ -48,7 +59,20 @@ namespace Org.BouncyCastle.Asn1.X509
 
         public virtual PolicyInformation[] GetPolicyInformation()
         {
-            return (PolicyInformation[])policyInformation.Clone();
+            return Copy(policyInformation);
+        }
+
+        public virtual PolicyInformation GetPolicyInformation(DerObjectIdentifier policyIdentifier)
+        {
+            for (int i = 0; i != policyInformation.Length; i++)
+            {
+                if (policyIdentifier.Equals(policyInformation[i].PolicyIdentifier))
+                {
+                    return policyInformation[i];
+                }
+            }
+
+            return null;
         }
 
         /**
diff --git a/crypto/src/asn1/x509/ExtendedKeyUsage.cs b/crypto/src/asn1/x509/ExtendedKeyUsage.cs
index 8f7e6a353..7e8c7a37c 100644
--- a/crypto/src/asn1/x509/ExtendedKeyUsage.cs
+++ b/crypto/src/asn1/x509/ExtendedKeyUsage.cs
@@ -14,9 +14,6 @@ namespace Org.BouncyCastle.Asn1.X509
     public class ExtendedKeyUsage
         : Asn1Encodable
     {
-        internal readonly IDictionary usageTable = Platform.CreateHashtable();
-        internal readonly Asn1Sequence seq;
-
         public static ExtendedKeyUsage GetInstance(
             Asn1TaggedObject	obj,
             bool				explicitly)
@@ -28,34 +25,32 @@ namespace Org.BouncyCastle.Asn1.X509
             object obj)
         {
             if (obj is ExtendedKeyUsage)
-            {
-                return (ExtendedKeyUsage) obj;
-            }
-
-            if (obj is Asn1Sequence)
-            {
-                return new ExtendedKeyUsage((Asn1Sequence) obj);
-            }
-
+                return (ExtendedKeyUsage)obj;
             if (obj is X509Extension)
-            {
-                return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
-            }
+                return GetInstance(X509Extension.ConvertValueToObject((X509Extension)obj));
+            if (obj == null)
+                return null;
+            return new ExtendedKeyUsage(Asn1Sequence.GetInstance(obj));
+        }
 
-            throw new ArgumentException("Invalid ExtendedKeyUsage: " + Platform.GetTypeName(obj));
+        public static ExtendedKeyUsage FromExtensions(X509Extensions extensions)
+        {
+            return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.ExtendedKeyUsage));
         }
 
+        internal readonly IDictionary usageTable = Platform.CreateHashtable();
+        internal readonly Asn1Sequence seq;
+
         private ExtendedKeyUsage(
             Asn1Sequence seq)
         {
             this.seq = seq;
 
-            foreach (object o in seq)
+            foreach (Asn1Encodable element in seq)
             {
-                if (!(o is DerObjectIdentifier))
-                    throw new ArgumentException("Only DerObjectIdentifier instances allowed in ExtendedKeyUsage.");
+                DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(element);
 
-                this.usageTable[o] = o;
+                this.usageTable[oid] = oid;
             }
         }
 
@@ -86,10 +81,10 @@ namespace Org.BouncyCastle.Asn1.X509
 
             foreach (object usage in usages)
             {
-                Asn1Encodable o = KeyPurposeID.GetInstance(usage);
+                DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(usage);
 
-                v.Add(o);
-                this.usageTable[o] = o;
+                v.Add(oid);
+                this.usageTable[oid] = oid;
             }
 
             this.seq = new DerSequence(v);
diff --git a/crypto/src/asn1/x509/GeneralNames.cs b/crypto/src/asn1/x509/GeneralNames.cs
index fcd2ecb24..c105f3b6e 100644
--- a/crypto/src/asn1/x509/GeneralNames.cs
+++ b/crypto/src/asn1/x509/GeneralNames.cs
@@ -8,32 +8,33 @@ namespace Org.BouncyCastle.Asn1.X509
 	public class GeneralNames
 		: Asn1Encodable
 	{
-		private readonly GeneralName[] names;
+        private static GeneralName[] Copy(GeneralName[] names)
+        {
+            return (GeneralName[])names.Clone();
+        }
 
-		public static GeneralNames GetInstance(
-			object obj)
+        public static GeneralNames GetInstance(object obj)
 		{
-			if (obj == null || obj is GeneralNames)
-			{
-				return (GeneralNames) obj;
-			}
-
-			if (obj is Asn1Sequence)
-			{
-				return new GeneralNames((Asn1Sequence) obj);
-			}
-
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+            if (obj is GeneralNames)
+                return (GeneralNames)obj;
+            if (obj == null)
+                return null;
+            return new GeneralNames(Asn1Sequence.GetInstance(obj));
 		}
 
-		public static GeneralNames GetInstance(
-			Asn1TaggedObject	obj,
-			bool				explicitly)
+		public static GeneralNames GetInstance(Asn1TaggedObject obj, bool explicitly)
 		{
 			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
 		}
 
-		/// <summary>Construct a GeneralNames object containing one GeneralName.</summary>
+        public static GeneralNames FromExtensions(X509Extensions extensions, DerObjectIdentifier extOid)
+        {
+            return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, extOid));
+        }
+
+        private readonly GeneralName[] names;
+
+        /// <summary>Construct a GeneralNames object containing one GeneralName.</summary>
 		/// <param name="name">The name to be contained.</param>
 		public GeneralNames(
 			GeneralName name)
@@ -44,7 +45,7 @@ namespace Org.BouncyCastle.Asn1.X509
         public GeneralNames(
             GeneralName[] names)
         {
-            this.names = (GeneralName[])names.Clone();
+            this.names = Copy(names);
         }
 
 		private GeneralNames(
@@ -60,7 +61,7 @@ namespace Org.BouncyCastle.Asn1.X509
 
 		public GeneralName[] GetNames()
 		{
-			return (GeneralName[]) names.Clone();
+            return Copy(names);
 		}
 
 		/**
diff --git a/crypto/src/asn1/x509/KeyUsage.cs b/crypto/src/asn1/x509/KeyUsage.cs
index aeaffb708..b31b54341 100644
--- a/crypto/src/asn1/x509/KeyUsage.cs
+++ b/crypto/src/asn1/x509/KeyUsage.cs
@@ -30,23 +30,23 @@ namespace Org.BouncyCastle.Asn1.X509
         public const int EncipherOnly     = (1 << 0);
         public const int DecipherOnly     = (1 << 15);
 
-		public static new KeyUsage GetInstance(
-			object obj)
+		public static new KeyUsage GetInstance(object obj)
 		{
 			if (obj is KeyUsage)
-			{
 				return (KeyUsage)obj;
-			}
-
-			if (obj is X509Extension)
-			{
-				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
-			}
-
+            if (obj is X509Extension)
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension)obj));
+            if (obj == null)
+                return null;
 			return new KeyUsage(DerBitString.GetInstance(obj));
 		}
 
-		/**
+        public static KeyUsage FromExtensions(X509Extensions extensions)
+        {
+            return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.KeyUsage));
+        }
+
+        /**
          * Basic constructor.
          *
          * @param usage - the bitwise OR of the Key Usage flags giving the
diff --git a/crypto/src/asn1/x509/SubjectKeyIdentifier.cs b/crypto/src/asn1/x509/SubjectKeyIdentifier.cs
index f2e6cc006..bb694681b 100644
--- a/crypto/src/asn1/x509/SubjectKeyIdentifier.cs
+++ b/crypto/src/asn1/x509/SubjectKeyIdentifier.cs
@@ -15,54 +15,44 @@ namespace Org.BouncyCastle.Asn1.X509
     public class SubjectKeyIdentifier
         : Asn1Encodable
     {
-        private readonly byte[] keyIdentifier;
-
-		public static SubjectKeyIdentifier GetInstance(
-            Asn1TaggedObject	obj,
-            bool				explicitly)
+		public static SubjectKeyIdentifier GetInstance(Asn1TaggedObject obj, bool explicitly)
         {
             return GetInstance(Asn1OctetString.GetInstance(obj, explicitly));
         }
 
-		public static SubjectKeyIdentifier GetInstance(
-            object obj)
+		public static SubjectKeyIdentifier GetInstance(object obj)
         {
             if (obj is SubjectKeyIdentifier)
-            {
-                return (SubjectKeyIdentifier) obj;
-            }
-
-			if (obj is SubjectPublicKeyInfo)
-            {
-                return new SubjectKeyIdentifier((SubjectPublicKeyInfo) obj);
-            }
-
-			if (obj is Asn1OctetString)
-            {
-                return new SubjectKeyIdentifier((Asn1OctetString) obj);
-            }
-
-			if (obj is X509Extension)
-			{
-				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
-			}
-
-            throw new ArgumentException("Invalid SubjectKeyIdentifier: " + Platform.GetTypeName(obj));
+                return (SubjectKeyIdentifier)obj;
+            if (obj is SubjectPublicKeyInfo)
+                return new SubjectKeyIdentifier((SubjectPublicKeyInfo)obj);
+            if (obj is X509Extension)
+                return GetInstance(X509Extension.ConvertValueToObject((X509Extension)obj));
+            if (obj == null)
+                return null;
+            return new SubjectKeyIdentifier(Asn1OctetString.GetInstance(obj));
         }
 
-		public SubjectKeyIdentifier(
+        public static SubjectKeyIdentifier FromExtensions(X509Extensions extensions)
+        {
+            return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.SubjectKeyIdentifier));
+        }
+
+        private readonly byte[] keyIdentifier;
+
+        public SubjectKeyIdentifier(
             byte[] keyID)
         {
 			if (keyID == null)
 				throw new ArgumentNullException("keyID");
 
-			this.keyIdentifier = keyID;
+			this.keyIdentifier = Arrays.Clone(keyID);
         }
 
 		public SubjectKeyIdentifier(
             Asn1OctetString keyID)
+            : this(keyID.GetOctets())
         {
-            this.keyIdentifier = keyID.GetOctets();
         }
 
 		/**
@@ -79,12 +69,12 @@ namespace Org.BouncyCastle.Asn1.X509
 
 		public byte[] GetKeyIdentifier()
 		{
-			return keyIdentifier;
+            return Arrays.Clone(keyIdentifier);
 		}
 
-		public override Asn1Object ToAsn1Object()
+        public override Asn1Object ToAsn1Object()
 		{
-			return new DerOctetString(keyIdentifier);
+			return new DerOctetString(GetKeyIdentifier());
 		}
 
 		/**
diff --git a/crypto/src/asn1/x509/X509Extensions.cs b/crypto/src/asn1/x509/X509Extensions.cs
index d1b9fa39a..42121fa60 100644
--- a/crypto/src/asn1/x509/X509Extensions.cs
+++ b/crypto/src/asn1/x509/X509Extensions.cs
@@ -172,6 +172,16 @@ namespace Org.BouncyCastle.Asn1.X509
         private readonly IDictionary extensions = Platform.CreateHashtable();
         private readonly IList ordering;
 
+        public static X509Extension GetExtension(X509Extensions extensions, DerObjectIdentifier oid)
+        {
+            return null == extensions ? null : extensions.GetExtension(oid);
+        }
+
+        public static Asn1Encodable GetExtensionParsedValue(X509Extensions extensions, DerObjectIdentifier oid)
+        {
+            return null == extensions ? null : extensions.GetExtensionParsedValue(oid);
+        }
+
 		public static X509Extensions GetInstance(
             Asn1TaggedObject	obj,
             bool				explicitly)
@@ -368,7 +378,20 @@ namespace Org.BouncyCastle.Asn1.X509
         public X509Extension GetExtension(
             DerObjectIdentifier oid)
         {
-             return (X509Extension) extensions[oid];
+             return (X509Extension)extensions[oid];
+        }
+
+        /**
+         * return the parsed value of the extension represented by the object identifier
+         * passed in.
+         *
+         * @return the parsed value of the extension if it's present, null otherwise.
+         */
+        public Asn1Encodable GetExtensionParsedValue(DerObjectIdentifier oid)
+        {
+            X509Extension ext = GetExtension(oid);
+
+            return ext == null ? null : ext.GetParsedValue();
         }
 
 		/**