<PackageReference Include="BouncyCastle.Cryptography" Version="2.3.0" />

X509Certificate

An Object representing an X509 Certificate. Has static methods for loading Certificates encoded in many forms that return X509Certificate Objects.
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.Crypto.Operators; 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; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; namespace Org.BouncyCastle.X509 { public class X509Certificate : X509ExtensionBase { private class CachedEncoding { private readonly byte[] encoding; private readonly CertificateEncodingException exception; internal byte[] Encoding => encoding; internal CachedEncoding(byte[] encoding, CertificateEncodingException exception) { this.encoding = encoding; this.exception = exception; } internal byte[] GetEncoded() { if (exception != null) throw exception; if (encoding == null) throw new CertificateEncodingException(); return encoding; } } private readonly X509CertificateStructure c; private readonly byte[] sigAlgParams; private readonly BasicConstraints basicConstraints; private readonly bool[] keyUsage; private string m_sigAlgName; private AsymmetricKeyParameter publicKeyValue; private CachedEncoding cachedEncoding; private volatile bool hashValueSet; private volatile int hashValue; public virtual X509CertificateStructure CertificateStructure => c; public virtual bool IsValidNow => IsValid(DateTime.UtcNow); public virtual int Version => c.Version; public virtual BigInteger SerialNumber => c.SerialNumber.Value; public virtual X509Name IssuerDN => c.Issuer; public virtual X509Name SubjectDN => c.Subject; public virtual DateTime NotBefore => c.StartDate.ToDateTime(); public virtual DateTime NotAfter => c.EndDate.ToDateTime(); public virtual TbsCertificateStructure TbsCertificate => c.TbsCertificate; public virtual string SigAlgName => Objects.EnsureSingletonInitialized(ref m_sigAlgName, SignatureAlgorithm, X509SignatureUtilities.GetSignatureName); public virtual string SigAlgOid => c.SignatureAlgorithm.Algorithm.Id; public virtual AlgorithmIdentifier SignatureAlgorithm => c.SignatureAlgorithm; public virtual DerBitString IssuerUniqueID => c.TbsCertificate.IssuerUniqueID; public virtual DerBitString SubjectUniqueID => c.TbsCertificate.SubjectUniqueID; public virtual SubjectPublicKeyInfo SubjectPublicKeyInfo => c.SubjectPublicKeyInfo; protected X509Certificate() { } public X509Certificate(byte[] certData) : this(X509CertificateStructure.GetInstance(certData)) { } public X509Certificate(X509CertificateStructure c) { this.c = c; try { sigAlgParams = c.SignatureAlgorithm.Parameters?.GetEncoded("DER"); } catch (Exception ex) { throw new CertificateParsingException("Certificate contents invalid: " + ex?.ToString()); } try { Asn1OctetString extensionValue = GetExtensionValue(X509Extensions.BasicConstraints); if (extensionValue != null) basicConstraints = BasicConstraints.GetInstance(X509ExtensionUtilities.FromExtensionValue(extensionValue)); } catch (Exception ex2) { throw new CertificateParsingException("cannot construct BasicConstraints: " + ex2?.ToString()); } try { Asn1OctetString extensionValue2 = GetExtensionValue(X509Extensions.KeyUsage); if (extensionValue2 != null) { DerBitString instance = DerBitString.GetInstance(X509ExtensionUtilities.FromExtensionValue(extensionValue2)); byte[] bytes = instance.GetBytes(); int num = bytes.Length * 8 - instance.PadBits; keyUsage = new bool[(num < 9) ? 9 : num]; for (int i = 0; i != num; i++) { keyUsage[i] = ((bytes[i / 8] & (128 >> i % 8)) != 0); } } else keyUsage = null; } catch (Exception ex3) { throw new CertificateParsingException("cannot construct KeyUsage: " + ex3?.ToString()); } } public virtual bool IsValid(DateTime time) { if (time.CompareTo(NotBefore) >= 0) return time.CompareTo(NotAfter) <= 0; return false; } public virtual void CheckValidity() { CheckValidity(DateTime.UtcNow); } public virtual void CheckValidity(DateTime time) { if (time.CompareTo(NotAfter) > 0) throw new CertificateExpiredException("certificate expired on " + c.EndDate?.ToString()); if (time.CompareTo(NotBefore) < 0) throw new CertificateNotYetValidException("certificate not valid until " + c.StartDate?.ToString()); } public virtual byte[] GetTbsCertificate() { return c.TbsCertificate.GetDerEncoded(); } public virtual byte[] GetSignature() { return c.GetSignatureOctets(); } public virtual byte[] GetSigAlgParams() { return Arrays.Clone(sigAlgParams); } public virtual bool[] GetKeyUsage() { return Arrays.Clone(keyUsage); } public virtual IList<DerObjectIdentifier> GetExtendedKeyUsage() { Asn1OctetString extensionValue = GetExtensionValue(X509Extensions.ExtendedKeyUsage); if (extensionValue != null) try { Asn1Sequence instance = Asn1Sequence.GetInstance(X509ExtensionUtilities.FromExtensionValue(extensionValue)); List<DerObjectIdentifier> list = new List<DerObjectIdentifier>(); foreach (DerObjectIdentifier item in instance) { list.Add(item); } return list; } catch (Exception innerException) { throw new CertificateParsingException("error processing extended key usage extension", innerException); } return null; } public virtual int GetBasicConstraints() { if (basicConstraints == null || !basicConstraints.IsCA()) return -1; return basicConstraints.PathLenConstraintInteger?.IntPositiveValueExact ?? 2147483647; } public virtual GeneralNames GetIssuerAlternativeNameExtension() { return GetAlternativeNameExtension(X509Extensions.IssuerAlternativeName); } public virtual GeneralNames GetSubjectAlternativeNameExtension() { return GetAlternativeNameExtension(X509Extensions.SubjectAlternativeName); } public virtual IList<IList<object>> GetIssuerAlternativeNames() { return GetAlternativeNames(X509Extensions.IssuerAlternativeName); } public virtual IList<IList<object>> GetSubjectAlternativeNames() { return GetAlternativeNames(X509Extensions.SubjectAlternativeName); } protected virtual GeneralNames GetAlternativeNameExtension(DerObjectIdentifier oid) { Asn1OctetString extensionValue = GetExtensionValue(oid); if (extensionValue == null) return null; return GeneralNames.GetInstance(X509ExtensionUtilities.FromExtensionValue(extensionValue)); } protected virtual IList<IList<object>> GetAlternativeNames(DerObjectIdentifier oid) { GeneralNames alternativeNameExtension = GetAlternativeNameExtension(oid); if (alternativeNameExtension == null) return null; GeneralName[] names = alternativeNameExtension.GetNames(); List<IList<object>> list = new List<IList<object>>(names.Length); GeneralName[] array = names; foreach (GeneralName generalName in array) { List<object> list2 = new List<object>(2); list2.Add(generalName.TagNo); switch (generalName.TagNo) { case 0: case 3: case 5: list2.Add(generalName.GetEncoded()); break; case 4: list2.Add(X509Name.GetInstance(generalName.Name).ToString()); break; case 1: case 2: case 6: list2.Add(((IAsn1String)generalName.Name).GetString()); break; case 8: list2.Add(DerObjectIdentifier.GetInstance(generalName.Name).Id); break; case 7: { IPAddress iPAddress = new IPAddress(Asn1OctetString.GetInstance(generalName.Name).GetOctets()); list2.Add(iPAddress.ToString()); break; } default: throw new IOException("Bad tag number: " + generalName.TagNo.ToString()); } list.Add(list2); } return list; } protected override X509Extensions GetX509Extensions() { if (c.Version < 3) return null; return c.TbsCertificate.Extensions; } public virtual AsymmetricKeyParameter GetPublicKey() { return Objects.EnsureSingletonInitialized(ref publicKeyValue, c, CreatePublicKey); } public virtual byte[] GetEncoded() { return Arrays.Clone(GetCachedEncoding().GetEncoded()); } public override bool Equals(object other) { if (this == other) return true; X509Certificate x509Certificate = other as X509Certificate; if (x509Certificate == null) return false; if (hashValueSet && x509Certificate.hashValueSet) { if (hashValue != x509Certificate.hashValue) return false; } else if (cachedEncoding == null || x509Certificate.cachedEncoding == null) { DerBitString signature = c.Signature; if (signature != null && !signature.Equals(x509Certificate.c.Signature)) return false; } byte[] encoding = GetCachedEncoding().Encoding; byte[] encoding2 = x509Certificate.GetCachedEncoding().Encoding; if (encoding != null && encoding2 != null) return Arrays.AreEqual(encoding, encoding2); return false; } public override int GetHashCode() { if (!hashValueSet) { byte[] encoding = GetCachedEncoding().Encoding; hashValue = Arrays.GetHashCode(encoding); hashValueSet = true; } return hashValue; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(" [0] Version: ").Append(Version).AppendLine(); stringBuilder.Append(" SerialNumber: ").Append(SerialNumber).AppendLine(); stringBuilder.Append(" IssuerDN: ").Append(IssuerDN).AppendLine(); stringBuilder.Append(" Start Date: ").Append(NotBefore).AppendLine(); stringBuilder.Append(" Final Date: ").Append(NotAfter).AppendLine(); stringBuilder.Append(" SubjectDN: ").Append(SubjectDN).AppendLine(); stringBuilder.Append(" Public Key: ").Append(GetPublicKey()).AppendLine(); stringBuilder.Append(" Signature Algorithm: ").Append(SigAlgName).AppendLine(); byte[] signature = GetSignature(); stringBuilder.Append(" Signature: ").AppendLine(Hex.ToHexString(signature, 0, 20)); for (int i = 20; i < signature.Length; i += 20) { int length = System.Math.Min(20, signature.Length - i); stringBuilder.Append(" ").AppendLine(Hex.ToHexString(signature, i, length)); } X509Extensions extensions = c.TbsCertificate.Extensions; if (extensions != null) { IEnumerator<DerObjectIdentifier> enumerator = extensions.ExtensionOids.GetEnumerator(); if (enumerator.MoveNext()) stringBuilder.AppendLine(" Extensions:"); do { DerObjectIdentifier current = enumerator.Current; X509Extension extension = extensions.GetExtension(current); if (extension.Value != null) { Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(extension.Value); stringBuilder.Append(" critical(").Append(extension.IsCritical).Append(") "); try { if (current.Equals(X509Extensions.BasicConstraints)) stringBuilder.Append(BasicConstraints.GetInstance(asn1Object)); else if (current.Equals(X509Extensions.KeyUsage)) { stringBuilder.Append(KeyUsage.GetInstance(asn1Object)); } else if (current.Equals(MiscObjectIdentifiers.NetscapeCertType)) { stringBuilder.Append(new NetscapeCertType((DerBitString)asn1Object)); } else if (current.Equals(MiscObjectIdentifiers.NetscapeRevocationUrl)) { stringBuilder.Append(new NetscapeRevocationUrl((DerIA5String)asn1Object)); } else if (current.Equals(MiscObjectIdentifiers.VerisignCzagExtension)) { stringBuilder.Append(new VerisignCzagExtension((DerIA5String)asn1Object)); } else { stringBuilder.Append(current.Id); stringBuilder.Append(" value = ").Append(Asn1Dump.DumpAsString(asn1Object)); } } catch (Exception) { stringBuilder.Append(current.Id); stringBuilder.Append(" value = ").Append("*****"); } } stringBuilder.AppendLine(); } while (enumerator.MoveNext()); } return stringBuilder.ToString(); } public virtual bool IsSignatureValid(AsymmetricKeyParameter key) { return CheckSignatureValid(new Asn1VerifierFactory(c.SignatureAlgorithm, key)); } public virtual bool IsSignatureValid(IVerifierFactoryProvider verifierProvider) { return CheckSignatureValid(verifierProvider.CreateVerifierFactory(c.SignatureAlgorithm)); } public virtual bool IsAlternativeSignatureValid(IVerifierFactoryProvider verifierProvider) { TbsCertificateStructure tbsCertificate = c.TbsCertificate; X509Extensions extensions = tbsCertificate.Extensions; AltSignatureAlgorithm altSignatureAlgorithm = AltSignatureAlgorithm.FromExtensions(extensions); AltSignatureValue altSignatureValue = AltSignatureValue.FromExtensions(extensions); IVerifierFactory verifierFactory = verifierProvider.CreateVerifierFactory(altSignatureAlgorithm.Algorithm); Asn1Sequence instance = Asn1Sequence.GetInstance(tbsCertificate.ToAsn1Object()); Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector(); for (int i = 0; i < instance.Count - 1; i++) { if (i != 2) asn1EncodableVector.Add(instance[i]); } asn1EncodableVector.Add(X509Utilities.TrimExtensions(3, extensions)); return X509Utilities.VerifySignature(verifierFactory, new DerSequence(asn1EncodableVector), altSignatureValue.Signature); } public virtual void Verify(AsymmetricKeyParameter key) { CheckSignature(new Asn1VerifierFactory(c.SignatureAlgorithm, key)); } public virtual void Verify(IVerifierFactoryProvider verifierProvider) { CheckSignature(verifierProvider.CreateVerifierFactory(c.SignatureAlgorithm)); } public virtual void VerifyAltSignature(IVerifierFactoryProvider verifierProvider) { if (!IsAlternativeSignatureValid(verifierProvider)) throw new InvalidKeyException("Public key presented not for certificate alternative signature"); } protected virtual void CheckSignature(IVerifierFactory verifier) { if (!CheckSignatureValid(verifier)) throw new InvalidKeyException("Public key presented not for certificate signature"); } protected virtual bool CheckSignatureValid(IVerifierFactory verifier) { TbsCertificateStructure tbsCertificate = c.TbsCertificate; if (!X509SignatureUtilities.AreEquivalentAlgorithms(c.SignatureAlgorithm, tbsCertificate.Signature)) throw new CertificateException("signature algorithm in TBS cert not same as outer cert"); return X509Utilities.VerifySignature(verifier, tbsCertificate, c.Signature); } private CachedEncoding GetCachedEncoding() { return Objects.EnsureSingletonInitialized(ref cachedEncoding, c, CreateCachedEncoding); } private static CachedEncoding CreateCachedEncoding(X509CertificateStructure c) { byte[] encoding = null; CertificateEncodingException exception = null; try { encoding = c.GetEncoded("DER"); } catch (IOException innerException) { exception = new CertificateEncodingException("Failed to DER-encode certificate", innerException); } return new CachedEncoding(encoding, exception); } private static AsymmetricKeyParameter CreatePublicKey(X509CertificateStructure c) { return PublicKeyFactory.CreateKey(c.SubjectPublicKeyInfo); } } }