Exemplo n.º 1
0
        public static void VerifyCrlCache()
        {
            string crlDirectory = PersistedFiles.GetUserFeatureDirectory("cryptography", "crls");
            string crlFile = Path.Combine(crlDirectory,MicrosoftDotComRootCrlFilename);

            Directory.CreateDirectory(crlDirectory);
            File.Delete(crlFile);

            using (var microsoftDotComIssuer = new X509Certificate2(TestData.MicrosoftDotComIssuerBytes))
            using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
            using (var unrelated = new X509Certificate2(TestData.DssCer))
            {
                X509Chain chain = new X509Chain();

                chain.ChainPolicy.ExtraStore.Add(unrelated);
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComRoot);
                
                // The very start of the CRL period.
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 6, 17, 0, 0, 0, DateTimeKind.Utc);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EndCertificateOnly;
                chain.ChainPolicy.VerificationFlags |= X509VerificationFlags.AllowUnknownCertificateAuthority;

                bool valid = chain.Build(microsoftDotComIssuer);
                Assert.True(valid, "Precondition: Chain builds with no revocation checks");

                int initialErrorCount = chain.ChainStatus.Length;
                Assert.InRange(initialErrorCount, 0, 1);

                if (initialErrorCount > 0)
                {
                    Assert.Equal(X509ChainStatusFlags.UntrustedRoot, chain.ChainStatus[0].Status);
                }

                chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;

                valid = chain.Build(microsoftDotComIssuer);
                Assert.False(valid, "Chain should not build validly");

                Assert.Equal(initialErrorCount + 1, chain.ChainStatus.Length);
                Assert.Equal(X509ChainStatusFlags.RevocationStatusUnknown, chain.ChainStatus[0].Status);

                File.WriteAllText(crlFile, MicrosoftDotComRootCrlPem, Encoding.ASCII);

                valid = chain.Build(microsoftDotComIssuer);
                Assert.True(valid, "Chain should build validly now");
                Assert.Equal(initialErrorCount, chain.ChainStatus.Length);

                // Rewind one second, the CRL is not "not yet valid"
                chain.ChainPolicy.VerificationTime = chain.ChainPolicy.VerificationTime.Subtract(TimeSpan.FromSeconds(1));

                valid = chain.Build(microsoftDotComIssuer);
                Assert.False(valid, "Chain should not build validly, CRL is not yet valid");

                Assert.Equal(initialErrorCount + 1, chain.ChainStatus.Length);
                Assert.Equal(X509ChainStatusFlags.RevocationStatusUnknown, chain.ChainStatus[0].Status);
            }
        }
Exemplo n.º 2
0
        public static void BuildChain()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            using (var microsoftDotComIssuer = new X509Certificate2(TestData.MicrosoftDotComIssuerBytes))
            using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
            using (var unrelated = new X509Certificate2(TestData.DssCer))
            {
                X509Chain chain = new X509Chain();

                chain.ChainPolicy.ExtraStore.Add(unrelated);
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComRoot);
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;

                // Halfway between microsoftDotCom's NotBefore and NotAfter
                // This isn't a boundary condition test.
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                bool valid = chain.Build(microsoftDotCom);
                Assert.True(valid, "Chain built validly");

                // The chain should have 3 members
                Assert.Equal(3, chain.ChainElements.Count);

                // These are the three specific members.
                Assert.Equal(microsoftDotCom, chain.ChainElements[0].Certificate);
                Assert.Equal(microsoftDotComIssuer, chain.ChainElements[1].Certificate);
                Assert.Equal(microsoftDotComRoot, chain.ChainElements[2].Certificate);
            }
        }
Exemplo n.º 3
0
        public static void BuildChainExtraStoreUntrustedRoot()
        {
            using (var testCert = new X509Certificate2(Path.Combine("TestData", "test.pfx"), TestData.ChainPfxPassword))
            {
                X509Certificate2Collection collection = new X509Certificate2Collection();
                collection.Import(Path.Combine("TestData", "test.pfx"), TestData.ChainPfxPassword, X509KeyStorageFlags.DefaultKeySet);

                X509Chain chain = new X509Chain();
                chain.ChainPolicy.ExtraStore.AddRange(collection);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 9, 22, 12, 25, 0);

                bool valid = chain.Build(testCert);

                Assert.False(valid);
                Assert.Contains(chain.ChainStatus, s => s.Status == X509ChainStatusFlags.UntrustedRoot);
            }
        }
Exemplo n.º 4
0
	public static void Test(X509IncludeOption include)
		{
		cert = EndCert ;
		X509Chain chain = new X509Chain() ; 
		chain.Build( cert ) ; 

		X509ChainElementCollection lmnts = chain.ChainElements ; 
		
		KeyInfoX509Data data = new KeyInfoX509Data( cert, include )  ; 	
		ArrayList al = data.Certificates ; 
		if( al == null ) return ; 
		for( int i = 0 ; i < al.Count ; i++ ) 
			{
			rv = lmnts[i].Certificate.ToString(true) == ((X509Certificate) al[i]).ToString(true) ;
			if( !rv ) 		
				Console.WriteLine( "i  = " + i.ToString() + " and include=" + include.ToString() ) ; 
			}
		Console.WriteLine( "*************************************************************" ) ; 
		}
Exemplo n.º 5
0
 public static bool MyRemoteCertificateValidationCallback(System.Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
 {
     bool isOk = true;
     // If there are errors in the certificate chain, look at each error to determine the cause.
     if (sslPolicyErrors != SslPolicyErrors.None) {
         for (int i=0; i<chain.ChainStatus.Length; i++) {
             if (chain.ChainStatus [i].Status != X509ChainStatusFlags.RevocationStatusUnknown) {
                 chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
                 chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                 chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan (0, 1, 0);
                 chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
                 bool chainIsValid = chain.Build ((X509Certificate2)certificate);
                 if (!chainIsValid) {
                     isOk = false;
                 }
             }
         }
     }
     return isOk;
 }
Exemplo n.º 6
0
        private bool RTServerCertificateCallbackHelper(
            RTHttpRequestMessage requestMessage,
            RTCertificate cert,
            IReadOnlyList <RTCertificate> intermediateCerts,
            IReadOnlyList <RTChainValidationResult> certErrors)
        {
            // Convert WinRT certificate to .NET certificate.
            X509Certificate2 serverCert = CertificateHelper.ConvertPublicKeyCertificate(cert);

            // Create .NET X509Chain from the WinRT information. We need to rebuild the chain since WinRT only
            // gives us an array of intermediate certificates and not a X509Chain object.
            var             serverChain     = new X509Chain();
            SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;

            foreach (RTCertificate intermediateCert in intermediateCerts)
            {
                serverChain.ChainPolicy.ExtraStore.Add(CertificateHelper.ConvertPublicKeyCertificate(cert));
            }
            serverChain.ChainPolicy.RevocationMode = X509RevocationMode.Online; // WinRT always checks revocation.
            serverChain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
            // Authenticate the remote party: (e.g. when operating in client mode, authenticate the server).
            serverChain.ChainPolicy.ApplicationPolicy.Add(s_serverAuthOid);
            if (!serverChain.Build(serverCert))
            {
                sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
            }

            // Determine name-mismatch error from the existing WinRT information since .NET X509Chain.Build does not
            // return that in the X509Chain.ChainStatus fields.
            foreach (RTChainValidationResult result in certErrors)
            {
                if (result == RTChainValidationResult.InvalidName)
                {
                    sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
                    break;
                }
            }

            // Get the .NET HttpRequestMessage we saved in the property bag of the WinRT HttpRequestMessage.
            HttpRequestMessage request = (HttpRequestMessage)requestMessage.Properties[RequestMessageLookupKey];

            // Call the .NET callback.
            bool success = false;

            try
            {
                success = _serverCertificateCustomValidationCallback(request, serverCert, serverChain, sslPolicyErrors);
            }
            catch (Exception ex)
            {
                // Save the exception info. We will return it later via the SendAsync response processing.
                requestMessage.Properties.Add(
                    SavedExceptionDispatchInfoLookupKey,
                    ExceptionDispatchInfo.Capture(ex));
            }
            finally
            {
                serverChain.Dispose();
                serverCert.Dispose();
            }

            return(success);
        }
		public virtual X509Chain ComputeX509Chain (XX509CertificateCollection certs, ref SslPolicyErrors errors, ref int status11)
		{
#if MOBILE
			return null;
#else
			if (is_macosx)
				return null;

			var chain = new X509Chain ();
			chain.ChainPolicy = new X509ChainPolicy ();

			chain.ChainPolicy.RevocationMode = revocation_mode;

			for (int i = 1; i < certs.Count; i++) {
				chain.ChainPolicy.ExtraStore.Add (certs [i]);
			}

			var leaf = (X509Certificate2)certs [0];

			try {
				if (!chain.Build (leaf))
					errors |= GetErrorsFromChain (chain);
			} catch (Exception e) {
				Console.Error.WriteLine ("ERROR building certificate chain: {0}", e);
				Console.Error.WriteLine ("Please, report this problem to the Mono team");
				errors |= SslPolicyErrors.RemoteCertificateChainErrors;
			}

			status11 = GetStatusFromChain (chain);

			return chain;
#endif
		}
Exemplo n.º 8
0
        /// <summary>
        /// Throws an exception if validation fails.
        /// </summary>
        /// <param name="certificate">The certificate to be checked.</param>
        /// <exception cref="ServiceResultException">If certificate cannot be accepted</exception>
        protected virtual void InternalValidate(X509Certificate2 certificate)
        {
            lock (m_lock)
            {
                // check for previously validated certificate.
                X509Certificate2 certificate2 = null;

                if (m_validatedCertificates.TryGetValue(certificate.Thumbprint, out certificate2))
                {
                    if (Utils.IsEqual(certificate2.RawData, certificate.RawData))
                    {
                        return;
                    }
                }

                CertificateIdentifier trustedCertificate = GetTrustedCertificate(certificate);

                // get the issuers (checks the revocation lists if using directory stores).
                List <CertificateIdentifier> issuers = new List <CertificateIdentifier>();
                bool isIssuerTrusted = GetIssuers(certificate, issuers);

                // setup policy chain
                X509ChainPolicy policy = new X509ChainPolicy();

                policy.RevocationFlag    = X509RevocationFlag.EntireChain;
                policy.RevocationMode    = X509RevocationMode.NoCheck;
                policy.VerificationFlags = X509VerificationFlags.NoFlag;

                foreach (CertificateIdentifier issuer in issuers)
                {
                    if ((issuer.ValidationOptions & CertificateValidationOptions.SuppressRevocationStatusUnknown) != 0)
                    {
                        policy.VerificationFlags |= X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown;
                        policy.VerificationFlags |= X509VerificationFlags.IgnoreCtlSignerRevocationUnknown;
                        policy.VerificationFlags |= X509VerificationFlags.IgnoreEndRevocationUnknown;
                        policy.VerificationFlags |= X509VerificationFlags.IgnoreRootRevocationUnknown;
                    }

                    // we did the revocation check in the GetIssuers call. No need here.
                    policy.RevocationMode = X509RevocationMode.NoCheck;
                    policy.ExtraStore.Add(issuer.Certificate);
                }

                // build chain.
                X509Chain chain = new X509Chain();
                chain.ChainPolicy = policy;
                chain.Build(certificate);

                // check the chain results.
                CertificateIdentifier target = trustedCertificate;

                if (target == null)
                {
                    target = new CertificateIdentifier(certificate);
                }

                for (int ii = 0; ii < chain.ChainElements.Count; ii++)
                {
                    X509ChainElement element = chain.ChainElements[ii];

                    CertificateIdentifier issuer = null;

                    if (ii < issuers.Count)
                    {
                        issuer = issuers[ii];
                    }

                    // check for chain status errors.
                    foreach (X509ChainStatus status in element.ChainElementStatus)
                    {
                        ServiceResult result = CheckChainStatus(status, target, issuer, (ii != 0));

                        if (ServiceResult.IsBad(result))
                        {
                            throw new ServiceResultException(result);
                        }
                    }

                    if (issuer != null)
                    {
                        target = issuer;
                    }
                }

                // check if certificate is trusted.
                if (trustedCertificate == null && !isIssuerTrusted)
                {
                    if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData))
                    {
                        throw ServiceResultException.Create(
                                  StatusCodes.BadCertificateUntrusted,
                                  "Certificate is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                                  certificate.SubjectName.Name,
                                  certificate.IssuerName.Name);
                    }
                }
            }
        }
Exemplo n.º 9
0
        private bool validationCallback(object sender, X509Certificate certificate, X509Chain chainEngine,
                                        SslPolicyErrors policyErrors)
        {
            X509Chain chain = new X509Chain(_instance.engine().useMachineContext());

            try
            {
                if (_instance.checkCRL() == 0)
                {
                    chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                }

                X509Certificate2Collection?caCerts = _instance.engine().caCerts();
                if (caCerts != null)
                {
                    //
                    // We need to set this flag to be able to use a certificate authority from the extra store.
                    //
                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                    foreach (X509Certificate2 cert in caCerts)
                    {
                        chain.ChainPolicy.ExtraStore.Add(cert);
                    }
                }

                string message = "";
                int    errors  = (int)policyErrors;
                if (certificate != null)
                {
                    chain.Build(new X509Certificate2(certificate));
                    if (chain.ChainStatus != null && chain.ChainStatus.Length > 0)
                    {
                        errors |= (int)SslPolicyErrors.RemoteCertificateChainErrors;
                    }
                    else if (_instance.engine().caCerts() != null)
                    {
                        X509ChainElement e = chain.ChainElements[chain.ChainElements.Count - 1];
                        if (!chain.ChainPolicy.ExtraStore.Contains(e.Certificate))
                        {
                            if (_verifyPeer > 0)
                            {
                                message += "\npuntrusted root certificate";
                            }
                            else
                            {
                                message  += "\nuntrusted root certificate (ignored)";
                                _verified = false;
                            }
                            errors |= (int)SslPolicyErrors.RemoteCertificateChainErrors;
                        }
                        else
                        {
                            _verified = true;
                            return(true);
                        }
                    }
                    else
                    {
                        _verified = true;
                        return(true);
                    }
                }

                if ((errors & (int)SslPolicyErrors.RemoteCertificateNotAvailable) > 0)
                {
                    //
                    // The RemoteCertificateNotAvailable case does not appear to be possible
                    // for an outgoing connection. Since .NET requires an authenticated
                    // connection, the remote peer closes the socket if it does not have a
                    // certificate to provide.
                    //

                    if (_incoming)
                    {
                        if (_verifyPeer > 1)
                        {
                            if (_instance.securityTraceLevel() >= 1)
                            {
                                _instance.logger().trace(_instance.securityTraceCategory(),
                                                         "SSL certificate validation failed - client certificate not provided");
                            }
                            return(false);
                        }
                        errors  ^= (int)SslPolicyErrors.RemoteCertificateNotAvailable;
                        message += "\nremote certificate not provided (ignored)";
                    }
                }

                bool certificateNameMismatch = (errors & (int)SslPolicyErrors.RemoteCertificateNameMismatch) > 0;
                if (certificateNameMismatch)
                {
                    if (_instance.engine().getCheckCertName() && !string.IsNullOrEmpty(_host))
                    {
                        if (_instance.securityTraceLevel() >= 1)
                        {
                            string msg = "SSL certificate validation failed - Hostname mismatch";
                            if (_verifyPeer == 0)
                            {
                                msg += " (ignored)";
                            }
                            _instance.logger().trace(_instance.securityTraceCategory(), msg);
                        }

                        if (_verifyPeer > 0)
                        {
                            return(false);
                        }
                        else
                        {
                            errors ^= (int)SslPolicyErrors.RemoteCertificateNameMismatch;
                        }
                    }
                    else
                    {
                        errors ^= (int)SslPolicyErrors.RemoteCertificateNameMismatch;
                        certificateNameMismatch = false;
                    }
                }

                if ((errors & (int)SslPolicyErrors.RemoteCertificateChainErrors) > 0 &&
                    chain.ChainStatus != null && chain.ChainStatus.Length > 0)
                {
                    int errorCount = 0;
                    foreach (X509ChainStatus status in chain.ChainStatus)
                    {
                        if (status.Status == X509ChainStatusFlags.UntrustedRoot && _instance.engine().caCerts() != null)
                        {
                            //
                            // Untrusted root is OK when using our custom chain engine if
                            // the CA certificate is present in the chain policy extra store.
                            //
                            X509ChainElement e = chain.ChainElements[chain.ChainElements.Count - 1];
                            if (!chain.ChainPolicy.ExtraStore.Contains(e.Certificate))
                            {
                                if (_verifyPeer > 0)
                                {
                                    message += "\npuntrusted root certificate";
                                    ++errorCount;
                                }
                                else
                                {
                                    message += "\nuntrusted root certificate (ignored)";
                                }
                            }
                            else
                            {
                                _verified = !certificateNameMismatch;
                            }
                        }
                        else if (status.Status == X509ChainStatusFlags.Revoked)
                        {
                            if (_instance.checkCRL() > 0)
                            {
                                message += "\ncertificate revoked";
                                ++errorCount;
                            }
                            else
                            {
                                message += "\ncertificate revoked (ignored)";
                            }
                        }
                        else if (status.Status == X509ChainStatusFlags.RevocationStatusUnknown)
                        {
                            //
                            // If a certificate's revocation status cannot be determined, the strictest
                            // policy is to reject the connection.
                            //
                            if (_instance.checkCRL() > 1)
                            {
                                message += "\ncertificate revocation status unknown";
                                ++errorCount;
                            }
                            else
                            {
                                message += "\ncertificate revocation status unknown (ignored)";
                            }
                        }
                        else if (status.Status == X509ChainStatusFlags.PartialChain)
                        {
                            if (_verifyPeer > 0)
                            {
                                message += "\npartial certificate chain";
                                ++errorCount;
                            }
                            else
                            {
                                message += "\npartial certificate chain (ignored)";
                            }
                        }
                        else if (status.Status != X509ChainStatusFlags.NoError)
                        {
                            message = message + "\ncertificate chain error: " + status.Status.ToString();
                            ++errorCount;
                        }
                    }

                    if (errorCount == 0)
                    {
                        errors ^= (int)SslPolicyErrors.RemoteCertificateChainErrors;
                    }
                }

                if (errors > 0)
                {
                    if (_instance.securityTraceLevel() >= 1)
                    {
                        if (message.Length > 0)
                        {
                            _instance.logger().trace(_instance.securityTraceCategory(),
                                                     "SSL certificate validation failed:" + message);
                        }
                        else
                        {
                            _instance.logger().trace(_instance.securityTraceCategory(),
                                                     "SSL certificate validation failed");
                        }
                    }
                    return(false);
                }
                else if (message.Length > 0 && _instance.securityTraceLevel() >= 1)
                {
                    _instance.logger().trace(_instance.securityTraceCategory(),
                                             "SSL certificate validation status:" + message);
                }
                return(true);
            }
            finally
            {
                if (chain.ChainElements != null && chain.ChainElements.Count > 0)
                {
                    _certs = new X509Certificate2[chain.ChainElements.Count];
                    for (int i = 0; i < chain.ChainElements.Count; ++i)
                    {
                        _certs[i] = chain.ChainElements[i].Certificate;
                    }
                }

                try
                {
                    chain.Dispose();
                }
                catch (Exception)
                {
                }
            }
        }
		public bool Verify ()
		{
			X509Chain chain = new X509Chain ();
			if (!chain.Build (this))
				return false;
			// TODO - check chain and other stuff ???
			return true;
		}
Exemplo n.º 11
0
        public static void BuildChain_WithCertificatePolicy_NoMatch()
        {
            using (var cert = new X509Certificate2(TestData.CertWithPolicies))
            using (X509Chain chain = new X509Chain())
            {
                chain.ChainPolicy.CertificatePolicy.Add(new Oid("2.999"));
                chain.ChainPolicy.VerificationFlags =
                    X509VerificationFlags.AllowUnknownCertificateAuthority;

                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                chain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);

                bool valid = chain.Build(cert);
                Assert.False(valid, "Chain built validly");

                Assert.InRange(chain.ChainElements.Count, 1, int.MaxValue);

                Assert.NotSame(cert, chain.ChainElements[0].Certificate);
                Assert.Equal(cert, chain.ChainElements[0].Certificate);

                X509ChainStatus[] chainElementStatus = chain.ChainElements[0].ChainElementStatus;
                Assert.InRange(chainElementStatus.Length, 1, int.MaxValue);
                Assert.Contains(chainElementStatus, x => x.Status == X509ChainStatusFlags.NotValidForUsage);
            }
        }
Exemplo n.º 12
0
        //private bool VerifySignature (ASN1 cs, byte[] calculatedMessageDigest, string hashName)
        private bool VerifySignature(PKCS7.SignedData sd, byte[] calculatedMessageDigest, HashAlgorithm ha)
        {
            string contentType   = null;
            ASN1   messageDigest = null;

//			string spcStatementType = null;
//			string spcSpOpusInfo = null;

            for (int i = 0; i < sd.SignerInfo.AuthenticatedAttributes.Count; i++)
            {
                ASN1   attr = (ASN1)sd.SignerInfo.AuthenticatedAttributes [i];
                string oid  = ASN1Convert.ToOid(attr[0]);
                switch (oid)
                {
                case "1.2.840.113549.1.9.3":
                    // contentType
                    contentType = ASN1Convert.ToOid(attr[1][0]);
                    break;

                case "1.2.840.113549.1.9.4":
                    // messageDigest
                    messageDigest = attr[1][0];
                    break;

                case "1.3.6.1.4.1.311.2.1.11":
                    // spcStatementType (Microsoft code signing)
                    // possible values
                    // - individualCodeSigning (1 3 6 1 4 1 311 2 1 21)
                    // - commercialCodeSigning (1 3 6 1 4 1 311 2 1 22)
//						spcStatementType = ASN1Convert.ToOid (attr[1][0][0]);
                    break;

                case "1.3.6.1.4.1.311.2.1.12":
                    // spcSpOpusInfo (Microsoft code signing)

                    /*						try {
                     *                                                      spcSpOpusInfo = System.Text.Encoding.UTF8.GetString (attr[1][0][0][0].Value);
                     *                                              }
                     *                                              catch (NullReferenceException) {
                     *                                                      spcSpOpusInfo = null;
                     *                                              }*/
                    break;

                default:
                    break;
                }
            }
            if (contentType != spcIndirectDataContext)
            {
                return(false);
            }

            // verify message digest
            if (messageDigest == null)
            {
                return(false);
            }
            if (!messageDigest.CompareValue(calculatedMessageDigest))
            {
                return(false);
            }

            // verify signature
            string hashOID = CryptoConfig.MapNameToOID(ha.ToString());

            // change to SET OF (not [0]) as per PKCS #7 1.5
            ASN1 aa = new ASN1(0x31);

            foreach (ASN1 a in sd.SignerInfo.AuthenticatedAttributes)
            {
                aa.Add(a);
            }
            ha.Initialize();
            byte[] p7hash = ha.ComputeHash(aa.GetBytes());

            byte[] signature = sd.SignerInfo.Signature;
            // we need to find the specified certificate
            string issuer = sd.SignerInfo.IssuerName;

            byte[] serial = sd.SignerInfo.SerialNumber;
            foreach (X509Certificate x509 in coll)
            {
                if (CompareIssuerSerial(issuer, serial, x509))
                {
                    // don't verify is key size don't match
                    if (x509.PublicKey.Length > (signature.Length >> 3))
                    {
                        // return the signing certificate even if the signature isn't correct
                        // (required behaviour for 2.0 support)
                        signingCertificate = x509;
                        RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)x509.RSA;
                        if (rsa.VerifyHash(p7hash, hashOID, signature))
                        {
                            signerChain.LoadCertificates(coll);
                            trustedRoot = signerChain.Build(x509);
                            break;
                        }
                    }
                }
            }

            // timestamp signature is optional
            if (sd.SignerInfo.UnauthenticatedAttributes.Count == 0)
            {
                trustedTimestampRoot = true;
            }
            else
            {
                for (int i = 0; i < sd.SignerInfo.UnauthenticatedAttributes.Count; i++)
                {
                    ASN1   attr = (ASN1)sd.SignerInfo.UnauthenticatedAttributes[i];
                    string oid  = ASN1Convert.ToOid(attr[0]);
                    switch (oid)
                    {
                    case PKCS7.Oid.countersignature:
                        // SEQUENCE {
                        //   OBJECT IDENTIFIER
                        //     countersignature (1 2 840 113549 1 9 6)
                        //   SET {
                        PKCS7.SignerInfo cs = new PKCS7.SignerInfo(attr[1]);
                        trustedTimestampRoot = VerifyCounterSignature(cs, signature);
                        break;

                    default:
                        // we don't support other unauthenticated attributes
                        break;
                    }
                }
            }

            return(trustedRoot && trustedTimestampRoot);
        }
		private void validateCertificates(X509CertificateCollection certificates)
		{
			ClientContext		context			= (ClientContext)this.Context;
			AlertDescription	description		= AlertDescription.BadCertificate;

#if NET_2_0
			if (context.SslStream.HaveRemoteValidation2Callback) {
				if (context.SslStream.RaiseServerCertificateValidation2 (certificates))
					return;
				// Give a chance to the 1.x ICertificatePolicy callback
			}
#endif
			// the leaf is the web server certificate
			X509Certificate leaf = certificates [0];
			X509Cert.X509Certificate cert = new X509Cert.X509Certificate (leaf.RawData);

			ArrayList errors = new ArrayList();

			// SSL specific check - not all certificates can be 
			// used to server-side SSL some rules applies after 
			// all ;-)
			if (!checkCertificateUsage (leaf)) 
			{
				// WinError.h CERT_E_PURPOSE 0x800B0106
				errors.Add ((int)-2146762490);
			}

			// SSL specific check - does the certificate match 
			// the host ?
			if (!checkServerIdentity (leaf))
			{
				// WinError.h CERT_E_CN_NO_MATCH 0x800B010F
				errors.Add ((int)-2146762481);
			}

			// Note: building and verifying a chain can take much time
			// so we do it last (letting simple things fails first)

			// Note: In TLS the certificates MUST be in order (and
			// optionally include the root certificate) so we're not
			// building the chain using LoadCertificate (it's faster)

			// Note: IIS doesn't seem to send the whole certificate chain
			// but only the server certificate :-( it's assuming that you
			// already have this chain installed on your computer. duh!
			// http://groups.google.ca/groups?q=IIS+server+certificate+chain&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=85058s%24avd%241%40nnrp1.deja.com&rnum=3

			// we must remove the leaf certificate from the chain
			X509CertificateCollection chain = new X509CertificateCollection (certificates);
			chain.Remove (leaf);
			X509Chain verify = new X509Chain (chain);

			bool result = false;

			try
			{
				result = verify.Build (leaf);
			}
			catch (Exception)
			{
				result = false;
			}

			// Attempt to use OSX certificates
			//
			// Ideally we should return the SecTrustResult
#if !MONOTOUCH
			if (System.IO.File.Exists (OSX509Certificates.SecurityLibrary)){
#endif
				OSX509Certificates.SecTrustResult trustResult =  OSX509Certificates.TrustEvaluateSsl (certificates);

				// We could use the other values of trustResult to pass this extra information to the .NET 2 callback
				// for values like SecTrustResult.Confirm
				result = (trustResult == OSX509Certificates.SecTrustResult.Proceed ||
					  trustResult == OSX509Certificates.SecTrustResult.Unspecified);
#if !MONOTOUCH
			}
#endif
			
			if (!result) 
			{
				switch (verify.Status) 
				{
					case X509ChainStatusFlags.InvalidBasicConstraints:
						// WinError.h TRUST_E_BASIC_CONSTRAINTS 0x80096019
						errors.Add ((int)-2146869223);
						break;
					
					case X509ChainStatusFlags.NotSignatureValid:
						// WinError.h TRUST_E_BAD_DIGEST 0x80096010
						errors.Add ((int)-2146869232);
						break;
					
					case X509ChainStatusFlags.NotTimeNested:
						// WinError.h CERT_E_VALIDITYPERIODNESTING 0x800B0102
						errors.Add ((int)-2146762494);
						break;
					
					case X509ChainStatusFlags.NotTimeValid:
						// WinError.h CERT_E_EXPIRED 0x800B0101
						description = AlertDescription.CertificateExpired;
						errors.Add ((int)-2146762495);
						break;
					
					case X509ChainStatusFlags.PartialChain:
						// WinError.h CERT_E_CHAINING 0x800B010A
						description = AlertDescription.UnknownCA;
						errors.Add ((int)-2146762486);
						break;
					
					case X509ChainStatusFlags.UntrustedRoot:
						// WinError.h CERT_E_UNTRUSTEDROOT 0x800B0109
						description = AlertDescription.UnknownCA;
						errors.Add ((int)-2146762487);
						break;
					
					default:
						// unknown error
						description = AlertDescription.CertificateUnknown;
						errors.Add ((int)verify.Status);
						break;
				}
			}

			int[] certificateErrors = (int[])errors.ToArray(typeof(int));

			if (!context.SslStream.RaiseServerCertificateValidation(
				cert, 
				certificateErrors))
			{
				throw new TlsException(
					description,
					"Invalid certificate received from server.");
			}
		}
        public static SslStreamCertificateContext Create(X509Certificate2 target, X509Certificate2Collection?additionalCertificates, bool offline = false, SslCertificateTrust?trust = null)
        {
            if (!target.HasPrivateKey)
            {
                throw new NotSupportedException(SR.net_ssl_io_no_server_cert);
            }

            X509Certificate2[] intermediates = Array.Empty <X509Certificate2>();
            using (X509Chain chain = new X509Chain())
            {
                if (additionalCertificates != null)
                {
                    foreach (X509Certificate cert in additionalCertificates)
                    {
                        chain.ChainPolicy.ExtraStore.Add(cert);
                    }
                }

                chain.ChainPolicy.VerificationFlags           = X509VerificationFlags.AllFlags;
                chain.ChainPolicy.RevocationMode              = X509RevocationMode.NoCheck;
                chain.ChainPolicy.DisableCertificateDownloads = offline;
                bool chainStatus = chain.Build(target);

                if (!chainStatus && NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(null, $"Failed to build chain for {target.Subject}");
                }

                int count = chain.ChainElements.Count - 1;

                // Some platforms (e.g. Android) can't ignore all verification and will return zero
                // certificates on failure to build a chain. Treat this as not finding any intermediates.
                if (count >= 0)
                {
#pragma warning disable 0162 // Disable unreachable code warning. TrimRootCertificate is const bool = false on some platforms
                    if (TrimRootCertificate)
                    {
                        count--;
                        foreach (X509ChainStatus status in chain.ChainStatus)
                        {
                            if (status.Status.HasFlag(X509ChainStatusFlags.PartialChain))
                            {
                                // The last cert isn't a root cert
                                count++;
                                break;
                            }
                        }
                    }
#pragma warning restore 0162

                    // Count can be zero for a self-signed certificate, or a cert issued directly from a root.
                    if (count > 0 && chain.ChainElements.Count > 1)
                    {
                        intermediates = new X509Certificate2[count];
                        for (int i = 0; i < count; i++)
                        {
                            intermediates[i] = chain.ChainElements[i + 1].Certificate;
                        }
                    }

                    // Dispose the copy of the target cert.
                    chain.ChainElements[0].Certificate.Dispose();

                    // Dispose the last cert, if we didn't include it.
                    for (int i = count + 1; i < chain.ChainElements.Count; i++)
                    {
                        chain.ChainElements[i].Certificate.Dispose();
                    }
                }
            }

            return(new SslStreamCertificateContext(target, intermediates, trust));
        }
Exemplo n.º 15
0
        internal static SslPolicyErrors VerifyCertificateProperties(
            X509Chain chain,
            X509Certificate2 remoteCertificate,
            bool checkCertName,
            bool isServer,
            string hostName)
        {
            SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;

            if (!chain.Build(remoteCertificate) &&                    // Build failed on handle or on policy.
                chain.SafeHandle.DangerousGetHandle() == IntPtr.Zero) // Build failed to generate a valid handle.
            {
                throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            if (checkCertName)
            {
                unsafe
                {
                    uint status = 0;

                    var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA()
                    {
                        cbSize         = (uint)Marshal.SizeOf <Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA>(),
                        dwAuthType     = isServer ? Interop.Crypt32.AuthType.AUTHTYPE_SERVER : Interop.Crypt32.AuthType.AUTHTYPE_CLIENT,
                        fdwChecks      = 0,
                        pwszServerName = null
                    };

                    var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA()
                    {
                        cbSize            = (uint)Marshal.SizeOf <Interop.Crypt32.CERT_CHAIN_POLICY_PARA>(),
                        dwFlags           = 0,
                        pvExtraPolicyPara = &eppStruct
                    };

                    fixed(char *namePtr = hostName)
                    {
                        eppStruct.pwszServerName = namePtr;
                        cppStruct.dwFlags       |=
                            (Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL &
                             ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG);

                        SafeX509ChainHandle chainContext = chain.SafeHandle;

                        status = Verify(chainContext, ref cppStruct);
                        if (status == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH)
                        {
                            sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
                        }
                    }
                }
            }

            X509ChainStatus[] chainStatusArray = chain.ChainStatus;
            if (chainStatusArray != null && chainStatusArray.Length != 0)
            {
                sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
            }

            return(sslPolicyErrors);
        }
Exemplo n.º 16
0
            async Task <int> CreateTransportAsync(HttpListenerContext context)
            {
                X509Certificate2 clientCertificate = null;

                if (this.listener.sslSettings != null && this.listener.sslSettings.ClientCertificateRequired)
                {
                    clientCertificate = await context.Request.GetClientCertificateAsync();;
                    if (clientCertificate == null)
                    {
                        return(40300);
                    }

                    if (this.listener.sslSettings.RemoteCertificateValidationCallback != null)
                    {
                        SslPolicyErrors sslError = SslPolicyErrors.None;
                        X509Chain       chain    = new X509Chain();
                        chain.ChainPolicy.RevocationMode = this.listener.sslSettings.CheckCertificateRevocation ?
                                                           X509RevocationMode.Online : X509RevocationMode.NoCheck;
                        chain.Build(clientCertificate);
                        if (chain.ChainStatus.Length > 0)
                        {
                            sslError = SslPolicyErrors.RemoteCertificateChainErrors;
                        }

                        bool success = this.listener.sslSettings.RemoteCertificateValidationCallback(
                            this, clientCertificate, chain, sslError);
                        if (!success)
                        {
                            return(40301);
                        }
                    }
                    else if (context.Request.ClientCertificateError != 0)
                    {
                        return(40302);
                    }
                }

                IPrincipal principal = context.User;

                if (principal == null && clientCertificate != null)
                {
                    principal = new GenericPrincipal(new X509Identity(clientCertificate), new string[0]);
                }

                string subProtocol = null;

                string[] subProtocols = context.Request.Headers.GetValues("Sec-WebSocket-Protocol");
                for (int i = 0; i < subProtocols.Length; i++)
                {
                    if (subProtocols[i].Equals(WebSocketTransport.WebSocketSubProtocol) ||
                        subProtocols[i].Equals("AMQPWSB10")     // defined by the previous draft
                        )
                    {
                        subProtocol = subProtocols[i];
                        break;
                    }
                }

                if (subProtocol == null)
                {
                    return(40003);
                }

                var wsContext = await context.AcceptWebSocketAsync(subProtocol);

                var wsTransport = new ListenerWebSocketTransport(wsContext.WebSocket, principal);

                await this.listener.HandleTransportAsync(wsTransport);

                return(0);
            }
Exemplo n.º 17
0
        public CertificateErrors Validate(X509Certificate2 certificate, X509KeyUsageFlags usage)
        {
            if (certificate == null)
            {
                return(CertificateErrors.Missing);
            }

            var result = CertificateErrors.None;

            if (DateTime.Now < certificate.NotBefore)
            {
                result |= CertificateErrors.StartDate;
            }
            if (DateTime.Now > certificate.NotAfter)
            {
                result |= CertificateErrors.EndDate;
            }

            foreach (var extension in certificate.Extensions)
            {
                switch (extension.Oid.Value)
                {
                case "2.5.29.15":     // Key usage
                    var usageExtension = (X509KeyUsageExtension)extension;
                    if ((usageExtension.KeyUsages & usage) != usage)
                    {
                        result |= CertificateErrors.Usage;
                    }
                    break;
                }
            }

            var chain = new X509Chain
            {
                ChainPolicy =
                {
                    RevocationMode      = _useOnlineRevocationCheck ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
                    RevocationFlag      = X509RevocationFlag.EntireChain,
                    UrlRetrievalTimeout = TimeSpan.FromSeconds(30),
                    VerificationTime    = DateTime.Now,
                }
            };

            using (chain)
            {
                if (chain.Build(certificate))
                {
                    return(result);
                }
                var sb = new StringBuilder();

                foreach (var status in chain.ChainStatus)
                {
                    // ReSharper disable once SwitchStatementMissingSomeCases
                    switch (status.Status)
                    {
                    case X509ChainStatusFlags.OfflineRevocation:
                    case X509ChainStatusFlags.RevocationStatusUnknown:
                        result |= CertificateErrors.RevokedUnknown;
                        break;

                    case X509ChainStatusFlags.Revoked:
                        result |= CertificateErrors.Revoked;
                        break;
                    }
                    sb.AppendLine(status.StatusInformation);
                }
                return(result);
            }
        }
Exemplo n.º 18
0
        // TODO: Issue #2165. Merge with similar code used in System.Net.Security move to Common/src//System/Net.
        public static void BuildChain(
            X509Certificate2 certificate,
            X509Certificate2Collection remoteCertificateStore,
            string hostName,
            bool checkCertificateRevocationList,
            out X509Chain chain,
            out SslPolicyErrors sslPolicyErrors)
        {
            chain           = null;
            sslPolicyErrors = SslPolicyErrors.None;

            // Build the chain.
            chain = new X509Chain();
            chain.ChainPolicy.RevocationMode =
                checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
            // Authenticate the remote party: (e.g. when operating in client mode, authenticate the server).
            chain.ChainPolicy.ApplicationPolicy.Add(s_serverAuthOid);

            if (remoteCertificateStore.Count > 0)
            {
                if (NetEventSource.IsEnabled)
                {
                    foreach (X509Certificate cert in remoteCertificateStore)
                    {
                        NetEventSource.Info(remoteCertificateStore, $"Adding cert to ExtraStore: {cert.Subject}");
                    }
                }

                chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore);
            }

            if (!chain.Build(certificate))
            {
                sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
            }

            // Verify the hostName matches the certificate.
            unsafe
            {
                Interop.Crypt32.CERT_CHAIN_POLICY_PARA cppStruct = default;
                cppStruct.cbSize  = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_PARA);
                cppStruct.dwFlags = 0;

                Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = default;
                eppStruct.cbSize     = (uint)sizeof(Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA);
                eppStruct.dwAuthType = Interop.Crypt32.AuthType.AUTHTYPE_SERVER;

                cppStruct.pvExtraPolicyPara = &eppStruct;

                fixed(char *namePtr = hostName)
                {
                    eppStruct.pwszServerName = namePtr;
                    cppStruct.dwFlags        =
                        Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL &
                        ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG;

                    Interop.Crypt32.CERT_CHAIN_POLICY_STATUS status = default;
                    status.cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_STATUS);
                    if (Interop.Crypt32.CertVerifyCertificateChainPolicy(
                            (IntPtr)Interop.Crypt32.CertChainPolicy.CERT_CHAIN_POLICY_SSL,
                            chain.SafeHandle,
                            ref cppStruct,
                            ref status))
                    {
                        if (status.dwError == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH)
                        {
                            if (NetEventSource.IsEnabled)
                            {
                                NetEventSource.Error(certificate, nameof(Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH));
                            }
                            sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
                        }
                    }
                    else
                    {
                        // Failure checking the policy. This is a rare error. We will assume the name check failed.
                        // TODO: Issue #2165. Log this error or perhaps throw an exception instead.
                        if (NetEventSource.IsEnabled)
                        {
                            NetEventSource.Error(certificate, $"Failure calling {nameof(Interop.Crypt32.CertVerifyCertificateChainPolicy)}");
                        }
                        sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
                    }
                }
            }
        }
Exemplo n.º 19
0
        private static int VerifyClientCertificate(int preverify_ok, IntPtr x509_ctx_ptr)
        {
            using (SafeX509StoreCtxHandle storeHandle = new SafeX509StoreCtxHandle(x509_ctx_ptr, false))
            {
                using (var chain = new X509Chain())
                {
                    chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;

                    using (SafeX509StackHandle chainStack = Crypto.X509StoreCtxGetChain(storeHandle))
                    {
                        if (chainStack.IsInvalid)
                        {
                            Debug.Fail("Invalid chain stack handle");
                            return 0;
                        }

                        IntPtr certPtr = Crypto.GetX509StackField(chainStack, 0);
                        if (IntPtr.Zero == certPtr)
                        {
                            return 0;
                        }

                        using (X509Certificate2 cert = new X509Certificate2(certPtr))
                        {
                            return chain.Build(cert) ? 1 : 0;
                        }
                    }
                }
            }
        }
Exemplo n.º 20
0
        private bool VerifyCounterSignature(PKCS7.SignerInfo cs, byte[] signature)
        {
            // SEQUENCE {
            //   INTEGER 1
            if (cs.Version != 1)
            {
                return(false);
            }
            //   SEQUENCE {
            //      SEQUENCE {

            string contentType   = null;
            ASN1   messageDigest = null;

            for (int i = 0; i < cs.AuthenticatedAttributes.Count; i++)
            {
                // SEQUENCE {
                //   OBJECT IDENTIFIER
                ASN1   attr = (ASN1)cs.AuthenticatedAttributes [i];
                string oid  = ASN1Convert.ToOid(attr[0]);
                switch (oid)
                {
                case "1.2.840.113549.1.9.3":
                    // contentType
                    contentType = ASN1Convert.ToOid(attr[1][0]);
                    break;

                case "1.2.840.113549.1.9.4":
                    // messageDigest
                    messageDigest = attr[1][0];
                    break;

                case "1.2.840.113549.1.9.5":
                    // SEQUENCE {
                    //   OBJECT IDENTIFIER
                    //     signingTime (1 2 840 113549 1 9 5)
                    //   SET {
                    //     UTCTime '030124013651Z'
                    //   }
                    // }
                    timestamp = ASN1Convert.ToDateTime(attr[1][0]);
                    break;

                default:
                    break;
                }
            }

            if (contentType != PKCS7.Oid.data)
            {
                return(false);
            }

            // verify message digest
            if (messageDigest == null)
            {
                return(false);
            }
            // TODO: must be read from the ASN.1 structure
            string hashName = null;

            switch (messageDigest.Length)
            {
            case 16:
                hashName = "MD5";
                break;

            case 20:
                hashName = "SHA1";
                break;
            }
            HashAlgorithm ha = HashAlgorithm.Create(hashName);

            if (!messageDigest.CompareValue(ha.ComputeHash(signature)))
            {
                return(false);
            }

            // verify signature
            byte[] counterSignature = cs.Signature;

            // change to SET OF (not [0]) as per PKCS #7 1.5
            ASN1 aa = new ASN1(0x31);

            foreach (ASN1 a in cs.AuthenticatedAttributes)
            {
                aa.Add(a);
            }
            byte[] p7hash = ha.ComputeHash(aa.GetBytes());

            // we need to try all certificates
            string issuer = cs.IssuerName;

            byte[] serial = cs.SerialNumber;
            foreach (X509Certificate x509 in coll)
            {
                if (CompareIssuerSerial(issuer, serial, x509))
                {
                    if (x509.PublicKey.Length > counterSignature.Length)
                    {
                        RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)x509.RSA;
                        // we need to HACK around bad (PKCS#1 1.5) signatures made by Verisign Timestamp Service
                        // and this means copying stuff into our own RSAManaged to get the required flexibility
                        RSAManaged rsam = new RSAManaged();
                        rsam.ImportParameters(rsa.ExportParameters(false));
                        if (PKCS1.Verify_v15(rsam, ha, p7hash, counterSignature, true))
                        {
                            timestampChain.LoadCertificates(coll);
                            return(timestampChain.Build(x509));
                        }
                    }
                }
            }
            // no certificate can verify this signature!
            return(false);
        }
Exemplo n.º 21
0
		static bool BuildX509Chain (XX509CertificateCollection certs, X509Chain chain, ref SslPolicyErrors errors, ref int status11)
		{
#if MOBILE
			return false;
#else
			if (is_macosx)
				return false;

			var leaf = (X509Certificate2)certs [0];

			bool ok;
			try {
				ok = chain.Build (leaf);
				if (!ok)
					errors |= GetErrorsFromChain (chain);
			} catch (Exception e) {
				Console.Error.WriteLine ("ERROR building certificate chain: {0}", e);
				Console.Error.WriteLine ("Please, report this problem to the Mono team");
				errors |= SslPolicyErrors.RemoteCertificateChainErrors;
				ok = false;
			}

			try {
				status11 = GetStatusFromChain (chain);
			} catch {
				status11 = -2146762485; // TRUST_E_FAIL - generic
			}

			return ok;
#endif
		}
Exemplo n.º 22
0
        public async Task <AttestationVerificationSuccess> VerifyAsync(CredentialCreateOptions originalOptions, string expectedOrigin, IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser, IMetadataService metadataService, byte[] requestTokenBindingId)
        {
            AttestationType attnType;

            X509Certificate2[] trustPath = null;
            BaseVerify(expectedOrigin, originalOptions.Challenge, requestTokenBindingId);
            // verify challenge is same as we expected
            // verify origin
            // done in baseclass

            if (Type != "webauthn.create")
            {
                throw new Fido2VerificationException("AttestationResponse is not type webauthn.create");
            }

            if (Raw.Id == null || Raw.Id.Length == 0)
            {
                throw new Fido2VerificationException("AttestationResponse is missing Id");
            }

            if (Raw.Type != "public-key")
            {
                throw new Fido2VerificationException("AttestationResponse is missing type with value 'public-key'");
            }

            if (null == AttestationObject.AuthData || 0 == AttestationObject.AuthData.Length)
            {
                throw new Fido2VerificationException("Missing or malformed authData");
            }
            AuthenticatorData authData = new AuthenticatorData(AttestationObject.AuthData);

            // 6
            //todo:  Verify that the value of C.tokenBinding.status matches the state of Token Binding for the TLS connection over which the assertion was obtained.If Token Binding was used on that TLS connection, also verify that C.tokenBinding.id matches the base64url encoding of the Token Binding ID for the connection.
            // This id done in BaseVerify.
            // todo: test that implmentation

            // 7
            // Compute the hash of response.clientDataJSON using SHA - 256.
            byte[] hashedClientDataJson;
            byte[] hashedRpId;
            using (var sha = SHA256.Create())
            {
                hashedClientDataJson = sha.ComputeHash(Raw.Response.ClientDataJson);
                hashedRpId           = sha.ComputeHash(Encoding.UTF8.GetBytes(originalOptions.Rp.Id));
            }

            // 9
            // Verify that the RP ID hash in authData is indeed the SHA - 256 hash of the RP ID expected by the RP.
            if (false == authData.RpIdHash.SequenceEqual(hashedRpId))
            {
                throw new Fido2VerificationException("Hash mismatch RPID");
            }

            // 10
            // Verify that the User Present bit of the flags in authData is set.
            if (false == authData.UserPresent)
            {
                throw new Fido2VerificationException("User Present flag not set in authenticator data");
            }

            // 11
            // If user verification is required for this registration, verify that the User Verified bit of the flags in authData is set.
            var userVerified = authData.UserVerified;

            // 12
            // Verify that the values of the client extension outputs in clientExtensionResults and the authenticator extension outputs in the extensions in authData are as expected
            // todo: Implement sort of like this: ClientExtensions.Keys.Any(x => options.extensions.contains(x);

            // A COSEAlgorithmIdentifier containing the identifier of the algorithm used to generate the attestation signature
            var alg = AttestationObject.AttStmt["alg"];
            // A byte string containing the attestation signature
            var sig = AttestationObject.AttStmt["sig"];
            // The elements of this array contain attestnCert and its certificate chain, each encoded in X.509 format
            var x5c = AttestationObject.AttStmt["x5c"];
            // The identifier of the ECDAA-Issuer public key
            var ecdaaKeyId = AttestationObject.AttStmt["ecdaaKeyId"];

            if (false == authData.AttestedCredentialDataPresent)
            {
                throw new Fido2VerificationException("Attestation flag not set on attestation data");
            }
            var credentialId             = authData.AttData.CredentialID;
            var credentialPublicKeyBytes = authData.AttData.CredentialPublicKey.ToArray();

            PeterO.Cbor.CBORObject credentialPublicKey = null;
            var coseKty = 0;
            var coseAlg = 0;

            try
            {
                credentialPublicKey = PeterO.Cbor.CBORObject.DecodeFromBytes(authData.AttData.CredentialPublicKey);
                coseKty             = credentialPublicKey[PeterO.Cbor.CBORObject.FromObject(1)].AsInt32();
                coseAlg             = credentialPublicKey[PeterO.Cbor.CBORObject.FromObject(3)].AsInt32();
            }
            catch (PeterO.Cbor.CBORException)
            {
                throw new Fido2VerificationException("Malformed credentialPublicKey");
            }
            byte[] data = new byte[AttestationObject.AuthData.Length + hashedClientDataJson.Length];
            Buffer.BlockCopy(AttestationObject.AuthData, 0, data, 0, AttestationObject.AuthData.Length);
            Buffer.BlockCopy(hashedClientDataJson, 0, data, AttestationObject.AuthData.Length, hashedClientDataJson.Length);
            // 13
            // Determine the attestation statement format by performing a USASCII case-sensitive match on fmt against the set of supported WebAuthn Attestation Statement Format Identifier values. The up-to-date list of registered WebAuthn Attestation Statement Format Identifier values is maintained in the in the IANA registry of the same name [WebAuthn-Registries].
            // https://www.w3.org/TR/webauthn/#defined-attestation-formats
            switch (AttestationObject.Fmt)
            {
            // 14
            // validate the attStmt

            case "none":
            {
                // https://www.w3.org/TR/webauthn/#none-attestation

                if (0 != AttestationObject.AttStmt.Keys.Count && 0 != AttestationObject.AttStmt.Values.Count)
                {
                    throw new Fido2VerificationException("Attestation format none should have no attestation statement");
                }
                attnType  = AttestationType.None;
                trustPath = null;
            }
            break;

            case "tpm":
            {
                // https://www.w3.org/TR/webauthn/#tpm-attestation

                if (null == sig || PeterO.Cbor.CBORType.ByteString != sig.Type || 0 == sig.GetByteString().Length)
                {
                    throw new Fido2VerificationException("Invalid TPM attestation signature");
                }
                if ("2.0" != AttestationObject.AttStmt["ver"].AsString())
                {
                    throw new Fido2VerificationException("FIDO2 only supports TPM 2.0");
                }

                // Verify that the public key specified by the parameters and unique fields of pubArea is identical to the credentialPublicKey in the attestedCredentialData in authenticatorData
                PubArea pubArea = null;
                if (null != AttestationObject.AttStmt["pubArea"] && PeterO.Cbor.CBORType.ByteString == AttestationObject.AttStmt["pubArea"].Type && 0 != AttestationObject.AttStmt["pubArea"].GetByteString().Length)
                {
                    pubArea = new PubArea(AttestationObject.AttStmt["pubArea"].GetByteString());
                }
                if (null == pubArea || null == pubArea.Unique || 0 == pubArea.Unique.Length)
                {
                    throw new Fido2VerificationException("Missing or malformed pubArea");
                }
                if (3 == coseKty)                                                                             // RSA
                {
                    var coseMod = credentialPublicKey[PeterO.Cbor.CBORObject.FromObject(-1)].GetByteString(); // modulus
                    var coseExp = credentialPublicKey[PeterO.Cbor.CBORObject.FromObject(-2)].GetByteString(); // exponent

                    if (!coseMod.ToArray().SequenceEqual(pubArea.Unique.ToArray()))
                    {
                        throw new Fido2VerificationException("Public key mismatch between pubArea and credentialPublicKey");
                    }
                    if ((coseExp[0] + (coseExp[1] << 8) + (coseExp[2] << 16)) != pubArea.Exponent)
                    {
                        throw new Fido2VerificationException("Public key exponent mismatch between pubArea and credentialPublicKey");
                    }
                }
                else if (2 == coseKty)         // ECC
                {
                    var curve = credentialPublicKey[PeterO.Cbor.CBORObject.FromObject(-1)].AsInt32();
                    var X     = credentialPublicKey[PeterO.Cbor.CBORObject.FromObject(-2)].GetByteString();
                    var Y     = credentialPublicKey[PeterO.Cbor.CBORObject.FromObject(-3)].GetByteString();

                    if (pubArea.EccCurve != AuthDataHelper.CoseCurveToTpm[curve])
                    {
                        throw new Fido2VerificationException("Curve mismatch between pubArea and credentialPublicKey");
                    }
                    if (!pubArea.ECPoint.X.SequenceEqual(X))
                    {
                        throw new Fido2VerificationException("X-coordinate mismatch between pubArea and credentialPublicKey");
                    }
                    if (!pubArea.ECPoint.Y.SequenceEqual(Y))
                    {
                        throw new Fido2VerificationException("Y-coordinate mismatch between pubArea and credentialPublicKey");
                    }
                }
                // Concatenate authenticatorData and clientDataHash to form attToBeSigned.
                // see data variable

                // Validate that certInfo is valid
                CertInfo certInfo = null;
                if (null != AttestationObject.AttStmt["certInfo"] && PeterO.Cbor.CBORType.ByteString == AttestationObject.AttStmt["certInfo"].Type && 0 != AttestationObject.AttStmt["certInfo"].GetByteString().Length)
                {
                    certInfo = new CertInfo(AttestationObject.AttStmt["certInfo"].GetByteString());
                }
                if (null == certInfo || null == certInfo.ExtraData || 0 == certInfo.ExtraData.Length)
                {
                    throw new Fido2VerificationException("CertInfo invalid parsing TPM format attStmt");
                }
                // Verify that magic is set to TPM_GENERATED_VALUE and type is set to TPM_ST_ATTEST_CERTIFY
                // handled in parser, see certInfo.Magic

                // Verify that extraData is set to the hash of attToBeSigned using the hash algorithm employed in "alg"
                if (null == alg || PeterO.Cbor.CBORType.Number != alg.Type || false == AuthDataHelper.algMap.ContainsKey(alg.AsInt32()))
                {
                    throw new Fido2VerificationException("Invalid TPM attestation algorithm");
                }
                if (!AuthDataHelper.GetHasher(AuthDataHelper.algMap[alg.AsInt32()]).ComputeHash(data).SequenceEqual(certInfo.ExtraData))
                {
                    throw new Fido2VerificationException("Hash value mismatch extraData and attToBeSigned");
                }

                // Verify that attested contains a TPMS_CERTIFY_INFO structure, whose name field contains a valid Name for pubArea, as computed using the algorithm in the nameAlg field of pubArea
                if (false == AuthDataHelper.GetHasher(AuthDataHelper.algMap[(int)certInfo.Alg]).ComputeHash(pubArea.Raw).SequenceEqual(certInfo.AttestedName))
                {
                    throw new Fido2VerificationException("Hash value mismatch attested and pubArea");
                }

                // If x5c is present, this indicates that the attestation type is not ECDAA
                if (null != x5c && PeterO.Cbor.CBORType.Array == x5c.Type && 0 != x5c.Count)
                {
                    if (null == x5c.Values || 0 == x5c.Values.Count || PeterO.Cbor.CBORType.ByteString != x5c.Values.First().Type || 0 == x5c.Values.First().GetByteString().Length)
                    {
                        throw new Fido2VerificationException("Malformed x5c in TPM attestation");
                    }

                    // Verify the sig is a valid signature over certInfo using the attestation public key in aikCert with the algorithm specified in alg.
                    var aikCert = new X509Certificate2(x5c.Values.First().GetByteString());

                    PeterO.Cbor.CBORObject coseKey = AuthDataHelper.CoseKeyFromCertAndAlg(aikCert, alg.AsInt32());

                    if (true != AuthDataHelper.VerifySigWithCoseKey(certInfo.Raw, coseKey, sig.GetByteString()))
                    {
                        throw new Fido2VerificationException("Bad signature in TPM with aikCert");
                    }

                    // Verify that aikCert meets the TPM attestation statement certificate requirements
                    // https://www.w3.org/TR/webauthn/#tpm-cert-requirements
                    // Version MUST be set to 3
                    if (3 != aikCert.Version)
                    {
                        throw new Fido2VerificationException("aikCert must be V3");
                    }

                    // Subject field MUST be set to empty - they actually mean subject name
                    if (0 != aikCert.SubjectName.Name.Length)
                    {
                        throw new Fido2VerificationException("aikCert subject must be empty");
                    }

                    // The Subject Alternative Name extension MUST be set as defined in [TPMv2-EK-Profile] section 3.2.9.
                    // https://www.w3.org/TR/webauthn/#tpm-cert-requirements
                    var SAN = AuthDataHelper.SANFromAttnCertExts(aikCert.Extensions);
                    if (null == SAN || 0 == SAN.Length)
                    {
                        throw new Fido2VerificationException("SAN missing from TPM attestation certificate");
                    }
                    // From https://www.trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf
                    // The issuer MUST include TPM manufacturer, TPM part number and TPM firmware version, using the directoryNameform within the GeneralName structure. The ASN.1 encoding is specified in section 3.1.2 TPM Device Attributes. In accordance with RFC 5280[11], this extension MUST be critical if subject is empty and SHOULD be non-critical if subject is non-empty.  
                    // Best I can figure to do for now?
                    if (false == SAN.Contains("TPMManufacturer") || false == SAN.Contains("TPMModel") || false == SAN.Contains("TPMVersion"))
                    {
                        throw new Fido2VerificationException("SAN missing TPMManufacturer, TPMModel, or TPMVersopm from TPM attestation certificate");
                    }
                    // The Extended Key Usage extension MUST contain the "joint-iso-itu-t(2) internationalorganizations(23) 133 tcg-kp(8) tcg-kp-AIKCertificate(3)" OID.
                    // OID is 2.23.133.8.3
                    var EKU = AuthDataHelper.EKUFromAttnCertExts(aikCert.Extensions);
                    if (null == EKU || 0 != EKU.CompareTo("Attestation Identity Key Certificate (2.23.133.8.3)"))
                    {
                        throw new Fido2VerificationException("Invalid EKU on AIK certificate");
                    }

                    // The Basic Constraints extension MUST have the CA component set to false.
                    if (AuthDataHelper.IsAttnCertCACert(aikCert.Extensions))
                    {
                        throw new Fido2VerificationException("aikCert Basic Constraints extension CA component must be false");
                    }

                    // If aikCert contains an extension with OID 1.3.6.1.4.1.45724.1.1.4 (id-fido-gen-ce-aaguid) verify that the value of this extension matches the aaguid in authenticatorData
                    var aaguid = AuthDataHelper.AaguidFromAttnCertExts(aikCert.Extensions);
                    if ((null != aaguid) && (!aaguid.SequenceEqual(Guid.Empty.ToByteArray())) && (!aaguid.SequenceEqual(authData.AttData.Aaguid.ToArray())))
                    {
                        throw new Fido2VerificationException("aaguid malformed");
                    }

                    // If successful, return attestation type AttCA and attestation trust path x5c.
                    attnType  = AttestationType.AttCa;
                    trustPath = x5c.Values
                                .Select(x => new X509Certificate2(x.GetByteString()))
                                .ToArray();
                }
                // If ecdaaKeyId is present, then the attestation type is ECDAA
                else if (null != ecdaaKeyId)
                {
                    // Perform ECDAA-Verify on sig to verify that it is a valid signature over certInfo
                    // https://www.w3.org/TR/webauthn/#biblio-fidoecdaaalgorithm
                    throw new Fido2VerificationException("ECDAA support for TPM attestation is not yet implemented");
                    // If successful, return attestation type ECDAA and the identifier of the ECDAA-Issuer public key ecdaaKeyId.
                    //attnType = AttestationType.ECDAA;
                    //trustPath = ecdaaKeyId;
                }
                else
                {
                    throw new Fido2VerificationException("Neither x5c nor ECDAA were found in the TPM attestation statement");
                }
            }
            break;

            case "android-key":
            {
                // https://www.w3.org/TR/webauthn/#android-key-attestation

                // Verify that attStmt is valid CBOR conforming to the syntax defined above and perform CBOR decoding on it to extract the contained fields
                if (0 == AttestationObject.AttStmt.Keys.Count || 0 == AttestationObject.AttStmt.Values.Count)
                {
                    throw new Fido2VerificationException("Attestation format packed must have attestation statement");
                }
                if (null == sig || PeterO.Cbor.CBORType.ByteString != sig.Type || 0 == sig.GetByteString().Length)
                {
                    throw new Fido2VerificationException("Invalid packed attestation signature");
                }
                // 2a. Verify that sig is a valid signature over the concatenation of authenticatorData and clientDataHash
                // using the attestation public key in attestnCert with the algorithm specified in alg
                if (null == x5c && PeterO.Cbor.CBORType.Array != x5c.Type && 0 == x5c.Count)
                {
                    throw new Fido2VerificationException("Malformed x5c in android-key attestation");
                }
                if (null == x5c.Values || 0 == x5c.Values.Count || PeterO.Cbor.CBORType.ByteString != x5c.Values.First().Type || 0 == x5c.Values.First().GetByteString().Length)
                {
                    throw new Fido2VerificationException("Malformed x5c in android-key attestation");
                }
                X509Certificate2 androidKeyCert   = null;
                ECDsaCng         androidKeyPubKey = null;
                try
                {
                    androidKeyCert   = new X509Certificate2(x5c.Values.First().GetByteString());
                    androidKeyPubKey = (ECDsaCng)androidKeyCert.GetECDsaPublicKey();         // attestation public key
                }
                catch (Exception ex)
                {
                    throw new Fido2VerificationException("Failed to extract public key from android key" + ex.Message);
                }
                if (null == alg || PeterO.Cbor.CBORType.Number != alg.Type || false == AuthDataHelper.algMap.ContainsKey(alg.AsInt32()))
                {
                    throw new Fido2VerificationException("Invalid attestation algorithm");
                }
                if (true != androidKeyPubKey.VerifyData(data, AuthDataHelper.SigFromEcDsaSig(sig.GetByteString()), AuthDataHelper.algMap[alg.AsInt32()]))
                {
                    throw new Fido2VerificationException("Invalid android key signature");
                }
                var cng = ECDsaCng.Create(new ECParameters
                    {
                        Curve = ECCurve.NamedCurves.nistP256,
                        Q     = new ECPoint
                        {
                            X = credentialPublicKey[PeterO.Cbor.CBORObject.FromObject(-2)].GetByteString(),
                            Y = credentialPublicKey[PeterO.Cbor.CBORObject.FromObject(-3)].GetByteString()
                        }
                    });
                // Verify that the public key in the first certificate in in x5c matches the credentialPublicKey in the attestedCredentialData in authenticatorData.
                if (true != cng.VerifyData(data, AuthDataHelper.SigFromEcDsaSig(sig.GetByteString()), AuthDataHelper.algMap[alg.AsInt32()]))
                {
                    throw new Fido2VerificationException("Invalid android key signature");
                }

                // Verify that in the attestation certificate extension data:
                var attExtBytes = AuthDataHelper.AttestationExtensionBytes(androidKeyCert.Extensions);

                // 1. The value of the attestationChallenge field is identical to clientDataHash.
                var attestationChallenge = AuthDataHelper.GetAttestationChallenge(attExtBytes);
                if (false == hashedClientDataJson.SequenceEqual(attestationChallenge))
                {
                    throw new Fido2VerificationException("Mismatched between attestationChallenge and hashedClientDataJson verifying android key attestation certificate extension");
                }

                // 2. The AuthorizationList.allApplications field is not present, since PublicKeyCredential MUST be bound to the RP ID.
                if (true == AuthDataHelper.FindAllApplicationsField(attExtBytes))
                {
                    throw new Fido2VerificationException("Found all applications field in android key attestation certificate extension");
                }

                // 3. The value in the AuthorizationList.origin field is equal to KM_ORIGIN_GENERATED ( which == 0).
                if (false == AuthDataHelper.IsOriginGenerated(attExtBytes))
                {
                    throw new Fido2VerificationException("Found origin field not set to KM_ORIGIN_GENERATED in android key attestation certificate extension");
                }

                // 4. The value in the AuthorizationList.purpose field is equal to KM_PURPOSE_SIGN (which == 2).
                if (false == AuthDataHelper.IsPurposeSign(attExtBytes))
                {
                    throw new Fido2VerificationException("Found purpose field not set to KM_PURPOSE_SIGN in android key attestation certificate extension");
                }

                attnType  = AttestationType.Basic;
                trustPath = x5c.Values
                            .Select(x => new X509Certificate2(x.GetByteString()))
                            .ToArray();
            }
            break;

            case "android-safetynet":
            {
                // https://www.w3.org/TR/webauthn/#android-safetynet-attestation

                // Verify that attStmt is valid CBOR conforming to the syntax defined above and perform CBOR decoding on it to extract the contained fields
                if ((PeterO.Cbor.CBORType.TextString != AttestationObject.AttStmt["ver"].Type) || (0 == AttestationObject.AttStmt["ver"].AsString().Length))
                {
                    throw new Fido2VerificationException("Invalid version in SafetyNet data");
                }

                // Verify that response is a valid SafetyNet response of version ver
                var ver = AttestationObject.AttStmt["ver"].AsString();

                if ((PeterO.Cbor.CBORType.ByteString != AttestationObject.AttStmt["response"].Type) || (0 == AttestationObject.AttStmt["response"].GetByteString().Length))
                {
                    throw new Fido2VerificationException("Invalid response in SafetyNet data");
                }
                var response = AttestationObject.AttStmt["response"].GetByteString();
                var signedAttestationStatement = Encoding.UTF8.GetString(response);
                var jwtToken           = new JwtSecurityToken(signedAttestationStatement);
                X509SecurityKey[] keys = (jwtToken.Header["x5c"] as JArray)
                                         .Values <string>()
                                         .Select(x => new X509SecurityKey(
                                                     new X509Certificate2(Convert.FromBase64String(x))))
                                         .ToArray();
                if ((null == keys) || (0 == keys.Count()))
                {
                    throw new Fido2VerificationException("SafetyNet attestation missing x5c");
                }
                var validationParameters = new TokenValidationParameters
                {
                    ValidateIssuer           = false,
                    ValidateAudience         = false,
                    ValidateLifetime         = false,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKeys        = keys
                };

                var           tokenHandler = new JwtSecurityTokenHandler();
                SecurityToken validatedToken;

                tokenHandler.ValidateToken(
                    signedAttestationStatement,
                    validationParameters,
                    out validatedToken);

                if (false == (validatedToken.SigningKey is X509SecurityKey))
                {
                    throw new Fido2VerificationException("Safetynet signing key invalid");
                }

                var nonce   = "";
                var payload = false;
                foreach (var claim in jwtToken.Claims)
                {
                    if (("nonce" == claim.Type) && ("http://www.w3.org/2001/XMLSchema#string" == claim.ValueType) && (0 != claim.Value.Length))
                    {
                        nonce = claim.Value;
                    }
                    if (("ctsProfileMatch" == claim.Type) && ("http://www.w3.org/2001/XMLSchema#boolean" == claim.ValueType))
                    {
                        payload = bool.Parse(claim.Value);
                    }
                    if (("timestampMs" == claim.Type) && ("http://www.w3.org/2001/XMLSchema#integer64" == claim.ValueType))
                    {
                        DateTime dt = DateTimeHelper.UnixEpoch.AddMilliseconds(double.Parse(claim.Value));
                        if ((DateTime.UtcNow < dt) || (DateTime.UtcNow.AddMinutes(-1) > dt))
                        {
                            throw new Fido2VerificationException("Android SafetyNet timestampMs must be between one minute ago and now");
                        }
                    }
                }

                // Verify that the nonce in the response is identical to the SHA-256 hash of the concatenation of authenticatorData and clientDataHash
                if ("" == nonce)
                {
                    throw new Fido2VerificationException("Nonce value not found in Android SafetyNet attestation");
                }
                if (!AuthDataHelper.GetHasher(HashAlgorithmName.SHA256).ComputeHash(data).SequenceEqual(Convert.FromBase64String(nonce)))
                {
                    throw new Fido2VerificationException("Android SafetyNet hash value mismatch");
                }

                // Verify that the attestation certificate is issued to the hostname "attest.android.com"
                if (false == ("attest.android.com").Equals((validatedToken.SigningKey as X509SecurityKey).Certificate.GetNameInfo(X509NameType.DnsName, false)))
                {
                    throw new Fido2VerificationException("Safetynet DnsName is not attest.android.com");
                }

                // Verify that the ctsProfileMatch attribute in the payload of response is true
                if (true != payload)
                {
                    throw new Fido2VerificationException("Android SafetyNet ctsProfileMatch must be true");
                }

                attnType  = AttestationType.Basic;
                trustPath = (jwtToken.Header["x5c"] as JArray)
                            .Values <string>()
                            .Select(x => new X509Certificate2(Convert.FromBase64String(x)))
                            .ToArray();
            }
            break;

            case "fido-u2f":
            {
                // https://www.w3.org/TR/webauthn/#fido-u2f-attestation

                // verify that aaguid is 16 empty bytes (note: required by fido2 conformance testing, could not find this in spec?)
                if (false == authData.AttData.Aaguid.SequenceEqual(Guid.Empty.ToByteArray()))
                {
                    throw new Fido2VerificationException("Aaguid was not empty parsing fido-u2f atttestation statement");
                }

                // 1. Verify that attStmt is valid CBOR conforming to the syntax defined above and perform CBOR decoding on it to extract the contained fields.
                if (null == x5c || PeterO.Cbor.CBORType.Array != x5c.Type || x5c.Count != 1)
                {
                    throw new Fido2VerificationException("Malformed x5c in fido - u2f attestation");
                }

                // 2a. the attestation certificate attestnCert MUST be the first element in the array
                if (null == x5c.Values || 0 == x5c.Values.Count || PeterO.Cbor.CBORType.ByteString != x5c.Values.First().Type || 0 == x5c.Values.First().GetByteString().Length)
                {
                    throw new Fido2VerificationException("Malformed x5c in fido-u2f attestation");
                }
                var cert = new X509Certificate2(x5c.Values.First().GetByteString());

                // 2b. If certificate public key is not an Elliptic Curve (EC) public key over the P-256 curve, terminate this algorithm and return an appropriate error
                var pubKey = (ECDsaCng)cert.GetECDsaPublicKey();
                if (CngAlgorithm.ECDsaP256 != pubKey.Key.Algorithm)
                {
                    throw new Fido2VerificationException("attestation certificate public key is not an Elliptic Curve (EC) public key over the P-256 curve");
                }

                // 3. Extract the claimed rpIdHash from authenticatorData, and the claimed credentialId and credentialPublicKey from authenticatorData
                // done above

                // 4. Convert the COSE_KEY formatted credentialPublicKey (see Section 7 of [RFC8152]) to CTAP1/U2F public Key format
                var publicKeyU2F = AuthDataHelper.U2FKeyFromCOSEKey(credentialPublicKey);

                // 5. Let verificationData be the concatenation of (0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F)
                var verificationData = new byte[1] {
                    0x00
                };
                verificationData = verificationData.Concat(hashedRpId).Concat(hashedClientDataJson).Concat(credentialId).Concat(publicKeyU2F.ToArray()).ToArray();

                // 6. Verify the sig using verificationData and certificate public key
                if (null == sig || PeterO.Cbor.CBORType.ByteString != sig.Type || 0 == sig.GetByteString().Length)
                {
                    throw new Fido2VerificationException("Invalid fido-u2f attestation signature");
                }
                var ecsig = AuthDataHelper.SigFromEcDsaSig(sig.GetByteString());
                if (null == ecsig)
                {
                    throw new Fido2VerificationException("Failed to decode fido-u2f attestation signature from ASN.1 encoded form");
                }
                if (true != pubKey.VerifyData(verificationData, ecsig, AuthDataHelper.algMap[coseAlg]))
                {
                    throw new Fido2VerificationException("Invalid fido-u2f attestation signature");
                }
                attnType  = AttestationType.Basic;
                trustPath = x5c.Values
                            .Select(x => new X509Certificate2(x.GetByteString()))
                            .ToArray();
            }
            break;

            case "packed":
            {
                // https://www.w3.org/TR/webauthn/#packed-attestation

                // Verify that attStmt is valid CBOR conforming to the syntax defined above and perform CBOR decoding on it to extract the contained fields.
                if (0 == AttestationObject.AttStmt.Keys.Count || 0 == AttestationObject.AttStmt.Values.Count)
                {
                    throw new Fido2VerificationException("Attestation format packed must have attestation statement");
                }
                if (null == sig || PeterO.Cbor.CBORType.ByteString != sig.Type || 0 == sig.GetByteString().Length)
                {
                    throw new Fido2VerificationException("Invalid packed attestation signature");
                }
                if (null == alg || PeterO.Cbor.CBORType.Number != alg.Type)
                {
                    throw new Fido2VerificationException("Invalid packed attestation algorithm");
                }

                // If x5c is present, this indicates that the attestation type is not ECDAA
                if (null != x5c)
                {
                    if (PeterO.Cbor.CBORType.Array != x5c.Type || 0 == x5c.Count || null != ecdaaKeyId)
                    {
                        throw new Fido2VerificationException("Malformed x5c array in packed attestation statement");
                    }
                    IEnumerator <PeterO.Cbor.CBORObject> enumerator = x5c.Values.GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        if (null == enumerator || null == enumerator.Current || PeterO.Cbor.CBORType.ByteString != enumerator.Current.Type || 0 == enumerator.Current.GetByteString().Length)
                        {
                            throw new Fido2VerificationException("Malformed x5c cert found in packed attestation statement");
                        }
                        var x5ccert = new X509Certificate2(enumerator.Current.GetByteString());
                        if (DateTime.UtcNow < x5ccert.NotBefore || DateTime.UtcNow > x5ccert.NotAfter)
                        {
                            throw new Fido2VerificationException("Packed signing certificate expired or not yet valid");
                        }
                    }

                    // The attestation certificate attestnCert MUST be the first element in the array.
                    var attestnCert = new X509Certificate2(x5c.Values.First().GetByteString());

                    // 2a. Verify that sig is a valid signature over the concatenation of authenticatorData and clientDataHash
                    // using the attestation public key in attestnCert with the algorithm specified in alg
                    var packedPubKey = (ECDsaCng)attestnCert.GetECDsaPublicKey();         // attestation public key
                    if (false == AuthDataHelper.algMap.ContainsKey(alg.AsInt32()))
                    {
                        throw new Fido2VerificationException("Invalid attestation algorithm");
                    }

                    var coseKey = AuthDataHelper.CoseKeyFromCertAndAlg(attestnCert, alg.AsInt32());

                    if (true != AuthDataHelper.VerifySigWithCoseKey(data, coseKey, sig.GetByteString()))
                    {
                        throw new Fido2VerificationException("Invalid full packed signature");
                    }

                    // Verify that attestnCert meets the requirements in https://www.w3.org/TR/webauthn/#packed-attestation-cert-requirements
                    // 2b. Version MUST be set to 3
                    if (3 != attestnCert.Version)
                    {
                        throw new Fido2VerificationException("Packed x5c attestation certificate not V3");
                    }

                    // Subject field MUST contain C, O, OU, CN
                    // OU must match "Authenticator Attestation"
                    if (true != AuthDataHelper.IsValidPackedAttnCertSubject(attestnCert.Subject))
                    {
                        throw new Fido2VerificationException("Invalid attestation cert subject");
                    }

                    // 2c. If the related attestation root certificate is used for multiple authenticator models,
                    // the Extension OID 1.3.6.1.4.1.45724.1.1.4 (id-fido-gen-ce-aaguid) MUST be present, containing the AAGUID as a 16-byte OCTET STRING
                    // verify that the value of this extension matches the aaguid in authenticatorData
                    var aaguid = AuthDataHelper.AaguidFromAttnCertExts(attestnCert.Extensions);
                    if (aaguid != null && !aaguid.SequenceEqual(authData.AttData.Aaguid.ToArray()))
                    {
                        throw new Fido2VerificationException("aaguid present in packed attestation but does not match aaguid from authData");
                    }

                    // 2d. The Basic Constraints extension MUST have the CA component set to false
                    if (AuthDataHelper.IsAttnCertCACert(attestnCert.Extensions))
                    {
                        throw new Fido2VerificationException("Attestion certificate has CA cert flag present");
                    }

                    // id-fido-u2f-ce-transports
                    var u2ftransports = AuthDataHelper.U2FTransportsFromAttnCert(attestnCert.Extensions);
                    attnType  = AttestationType.Basic;
                    trustPath = x5c.Values
                                .Select(x => new X509Certificate2(x.GetByteString()))
                                .ToArray();
                }
                // If ecdaaKeyId is present, then the attestation type is ECDAA
                else if (null != ecdaaKeyId)
                {
                    // Verify that sig is a valid signature over the concatenation of authenticatorData and clientDataHash
                    // using ECDAA-Verify with ECDAA-Issuer public key identified by ecdaaKeyId
                    // https://www.w3.org/TR/webauthn/#biblio-fidoecdaaalgorithm

                    throw new Fido2VerificationException("ECDAA is not yet implemented");
                    // If successful, return attestation type ECDAA and attestation trust path ecdaaKeyId.
                    //attnType = AttestationType.ECDAA;
                    //trustPath = ecdaaKeyId;
                }
                // If neither x5c nor ecdaaKeyId is present, self attestation is in use
                else
                {
                    // Validate that alg matches the algorithm of the credentialPublicKey in authenticatorData
                    if (alg.AsInt32() != coseAlg)
                    {
                        throw new Fido2VerificationException("Algorithm mismatch between credential public key and authenticator data in self attestation statement");
                    }
                    // Verify that sig is a valid signature over the concatenation of authenticatorData and clientDataHash using the credential public key with alg
                    if (true != AuthDataHelper.VerifySigWithCoseKey(data, credentialPublicKey, sig.GetByteString()))
                    {
                        throw new Fido2VerificationException("Failed to validate signature");
                    }

                    // If successful, return attestation type Self and empty attestation trust path.
                    attnType  = AttestationType.Self;
                    trustPath = null;
                }
            }
            break;

            default: throw new Fido2VerificationException("Missing or unknown attestation type");
            }

            /*
             * 15
             * If validation is successful, obtain a list of acceptable trust anchors (attestation root certificates or ECDAA-Issuer public keys) for that attestation type and attestation statement format fmt, from a trusted source or from policy. For example, the FIDO Metadata Service [FIDOMetadataService] provides one way to obtain such information, using the aaguid in the attestedCredentialData in authData.
             * */
            // MetadataService

            /*
             * 16
             * Assess the attestation trustworthiness using the outputs of the verification procedure in step 14, as follows: https://www.w3.org/TR/webauthn/#registering-a-new-credential
             * */
            // todo: implement (this is not for attfmt none)
            // use aaguid (authData.AttData.Aaguid) to find root certs in metadata
            // use root plus trustPath to build trust chain

            if (null != metadataService)
            {
                MetadataTOCPayloadEntry entry = metadataService.GetEntry(authData.AttData.GuidAaguid);

                if (null != entry)
                {
                    if (entry.Hash != entry.MetadataStatement.Hash)
                    {
                        throw new Fido2VerificationException("Authenticator metadata statement has invalid hash");
                    }
                    if (null != entry.MetadataStatement)
                    {
                        var hasBasicFull = entry.MetadataStatement.AttestationTypes.Contains((ushort)MetadataAttestationType.ATTESTATION_BASIC_FULL);
                        if (false == hasBasicFull &&
                            null != trustPath && trustPath.FirstOrDefault().Subject != trustPath.FirstOrDefault().Issuer)
                        {
                            throw new Fido2VerificationException("Attestation with full attestation from authentictor that does not support full attestation");
                        }
                        if (true == hasBasicFull && null != trustPath && trustPath.FirstOrDefault().Subject != trustPath.FirstOrDefault().Issuer)
                        {
                            var root  = new X509Certificate2(Convert.FromBase64String(entry.MetadataStatement.AttestationRootCertificates.FirstOrDefault()));
                            var chain = new X509Chain();
                            chain.ChainPolicy.ExtraStore.Add(root);
                            if (trustPath.Length > 1)
                            {
                                foreach (X509Certificate2 cert in trustPath.Skip(1).Reverse())
                                {
                                    chain.ChainPolicy.ExtraStore.Add(cert);
                                }
                            }
                            var valid = chain.Build(trustPath[0]);
                            if (false == valid)
                            {
                            }
                        }
                    }

                    foreach (StatusReport report in entry.StatusReports)
                    {
                        if (true == Enum.IsDefined(typeof(UndesiredAuthenticatorStatus), (UndesiredAuthenticatorStatus)report.Status))
                        {
                            throw new Fido2VerificationException("Authenticator found with undesirable status");
                        }
                    }
                }
            }

            /*
             * 17
             * Check that the credentialId is not yet registered to any other user.
             * If registration is requested for a credential that is already registered to a different user, the Relying Party SHOULD fail this registration ceremony, or it MAY decide to accept the registration, e.g. while deleting the older registration.
             * */
            if (false == await isCredentialIdUniqueToUser(new IsCredentialIdUniqueToUserParams(credentialId, originalOptions.User)))
            {
                throw new Fido2VerificationException("CredentialId is not unique to this user");
            }

            /*
             * 18
             * If the attestation statement attStmt verified successfully and is found to be trustworthy, then register the new credential with the account that was denoted in the options.user passed to create(), by associating it with the credentialId and credentialPublicKey in the attestedCredentialData in authData, as appropriate for the Relying Party's system.
             * */
            // This is handled by code att call site and result object.


            /*
             * 19
             * If the attestation statement attStmt successfully verified but is not trustworthy per step 16 above, the Relying Party SHOULD fail the registration ceremony.
             * NOTE: However, if permitted by policy, the Relying Party MAY register the credential ID and credential public key but treat the credential as one with self attestation (see §6.3.3 Attestation Types). If doing so, the Relying Party is asserting there is no cryptographic proof that the public key credential has been generated by a particular authenticator model. See [FIDOSecRef] and [UAFProtocol] for a more detailed discussion.
             * */
            // todo: implement (this is not for attfmt none)

            var result = new AttestationVerificationSuccess()
            {
                CredentialId = credentialId,
                PublicKey    = credentialPublicKeyBytes,
                User         = originalOptions.User,
                Counter      = BitConverter.ToUInt32(authData.SignCount.ToArray().Reverse().ToArray(), 0)
            };

            return(result);
        }
Exemplo n.º 23
0
		public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
		{
			if (IsAuthenticated)
				throw new InvalidOperationException ("This SslStream is already authenticated");

			SslClientStream s = new SslClientStream (InnerStream, targetHost, !LeaveInnerStreamOpen, GetMonoSslProtocol (enabledSslProtocols), clientCertificates);
			s.CheckCertRevocationStatus = checkCertificateRevocation;

			// Due to the Mono.Security internal, it cannot reuse
			// the delegated argument, as Mono.Security creates 
			// another instance of X509Certificate which lacks 
			// private key but is filled the private key via this
			// delegate.
			s.PrivateKeyCertSelectionDelegate = delegate (X509Certificate cert, string host) {
				string hash = cert.GetCertHashString ();
				// ... so, we cannot use the delegate argument.
				foreach (X509Certificate cc in clientCertificates) {
					if (cc.GetCertHashString () != hash)
						continue;
					X509Certificate2 cert2 = cc as X509Certificate2;
					cert2 = cert2 ?? new X509Certificate2 (cc);
					return cert2.PrivateKey;
				}
				return null;
			};

#if MONOTOUCH || MONODROID
			// Even if validation_callback is null this allows us to verify requests where the user
			// does not provide a verification callback but attempts to authenticate with the website
			// as a client (see https://bugzilla.xamarin.com/show_bug.cgi?id=18962 for an example)
			var helper = new ServicePointManager.ChainValidationHelper (this, targetHost);
			helper.ServerCertificateValidationCallback = validation_callback;
			s.ServerCertValidation2 += new CertificateValidationCallback2 (helper.ValidateChain);
#else
			if (validation_callback != null) {
				s.ServerCertValidationDelegate = delegate (X509Certificate cert, int [] certErrors) {
					X509Chain chain = new X509Chain ();
					X509Certificate2 x2 = (cert as X509Certificate2);
					if (x2 == null)
						x2 = new X509Certificate2 (cert);

					if (!ServicePointManager.CheckCertificateRevocationList)
						chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

					// SSL specific checks (done by Mono.Security.dll SSL/TLS implementation) 
					SslPolicyErrors errors = SslPolicyErrors.None;
					foreach (int i in certErrors) {
						switch (i) {
						case -2146762490: // CERT_E_PURPOSE
							errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
							break;
						case -2146762481: // CERT_E_CN_NO_MATCH
							errors |= SslPolicyErrors.RemoteCertificateNameMismatch;
							break;
						default:
							errors |= SslPolicyErrors.RemoteCertificateChainErrors;
							break;
						}
					}

					chain.Build (x2);

					// non-SSL specific X509 checks (i.e. RFC3280 related checks)
					foreach (X509ChainStatus status in chain.ChainStatus) {
						if (status.Status == X509ChainStatusFlags.NoError)
							continue;
						if ((status.Status & X509ChainStatusFlags.PartialChain) != 0)
							errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
						else
							errors |= SslPolicyErrors.RemoteCertificateChainErrors;
					}

					return validation_callback (this, cert, chain, errors);
				};
			}
#endif
			if (selection_callback != null)
				s.ClientCertSelectionDelegate = OnCertificateSelection;

			ssl_stream = s;

			return BeginWrite (new byte [0], 0, 0, asyncCallback, asyncState);
		}
        /// <summary>
        /// Throws an exception if validation fails.
        /// </summary>
        /// <param name="certificates">The certificates to be checked.</param>
        /// <exception cref="ServiceResultException">If certificate[0] cannot be accepted</exception>
        protected virtual async Task InternalValidate(X509Certificate2Collection certificates)
        {
            X509Certificate2 certificate = certificates[0];

            // check for previously validated certificate.
            X509Certificate2 certificate2 = null;

            if (m_validatedCertificates.TryGetValue(certificate.Thumbprint, out certificate2))
            {
                if (Utils.IsEqual(certificate2.RawData, certificate.RawData))
                {
                    return;
                }
            }

            CertificateIdentifier trustedCertificate = await GetTrustedCertificate(certificate);

            // get the issuers (checks the revocation lists if using directory stores).
            List <CertificateIdentifier> issuers = new List <CertificateIdentifier>();
            bool isIssuerTrusted = await GetIssuers(certificates, issuers);

            // setup policy chain
            X509ChainPolicy policy = new X509ChainPolicy();

            policy.RevocationFlag    = X509RevocationFlag.EntireChain;
            policy.RevocationMode    = X509RevocationMode.NoCheck;
            policy.VerificationFlags = X509VerificationFlags.NoFlag;

            foreach (CertificateIdentifier issuer in issuers)
            {
                if ((issuer.ValidationOptions & CertificateValidationOptions.SuppressRevocationStatusUnknown) != 0)
                {
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreCtlSignerRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreEndRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreRootRevocationUnknown;
                }

                // we did the revocation check in the GetIssuers call. No need here.
                policy.RevocationMode = X509RevocationMode.NoCheck;
                policy.ExtraStore.Add(issuer.Certificate);
            }

            // build chain.
            bool      chainStatusChecked = false;
            X509Chain chain = new X509Chain();

            chain.ChainPolicy = policy;
            chain.Build(certificate);

            // check the chain results.
            CertificateIdentifier target = trustedCertificate;

            if (target == null)
            {
                target = new CertificateIdentifier(certificate);
            }

            for (int ii = 0; ii < chain.ChainElements.Count; ii++)
            {
                X509ChainElement element = chain.ChainElements[ii];

                CertificateIdentifier issuer = null;

                if (ii < issuers.Count)
                {
                    issuer = issuers[ii];
                }

                // check for chain status errors.
                if (element.ChainElementStatus.Length > 0)
                {
                    foreach (X509ChainStatus status in element.ChainElementStatus)
                    {
                        ServiceResult result = CheckChainStatus(status, target, issuer, (ii != 0));

                        if (ServiceResult.IsBad(result))
                        {
                            // check untrusted certificates.
                            if (trustedCertificate == null)
                            {
                                ServiceResult errorResult = new ServiceResult(
                                    result.StatusCode,
                                    result.SymbolicId,
                                    result.NamespaceUri,
                                    result.LocalizedText,
                                    result.AdditionalInfo,
                                    StatusCodes.BadCertificateUntrusted);

                                throw new ServiceResultException(errorResult);
                            }

                            throw new ServiceResultException(result);
                        }

                        chainStatusChecked = true;
                    }
                }
                else
                {
                    chainStatusChecked = true;
                }

                if (issuer != null)
                {
                    target = issuer;
                }
            }

            // check whether the chain is complete (if there is a chain)
            bool issuedByCA      = !X509Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer);
            bool chainIncomplete = false;

            if (issuers.Count > 0)
            {
                var rootCertificate = issuers[issuers.Count - 1].Certificate;
                if (!X509Utils.CompareDistinguishedName(rootCertificate.Subject, rootCertificate.Issuer))
                {
                    chainIncomplete = true;
                }
            }
            else
            {
                if (issuedByCA)
                {
                    // no issuer found at all
                    chainIncomplete = true;
                }
            }

            if (issuedByCA && (!chainStatusChecked || chainIncomplete))
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadCertificateChainIncomplete,
                          "Certificate chain validation incomplete.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                          certificate.SubjectName.Name,
                          certificate.IssuerName.Name);
            }

            // check if certificate issuer is trusted.
            if (issuedByCA && !isIssuerTrusted && trustedCertificate == null)
            {
                if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData))
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadCertificateUntrusted,
                              "Certificate issuer is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                              certificate.SubjectName.Name,
                              certificate.IssuerName.Name);
                }
            }

            // check if certificate is trusted.
            if (trustedCertificate == null && !isIssuerTrusted)
            {
                if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData))
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadCertificateUntrusted,
                              "Certificate is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                              certificate.SubjectName.Name,
                              certificate.IssuerName.Name);
                }
            }

            // check if certificate is valid for use as app/sw or user cert
            X509KeyUsageFlags certificateKeyUsage = X509Utils.GetKeyUsage(certificate);

            if ((certificateKeyUsage & X509KeyUsageFlags.DataEncipherment) == 0)
            {
                throw new ServiceResultException(StatusCodes.BadCertificateUseNotAllowed, "Usage of certificate is not allowed.");
            }

            // check if minimum requirements are met
            if (m_rejectSHA1SignedCertificates && IsSHA1SignatureAlgorithm(certificate.SignatureAlgorithm))
            {
                throw new ServiceResultException(StatusCodes.BadCertificatePolicyCheckFailed, "SHA1 signed certificates are not trusted");
            }

            int keySize = X509Utils.GetRSAPublicKeySize(certificate);

            if (keySize < m_minimumCertificateKeySize)
            {
                throw new ServiceResultException(StatusCodes.BadCertificatePolicyCheckFailed, "Certificate doesn't meet minimum key length requirement");
            }
        }
Exemplo n.º 25
0
        public static void BuildChain_WithApplicationPolicy_Match()
        {
            using (var msCer = new X509Certificate2(TestData.MsCertificate))
            using (X509Chain chain = new X509Chain())
            {
                // Code Signing
                chain.ChainPolicy.ApplicationPolicy.Add(new Oid("1.3.6.1.5.5.7.3.3"));
                chain.ChainPolicy.VerificationTime = msCer.NotBefore.AddHours(2);
                chain.ChainPolicy.VerificationFlags =
                    X509VerificationFlags.AllowUnknownCertificateAuthority;

                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                bool valid = chain.Build(msCer);
                Assert.True(valid, "Chain built validly");
            }
        }
Exemplo n.º 26
0
        /// <summary>
        /// Verifies the server certificate by calling into ServicePointManager.ServerCertificateValidationCallback or,
        /// if the is no delegate attached to it by using the default hostname verifier.
        /// </summary>
        /// <returns><c>true</c>, if server certificate was verifyed, <c>false</c> otherwise.</returns>
        /// <param name="hostname"></param>
        /// <param name="session"></param>
        public static bool verifyServerCertificate(string hostname, ISSLSession session)
        {
            var defaultVerifier = HttpsURLConnection.DefaultHostnameVerifier;

            // Call custom ServicePointManager.ServerCertificateValidationCallback delegate
            // if customSSLVerification is true
            if (ServicePointManager.ServerCertificateValidationCallback == null)
            {
                return(defaultVerifier.Verify(hostname, session));
            }

            // Convert java certificates to .NET certificates and build cert chain from root certificate
            var certificates      = session.GetPeerCertificateChain();
            var chain             = new X509Chain();
            X509Certificate2 root = null;
            var errors            = System.Net.Security.SslPolicyErrors.None;

            // Build certificate chain and check for errors
            if (certificates == null || certificates.Length == 0)
            {//no cert at all
                errors = System.Net.Security.SslPolicyErrors.RemoteCertificateNotAvailable;
                goto bail;
            }

            if (certificates.Length == 1)
            {//no root?
                errors = System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors;
                goto bail;
            }

            var netCerts = certificates.Select(x => new X509Certificate2(x.GetEncoded())).ToArray();

            for (int i = 1; i < netCerts.Length; i++)
            {
                chain.ChainPolicy.ExtraStore.Add(netCerts[i]);
            }

            root = netCerts[0];

            chain.ChainPolicy.RevocationFlag      = X509RevocationFlag.EntireChain;
            chain.ChainPolicy.RevocationMode      = X509RevocationMode.NoCheck;
            chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
            chain.ChainPolicy.VerificationFlags   = X509VerificationFlags.AllowUnknownCertificateAuthority;

            if (!chain.Build(root))
            {
                errors = System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors;
                goto bail;
            }

            var subject   = root.Subject;
            var subjectCn = cnRegex.Match(subject).Groups[1].Value;

            if (String.IsNullOrWhiteSpace(subjectCn) || !Utility.MatchHostnameToPattern(hostname, subjectCn))
            {
                errors = System.Net.Security.SslPolicyErrors.RemoteCertificateNameMismatch;
                goto bail;
            }

bail:
            // Call the delegate to validate
            return(ServicePointManager.ServerCertificateValidationCallback(hostname, root, chain, errors));
        }
Exemplo n.º 27
0
    static void Main(string[] args)
    {
        //Do webrequest to get info on secure site

        Console.Write("Enter web site name:  ");
        string WebSitename = Console.ReadLine();

        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(WebSitename);

            //  HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://mail.outlook.com");

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            response.Close();

            //retrieve the ssl cert and assign it to an X509Certificate object
            X509Certificate cert = request.ServicePoint.Certificate;

            //convert the X509Certificate to an X509Certificate2 object by passing it into the constructor
            X509Certificate2 cert2 = new X509Certificate2(cert);

            string cn = cert2.GetIssuerName();
            string cedate = cert2.GetExpirationDateString();
            string cpub = cert2.GetPublicKeyString();

            //display the cert dialog box
            X509Certificate2UI.DisplayCertificate(cert2);

            // Output chain information of the selected certificate.

            X509Chain ch = new X509Chain();
            ch.Build(cert2);
            Console.WriteLine("Chain Information");
            ch.ChainPolicy.RevocationMode = X509RevocationMode.Online;
            Console.WriteLine("Chain revocation flag: {0}", ch.ChainPolicy.RevocationFlag);
            Console.WriteLine("Chain revocation mode: {0}", ch.ChainPolicy.RevocationMode);
            Console.WriteLine("Chain verification flag: {0}", ch.ChainPolicy.VerificationFlags);
            Console.WriteLine("Chain verification time: {0}", ch.ChainPolicy.VerificationTime);
            Console.WriteLine("Chain status length: {0}", ch.ChainStatus.Length);
            Console.WriteLine("Chain application policy count: {0}", ch.ChainPolicy.ApplicationPolicy.Count);
            Console.WriteLine("Chain certificate policy count: {0} {1}", ch.ChainPolicy.CertificatePolicy.Count, Environment.NewLine);
            //Output chain element information.
            Console.WriteLine("Chain Element Information");
            Console.WriteLine("Number of chain elements: {0}", ch.ChainElements.Count);
            Console.WriteLine("Chain elements synchronized? {0} {1}", ch.ChainElements.IsSynchronized, Environment.NewLine);

            foreach (X509ChainElement element in ch.ChainElements)
            {
                Console.WriteLine("Element issuer name: {0}", element.Certificate.Issuer);
                Console.WriteLine("Element certificate valid until: {0}", element.Certificate.NotAfter);
                Console.WriteLine("Element certificate is valid: {0}", element.Certificate.Verify());

                //break out specific certifcate data
                Console.WriteLine("Signature Algorithm: {0}", cert2.SignatureAlgorithm.FriendlyName);
                // Console.WriteLine("Public Key: {0}", cert2.PublicKey.Key.ToXmlString(false));
                Console.WriteLine("Public Key: {0}{1}", cert2.PublicKey.Key.ToXmlString(false), Environment.NewLine);

                Console.WriteLine("Element error status length: {0}", element.ChainElementStatus.Length);
                Console.WriteLine("Element information: {0}", element.Information);
                Console.WriteLine("Number of element extensions: {0}{1}", element.Certificate.Extensions.Count, Environment.NewLine);

                X509Certificate2 certTest = new X509Certificate2(element.Certificate);

                // byte[] rawdata = certTest;

                // Console.WriteLine("Content Type: {0}{1}", certTest.GetCertContentType(rawdata), Environment.NewLine);
                Console.WriteLine("Friendly Name: {0}{1}", certTest.FriendlyName, Environment.NewLine);

                if (ch.ChainStatus.Length > 1)
                {
                    for (int index = 0; index < element.ChainElementStatus.Length; index++)
                    {
                        Console.WriteLine(element.ChainElementStatus[index].Status);
                        Console.WriteLine(element.ChainElementStatus[index].StatusInformation);
                    }
                }
            }
        }

        catch (Exception e)

        // catch (WebException e)
        {
            Console.WriteLine("Error:  ");
            Console.WriteLine ( e.Message);

            return;
        }

        finally
        {

            Console.WriteLine("all good");

        }
    }
        private static bool ValidIntermediateCa(X509Certificate caCertificate, X509Certificate certificate, X509Chain chain, bool trustRoot,
                                                X509RevocationMode revocationMode
                                                )
        {
            var ca           = new X509Certificate2(caCertificate);
            var privateChain = new X509Chain {
                ChainPolicy = { RevocationMode = revocationMode }
            };

            privateChain.ChainPolicy.ExtraStore.Add(ca);
            privateChain.Build(new X509Certificate2(certificate));

            //Assert our chain has the same number of elements as the certifcate presented by the server
            if (chain.ChainElements.Count != privateChain.ChainElements.Count)
            {
                return(false);
            }

            //lets validate the our chain status
            foreach (var chainStatus in privateChain.ChainStatus)
            {
                //custom CA's that are not in the machine trusted store will always have this status
                //by setting trustRoot = true (default) we skip this error
                if (chainStatus.Status == X509ChainStatusFlags.UntrustedRoot && trustRoot)
                {
                    continue;
                }

                //trustRoot is false so we expected our CA to be in the machines trusted store
                if (chainStatus.Status == X509ChainStatusFlags.UntrustedRoot)
                {
                    return(false);
                }

                //otherwise if the chain has any error of any sort return false
                if (chainStatus.Status != X509ChainStatusFlags.NoError)
                {
                    return(false);
                }
            }

            var found = false;

            //We are going to walk both chains and make sure the thumbprints align
            //while making sure one of the chains certificates presented by the server has our expected CA thumbprint
            for (var i = 0; i < chain.ChainElements.Count; i++)
            {
                var c        = chain.ChainElements[i].Certificate.Thumbprint;
                var cPrivate = privateChain.ChainElements[i].Certificate.Thumbprint;
                if (!found && c == ca.Thumbprint)
                {
                    found = true;
                }

                //mis aligned certificate chain, return false so we do not accept this certificate
                if (c != cPrivate)
                {
                    return(false);
                }
            }
            return(found);
        }
        private static string CreateClientToken(SigningCredentials credential, string clientId, string audience,
                                                List <string> rootCertSubject)
        {
            // oz
            //// string x5c = "";
            string[]         x5c          = null;
            string           certFileName = certPfx;
            string           password     = certPfxPW;
            X509Certificate2 certificate  = null;

            if (credential == null)
            {
                X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
                store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

                X509Certificate2Collection collection  = (X509Certificate2Collection)store.Certificates;
                X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(
                    X509FindType.FindByTimeValid, DateTime.Now, false);

                Boolean rootCertFound = false;
                X509Certificate2Collection fcollection2 = new X509Certificate2Collection();
                foreach (X509Certificate2 fc in fcollection)
                {
                    X509Chain fch = new X509Chain();
                    fch.Build(fc);
                    foreach (X509ChainElement element in fch.ChainElements)
                    {
                        if (rootCertSubject.Contains(element.Certificate.Subject))
                        {
                            rootCertFound = true;
                            fcollection2.Add(fc);
                        }
                    }
                }
                if (rootCertFound)
                {
                    fcollection = fcollection2;
                }

                X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection,
                                                                                                 "Test Certificate Select",
                                                                                                 "Select a certificate from the following list to get information on that certificate",
                                                                                                 X509SelectionFlag.SingleSelection);
                if (scollection.Count != 0)
                {
                    certificate = scollection[0];
                    X509Chain ch = new X509Chain();
                    ch.Build(certificate);

                    string[] X509Base64 = new string[ch.ChainElements.Count];

                    int j = 0;
                    foreach (X509ChainElement element in ch.ChainElements)
                    {
                        X509Base64[j++] = Convert.ToBase64String(element.Certificate.GetRawCertData());
                    }

                    x5c = X509Base64;
                }
            }
            else
            {
                // use old fixed certificate chain
                X509Certificate2Collection xc = new X509Certificate2Collection();
                xc.Import(certFileName, password, X509KeyStorageFlags.PersistKeySet);

                string[] X509Base64 = new string[xc.Count];

                int j   = xc.Count;
                var xce = xc.GetEnumerator();
                for (int i = 0; i < xc.Count; i++)
                {
                    xce.MoveNext();
                    X509Base64[--j] = Convert.ToBase64String(xce.Current.GetRawCertData());
                }
                x5c = X509Base64;

                certificate = new X509Certificate2(certFileName, password);
            }

            string email   = "";
            string subject = certificate.Subject;
            var    split   = subject.Split(new Char[] { ',' });

            if (split[0] != "")
            {
                var split2 = split[0].Split(new Char[] { '=' });
                if (split2[0] == "E")
                {
                    email = split2[1];
                }
            }
            Console.WriteLine("email: " + email);

            //
            StringBuilder builder = new StringBuilder();

            builder.AppendLine("-----BEGIN CERTIFICATE-----");
            builder.AppendLine(
                Convert.ToBase64String(certificate.RawData, Base64FormattingOptions.InsertLineBreaks));
            builder.AppendLine("-----END CERTIFICATE-----");

            System.Windows.Forms.MessageBox.Show(builder.ToString(), "Client Certificate", MessageBoxButtons.OK);
            //

            credential = new X509SigningCredentials(certificate);
            // oz end

            var now = DateTime.UtcNow;

            var token = new JwtSecurityToken(
                clientId,
                audience,
                new List <Claim>()
            {
                new Claim(JwtClaimTypes.JwtId, Guid.NewGuid().ToString()),
                new Claim(JwtClaimTypes.Subject, clientId),
                new Claim(JwtClaimTypes.IssuedAt, now.ToEpochTime().ToString(), ClaimValueTypes.Integer64),
                // OZ
                new Claim(JwtClaimTypes.Email, email)
                // new Claim("x5c", x5c)
            },
                now,
                now.AddMinutes(1),
                credential)
            ;

            token.Header.Add("x5c", x5c);
            // oz

            var tokenHandler = new JwtSecurityTokenHandler();

            return(tokenHandler.WriteToken(token));
        }
Exemplo n.º 30
0
        public static void BuildChain_MicrosoftDotCom_WithRootCertInUserAndSystemRootCertStores()
        {
            // Verifies that when the same root cert is placed in both a user and machine root certificate store,
            // any certs chain building to that root cert will build correctly
            //
            // We use a copy of the microsoft.com SSL certs and root certs to validate that the chain can build
            // successfully

            bool shouldInstallCertToUserStore = true;
            bool installedCertToUserStore     = false;

            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
                using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
                {
                    // Check that microsoft.com's root certificate IS installed in the machine root store as a sanity step
                    using (var machineRootStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
                    {
                        machineRootStore.Open(OpenFlags.ReadOnly);
                        bool foundCert = false;

                        foreach (var machineCert in machineRootStore.Certificates)
                        {
                            if (machineCert.Equals(microsoftDotComRoot))
                            {
                                foundCert = true;
                            }

                            machineCert.Dispose();
                        }

                        Assert.True(foundCert, string.Format("Did not find expected certificate with thumbprint '{0}' in the machine root store", microsoftDotComRoot.Thumbprint));
                    }

                    // Concievably at this point there could still be something wrong and we still don't chain build correctly - if that's
                    // the case, then there's likely something wrong with the machine. Validating that happy path is out of scope
                    // of this particular test.

                    // Check that microsoft.com's root certificate is NOT installed on in the user cert store as a sanity step
                    // We won't try to install the microsoft.com root cert into the user root store if it's already there
                    using (var userRootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
                    {
                        userRootStore.Open(OpenFlags.ReadOnly);

                        foreach (var userCert in userRootStore.Certificates)
                        {
                            bool foundCert = false;
                            if (userCert.Equals(microsoftDotComRoot))
                            {
                                foundCert = true;
                            }

                            userCert.Dispose();

                            if (foundCert)
                            {
                                shouldInstallCertToUserStore = false;
                            }
                        }
                    }

                    using (var userRootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
                        using (var chainHolder = new ChainHolder())
                        {
                            try
                            {
                                if (shouldInstallCertToUserStore)
                                {
                                    try
                                    {
                                        userRootStore.Open(OpenFlags.ReadWrite);
                                    }
                                    catch (CryptographicException)
                                    {
                                        return;
                                    }

                                    userRootStore.Add(microsoftDotComRoot); // throws CryptographicException
                                    installedCertToUserStore = true;
                                }

                                X509Chain chainValidator = chainHolder.Chain;
                                chainValidator.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                                chainValidator.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;

                                bool chainBuildResult = chainValidator.Build(microsoftDotCom);

                                StringBuilder builder = new StringBuilder();
                                foreach (var status in chainValidator.ChainStatus)
                                {
                                    builder.AppendFormat("{0} {1}{2}", status.Status, status.StatusInformation, Environment.NewLine);
                                }

                                Assert.True(chainBuildResult,
                                            string.Format("Certificate chain build failed. ChainStatus is:{0}{1}", Environment.NewLine, builder.ToString()));
                            }
                            finally
                            {
                                if (installedCertToUserStore)
                                {
                                    userRootStore.Remove(microsoftDotComRoot);
                                }
                            }
                        }
                }
        }
Exemplo n.º 31
0
        private static void ConfigureSsl(ConnectionFactory connectionFactory, RabbitMqOptions options,
                                         ILogger <IRabbitMqClient> logger)
        {
            if (options.Ssl is null || string.IsNullOrWhiteSpace(options.Ssl.ServerName))
            {
                connectionFactory.Ssl = new SslOption();
                return;
            }

            connectionFactory.Ssl = new SslOption(options.Ssl.ServerName, options.Ssl.CertificatePath,
                                                  options.Ssl.Enabled);

            logger.LogDebug($"RabbitMQ SSL is: {(options.Ssl.Enabled ? "enabled" : "disabled")}, " +
                            $"server: '{options.Ssl.ServerName}', client certificate: '{options.Ssl.CertificatePath}', " +
                            $"CA certificate: '{options.Ssl.CaCertificatePath}'.");

            if (string.IsNullOrWhiteSpace(options.Ssl.CaCertificatePath))
            {
                return;
            }

            connectionFactory.Ssl.CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
            {
                if (sslPolicyErrors == SslPolicyErrors.None)
                {
                    return(true);
                }

                if (chain is null)
                {
                    return(false);
                }

                chain = new X509Chain();
                var certificate2       = new X509Certificate2(certificate);
                var signerCertificate2 = new X509Certificate2(options.Ssl.CaCertificatePath);
                chain.ChainPolicy.ExtraStore.Add(signerCertificate2);
                chain.Build(certificate2);
                var ignoredStatuses = Enumerable.Empty <X509ChainStatusFlags>();
                if (options.Ssl.X509IgnoredStatuses?.Any() is true)
                {
                    logger.LogDebug("Ignored X509 certificate chain statuses: " +
                                    $"{string.Join(", ", options.Ssl.X509IgnoredStatuses)}.");
                    ignoredStatuses = options.Ssl.X509IgnoredStatuses
                                      .Select(s => Enum.Parse <X509ChainStatusFlags>(s, true));
                }

                var statuses = chain.ChainStatus.ToList();
                logger.LogDebug("Received X509 certificate chain statuses: " +
                                $"{string.Join(", ", statuses.Select(x => x.Status))}");

                var isValid = statuses.All(chainStatus => chainStatus.Status == X509ChainStatusFlags.NoError ||
                                           ignoredStatuses.Contains(chainStatus.Status));
                if (!isValid)
                {
                    logger.LogError(string.Join(Environment.NewLine,
                                                statuses.Select(s => $"{s.Status} - {s.StatusInformation}")));
                }

                return(isValid);
            };
        }
Exemplo n.º 32
0
        public static void VerifyWithRevocation()
        {
            using (var cert = new X509Certificate2(Path.Combine("TestData", "MS.cer")))
                using (var onlineChainHolder = new ChainHolder())
                    using (var offlineChainHolder = new ChainHolder())
                    {
                        X509Chain onlineChain  = onlineChainHolder.Chain;
                        X509Chain offlineChain = offlineChainHolder.Chain;

                        onlineChain.ChainPolicy.VerificationFlags =
                            X509VerificationFlags.AllowUnknownCertificateAuthority;

                        onlineChain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);
                        onlineChain.ChainPolicy.RevocationMode   = X509RevocationMode.Online;
                        onlineChain.ChainPolicy.RevocationFlag   = X509RevocationFlag.EntireChain;

                        // Attempt the online test a couple of times, in case there was just a CRL
                        // download failure.
                        const int RetryLimit = 3;
                        bool      valid      = false;

                        for (int i = 0; i < RetryLimit; i++)
                        {
                            valid = onlineChain.Build(cert);

                            if (valid)
                            {
                                break;
                            }

                            for (int j = 0; j < onlineChain.ChainElements.Count; j++)
                            {
                                X509ChainElement chainElement = onlineChain.ChainElements[j];

                                // Since `NoError` gets mapped as the empty array, just look for non-empty arrays
                                if (chainElement.ChainElementStatus.Length > 0)
                                {
                                    X509ChainStatusFlags allFlags = chainElement.ChainElementStatus.Aggregate(
                                        X509ChainStatusFlags.NoError,
                                        (cur, status) => cur | status.Status);

                                    Console.WriteLine(
                                        $"{nameof(VerifyWithRevocation)}: online attempt {i} - errors at depth {j}: {allFlags}");
                                }

                                chainElement.Certificate.Dispose();
                            }

                            Thread.Sleep(1000); // For network flakiness
                        }

                        if (TestEnvironmentConfiguration.RunManualTests)
                        {
                            Assert.True(valid, $"Online Chain Built Validly within {RetryLimit} tries");
                        }
                        else if (!valid)
                        {
                            Console.WriteLine($"SKIP [{nameof(VerifyWithRevocation)}]: Chain failed to build within {RetryLimit} tries.");
                            return;
                        }

                        // Since the network was enabled, we should get the whole chain.
                        Assert.Equal(3, onlineChain.ChainElements.Count);

                        Assert.Equal(0, onlineChain.ChainElements[0].ChainElementStatus.Length);
                        Assert.Equal(0, onlineChain.ChainElements[1].ChainElementStatus.Length);

                        // The root CA is not expected to be installed on everyone's machines,
                        // so allow for it to report UntrustedRoot, but nothing else..
                        X509ChainStatus[] rootElementStatus = onlineChain.ChainElements[2].ChainElementStatus;

                        if (rootElementStatus.Length != 0)
                        {
                            Assert.Equal(1, rootElementStatus.Length);
                            Assert.Equal(X509ChainStatusFlags.UntrustedRoot, rootElementStatus[0].Status);
                        }

                        // Now that everything is cached, try again in Offline mode.
                        offlineChain.ChainPolicy.VerificationFlags = onlineChain.ChainPolicy.VerificationFlags;
                        offlineChain.ChainPolicy.VerificationTime  = onlineChain.ChainPolicy.VerificationTime;
                        offlineChain.ChainPolicy.RevocationMode    = X509RevocationMode.Offline;
                        offlineChain.ChainPolicy.RevocationFlag    = onlineChain.ChainPolicy.RevocationFlag;

                        valid = offlineChain.Build(cert);
                        Assert.True(valid, "Offline Chain Built Validly");

                        // Everything should look just like the online chain:
                        Assert.Equal(onlineChain.ChainElements.Count, offlineChain.ChainElements.Count);

                        for (int i = 0; i < offlineChain.ChainElements.Count; i++)
                        {
                            X509ChainElement onlineElement  = onlineChain.ChainElements[i];
                            X509ChainElement offlineElement = offlineChain.ChainElements[i];

                            Assert.Equal(onlineElement.ChainElementStatus, offlineElement.ChainElementStatus);
                            Assert.Equal(onlineElement.Certificate, offlineElement.Certificate);
                        }
                    }
        }
Exemplo n.º 33
0
        public static void BuildInvalidSignatureTwice(
            X509ChainStatusFlags endEntityErrors,
            X509ChainStatusFlags intermediateErrors,
            X509ChainStatusFlags rootErrors)
        {
            TestDataGenerator.MakeTestChain3(
                out X509Certificate2 endEntityCert,
                out X509Certificate2 intermediateCert,
                out X509Certificate2 rootCert);

            X509Certificate2 TamperIfNeeded(X509Certificate2 input, X509ChainStatusFlags flags)
            {
                if ((flags & X509ChainStatusFlags.NotSignatureValid) != 0)
                {
                    X509Certificate2 tampered = TamperSignature(input);
                    input.Dispose();
                    return(tampered);
                }

                return(input);
            }

            DateTime RewindIfNeeded(DateTime input, X509Certificate2 cert, X509ChainStatusFlags flags)
            {
                if ((flags & X509ChainStatusFlags.NotTimeValid) != 0)
                {
                    return(cert.NotBefore.AddMinutes(-1));
                }

                return(input);
            }

            int expectedCount = 3;

            DateTime verificationTime = endEntityCert.NotBefore.AddMinutes(1);

            verificationTime = RewindIfNeeded(verificationTime, endEntityCert, endEntityErrors);
            verificationTime = RewindIfNeeded(verificationTime, intermediateCert, intermediateErrors);
            verificationTime = RewindIfNeeded(verificationTime, rootCert, rootErrors);

            // Replace the certs for the scenario.
            endEntityCert    = TamperIfNeeded(endEntityCert, endEntityErrors);
            intermediateCert = TamperIfNeeded(intermediateCert, intermediateErrors);
            rootCert         = TamperIfNeeded(rootCert, rootErrors);

            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // For the lower levels, turn NotSignatureValid into PartialChain,
                // and clear all errors at higher levels.

                if ((endEntityErrors & X509ChainStatusFlags.NotSignatureValid) != 0)
                {
                    expectedCount      = 1;
                    endEntityErrors   &= ~X509ChainStatusFlags.NotSignatureValid;
                    endEntityErrors   |= X509ChainStatusFlags.PartialChain;
                    intermediateErrors = X509ChainStatusFlags.NoError;
                    rootErrors         = X509ChainStatusFlags.NoError;
                }
                else if ((intermediateErrors & X509ChainStatusFlags.NotSignatureValid) != 0)
                {
                    expectedCount       = 2;
                    intermediateErrors &= ~X509ChainStatusFlags.NotSignatureValid;
                    intermediateErrors |= X509ChainStatusFlags.PartialChain;
                    rootErrors          = X509ChainStatusFlags.NoError;
                }
                else if ((rootErrors & X509ChainStatusFlags.NotSignatureValid) != 0)
                {
                    rootErrors &= ~X509ChainStatusFlags.NotSignatureValid;

                    // On 10.12 this is just UntrustedRoot.
                    // On 10.13+ it becomes PartialChain, and UntrustedRoot goes away.
                    if (PlatformDetection.IsMacOsHighSierraOrHigher)
                    {
                        rootErrors &= ~X509ChainStatusFlags.UntrustedRoot;
                        rootErrors |= X509ChainStatusFlags.PartialChain;
                    }
                }
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                // Windows only reports NotTimeValid on the start-of-chain (end-entity in this case)
                // If it were possible in this suite to get only a higher-level cert as NotTimeValid
                // without the lower one, that would have resulted in NotTimeNested.
                intermediateErrors &= ~X509ChainStatusFlags.NotTimeValid;
                rootErrors         &= ~X509ChainStatusFlags.NotTimeValid;
            }

            X509ChainStatusFlags expectedAllErrors = endEntityErrors | intermediateErrors | rootErrors;

            // If PartialChain or UntrustedRoot are the only remaining errors, the chain will succeed.
            const X509ChainStatusFlags SuccessCodes =
                X509ChainStatusFlags.UntrustedRoot | X509ChainStatusFlags.PartialChain;

            bool expectSuccess = (expectedAllErrors & ~SuccessCodes) == 0;

            using (endEntityCert)
                using (intermediateCert)
                    using (rootCert)
                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            X509Chain chain = chainHolder.Chain;
                            chain.ChainPolicy.VerificationTime = verificationTime;
                            chain.ChainPolicy.RevocationMode   = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.ExtraStore.Add(intermediateCert);
                            chain.ChainPolicy.ExtraStore.Add(rootCert);

                            chain.ChainPolicy.VerificationFlags |=
                                X509VerificationFlags.AllowUnknownCertificateAuthority;

                            int i = 0;

                            void CheckChain()
                            {
                                i++;

                                bool valid = chain.Build(endEntityCert);

                                if (expectSuccess)
                                {
                                    Assert.True(valid, $"Chain build on iteration {i}");
                                }
                                else
                                {
                                    Assert.False(valid, $"Chain build on iteration {i}");
                                }

                                Assert.Equal(expectedCount, chain.ChainElements.Count);
                                Assert.Equal(expectedAllErrors, chain.AllStatusFlags());

                                Assert.Equal(endEntityErrors, chain.ChainElements[0].AllStatusFlags());

                                if (expectedCount > 2)
                                {
                                    Assert.Equal(rootErrors, chain.ChainElements[2].AllStatusFlags());
                                }

                                if (expectedCount > 1)
                                {
                                    Assert.Equal(intermediateErrors, chain.ChainElements[1].AllStatusFlags());
                                }

                                chainHolder.DisposeChainElements();
                            }

                            CheckChain();
                            CheckChain();
                        }
        }
Exemplo n.º 34
0
        protected X509Certificate SelectClientCertificate(string[] acceptableIssuers)
        {
            if (Settings.DisallowUnauthenticatedCertificateRequest && !IsAuthenticated)
            {
                return(null);
            }

            if (RemoteCertificate == null)
            {
                throw new TlsException(AlertDescription.InternalError, "Cannot request client certificate before receiving one from the server.");
            }

            /*
             * We need to pass null to the user selection callback during the initial handshake, to allow the callback to distinguish
             * between an authenticated and unauthenticated session.
             */
            X509Certificate certificate;
            var             selected = certificateValidator.SelectClientCertificate(
                TargetHost, ClientCertificates, IsAuthenticated ? RemoteCertificate : null, acceptableIssuers, out certificate);

            if (selected)
            {
                return(certificate);
            }

            if (ClientCertificates == null || ClientCertificates.Count == 0)
            {
                return(null);
            }

            /*
             * .NET actually scans the entire collection to ensure the selected certificate has a private key in it.
             *
             * However, since we do not support private key retrieval from the key store, we require all certificates
             * to have a private key in them (explicitly or implicitly via OS X keychain lookup).
             */
            if (acceptableIssuers == null || acceptableIssuers.Length == 0)
            {
                return(ClientCertificates [0]);
            }

            // Copied from the referencesource implementation in referencesource/System/net/System/Net/_SecureChannel.cs.
            for (int i = 0; i < ClientCertificates.Count; i++)
            {
                var certificate2 = ClientCertificates[i] as X509Certificate2;
                if (certificate2 == null)
                {
                    continue;
                }

                X509Chain chain = null;
                try {
                    chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreInvalidName;
                    chain.Build(certificate2);

                    //
                    // We ignore any errors happened with chain.
                    // Consider: try to locate the "best" client cert that has no errors and the lognest validity internal
                    //
                    if (chain.ChainElements.Count == 0)
                    {
                        continue;
                    }
                    for (int ii = 0; ii < chain.ChainElements.Count; ++ii)
                    {
                        var issuer = chain.ChainElements[ii].Certificate.Issuer;
                        if (Array.IndexOf(acceptableIssuers, issuer) != -1)
                        {
                            return(certificate2);
                        }
                    }
                } catch {
                    ;                     // ignore errors
                } finally {
                    if (chain != null)
                    {
                        chain.Reset();
                    }
                }
            }

            // No certificate matches.
            return(null);
        }
Exemplo n.º 35
0
        public static void VerifyWithRevocation()
        {
            using (var cert = new X509Certificate2(Path.Combine("TestData", "MS.cer")))
            using (var onlineChain = new X509Chain())
            using (var offlineChain = new X509Chain())
            {
                onlineChain.ChainPolicy.VerificationFlags =
                    X509VerificationFlags.AllowUnknownCertificateAuthority;

                onlineChain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);
                onlineChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                onlineChain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;

                bool valid = onlineChain.Build(cert);
                Assert.True(valid, "Online Chain Built Validly");

                // Since the network was enabled, we should get the whole chain.
                Assert.Equal(3, onlineChain.ChainElements.Count);

                Assert.Equal(0, onlineChain.ChainElements[0].ChainElementStatus.Length);
                Assert.Equal(0, onlineChain.ChainElements[1].ChainElementStatus.Length);

                // The root CA is not expected to be installed on everyone's machines,
                // so allow for it to report UntrustedRoot, but nothing else..
                X509ChainStatus[] rootElementStatus = onlineChain.ChainElements[2].ChainElementStatus;
                
                if (rootElementStatus.Length != 0)
                {
                    Assert.Equal(1, rootElementStatus.Length);
                    Assert.Equal(X509ChainStatusFlags.UntrustedRoot, rootElementStatus[0].Status);
                }

                // Now that everything is cached, try again in Offline mode.
                offlineChain.ChainPolicy.VerificationFlags = onlineChain.ChainPolicy.VerificationFlags;
                offlineChain.ChainPolicy.VerificationTime = onlineChain.ChainPolicy.VerificationTime;
                offlineChain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
                offlineChain.ChainPolicy.RevocationFlag = onlineChain.ChainPolicy.RevocationFlag;

                valid = offlineChain.Build(cert);
                Assert.True(valid, "Offline Chain Built Validly");

                // Everything should look just like the online chain:
                Assert.Equal(onlineChain.ChainElements.Count, offlineChain.ChainElements.Count);

                for (int i = 0; i < offlineChain.ChainElements.Count; i++)
                {
                    X509ChainElement onlineElement = onlineChain.ChainElements[i];
                    X509ChainElement offlineElement = offlineChain.ChainElements[i];

                    Assert.Equal(onlineElement.ChainElementStatus, offlineElement.ChainElementStatus);
                    Assert.Equal(onlineElement.Certificate, offlineElement.Certificate);
                }
            }
        }
Exemplo n.º 36
0
        private static uint HandleEventPeerCertificateReceived(State state, ref ConnectionEvent connectionEvent)
        {
            SslPolicyErrors            sslPolicyErrors        = SslPolicyErrors.None;
            X509Chain?                 chain                  = null;
            X509Certificate2?          certificate            = null;
            X509Certificate2Collection?additionalCertificates = null;

            MsQuicConnection?connection = state.Connection;

            if (connection == null)
            {
                return(MsQuicStatusCodes.InvalidState);
            }

            if (connection._isServer)
            {
                state.Connection = null;
            }

            try
            {
                if (connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle != IntPtr.Zero)
                {
                    if (OperatingSystem.IsWindows())
                    {
                        certificate = new X509Certificate2(connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle);
                    }
                    else
                    {
                        unsafe
                        {
                            ReadOnlySpan <QuicBuffer> quicBuffer = new ReadOnlySpan <QuicBuffer>((void *)connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle, sizeof(QuicBuffer));
                            certificate = new X509Certificate2(new ReadOnlySpan <byte>(quicBuffer[0].Buffer, (int)quicBuffer[0].Length));

                            if (connectionEvent.Data.PeerCertificateReceived.PlatformCertificateChainHandle != IntPtr.Zero)
                            {
                                quicBuffer = new ReadOnlySpan <QuicBuffer>((void *)connectionEvent.Data.PeerCertificateReceived.PlatformCertificateChainHandle, sizeof(QuicBuffer));
                                if (quicBuffer[0].Length != 0 && quicBuffer[0].Buffer != null)
                                {
                                    additionalCertificates = new X509Certificate2Collection();
                                    additionalCertificates.Import(new ReadOnlySpan <byte>(quicBuffer[0].Buffer, (int)quicBuffer[0].Length));
                                }
                            }
                        }
                    }
                }

                if (certificate == null)
                {
                    if (NetEventSource.Log.IsEnabled() && connection._remoteCertificateRequired)
                    {
                        NetEventSource.Error(state.Connection, "Remote certificate required, but no remote certificate received");
                    }
                    sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable;
                }
                else
                {
                    chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode = connection._revocationMode;
                    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
                    chain.ChainPolicy.ApplicationPolicy.Add(connection._isServer ? s_clientAuthOid : s_serverAuthOid);

                    if (additionalCertificates != null && additionalCertificates.Count > 1)
                    {
                        chain.ChainPolicy.ExtraStore.AddRange(additionalCertificates);
                    }

                    if (!chain.Build(certificate))
                    {
                        sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
                    }
                }

                if (!connection._remoteCertificateRequired)
                {
                    sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNotAvailable;
                }

                if (connection._remoteCertificateValidationCallback != null)
                {
                    bool success = connection._remoteCertificateValidationCallback(connection, certificate, chain, sslPolicyErrors);
                    if (!success && NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Error(state, $"[Connection#{state.GetHashCode()}] remote  certificate rejected by verification callback");
                    }
                    return(success ? MsQuicStatusCodes.Success : MsQuicStatusCodes.HandshakeFailure);
                }

                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Info(state, $"[Connection#{state.GetHashCode()}] certificate validation for '${certificate?.Subject}' finished with ${sslPolicyErrors}");
                }

                return((sslPolicyErrors == SslPolicyErrors.None) ? MsQuicStatusCodes.Success : MsQuicStatusCodes.HandshakeFailure);
            }
            catch (Exception ex)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(state, $"[Connection#{state.GetHashCode()}] certificate validation failed ${ex.Message}");
                }
            }

            return(MsQuicStatusCodes.InternalError);
        }
Exemplo n.º 37
0
		void LocalValidation (ClientContext context, AlertDescription description)
		{
			// the leaf is the web server certificate
			X509Certificate leaf = certificates [0];
			X509Cert.X509Certificate cert = new X509Cert.X509Certificate (leaf.RawData);

			ArrayList errors = new ArrayList();

			// SSL specific check - not all certificates can be 
			// used to server-side SSL some rules applies after 
			// all ;-)
			if (!checkCertificateUsage (leaf)) 
			{
				// WinError.h CERT_E_PURPOSE 0x800B0106
				errors.Add ((int)-2146762490);
			}

			// SSL specific check - does the certificate match 
			// the host ?
			if (!checkServerIdentity (leaf))
			{
				// WinError.h CERT_E_CN_NO_MATCH 0x800B010F
				errors.Add ((int)-2146762481);
			}

			// Note: building and verifying a chain can take much time
			// so we do it last (letting simple things fails first)

			// Note: In TLS the certificates MUST be in order (and
			// optionally include the root certificate) so we're not
			// building the chain using LoadCertificate (it's faster)

			// Note: IIS doesn't seem to send the whole certificate chain
			// but only the server certificate :-( it's assuming that you
			// already have this chain installed on your computer. duh!
			// http://groups.google.ca/groups?q=IIS+server+certificate+chain&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=85058s%24avd%241%40nnrp1.deja.com&rnum=3

			// we must remove the leaf certificate from the chain
			X509CertificateCollection chain = new X509CertificateCollection (certificates);
			chain.Remove (leaf);
			X509Chain verify = new X509Chain (chain);

			bool result = false;

			try
			{
				result = verify.Build (leaf);
			}
			catch (Exception)
			{
				result = false;
			}

			if (!result) 
			{
				switch (verify.Status) 
				{
					case X509ChainStatusFlags.InvalidBasicConstraints:
						// WinError.h TRUST_E_BASIC_CONSTRAINTS 0x80096019
						errors.Add ((int)-2146869223);
						break;
					
					case X509ChainStatusFlags.NotSignatureValid:
						// WinError.h TRUST_E_BAD_DIGEST 0x80096010
						errors.Add ((int)-2146869232);
						break;
					
					case X509ChainStatusFlags.NotTimeNested:
						// WinError.h CERT_E_VALIDITYPERIODNESTING 0x800B0102
						errors.Add ((int)-2146762494);
						break;
					
					case X509ChainStatusFlags.NotTimeValid:
						// WinError.h CERT_E_EXPIRED 0x800B0101
						description = AlertDescription.CertificateExpired;
						errors.Add ((int)-2146762495);
						break;
					
					case X509ChainStatusFlags.PartialChain:
						// WinError.h CERT_E_CHAINING 0x800B010A
						description = AlertDescription.UnknownCA;
						errors.Add ((int)-2146762486);
						break;
					
					case X509ChainStatusFlags.UntrustedRoot:
						// WinError.h CERT_E_UNTRUSTEDROOT 0x800B0109
						description = AlertDescription.UnknownCA;
						errors.Add ((int)-2146762487);
						break;
					
					default:
						// unknown error
						description = AlertDescription.CertificateUnknown;
						errors.Add ((int)verify.Status);
						break;
				}
			}

			int[] certificateErrors = (int[])errors.ToArray(typeof(int));

			if (!context.SslStream.RaiseServerCertificateValidation(
				cert, 
				certificateErrors))
			{
				throw new TlsException(
					description,
					"Invalid certificate received from server.");
			}
		}
Exemplo n.º 38
0
        internal SignerInfoAsn Sign(
            ReadOnlyMemory <byte> data,
            string contentTypeOid,
            bool silent,
            out X509Certificate2Collection chainCerts)
        {
            HashAlgorithmName hashAlgorithmName = Helpers.GetDigestAlgorithm(DigestAlgorithm);
            IncrementalHash   hasher            = IncrementalHash.CreateHash(hashAlgorithmName);

            hasher.AppendData(data.Span);
            byte[] dataHash = hasher.GetHashAndReset();

            SignerInfoAsn newSignerInfo = new SignerInfoAsn();

            newSignerInfo.DigestAlgorithm.Algorithm = DigestAlgorithm;

            // If the user specified attributes (not null, count > 0) we need attributes.
            // If the content type is null we're counter-signing, and need the message digest attr.
            // If the content type is otherwise not-data we need to record it as the content-type attr.
            if (SignedAttributes?.Count > 0 || contentTypeOid != Oids.Pkcs7Data)
            {
                List <AttributeAsn> signedAttrs = BuildAttributes(SignedAttributes);

                using (var writer = new AsnWriter(AsnEncodingRules.DER))
                {
                    writer.PushSetOf();
                    writer.WriteOctetString(dataHash);
                    writer.PopSetOf();

                    signedAttrs.Add(
                        new AttributeAsn
                    {
                        AttrType   = new Oid(Oids.MessageDigest, Oids.MessageDigest),
                        AttrValues = writer.Encode(),
                    });
                }

                if (contentTypeOid != null)
                {
                    using (var writer = new AsnWriter(AsnEncodingRules.DER))
                    {
                        writer.PushSetOf();
                        writer.WriteObjectIdentifier(contentTypeOid);
                        writer.PopSetOf();

                        signedAttrs.Add(
                            new AttributeAsn
                        {
                            AttrType   = new Oid(Oids.ContentType, Oids.ContentType),
                            AttrValues = writer.Encode(),
                        });
                    }
                }

                // Use the serializer/deserializer to DER-normalize the attribute order.
                newSignerInfo.SignedAttributes = Helpers.NormalizeSet(
                    signedAttrs.ToArray(),
                    normalized =>
                {
                    AsnReader reader = new AsnReader(normalized, AsnEncodingRules.DER);
                    hasher.AppendData(reader.PeekContentBytes().Span);
                });

                dataHash = hasher.GetHashAndReset();
            }

            switch (SignerIdentifierType)
            {
            case SubjectIdentifierType.IssuerAndSerialNumber:
                byte[] serial = Certificate.GetSerialNumber();
                Array.Reverse(serial);

                newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn
                {
                    Issuer       = Certificate.IssuerName.RawData,
                    SerialNumber = serial,
                };

                newSignerInfo.Version = 1;
                break;

            case SubjectIdentifierType.SubjectKeyIdentifier:
                newSignerInfo.Sid.SubjectKeyIdentifier = Certificate.GetSubjectKeyIdentifier();
                newSignerInfo.Version = 3;
                break;

            case SubjectIdentifierType.NoSignature:
                newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn
                {
                    Issuer       = SubjectIdentifier.DummySignerEncodedValue,
                    SerialNumber = new byte[1],
                };
                newSignerInfo.Version = 1;
                break;

            default:
                Debug.Fail($"Unresolved SignerIdentifierType value: {SignerIdentifierType}");
                throw new CryptographicException();
            }

            if (UnsignedAttributes != null && UnsignedAttributes.Count > 0)
            {
                List <AttributeAsn> attrs = BuildAttributes(UnsignedAttributes);

                newSignerInfo.UnsignedAttributes = Helpers.NormalizeSet(attrs.ToArray());
            }

            bool signed = CmsSignature.Sign(
                dataHash,
                hashAlgorithmName,
                Certificate,
                PrivateKey,
                silent,
                out Oid signatureAlgorithm,
                out ReadOnlyMemory <byte> signatureValue);

            if (!signed)
            {
                throw new CryptographicException(SR.Cryptography_Cms_CannotDetermineSignatureAlgorithm);
            }

            newSignerInfo.SignatureValue = signatureValue;
            newSignerInfo.SignatureAlgorithm.Algorithm = signatureAlgorithm;

            X509Certificate2Collection certs = new X509Certificate2Collection();

            certs.AddRange(Certificates);

            if (SignerIdentifierType != SubjectIdentifierType.NoSignature)
            {
                if (IncludeOption == X509IncludeOption.EndCertOnly)
                {
                    certs.Add(Certificate);
                }
                else if (IncludeOption != X509IncludeOption.None)
                {
                    X509Chain chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;

                    if (!chain.Build(Certificate))
                    {
                        foreach (X509ChainStatus status in chain.ChainStatus)
                        {
                            if (status.Status == X509ChainStatusFlags.PartialChain)
                            {
                                throw new CryptographicException(SR.Cryptography_Cms_IncompleteCertChain);
                            }
                        }
                    }

                    X509ChainElementCollection elements = chain.ChainElements;
                    int count = elements.Count;
                    int last  = count - 1;

                    if (last == 0)
                    {
                        // If there's always one cert treat it as EE, not root.
                        last = -1;
                    }

                    for (int i = 0; i < count; i++)
                    {
                        X509Certificate2 cert = elements[i].Certificate;

                        if (i == last &&
                            IncludeOption == X509IncludeOption.ExcludeRoot &&
                            cert.SubjectName.RawData.AsSpan().SequenceEqual(cert.IssuerName.RawData))
                        {
                            break;
                        }

                        certs.Add(cert);
                    }
                }
            }

            chainCerts = certs;
            return(newSignerInfo);
        }
Exemplo n.º 39
0
        public virtual IAsyncResult BeginAuthenticateAsClient(string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
        {
            if (IsAuthenticated)
            {
                throw new InvalidOperationException("This SslStream is already authenticated");
            }

            SslClientStream s = new SslClientStream(InnerStream, targetHost, !LeaveInnerStreamOpen, GetMonoSslProtocol(enabledSslProtocols), clientCertificates);

            s.CheckCertRevocationStatus = checkCertificateRevocation;

            // Due to the Mono.Security internal, it cannot reuse
            // the delegated argument, as Mono.Security creates
            // another instance of X509Certificate which lacks
            // private key but is filled the private key via this
            // delegate.
            s.PrivateKeyCertSelectionDelegate = delegate(X509Certificate cert, string host) {
                string hash = cert.GetCertHashString();
                // ... so, we cannot use the delegate argument.
                foreach (X509Certificate cc in clientCertificates)
                {
                    if (cc.GetCertHashString() != hash)
                    {
                        continue;
                    }
                    X509Certificate2 cert2 = cc as X509Certificate2;
                    cert2 = cert2 ?? new X509Certificate2(cc);
                    return(cert2.PrivateKey);
                }
                return(null);
            };

#if MONOTOUCH || MONODROID
            // Even if validation_callback is null this allows us to verify requests where the user
            // does not provide a verification callback but attempts to authenticate with the website
            // as a client (see https://bugzilla.xamarin.com/show_bug.cgi?id=18962 for an example)
            var helper = new ServicePointManager.ChainValidationHelper(this, targetHost);
            helper.ServerCertificateValidationCallback = validation_callback;
            s.ServerCertValidation2 += new CertificateValidationCallback2(helper.ValidateChain);
#else
            if (validation_callback != null)
            {
                s.ServerCertValidationDelegate = delegate(X509Certificate cert, int [] certErrors) {
                    X509Chain        chain = new X509Chain();
                    X509Certificate2 x2    = (cert as X509Certificate2);
                    if (x2 == null)
                    {
                        x2 = new X509Certificate2(cert);
                    }

                    if (!ServicePointManager.CheckCertificateRevocationList)
                    {
                        chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                    }

                    // SSL specific checks (done by Mono.Security.dll SSL/TLS implementation)
                    SslPolicyErrors errors = SslPolicyErrors.None;
                    foreach (int i in certErrors)
                    {
                        switch (i)
                        {
                        case -2146762490:                         // CERT_E_PURPOSE
                            errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
                            break;

                        case -2146762481:                         // CERT_E_CN_NO_MATCH
                            errors |= SslPolicyErrors.RemoteCertificateNameMismatch;
                            break;

                        default:
                            errors |= SslPolicyErrors.RemoteCertificateChainErrors;
                            break;
                        }
                    }

                    chain.Build(x2);

                    // non-SSL specific X509 checks (i.e. RFC3280 related checks)
                    foreach (X509ChainStatus status in chain.ChainStatus)
                    {
                        if (status.Status == X509ChainStatusFlags.NoError)
                        {
                            continue;
                        }
                        if ((status.Status & X509ChainStatusFlags.PartialChain) != 0)
                        {
                            errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
                        }
                        else
                        {
                            errors |= SslPolicyErrors.RemoteCertificateChainErrors;
                        }
                    }

                    return(validation_callback(this, cert, chain, errors));
                };
            }
#endif
            if (selection_callback != null)
            {
                s.ClientCertSelectionDelegate = OnCertificateSelection;
            }

            ssl_stream = s;

            return(BeginWrite(new byte [0], 0, 0, asyncCallback, asyncState));
        }
Exemplo n.º 40
0
        protected async Task <MetadataTOCPayload> DeserializeAndValidateToc(string rawTocJwt)
        {
            if (string.IsNullOrWhiteSpace(rawTocJwt))
            {
                throw new ArgumentNullException(nameof(rawTocJwt));
            }

            var jwtParts = rawTocJwt.Split('.');

            if (jwtParts.Length != 3)
            {
                throw new ArgumentException("The JWT does not have the 3 expected components");
            }

            var tocHeaderString = jwtParts.First();
            var tocHeader       = JObject.Parse(Encoding.UTF8.GetString(Base64Url.Decode(tocHeaderString)));

            var tocAlg = tocHeader["alg"]?.Value <string>();

            if (tocAlg == null)
            {
                throw new ArgumentNullException("No alg value was present in the TOC header.");
            }

            var x5cArray = tocHeader["x5c"] as JArray;

            if (x5cArray == null)
            {
                throw new Exception("No x5c array was present in the TOC header.");
            }

            var keyStrings = x5cArray.Values <string>().ToList();

            if (keyStrings.Count == 0)
            {
                throw new ArgumentException("No keys were present in the TOC header.");
            }

            var rootCert      = GetX509Certificate(ROOT_CERT);
            var tocCerts      = keyStrings.Select(o => GetX509Certificate(o)).ToArray();
            var tocPublicKeys = keyStrings.Select(o => GetECDsaPublicKey(o)).ToArray();

            var certChain = new X509Chain();

            certChain.ChainPolicy.ExtraStore.Add(rootCert);
            certChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

            var validationParameters = new TokenValidationParameters
            {
                ValidateIssuer           = false,
                ValidateAudience         = false,
                ValidateLifetime         = false,
                ValidateIssuerSigningKey = true,
                IssuerSigningKeys        = tocPublicKeys,
            };

            var tokenHandler = new JwtSecurityTokenHandler();

            tokenHandler.ValidateToken(
                rawTocJwt,
                validationParameters,
                out var validatedToken);

            if (tocCerts.Length > 1)
            {
                certChain.ChainPolicy.ExtraStore.AddRange(tocCerts.Skip(1).ToArray());
            }

            var certChainIsValid = certChain.Build(tocCerts.First());

            // if the root is trusted in the context we are running in, valid should be true here
            if (!certChainIsValid)
            {
                foreach (var element in certChain.ChainElements)
                {
                    if (element.Certificate.Issuer != element.Certificate.Subject)
                    {
                        var cdp     = CryptoUtils.CDPFromCertificateExts(element.Certificate.Extensions);
                        var crlFile = await DownloadDataAsync(cdp);

                        if (true == CryptoUtils.IsCertInCRL(crlFile, element.Certificate))
                        {
                            throw new Fido2VerificationException(string.Format("Cert {0} found in CRL {1}", element.Certificate.Subject, cdp));
                        }
                    }
                }

                // otherwise we have to manually validate that the root in the chain we are testing is the root we downloaded
                if (rootCert.Thumbprint == certChain.ChainElements[certChain.ChainElements.Count - 1].Certificate.Thumbprint &&
                    // and that the number of elements in the chain accounts for what was in x5c plus the root we added
                    certChain.ChainElements.Count == (keyStrings.Count + 1) &&
                    // and that the root cert has exactly one status listed against it
                    certChain.ChainElements[certChain.ChainElements.Count - 1].ChainElementStatus.Length == 1 &&
                    // and that that status is a status of exactly UntrustedRoot
                    certChain.ChainElements[certChain.ChainElements.Count - 1].ChainElementStatus[0].Status == X509ChainStatusFlags.UntrustedRoot)
                {
                    // if we are good so far, that is a good sign
                    certChainIsValid = true;
                    for (var i = 0; i < certChain.ChainElements.Count - 1; i++)
                    {
                        // check each non-root cert to verify zero status listed against it, otherwise, invalidate chain
                        if (0 != certChain.ChainElements[i].ChainElementStatus.Length)
                        {
                            certChainIsValid = false;
                        }
                    }
                }
            }

            if (!certChainIsValid)
            {
                throw new Fido2VerificationException("Failed to validate cert chain while parsing TOC");
            }

            var tocPayload = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson();

            var toc = Newtonsoft.Json.JsonConvert.DeserializeObject <MetadataTOCPayload>(tocPayload);

            toc.JwtAlg = tocAlg;
            return(toc);
        }
Exemplo n.º 41
0
			// Used when the obsolete ICertificatePolicy is set to DefaultCertificatePolicy
			// and the new ServerCertificateValidationCallback is not null
			internal ValidationResult ValidateChain (Mono.Security.X509.X509CertificateCollection certs)
			{
				// user_denied is true if the user callback is called and returns false
				bool user_denied = false;
				if (certs == null || certs.Count == 0)
					return null;

				ICertificatePolicy policy = ServicePointManager.CertificatePolicy;
				RemoteCertificateValidationCallback cb = ServicePointManager.ServerCertificateValidationCallback;

				X509Chain chain = new X509Chain ();
				chain.ChainPolicy = new X509ChainPolicy ();
				chain.ChainPolicy.RevocationMode = revocation_mode;
				for (int i = 1; i < certs.Count; i++) {
					X509Certificate2 c2 = new X509Certificate2 (certs [i].RawData);
					chain.ChainPolicy.ExtraStore.Add (c2);
				}

				X509Certificate2 leaf = new X509Certificate2 (certs [0].RawData);
				int status11 = 0; // Error code passed to the obsolete ICertificatePolicy callback
				SslPolicyErrors errors = 0;
				try {
					if (!chain.Build (leaf))
						errors |= GetErrorsFromChain (chain);
				} catch (Exception e) {
					Console.Error.WriteLine ("ERROR building certificate chain: {0}", e);
					Console.Error.WriteLine ("Please, report this problem to the Mono team");
					errors |= SslPolicyErrors.RemoteCertificateChainErrors;
				}

				if (!CheckCertificateUsage (leaf)) {
					errors |= SslPolicyErrors.RemoteCertificateChainErrors;
					status11 = -2146762490; //CERT_E_PURPOSE 0x800B0106
				}

				if (!CheckServerIdentity (certs [0], Host)) {
					errors |= SslPolicyErrors.RemoteCertificateNameMismatch;
					status11 = -2146762481; // CERT_E_CN_NO_MATCH 0x800B010F
				}

				bool result = false;
				// No certificate root found means no mozroots or monotouch
#if !MONOTOUCH
				if (is_macosx) {
#endif
					// Attempt to use OSX certificates
					// Ideally we should return the SecTrustResult
					MSX.OSX509Certificates.SecTrustResult trustResult;
					try {
						trustResult = MSX.OSX509Certificates.TrustEvaluateSsl (certs);
						// We could use the other values of trustResult to pass this extra information
						// to the .NET 2 callback for values like SecTrustResult.Confirm
						result = (trustResult == MSX.OSX509Certificates.SecTrustResult.Proceed ||
								  trustResult == MSX.OSX509Certificates.SecTrustResult.Unspecified);

					} catch {
						// Ignore
					}
					// Clear error status if the OS told us to trust the certificate
					if (result) {
						status11 = 0;
						errors = 0;
					}
#if !MONOTOUCH
				}
#endif

				if (policy != null && (!(policy is DefaultCertificatePolicy) || cb == null)) {
					ServicePoint sp = null;
					HttpWebRequest req = sender as HttpWebRequest;
					if (req != null)
						sp = req.ServicePoint;
					if (status11 == 0 && errors != 0)
						status11 = GetStatusFromChain (chain);

					// pre 2.0 callback
					result = policy.CheckValidationResult (sp, leaf, req, status11);
					user_denied = !result && !(policy is DefaultCertificatePolicy);
				}
				// If there's a 2.0 callback, it takes precedence
				if (cb != null) {
					result = cb (sender, leaf, chain, errors);
					user_denied = !result;
				}
				return new ValidationResult (result, user_denied, status11);
			}
        public void Build_Null()
        {
            X509Chain c = new X509Chain();

            c.Build(null);
        }
Exemplo n.º 43
0
		public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
		{
			if (IsAuthenticated)
				throw new InvalidOperationException ("This SslStream is already authenticated");

			SslServerStream s = new SslServerStream (InnerStream, serverCertificate, clientCertificateRequired, !LeaveInnerStreamOpen, GetMonoSslProtocol (enabledSslProtocols));
			s.CheckCertRevocationStatus = checkCertificateRevocation;
			// Due to the Mono.Security internal, it cannot reuse
			// the delegated argument, as Mono.Security creates 
			// another instance of X509Certificate which lacks 
			// private key but is filled the private key via this
			// delegate.
			s.PrivateKeyCertSelectionDelegate = delegate (X509Certificate cert, string targetHost) {
				// ... so, we cannot use the delegate argument.
				X509Certificate2 cert2 = serverCertificate as X509Certificate2 ?? new X509Certificate2 (serverCertificate);
				return cert2 != null ? cert2.PrivateKey : null;
			};

			if (validation_callback != null)
				s.ClientCertValidationDelegate = delegate (X509Certificate cert, int [] certErrors) {
					X509Chain chain = null;
					if (cert is X509Certificate2) {
						chain = new X509Chain ();
						chain.Build ((X509Certificate2) cert);
					}
					// FIXME: SslPolicyErrors is incomplete
					SslPolicyErrors errors = certErrors.Length > 0 ? SslPolicyErrors.RemoteCertificateChainErrors : SslPolicyErrors.None;
					return validation_callback (this, cert, chain, errors);
				};

			ssl_stream = s;

			return BeginWrite (new byte[0], 0, 0, asyncCallback, asyncState);
		}
        public void Build_Empty()
        {
            X509Chain c = new X509Chain();

            c.Build(cert_empty);
        }
Exemplo n.º 45
0
 private void LogVerifyErrors(X509Certificate2 cert, string testName)
 {
     // Emulate cert.Verify() implementation in order to capture and log errors.
     try
     {
         using (var chain = new X509Chain())
         {
             if (!chain.Build(cert))
             {
                 foreach (X509ChainStatus chainStatus in chain.ChainStatus)
                 {
                     _log.WriteLine(string.Format($"X509Certificate2.Verify error: {testName}, {chainStatus.Status}, {chainStatus.StatusInformation}"));
                 }
             }
             else
             {
                 _log.WriteLine(string.Format($"X509Certificate2.Verify expected error; received none: {testName}"));
             }
         }
     }
     catch (Exception e)
     {
         _log.WriteLine($"X509Certificate2.Verify exception: {testName}, {e}");
     }
 }
Exemplo n.º 46
0
	private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
	{
		if (sslPolicyErrors == SslPolicyErrors.None)
        	return true;
		
		if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0)
		{
			if (chain != null && chain.ChainStatus != null)
	        {
				X509Certificate2 cert2 = new X509Certificate2(certificate);
				chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
				//chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
				//chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(1000);
				//chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
				//chain.ChainPolicy.VerificationTime = DateTime.Now;
				chain.Build(cert2);
				
				foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
				{
				    if ((certificate.Subject == certificate.Issuer) &&
				       (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot)) 
				    {
				      // Self-signed certificates with an untrusted root are valid. 
				      continue;
				    }
				    else
				    {
				      if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
				      {
				        // If there are any other errors in the certificate chain, the certificate is invalid,
				     	// so the method returns false.
				        return false;
				      }
				    }
				}
	        }
			
        	return true;
		}
		
	    // Do not allow this client to communicate with unauthenticated servers. 
	    return false;
	}	
Exemplo n.º 47
0
        public static void BuildChain_WithCertificatePolicy_Match()
        {
            using (var cert = new X509Certificate2(TestData.CertWithPolicies))
            using (X509Chain chain = new X509Chain())
            {
                // Code Signing
                chain.ChainPolicy.CertificatePolicy.Add(new Oid("2.18.19"));
                chain.ChainPolicy.VerificationFlags =
                    X509VerificationFlags.AllowUnknownCertificateAuthority;
                chain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2);

                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                bool valid = chain.Build(cert);
                Assert.True(valid, "Chain built validly");
            }
        }
Exemplo n.º 48
0
        public static void X509ChainElementCollection_IndexerVsEnumerator()
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            using (var microsoftDotComIssuer = new X509Certificate2(TestData.MicrosoftDotComIssuerBytes))
            using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
            using (X509Chain chain = new X509Chain())
            {
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComRoot);
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;

                // Halfway between microsoftDotCom's NotBefore and NotAfter
                // This isn't a boundary condition test.
                chain.ChainPolicy.VerificationTime = new DateTime(2015, 10, 15, 12, 01, 01, DateTimeKind.Local);
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                bool valid = chain.Build(microsoftDotCom);
                Assert.True(valid, "Precondition: Chain built validly");

                int position = 0;

                foreach (X509ChainElement chainElement in chain.ChainElements)
                {
                    X509ChainElement indexerElement = chain.ChainElements[position];

                    Assert.NotNull(chainElement);
                    Assert.NotNull(indexerElement);

                    Assert.Same(indexerElement, chainElement);
                    position++;
                }
            }
        }
Exemplo n.º 49
0
        public static void VerifyExpiration_LocalTime(DateTime verificationTime, bool shouldBeValid, DateTimeKind kind)
        {
            using (var microsoftDotCom = new X509Certificate2(TestData.MicrosoftDotComSslCertBytes))
            using (var microsoftDotComIssuer = new X509Certificate2(TestData.MicrosoftDotComIssuerBytes))
            using (var microsoftDotComRoot = new X509Certificate2(TestData.MicrosoftDotComRootBytes))
            {
                X509Chain chain = new X509Chain();

                chain.ChainPolicy.ExtraStore.Add(microsoftDotComIssuer);
                chain.ChainPolicy.ExtraStore.Add(microsoftDotComRoot);

                // Ignore anything except NotTimeValid
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags & ~X509VerificationFlags.IgnoreNotTimeValid;
                chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                chain.ChainPolicy.VerificationTime = verificationTime;

                bool builtSuccessfully = chain.Build(microsoftDotCom);

                Assert.Equal(shouldBeValid, builtSuccessfully);

                // If we failed to build the chain, ensure that NotTimeValid is one of the reasons.
                if (!shouldBeValid)
                {
                    Assert.Contains(chain.ChainStatus, s => s.Status == X509ChainStatusFlags.NotTimeValid);
                }
            }
        }
Exemplo n.º 50
0
        private async Task <byte[]> GenerateCertificateInternal(TransactionOperationContext ctx, CertificateDefinition certificate)
        {
            ValidateCertificate(certificate, ServerStore);

            if (certificate.SecurityClearance == SecurityClearance.ClusterAdmin && IsClusterAdmin() == false)
            {
                var clientCert = (HttpContext.Features.Get <IHttpAuthenticationFeature>() as RavenServer.AuthenticateConnection)?.Certificate;
                throw new InvalidOperationException($"Cannot generate the certificate '{certificate.Name}' with 'Cluster Admin' security clearance because the current client certificate being used has a lower clearance: {clientCert}");
            }



            if (Server.ClusterCertificateHolder?.Certificate == null)
            {
                var keys = new[]
                {
                    RavenConfiguration.GetKey(x => x.Security.CertificatePath),
                    RavenConfiguration.GetKey(x => x.Security.CertificateExec),
                    RavenConfiguration.GetKey(x => x.Security.ClusterCertificatePath),
                    RavenConfiguration.GetKey(x => x.Security.ClusterCertificateExec)
                };

                throw new InvalidOperationException($"Cannot generate the client certificate '{certificate.Name}' becuase the server certificate is not loaded. " +
                                                    $"You can supply a server certificate by using the following configuration keys: {keys}" +
                                                    "For a more detailed explanation please read about authentication and certificates in the RavenDB documentation.");
            }

            if (PlatformDetails.RunningOnPosix)
            {
                // Implementation of SslStream AuthenticateAsServer is different in Linux. See RavenDB-8524
                // A list of allowed CAs is sent from the server to the client. The handshake will fail if the client's CA is not in that list. This list is taken from the root and certificate authority stores of the OS.
                // In this workaround we make sure that the CA (who signed the server cert, which in turn signed the client cert) is registered in one of the OS stores.

                var chain = new X509Chain
                {
                    ChainPolicy =
                    {
                        RevocationMode      = X509RevocationMode.NoCheck,
                        RevocationFlag      = X509RevocationFlag.ExcludeRoot,
                        VerificationFlags   = X509VerificationFlags.AllowUnknownCertificateAuthority,
                        VerificationTime    = DateTime.UtcNow,
                        UrlRetrievalTimeout = new TimeSpan(0, 0, 0)
                    }
                };

                if (chain.Build(Server.ClusterCertificateHolder.Certificate) == false)
                {
                    throw new InvalidOperationException($"Cannot generate the client certificate '{certificate.Name}'. The server certificate chain is broken, admin assistance required.");
                }

                var rootCert = GetRootCertificate(chain);
                if (rootCert == null)
                {
                    throw new InvalidOperationException($"Cannot generate the client certificate '{certificate.Name}'. The server certificate chain is broken, admin assistance required.");
                }


                using (var machineRootStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine, OpenFlags.ReadOnly))
                    using (var machineCaStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine, OpenFlags.ReadOnly))
                        using (var userRootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser, OpenFlags.ReadOnly))
                            using (var userCaStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser, OpenFlags.ReadOnly))
                            {
                                // workaround for lack of cert store inheritance RavenDB-8904
                                if (machineCaStore.Certificates.Contains(rootCert) == false &&
                                    machineRootStore.Certificates.Contains(rootCert) == false &&
                                    userCaStore.Certificates.Contains(rootCert) == false &&
                                    userRootStore.Certificates.Contains(rootCert) == false)
                                {
                                    var path = new[]
                                    {
                                        ServerStore.Configuration.Security.CertificatePath,
                                        ServerStore.Configuration.Security.ClusterCertificatePath,
                                        ServerStore.Configuration.Security.CertificateExec,
                                        ServerStore.Configuration.Security.ClusterCertificateExec
                                    }.FirstOrDefault(File.Exists) ?? "no path defined";

                                    throw new InvalidOperationException($"Cannot generate the client certificate '{certificate.Name}'. " +
                                                                        $"First, you must register the CA of the server certificate '{Server.ClusterCertificateHolder.Certificate.SubjectName.Name}' in the trusted root store, on the server machine." +
                                                                        $"The server certificate is located in: '{path}'" +
                                                                        "This step is required because you are using a self-signed server certificate.");
                                }
                            }
            }

            // this creates a client certificate which is signed by the current server certificate
            var selfSignedCertificate = CertificateUtils.CreateSelfSignedClientCertificate(certificate.Name, Server.ClusterCertificateHolder);

            var res = await ServerStore.PutValueInClusterAsync(new PutCertificateCommand(Constants.Certificates.Prefix + selfSignedCertificate.Thumbprint,
                                                                                         new CertificateDefinition
            {
                Name = certificate.Name,
                // this does not include the private key, that is only for the client
                Certificate = Convert.ToBase64String(selfSignedCertificate.Export(X509ContentType.Cert)),
                Permissions = certificate.Permissions,
                SecurityClearance = certificate.SecurityClearance,
                Thumbprint = selfSignedCertificate.Thumbprint
            }));

            await ServerStore.Cluster.WaitForIndexNotification(res.Index);

            return(selfSignedCertificate.Export(X509ContentType.Pfx, certificate.Password));
        }
        private void CheckCert1(X509Chain c)
        {
            X509VerificationFlags success_mask;

            switch (c.ChainPolicy.RevocationMode)
            {
            case X509RevocationMode.Offline:
            case X509RevocationMode.Online:
                success_mask = X509VerificationFlags.IgnoreNotTimeValid | X509VerificationFlags.AllowUnknownCertificateAuthority;
                break;

            case X509RevocationMode.NoCheck:
            default:
                success_mask = X509VerificationFlags.AllowUnknownCertificateAuthority;
                break;
            }

            Assert.AreEqual(((c.ChainPolicy.VerificationFlags & success_mask) == success_mask), c.Build(cert1), "Build");
            Assert.AreEqual(1, c.ChainElements.Count, "ChainElements");
            Assert.AreEqual(String.Empty, c.ChainElements[0].Information, "ChainElements[0].Information");
            Assert.AreEqual(cert1, c.ChainElements[0].Certificate, "ChainElements[0].Certificate");

            switch (c.ChainPolicy.RevocationMode)
            {
            case X509RevocationMode.Offline:
            case X509RevocationMode.Online:
                CheckChainStatus(X509ChainStatusFlags.PartialChain | X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation, c.ChainStatus, "c.ChainStatus");
                CheckChainStatus(X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation, c.ChainElements[0].ChainElementStatus, "c.ChainElements[0].ChainElementStatus");
                break;

            case X509RevocationMode.NoCheck:
                CheckChainStatus(X509ChainStatusFlags.PartialChain, c.ChainStatus, "c.ChainStatus");
                CheckChainStatus(X509ChainStatusFlags.NoError, c.ChainElements[0].ChainElementStatus, "c.ChainElements[0].ChainElementStatus");
                break;
            }
        }
Exemplo n.º 52
0
        private void InstallCertificate(X509Certificate2 certificate)
        {
            X509Store rootStore = null;

            try
            {
                rootStore = new X509Store(StoreName.AuthRoot, StoreLocation.LocalMachine);
                rootStore.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);
            }
            catch
            {
                _log.Warning("Error encountered while opening root store");
                rootStore = null;
            }

            X509Store imStore = null;

            try
            {
                imStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine);
                imStore.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);
            }
            catch
            {
                _log.Warning("Error encountered while opening intermediate certificate store");
                imStore = null;
            }

            try
            {
                _store.Open(OpenFlags.ReadWrite);
                _log.Debug("Opened certificate store {Name}", _store.Name);
            }
            catch (Exception ex)
            {
                _log.Error(ex, "Error encountered while opening certificate store {name}", _store.Name);
                throw;
            }

            try
            {
                _log.Information(true, "Adding certificate {FriendlyName} to store {name}", certificate.FriendlyName, _store.Name);
                var chain = new X509Chain();
                chain.Build(certificate);
                foreach (var chainElement in chain.ChainElements)
                {
                    var cert = chainElement.Certificate;
                    if (cert.HasPrivateKey)
                    {
                        _log.Verbose("{sub} - {iss} ({thumb})", cert.Subject, cert.Issuer, cert.Thumbprint);
                        _store.Add(cert);
                    }
                    else if (cert.Subject != cert.Issuer && imStore != null)
                    {
                        _log.Verbose("{sub} - {iss} ({thumb}) to CA store", cert.Subject, cert.Issuer, cert.Thumbprint);
                        imStore.Add(cert);
                    }
                    else if (cert.Subject == cert.Issuer && rootStore != null)
                    {
                        _log.Verbose("{sub} - {iss} ({thumb}) to AuthRoot store", cert.Subject, cert.Issuer, cert.Thumbprint);
                        rootStore.Add(cert);
                    }
                }
            }
            catch (Exception ex)
            {
                _log.Error(ex, "Error saving certificate");
            }
            _log.Debug("Closing certificate stores");
            _store.Close();
            imStore.Close();
            rootStore.Close();
        }
Exemplo n.º 53
0
        public static void X509CertStoreChain()
        {
            X509Store store = new X509Store("My", StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadOnly);
            // can't guarantee there is a certificate in store
            if (store.Certificates.Count > 0)
            {
                X509Chain chain = new X509Chain();
                Assert.NotNull(chain.SafeHandle);
                Assert.Same(chain.SafeHandle, chain.SafeHandle);
                Assert.True(chain.SafeHandle.IsInvalid);

                foreach (X509Certificate2 c in store.Certificates)
                {
                    // can't guarantee success, so no Assert 
                    if (chain.Build(c))
                    {
                        foreach (X509ChainElement k in chain.ChainElements)
                        {
                            Assert.NotNull(k.Certificate.IssuerName.Name);
                        }
                    }
                }
            }
        }
        private void CheckCert2(X509Chain c)
        {
            X509VerificationFlags success_mask = X509VerificationFlags.IgnoreNotTimeValid | X509VerificationFlags.AllowUnknownCertificateAuthority;

            Assert.AreEqual(((c.ChainPolicy.VerificationFlags & success_mask) == success_mask), c.Build(cert2), "Build");
            Assert.AreEqual(1, c.ChainElements.Count, "ChainElements");
            Assert.AreEqual(String.Empty, c.ChainElements[0].Information, "ChainElements[0].Information");
            Assert.AreEqual(cert2, c.ChainElements[0].Certificate, "ChainElements[0].Certificate");

            CheckChainStatus(X509ChainStatusFlags.UntrustedRoot | X509ChainStatusFlags.NotTimeValid, c.ChainStatus, "c.ChainStatus");
            CheckChainStatus(X509ChainStatusFlags.UntrustedRoot | X509ChainStatusFlags.NotTimeValid, c.ChainElements[0].ChainElementStatus, "c.ChainElements[0].ChainElementStatus");
        }