summary refs log tree commit diff
path: root/crypto/src/x509/X509Certificate.cs
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2013-06-28 15:26:06 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2013-06-28 15:26:06 +0700
commit44288db4414158ac9b98a507b15e81d0d3c66ca6 (patch)
treeaa5ef88948ebb68ed6c8df81eb5da889641a9b50 /crypto/src/x509/X509Certificate.cs
parentSet up text/binary handling for existing file types (diff)
downloadBouncyCastle.NET-ed25519-44288db4414158ac9b98a507b15e81d0d3c66ca6.tar.xz
Initial import of old CVS repository
Diffstat (limited to 'crypto/src/x509/X509Certificate.cs')
-rw-r--r--crypto/src/x509/X509Certificate.cs595
1 files changed, 595 insertions, 0 deletions
diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs
new file mode 100644
index 000000000..f156f3147
--- /dev/null
+++ b/crypto/src/x509/X509Certificate.cs
@@ -0,0 +1,595 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+    /// <summary>
+    /// An Object representing an X509 Certificate.
+    /// Has static methods for loading Certificates encoded in many forms that return X509Certificate Objects.
+    /// </summary>
+    public class X509Certificate
+		:	X509ExtensionBase
+//		, PKCS12BagAttributeCarrier
+    {
+        private readonly X509CertificateStructure c;
+//        private Hashtable pkcs12Attributes = new Hashtable();
+//        private ArrayList pkcs12Ordering = new ArrayList();
+		private readonly BasicConstraints basicConstraints;
+		private readonly bool[] keyUsage;
+
+		private bool hashValueSet;
+		private int hashValue;
+
+		protected X509Certificate()
+		{
+		}
+
+		public X509Certificate(
+			X509CertificateStructure c)
+		{
+			this.c = c;
+
+			try
+			{
+				Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.19"));
+
+				if (str != null)
+				{
+					basicConstraints = BasicConstraints.GetInstance(
+						X509ExtensionUtilities.FromExtensionValue(str));
+				}
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+			}
+
+			try
+			{
+				Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.15"));
+
+				if (str != null)
+				{
+					DerBitString bits = DerBitString.GetInstance(
+						X509ExtensionUtilities.FromExtensionValue(str));
+
+					byte[] bytes = bits.GetBytes();
+					int length = (bytes.Length * 8) - bits.PadBits;
+
+					keyUsage = new bool[(length < 9) ? 9 : length];
+
+					for (int i = 0; i != length; i++)
+					{
+//						keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+						keyUsage[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0;
+					}
+				}
+				else
+				{
+					keyUsage = null;
+				}
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+			}
+		}
+
+//		internal X509Certificate(
+//			Asn1Sequence seq)
+//        {
+//            this.c = X509CertificateStructure.GetInstance(seq);
+//        }
+
+//		/// <summary>
+//        /// Load certificate from byte array.
+//        /// </summary>
+//        /// <param name="encoded">Byte array containing encoded X509Certificate.</param>
+//        public X509Certificate(
+//            byte[] encoded)
+//			: this((Asn1Sequence) new Asn1InputStream(encoded).ReadObject())
+//		{
+//        }
+//
+//        /// <summary>
+//        /// Load certificate from Stream.
+//        /// Must be positioned at start of certificate.
+//        /// </summary>
+//        /// <param name="input"></param>
+//        public X509Certificate(
+//            Stream input)
+//			: this((Asn1Sequence) new Asn1InputStream(input).ReadObject())
+//        {
+//        }
+
+		public virtual X509CertificateStructure CertificateStructure
+		{
+			get { return c; }
+		}
+
+		/// <summary>
+        /// Return true if the current time is within the start and end times nominated on the certificate.
+        /// </summary>
+        /// <returns>true id certificate is valid for the current time.</returns>
+        public virtual bool IsValidNow
+        {
+			get { return IsValid(DateTime.UtcNow); }
+        }
+
+		/// <summary>
+        /// Return true if the nominated time is within the start and end times nominated on the certificate.
+        /// </summary>
+        /// <param name="time">The time to test validity against.</param>
+        /// <returns>True if certificate is valid for nominated time.</returns>
+        public virtual bool IsValid(
+			DateTime time)
+        {
+            return time.CompareTo(NotBefore) >= 0 && time.CompareTo(NotAfter) <= 0;
+        }
+
+		/// <summary>
+		/// Checks if the current date is within certificate's validity period.
+		/// </summary>
+		public virtual void CheckValidity()
+		{
+			this.CheckValidity(DateTime.UtcNow);
+		}
+
+		/// <summary>
+		/// Checks if the given date is within certificate's validity period.
+		/// </summary>
+		/// <exception cref="CertificateExpiredException">if the certificate is expired by given date</exception>
+		/// <exception cref="CertificateNotYetValidException">if the certificate is not yet valid on given date</exception>
+		public virtual void CheckValidity(
+			DateTime time)
+		{
+			if (time.CompareTo(NotAfter) > 0)
+				throw new CertificateExpiredException("certificate expired on " + c.EndDate.GetTime());
+			if (time.CompareTo(NotBefore) < 0)
+				throw new CertificateNotYetValidException("certificate not valid until " + c.StartDate.GetTime());
+		}
+
+		/// <summary>
+        /// Return the certificate's version.
+        /// </summary>
+        /// <returns>An integer whose value Equals the version of the cerficate.</returns>
+        public virtual int Version
+        {
+            get { return c.Version; }
+        }
+
+		/// <summary>
+        /// Return a <see cref="Org.BouncyCastle.Math.BigInteger">BigInteger</see> containing the serial number.
+        /// </summary>
+        /// <returns>The Serial number.</returns>
+        public virtual BigInteger SerialNumber
+        {
+            get { return c.SerialNumber.Value; }
+        }
+
+		/// <summary>
+        /// Get the Issuer Distinguished Name. (Who signed the certificate.)
+        /// </summary>
+        /// <returns>And X509Object containing name and value pairs.</returns>
+//        public IPrincipal IssuerDN
+		public virtual X509Name IssuerDN
+		{
+            get { return c.Issuer; }
+        }
+
+		/// <summary>
+        /// Get the subject of this certificate.
+        /// </summary>
+        /// <returns>An X509Name object containing name and value pairs.</returns>
+//        public IPrincipal SubjectDN
+		public virtual X509Name SubjectDN
+		{
+            get { return c.Subject; }
+        }
+
+		/// <summary>
+		/// The time that this certificate is valid from.
+		/// </summary>
+		/// <returns>A DateTime object representing that time in the local time zone.</returns>
+		public virtual DateTime NotBefore
+		{
+			get { return c.StartDate.ToDateTime(); }
+		}
+
+		/// <summary>
+        /// The time that this certificate is valid up to.
+        /// </summary>
+        /// <returns>A DateTime object representing that time in the local time zone.</returns>
+        public virtual DateTime NotAfter
+        {
+			get { return c.EndDate.ToDateTime(); }
+        }
+
+		/// <summary>
+		/// Return the Der encoded TbsCertificate data.
+		/// This is the certificate component less the signature.
+		/// To Get the whole certificate call the GetEncoded() member.
+		/// </summary>
+		/// <returns>A byte array containing the Der encoded Certificate component.</returns>
+		public virtual byte[] GetTbsCertificate()
+		{
+			return c.TbsCertificate.GetDerEncoded();
+		}
+
+		/// <summary>
+		/// The signature.
+		/// </summary>
+		/// <returns>A byte array containg the signature of the certificate.</returns>
+		public virtual byte[] GetSignature()
+		{
+			return c.Signature.GetBytes();
+		}
+
+		/// <summary>
+		/// A meaningful version of the Signature Algorithm. (EG SHA1WITHRSA)
+		/// </summary>
+		/// <returns>A sting representing the signature algorithm.</returns>
+		public virtual string SigAlgName
+		{
+			get { return SignerUtilities.GetEncodingName(c.SignatureAlgorithm.ObjectID); }
+		}
+
+		/// <summary>
+		/// Get the Signature Algorithms Object ID.
+		/// </summary>
+		/// <returns>A string containg a '.' separated object id.</returns>
+		public virtual string SigAlgOid
+		{
+			get { return c.SignatureAlgorithm.ObjectID.Id; }
+		}
+
+		/// <summary>
+		/// Get the signature algorithms parameters. (EG DSA Parameters)
+		/// </summary>
+		/// <returns>A byte array containing the Der encoded version of the parameters or null if there are none.</returns>
+		public virtual byte[] GetSigAlgParams()
+		{
+			if (c.SignatureAlgorithm.Parameters != null)
+			{
+				return c.SignatureAlgorithm.Parameters.GetDerEncoded();
+			}
+
+			return null;
+		}
+
+		/// <summary>
+		/// Get the issuers UID.
+		/// </summary>
+		/// <returns>A DerBitString.</returns>
+		public virtual DerBitString IssuerUniqueID
+		{
+			get { return c.TbsCertificate.IssuerUniqueID; }
+		}
+
+		/// <summary>
+		/// Get the subjects UID.
+		/// </summary>
+		/// <returns>A DerBitString.</returns>
+		public virtual DerBitString SubjectUniqueID
+		{
+			get { return c.TbsCertificate.SubjectUniqueID; }
+		}
+
+		/// <summary>
+		/// Get a key usage guidlines.
+		/// </summary>
+		public virtual bool[] GetKeyUsage()
+		{
+			return keyUsage == null ? null : (bool[]) keyUsage.Clone();
+		}
+
+		// TODO Replace with something that returns a list of DerObjectIdentifier
+		public virtual IList GetExtendedKeyUsage()
+		{
+			Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.37"));
+
+			if (str == null)
+				return null;
+
+			try
+			{
+				Asn1Sequence seq = Asn1Sequence.GetInstance(
+					X509ExtensionUtilities.FromExtensionValue(str));
+
+                IList list = Platform.CreateArrayList();
+
+				foreach (DerObjectIdentifier oid in seq)
+				{
+					list.Add(oid.Id);
+				}
+
+				return list;
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException("error processing extended key usage extension", e);
+			}
+		}
+
+		public virtual int GetBasicConstraints()
+		{
+			if (basicConstraints != null && basicConstraints.IsCA())
+			{
+				if (basicConstraints.PathLenConstraint == null)
+				{
+					return int.MaxValue;
+				}
+
+				return basicConstraints.PathLenConstraint.IntValue;
+			}
+
+			return -1;
+		}
+
+		public virtual ICollection GetSubjectAlternativeNames()
+		{
+			return GetAlternativeNames("2.5.29.17");
+		}
+
+		public virtual ICollection GetIssuerAlternativeNames()
+		{
+			return GetAlternativeNames("2.5.29.18");
+		}
+
+		protected virtual ICollection GetAlternativeNames(
+			string oid)
+		{
+			Asn1OctetString altNames = GetExtensionValue(new DerObjectIdentifier(oid));
+
+			if (altNames == null)
+				return null;
+
+			Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(altNames);
+
+			GeneralNames gns = GeneralNames.GetInstance(asn1Object);
+
+            IList result = Platform.CreateArrayList();
+			foreach (GeneralName gn in gns.GetNames())
+			{
+                IList entry = Platform.CreateArrayList();
+				entry.Add(gn.TagNo);
+				entry.Add(gn.Name.ToString());
+				result.Add(entry);
+			}
+			return result;
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return c.Version == 3
+				?	c.TbsCertificate.Extensions
+				:	null;
+		}
+
+		/// <summary>
+		/// Get the public key of the subject of the certificate.
+		/// </summary>
+		/// <returns>The public key parameters.</returns>
+		public virtual AsymmetricKeyParameter GetPublicKey()
+		{
+			return PublicKeyFactory.CreateKey(c.SubjectPublicKeyInfo);
+		}
+
+		/// <summary>
+		/// Return a Der encoded version of this certificate.
+		/// </summary>
+		/// <returns>A byte array.</returns>
+		public virtual byte[] GetEncoded()
+		{
+			return c.GetDerEncoded();
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			X509Certificate other = obj as X509Certificate;
+
+			if (other == null)
+				return false;
+
+			return c.Equals(other.c);
+
+			// NB: May prefer this implementation of Equals if more than one certificate implementation in play
+//			return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+		}
+
+		public override int GetHashCode()
+		{
+			lock (this)
+			{
+				if (!hashValueSet)
+				{
+					hashValue = c.GetHashCode();
+					hashValueSet = true;
+				}
+			}
+
+			return hashValue;
+		}
+
+//		public void setBagAttribute(
+//			DERObjectIdentifier oid,
+//			DEREncodable        attribute)
+//		{
+//			pkcs12Attributes.put(oid, attribute);
+//			pkcs12Ordering.addElement(oid);
+//		}
+//
+//		public DEREncodable getBagAttribute(
+//			DERObjectIdentifier oid)
+//		{
+//			return (DEREncodable)pkcs12Attributes.get(oid);
+//		}
+//
+//		public Enumeration getBagAttributeKeys()
+//		{
+//			return pkcs12Ordering.elements();
+//		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string nl = Platform.NewLine;
+
+			buf.Append("  [0]         Version: ").Append(this.Version).Append(nl);
+			buf.Append("         SerialNumber: ").Append(this.SerialNumber).Append(nl);
+			buf.Append("             IssuerDN: ").Append(this.IssuerDN).Append(nl);
+			buf.Append("           Start Date: ").Append(this.NotBefore).Append(nl);
+			buf.Append("           Final Date: ").Append(this.NotAfter).Append(nl);
+			buf.Append("            SubjectDN: ").Append(this.SubjectDN).Append(nl);
+			buf.Append("           Public Key: ").Append(this.GetPublicKey()).Append(nl);
+			buf.Append("  Signature Algorithm: ").Append(this.SigAlgName).Append(nl);
+
+			byte[] sig = this.GetSignature();
+			buf.Append("            Signature: ").Append(Hex.ToHexString(sig, 0, 20)).Append(nl);
+
+			for (int i = 20; i < sig.Length; i += 20)
+			{
+				int len = System.Math.Min(20, sig.Length - i);
+				buf.Append("                       ").Append(Hex.ToHexString(sig, i, len)).Append(nl);
+			}
+
+			X509Extensions extensions = c.TbsCertificate.Extensions;
+
+			if (extensions != null)
+			{
+				IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+
+				if (e.MoveNext())
+				{
+					buf.Append("       Extensions: \n");
+				}
+
+				do
+				{
+					DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
+					X509Extension ext = extensions.GetExtension(oid);
+
+					if (ext.Value != null)
+					{
+						byte[] octs = ext.Value.GetOctets();
+						Asn1Object obj = Asn1Object.FromByteArray(octs);
+						buf.Append("                       critical(").Append(ext.IsCritical).Append(") ");
+						try
+						{
+							if (oid.Equals(X509Extensions.BasicConstraints))
+							{
+								buf.Append(BasicConstraints.GetInstance(obj));
+							}
+							else if (oid.Equals(X509Extensions.KeyUsage))
+							{
+								buf.Append(KeyUsage.GetInstance(obj));
+							}
+							else if (oid.Equals(MiscObjectIdentifiers.NetscapeCertType))
+							{
+								buf.Append(new NetscapeCertType((DerBitString) obj));
+							}
+							else if (oid.Equals(MiscObjectIdentifiers.NetscapeRevocationUrl))
+							{
+								buf.Append(new NetscapeRevocationUrl((DerIA5String) obj));
+							}
+							else if (oid.Equals(MiscObjectIdentifiers.VerisignCzagExtension))
+							{
+								buf.Append(new VerisignCzagExtension((DerIA5String) obj));
+							}
+							else
+							{
+								buf.Append(oid.Id);
+								buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj));
+								//buf.Append(" value = ").Append("*****").Append(nl);
+							}
+						}
+						catch (Exception)
+						{
+							buf.Append(oid.Id);
+							//buf.Append(" value = ").Append(new string(Hex.encode(ext.getValue().getOctets()))).Append(nl);
+							buf.Append(" value = ").Append("*****");
+						}
+					}
+
+					buf.Append(nl);
+				}
+				while (e.MoveNext());
+			}
+
+			return buf.ToString();
+		}
+
+		/// <summary>
+		/// Verify the certificate's signature using the nominated public key.
+		/// </summary>
+		/// <param name="key">An appropriate public key parameter object, RsaPublicKeyParameters, DsaPublicKeyParameters or ECDsaPublicKeyParameters</param>
+		/// <returns>True if the signature is valid.</returns>
+		/// <exception cref="Exception">If key submitted is not of the above nominated types.</exception>
+		public virtual void Verify(
+			AsymmetricKeyParameter key)
+		{
+			string sigName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
+			ISigner signature = SignerUtilities.GetSigner(sigName);
+
+			CheckSignature(key, signature);
+		}
+
+		protected virtual void CheckSignature(
+			AsymmetricKeyParameter	publicKey,
+			ISigner					signature)
+		{
+			if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature))
+				throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+
+			Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
+
+			X509SignatureUtilities.SetSignatureParameters(signature, parameters);
+
+			signature.Init(false, publicKey);
+
+			byte[] b = this.GetTbsCertificate();
+			signature.BlockUpdate(b, 0, b.Length);
+
+			byte[] sig = this.GetSignature();
+			if (!signature.VerifySignature(sig))
+			{
+				throw new InvalidKeyException("Public key presented not for certificate signature");
+			}
+		}
+
+		private static bool IsAlgIDEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+		{
+			if (!id1.ObjectID.Equals(id2.ObjectID))
+				return false;
+
+			Asn1Encodable p1 = id1.Parameters;
+			Asn1Encodable p2 = id2.Parameters;
+
+			if ((p1 == null) == (p2 == null))
+				return Platform.Equals(p1, p2);
+
+			// Exactly one of p1, p2 is null at this point
+			return p1 == null
+				?	p2.ToAsn1Object() is Asn1Null
+				:	p1.ToAsn1Object() is Asn1Null;
+		}
+	}
+}