/// <summary> /// Determines if a certificate is self-issued. /// </summary> /// <remarks>Warning: this method does not evaluate certificate trust, revocation status, or validity! /// This method attempts to build a chain for the provided certificate, and although revocation status /// checking is explicitly skipped, the underlying chain building engine may go online to fetch /// additional information (e.g.: the issuer's certificate). This method is not a guaranteed offline /// check.</remarks> /// <param name="certificate">The certificate to check.</param> /// <returns><c>true</c> if the certificate is self-issued; otherwise, <c>false</c>.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="certificate" /> is <c>null</c>.</exception> public static bool IsSelfIssued(X509Certificate2 certificate) { if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } using (var chainHolder = new X509ChainHolder()) { var chain = chainHolder.Chain; chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority | X509VerificationFlags.IgnoreRootRevocationUnknown | X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown | X509VerificationFlags.IgnoreEndRevocationUnknown; chain.Build(certificate); if (chain.ChainElements.Count != 1) { return(false); } if (chain.ChainStatus.Any( chainStatus => chainStatus.Status.HasFlag(X509ChainStatusFlags.Cyclic) || chainStatus.Status.HasFlag(X509ChainStatusFlags.PartialChain) || chainStatus.Status.HasFlag(X509ChainStatusFlags.NotSignatureValid))) { return(false); } if (!certificate.IssuerName.RawData.SequenceEqual(certificate.SubjectName.RawData)) { return(false); } var akiExtension = certificate.Extensions[Oids.AuthorityKeyIdentifier]; var skiExtension = certificate.Extensions[Oids.SubjectKeyIdentifier] as X509SubjectKeyIdentifierExtension; if (akiExtension != null && skiExtension != null) { var reader = new DerSequenceReader(akiExtension.RawData); var keyIdentifierTag = (DerSequenceReader.DerTag)DerSequenceReader.ContextSpecificTagFlag; if (reader.HasTag(keyIdentifierTag)) { var keyIdentifier = reader.ReadValue(keyIdentifierTag); var akiKeyIdentifier = BitConverter.ToString(keyIdentifier).Replace("-", ""); return(string.Equals(skiExtension.SubjectKeyIdentifier, akiKeyIdentifier, StringComparison.OrdinalIgnoreCase)); } } return(true); } }