Esempio n. 1
0
        /// <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);
            }
        }