private static BigIntegerRSAPublicKey ThaliServerCertificateValidationCallback( X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (certificate == null || (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0) { throw new ApplicationException(); } if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0) { const X509ChainStatusFlags AcceptableCertChainErrors = X509ChainStatusFlags.UntrustedRoot | X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation | X509ChainStatusFlags.NoError; if ( chain.ChainStatus.Any( chainStatus => (chainStatus.Status | AcceptableCertChainErrors) != AcceptableCertChainErrors)) { throw new ApplicationException(); } } // TODO: Actually prove that the last entry in the chain is the root var x509Certv2 = chain.ChainElements[chain.ChainElements.Count - 1].Certificate; var serverPublicKeyParameters = ((RSACryptoServiceProvider)x509Certv2.PublicKey.Key).ExportParameters(false); var serverPresentedRsaKey = new BigIntegerRSAPublicKey(serverPublicKeyParameters); return(serverPresentedRsaKey); }
// private stuff // note: flags isn't a flag (i.e. multiple values) when used here static internal string GetInformation(X509ChainStatusFlags flags) { switch (flags) { case X509ChainStatusFlags.NotTimeValid: case X509ChainStatusFlags.NotTimeNested: case X509ChainStatusFlags.Revoked: case X509ChainStatusFlags.NotSignatureValid: case X509ChainStatusFlags.NotValidForUsage: case X509ChainStatusFlags.UntrustedRoot: case X509ChainStatusFlags.RevocationStatusUnknown: case X509ChainStatusFlags.Cyclic: case X509ChainStatusFlags.InvalidExtension: case X509ChainStatusFlags.InvalidPolicyConstraints: case X509ChainStatusFlags.InvalidBasicConstraints: case X509ChainStatusFlags.InvalidNameConstraints: case X509ChainStatusFlags.HasNotSupportedNameConstraint: case X509ChainStatusFlags.HasNotDefinedNameConstraint: case X509ChainStatusFlags.HasNotPermittedNameConstraint: case X509ChainStatusFlags.HasExcludedNameConstraint: case X509ChainStatusFlags.PartialChain: case X509ChainStatusFlags.CtlNotTimeValid: case X509ChainStatusFlags.CtlNotSignatureValid: case X509ChainStatusFlags.CtlNotValidForUsage: case X509ChainStatusFlags.OfflineRevocation: case X509ChainStatusFlags.NoIssuanceChainPolicy: return(Locale.GetText(flags.ToString())); // FIXME - add a better description case X509ChainStatusFlags.NoError: default: // should never happen return(String.Empty); } }
protected override int InternalExecute() { if (string.IsNullOrEmpty(this.certRawData)) { return(-1); } int result; try { byte[] rawData = Convert.FromBase64String(this.certRawData); X509Certificate2 certificate = new X509Certificate2(rawData); X509Chain x509Chain = new X509Chain(true); x509Chain.Build(certificate); X509ChainStatusFlags x509ChainStatusFlags = X509ChainStatusFlags.NoError; foreach (X509ChainStatus x509ChainStatus in x509Chain.ChainStatus) { x509ChainStatusFlags |= x509ChainStatus.Status; } result = (int)x509ChainStatusFlags; } catch { result = -1; } return(result); }
private bool IsParent(X509Certificate child, X509Certificate parent) { if (child.IssuerName != parent.SubjectName) { return(false); } if (parent.Version > 2 && !this.IsTrusted(parent)) { X509Extension x509Extension = parent.Extensions["2.5.29.19"]; if (x509Extension != null) { BasicConstraintsExtension basicConstraintsExtension = new BasicConstraintsExtension(x509Extension); if (!basicConstraintsExtension.CertificateAuthority) { this._status = X509ChainStatusFlags.InvalidBasicConstraints; } } else { this._status = X509ChainStatusFlags.InvalidBasicConstraints; } } if (!child.VerifySignature(parent.RSA)) { this._status = X509ChainStatusFlags.NotSignatureValid; return(false); } return(true); }
public X509ChainErrorMapping(CertTrustErrorStatus win32Flag, int win32ErrorCode, X509ChainStatusFlags chainStatusFlag) { Win32Flag = win32Flag; Win32ErrorCode = win32ErrorCode; ChainStatusFlag = chainStatusFlag; Message = Interop.Kernel32.GetMessage(win32ErrorCode); }
private static void FixupStatus( X509Certificate2 cert, X509RevocationMode revocationMode, ref int dwStatus) { X509ChainStatusFlags flags = (X509ChainStatusFlags)dwStatus; if ((flags & X509ChainStatusFlags.UntrustedRoot) != 0) { X509ChainStatusFlags newFlag = FindUntrustedRootReason(cert); if (newFlag != X509ChainStatusFlags.UntrustedRoot) { flags &= ~X509ChainStatusFlags.UntrustedRoot; flags |= newFlag; dwStatus = (int)flags; } } if (revocationMode == X509RevocationMode.NoCheck) { // Clear any revocation-related flags if NoCheck was requested, since // the OS may use cached results opportunistically. flags &= ~RevocationRelevantFlags; dwStatus = (int)flags; } }
private X509Certificate FindCertificateRoot(X509Certificate potentialRoot) { if (potentialRoot == null) { this._status = X509ChainStatusFlags.PartialChain; return(null); } if (this.IsTrusted(potentialRoot)) { return(potentialRoot); } foreach (X509Certificate x509Certificate in this.TrustAnchors) { if (this.IsParent(potentialRoot, x509Certificate)) { return(x509Certificate); } } if (potentialRoot.IsSelfSigned) { this._status = X509ChainStatusFlags.UntrustedRoot; return(potentialRoot); } this._status = X509ChainStatusFlags.PartialChain; return(null); }
private static void AddElementStatus( Interop.Crypto.X509VerifyStatusCode errorCode, List <X509ChainStatus> elementStatus, List <X509ChainStatus> overallStatus) { X509ChainStatusFlags statusFlag = MapVerifyErrorToChainStatus(errorCode); Debug.Assert( (statusFlag & (statusFlag - 1)) == 0, "Status flag has more than one bit set", "More than one bit is set in status '{0}' for error code '{1}'", statusFlag, errorCode); foreach (X509ChainStatus currentStatus in elementStatus) { if ((currentStatus.Status & statusFlag) != 0) { return; } } X509ChainStatus chainStatus = new X509ChainStatus { Status = statusFlag, StatusInformation = Interop.Crypto.GetX509VerifyCertErrorString(errorCode), }; elementStatus.Add(chainStatus); AddUniqueStatus(overallStatus, ref chainStatus); }
/// <summary> /// Create a Trust Model from the given settings /// </summary> /// <returns>TrustModel</returns> public TrustModel CreateTrustModel() { TrustChainValidator validator = new TrustChainValidator(); validator.RevocationCheckMode = this.RevocationCheckMode; validator.RevocationCheckGranularity = this.RevocationCheckGranularity; if (this.MaxIssuerChainLength > 0) { validator.MaxIssuerChainLength = this.MaxIssuerChainLength; } if (this.TimeoutMilliseconds > 0) { validator.ValidationPolicy.UrlRetrievalTimeout = TimeSpan.FromMilliseconds(this.TimeoutMilliseconds); } TrustModel trustModel = new TrustModel(validator); if (this.ProblemFlags != null) { X509ChainStatusFlags flags = X509ChainStatusFlags.NoError; foreach (X509ChainStatusFlags flag in this.ProblemFlags) { flags = (flags | flag); } trustModel.CertChainValidator.ProblemFlags = flags; } return(trustModel); }
public static void EmptyAiaResponseIsIgnored() { CertificateAuthority.BuildPrivatePki( PkiOptions.AllRevocation, out RevocationResponder responder, out CertificateAuthority root, out CertificateAuthority intermediate, out X509Certificate2 endEntity, pkiOptionsInSubject: false); using (responder) using (root) using (intermediate) using (endEntity) using (ChainHolder holder = new ChainHolder()) using (X509Certificate2 rootCert = root.CloneIssuerCert()) using (X509Certificate2 intermediateCert = intermediate.CloneIssuerCert()) { responder.RespondEmpty = true; X509Chain chain = holder.Chain; chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; chain.ChainPolicy.VerificationTime = endEntity.NotBefore.AddMinutes(1); chain.ChainPolicy.UrlRetrievalTimeout = DynamicRevocationTests.s_urlRetrievalLimit; chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; Assert.False(chain.Build(endEntity)); X509ChainStatusFlags chainFlags = chain.AllStatusFlags(); Assert.True(chainFlags.HasFlag(X509ChainStatusFlags.PartialChain), $"expected partial chain flags, got {chainFlags}"); } }
public static void CustomRootTrustDoesNotTrustIntermediates( bool saveAllInCustomTrustStore, X509ChainStatusFlags chainFlags) { TestDataGenerator.MakeTestChain3( out X509Certificate2 endEntityCert, out X509Certificate2 intermediateCert, out X509Certificate2 rootCert); using (endEntityCert) using (intermediateCert) using (rootCert) using (ChainHolder chainHolder = new ChainHolder()) { X509Chain chain = chainHolder.Chain; chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; chain.ChainPolicy.CustomTrustStore.Add(intermediateCert); if (saveAllInCustomTrustStore) { chain.ChainPolicy.CustomTrustStore.Add(rootCert); } else { chain.ChainPolicy.ExtraStore.Add(rootCert); } Assert.Equal(saveAllInCustomTrustStore, chain.Build(endEntityCert)); Assert.Equal(3, chain.ChainElements.Count); Assert.Equal(chainFlags, chain.AllStatusFlags()); } }
private bool IsParent(X509Certificate child, X509Certificate parent) { if (child.IssuerName != parent.SubjectName) { return(false); } // parent MUST have the Basic Constraint CA=true (except for trusted roots) // see why at http://www.microsoft.com/technet/security/bulletin/MS02-050.asp if ((parent.Version > 2) && (!IsTrusted(parent))) { // TODO: we do not support pathLenConstraint X509Extension ext = parent.Extensions ["2.5.29.19"]; if (ext != null) { BasicConstraintsExtension bc = new BasicConstraintsExtension(ext); if (!bc.CertificateAuthority) { _status = X509ChainStatusFlags.InvalidBasicConstraints; } } else { _status = X509ChainStatusFlags.InvalidBasicConstraints; } } if (!child.VerifySignature(parent.RSA)) { _status = X509ChainStatusFlags.NotSignatureValid; return(false); } return(true); }
private X509Certificate FindCertificateRoot(X509Certificate potentialRoot) { if (potentialRoot == null) { _status = X509ChainStatusFlags.PartialChain; return(null); } // if the trusted root is in the chain if (IsTrusted(potentialRoot)) { return(potentialRoot); } // if the root isn't in the chain foreach (X509Certificate root in TrustAnchors) { if (IsParent(potentialRoot, root)) { return(root); } } // is it a (untrusted) root ? if (potentialRoot.IsSelfSigned) { _status = X509ChainStatusFlags.UntrustedRoot; return(potentialRoot); } _status = X509ChainStatusFlags.PartialChain; return(null); }
// private stuff // note: flags isn't a flag (i.e. multiple values) when used here static internal string GetInformation (X509ChainStatusFlags flags) { switch (flags) { case X509ChainStatusFlags.NotTimeValid: case X509ChainStatusFlags.NotTimeNested: case X509ChainStatusFlags.Revoked: case X509ChainStatusFlags.NotSignatureValid: case X509ChainStatusFlags.NotValidForUsage: case X509ChainStatusFlags.UntrustedRoot: case X509ChainStatusFlags.RevocationStatusUnknown: case X509ChainStatusFlags.Cyclic: case X509ChainStatusFlags.InvalidExtension: case X509ChainStatusFlags.InvalidPolicyConstraints: case X509ChainStatusFlags.InvalidBasicConstraints: case X509ChainStatusFlags.InvalidNameConstraints: case X509ChainStatusFlags.HasNotSupportedNameConstraint: case X509ChainStatusFlags.HasNotDefinedNameConstraint: case X509ChainStatusFlags.HasNotPermittedNameConstraint: case X509ChainStatusFlags.HasExcludedNameConstraint: case X509ChainStatusFlags.PartialChain: case X509ChainStatusFlags.CtlNotTimeValid: case X509ChainStatusFlags.CtlNotSignatureValid: case X509ChainStatusFlags.CtlNotValidForUsage: case X509ChainStatusFlags.OfflineRevocation: case X509ChainStatusFlags.NoIssuanceChainPolicy: return Locale.GetText (flags.ToString ()); // FIXME - add a better description case X509ChainStatusFlags.NoError: default: // should never happen return String.Empty; } }
private static string RunChain( X509Chain chain, X509Certificate2 cert, string msg) { bool success = chain.Build(cert); FormattableString errMsg = null; if (!success) { for (int i = 0; i < chain.ChainElements.Count; i++) { X509ChainElement element = chain.ChainElements[i]; if (element.ChainElementStatus.Length != 0) { X509ChainStatusFlags flags = element.ChainElementStatus.Select(ces => ces.Status).Aggregate((a, b) => a | b); errMsg = $"{msg}: chain error at depth {i}: {flags}"; break; } } } return(errMsg?.ToString(formatProvider: CultureInfo.CurrentCulture)); }
public void InvalidCertificateInvalidatesSignatures( EndCertificateUse use, X509ChainStatusFlags flags, SignatureDecision ingestionDecision, SignatureDecision gracePeriodDecision, SignatureDecision afterGracePeriodDecision) { // Arrange var certificate = new EndCertificate { Use = use }; var result = new CertificateVerificationResult( status: EndCertificateStatus.Invalid, statusFlags: flags); var signatureAtIngestion = new PackageSignature { Status = PackageSignatureStatus.Unknown }; var signatureAtGracePeriod = new PackageSignature { Status = PackageSignatureStatus.InGracePeriod }; var signatureAfterGracePeriod = new PackageSignature { Status = PackageSignatureStatus.Valid }; // Act & Assert var decider = _target.MakeDeciderForInvalidatedCertificate(certificate, result); Assert.Equal(ingestionDecision, decider(signatureAtIngestion)); Assert.Equal(gracePeriodDecision, decider(signatureAtGracePeriod)); Assert.Equal(afterGracePeriodDecision, decider(signatureAfterGracePeriod)); }
// Performs Attestation per the protocol used by Virtual Secure Modules. private void VerifyAttestationInfo(string attestationUrl, HealthReport healthReport, EnclaveReportPackage enclaveReportPackage) { bool shouldRetryValidation; bool shouldForceUpdateSigningKeys = false; do { shouldRetryValidation = false; // Get HGS Root signing certs from HGS X509Certificate2Collection signingCerts = GetSigningCertificate(attestationUrl, shouldForceUpdateSigningKeys); // Verify SQL Health report root chain of trust is the HGS root signing cert X509ChainStatusFlags chainStatus = VerifyHealthReportAgainstRootCertificate(signingCerts, healthReport.Certificate); if (chainStatus != X509ChainStatusFlags.NoError) { // In cases if we fail to validate the health report, it might be possible that we are using old signing keys // let's re-download the signing keys again and re-validate the health report if (!shouldForceUpdateSigningKeys) { shouldForceUpdateSigningKeys = true; shouldRetryValidation = true; } else { throw new AlwaysEncryptedAttestationException(String.Format(Strings.VerifyHealthCertificateChainFormat, attestationUrl, chainStatus)); } } } while (shouldRetryValidation); // Verify enclave report is signed by IDK_S from health report VerifyEnclaveReportSignature(enclaveReportPackage, healthReport.Certificate); }
private X509Certificate FindCertificateRoot(X509Certificate potentialRoot) { if (potentialRoot == null) { _status = X509ChainStatusFlags.PartialChain; return(null); } if (IsTrusted(potentialRoot)) { return(potentialRoot); } foreach (X509Certificate trustAnchor in TrustAnchors) { if (IsParent(potentialRoot, trustAnchor)) { return(trustAnchor); } } if (potentialRoot.IsSelfSigned) { _status = X509ChainStatusFlags.UntrustedRoot; return(potentialRoot); } _status = X509ChainStatusFlags.PartialChain; return(null); }
public static void TestLeafCertificateWithUnknownCriticalExtension() { using (RSA key = RSA.Create()) { CertificateRequest certReq = new CertificateRequest( new X500DistinguishedName("CN=Cert"), key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); const string PrecertificatePoisonExtensionOid = "1.3.6.1.4.1.11129.2.4.3"; certReq.CertificateExtensions.Add(new X509Extension( new AsnEncodedData( new Oid(PrecertificatePoisonExtensionOid), new byte[] { 5, 0 }), critical: true)); DateTimeOffset notBefore = DateTimeOffset.UtcNow.AddDays(-1); DateTimeOffset notAfter = notBefore.AddDays(30); using (X509Certificate2 cert = certReq.CreateSelfSigned(notBefore, notAfter)) using (ChainHolder holder = new ChainHolder()) { X509Chain chain = holder.Chain; chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; Assert.False(chain.Build(cert)); X509ChainElement certElement = chain.ChainElements.OfType <X509ChainElement>().Single(); const X509ChainStatusFlags ExpectedFlag = X509ChainStatusFlags.HasNotSupportedCriticalExtension; X509ChainStatusFlags actualFlags = certElement.AllStatusFlags(); Assert.True((actualFlags & ExpectedFlag) == ExpectedFlag, $"Has expected flag {ExpectedFlag} but was {actualFlags}"); } } }
// This isn't how RFC3280 (section 6.3) deals with CRL, but then we don't (yet) support DP, deltas... private X509ChainStatusFlags CheckRevocation(X509Certificate2 certificate, int ca, bool online) { X509ChainStatusFlags result = X509ChainStatusFlags.RevocationStatusUnknown; X509ChainElement element = elements [ca]; X509Certificate2 ca_cert = element.Certificate; // find the CRL from the "right" CA while (IsSelfIssued(ca_cert) && (ca < elements.Count - 1)) { // try with this self-issued result = CheckRevocation(certificate, ca_cert, online); if (result != X509ChainStatusFlags.RevocationStatusUnknown) { break; } ca++; element = elements [ca]; ca_cert = element.Certificate; } if (result == X509ChainStatusFlags.RevocationStatusUnknown) { result = CheckRevocation(certificate, ca_cert, online); } return(result); }
private void ValidateChain(X509ChainStatusFlags flag) { int num = this.elements.Count - 1; X509Certificate2 certificate = this.elements[num].Certificate; if ((flag & X509ChainStatusFlags.PartialChain) == X509ChainStatusFlags.NoError) { this.Process(num); if (num == 0) { this.elements[0].UncompressFlags(); return; } num--; } this.working_public_key = certificate.PublicKey.Key; this.working_issuer_name = certificate.IssuerName; this.max_path_length = num; for (int i = num; i > 0; i--) { this.Process(i); this.PrepareForNextCertificate(i); } this.Process(0); this.CheckRevocationOnChain(flag); this.WrapUp(); }
/// <summary> /// Create an LDAP certificate resolver, using timeout and default DNS server for SRV lookup /// </summary> /// <param name="dnsServerIp">An <see cref="IPAddress"/> IP address of the DNS server to use for DNS lookups</param> /// <param name="timeout">Timeout value for DNS and LDAP lookups</param> /// <param name="cacheEnabled">boolean flag indicating whether or not to use the DNS client with cache</param> public LdapCertResolver(IPAddress dnsServerIp, TimeSpan timeout, bool cacheEnabled) { if (dnsServerIp == null) { dnsServerIp = GetLocalServerDns(dnsServerIp); } if (dnsServerIp == null) { throw new ArgumentNullException("dnsServerIp"); } if (timeout.Ticks < 0) { throw new ArgumentException("timeout value was less than zero", "timeout"); } m_dnsServerIp = dnsServerIp; m_timeout = timeout; m_cacheEnabled = cacheEnabled; m_policy = new X509ChainPolicy(); m_policy.VerificationFlags = (X509VerificationFlags.IgnoreWrongUsage); m_problemFlags = DefaultProblemFlags; }
// *** certificate chain/path validation stuff *** // Currently a subset of RFC3280 (hopefully a full implementation someday) private void ValidateChain(X509ChainStatusFlags flag) { // 'n' should be the root certificate... int n = elements.Count - 1; X509Certificate2 certificate = elements [n].Certificate; // ... and, if so, must be treated outside the chain... if (((flag & X509ChainStatusFlags.PartialChain) == 0)) { Process(n); // deal with the case where the chain == the root certificate // (which isn't for RFC3280) part of the chain if (n == 0) { elements [0].UncompressFlags(); return; } // skip the root certificate when processing the chain (in 6.1.3) n--; } // ... unless the chain is a partial one (then we start with that one) // 6.1.1 - Inputs // 6.1.1.a - a prospective certificate path of length n (i.e. elements) // 6.1.1.b - the current date/time (i.e. ChainPolicy.VerificationTime) // 6.1.1.c - user-initial-policy-set (i.e. ChainPolicy.CertificatePolicy) // 6.1.1.d - the trust anchor information (i.e. certificate, unless it's a partial chain) // 6.1.1.e - initial-policy-mapping-inhibit (NOT SUPPORTED BY THE API) // 6.1.1.f - initial-explicit-policy (NOT SUPPORTED BY THE API) // 6.1.1.g - initial-any-policy-inhibit (NOT SUPPORTED BY THE API) // 6.1.2 - Initialization (incomplete) // 6.1.2.a-f - policy stuff, some TODO, some not supported // 6.1.2.g - working public key algorithm // working_public_key_algorithm = certificate.PublicKey.Oid.Value; // 6.1.2.h-i - our key contains both the "working public key" and "working public key parameters" data working_public_key = certificate.PublicKey.Key; // 6.1.2.j - working issuer name working_issuer_name = certificate.IssuerName; // 6.1.2.k - this integer is initialized to n, is decremented for each non-self-issued, certificate and // may be reduced to the value in the path length constraint field max_path_length = n; // 6.1.3 - Basic Certificate Processing // note: loop looks reversed (the list is) but we process this part just like RFC3280 does for (int i = n; i > 0; i--) { Process(i); // 6.1.4 - preparation for certificate i+1 (for not with i+1, or i-1 in our loop) PrepareForNextCertificate(i); } Process(0); // 6.1.3.a.3 - revocation checks CheckRevocationOnChain(flag); // 6.1.5 - Wrap-up procedure WrapUp(); }
public override void AddStatus(X509ChainStatusFlags errorCode) { if (chainStatusList == null) { chainStatusList = new List <X509ChainStatus>(); } chainStatusList.Add(new X509ChainStatus(errorCode)); }
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)) using (var chainHolder = new ChainHolder()) { X509Chain chain = chainHolder.Chain; 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); X509ChainStatusFlags initialFlags = chain.AllStatusFlags(); if (initialFlags != X509ChainStatusFlags.NoError) { Assert.Equal(X509ChainStatusFlags.UntrustedRoot, initialFlags); } chainHolder.DisposeChainElements(); chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; valid = chain.Build(microsoftDotComIssuer); Assert.False(valid, "Chain should not build validly"); const X509ChainStatusFlags UnknownOffline = X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation; Assert.Equal(initialFlags | UnknownOffline, chain.AllStatusFlags()); File.WriteAllText(crlFile, MicrosoftDotComRootCrlPem, Encoding.ASCII); chainHolder.DisposeChainElements(); valid = chain.Build(microsoftDotComIssuer); Assert.True(valid, "Chain should build validly now"); Assert.Equal(initialErrorCount, chain.ChainStatus.Length); } }
public static void InvalidSelfSignedSignature() { X509ChainStatusFlags expectedFlags; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { expectedFlags = X509ChainStatusFlags.NotSignatureValid; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { // For OSX alone expectedFlags here means OR instead of AND. // Because the error code changed in 10.13.4 from UntrustedRoot to PartialChain // and we handle that later in this test. expectedFlags = X509ChainStatusFlags.UntrustedRoot | X509ChainStatusFlags.PartialChain; } else { expectedFlags = X509ChainStatusFlags.NotSignatureValid | X509ChainStatusFlags.UntrustedRoot; } byte[] certBytes = (byte[])TestData.MicrosoftDotComRootBytes.Clone(); // The signature goes up to the very last byte, so flip some bits in it. certBytes[certBytes.Length - 1] ^= 0xFF; using (var cert = new X509Certificate2(certBytes)) using (ChainHolder holder = new ChainHolder()) { X509Chain chain = holder.Chain; X509ChainPolicy policy = chain.ChainPolicy; policy.VerificationTime = cert.NotBefore.AddDays(3); policy.RevocationMode = X509RevocationMode.NoCheck; chain.Build(cert); X509ChainStatusFlags allFlags = chain.ChainStatus.Select(cs => cs.Status).Aggregate( X509ChainStatusFlags.NoError, (a, b) => a | b); if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { // If we're on 10.13.3 or older we get UntrustedRoot. // If we're on 10.13.4 or newer we get PartialChain. // // So make the expectedValue be whichever of those two is set. expectedFlags = (expectedFlags & allFlags); // One of them has to be set. Assert.NotEqual(X509ChainStatusFlags.NoError, expectedFlags); // Continue executing now to ensure that no other unexpected flags were set. } Assert.Equal(expectedFlags, allFlags); } }
private static bool VerifyChainStatus(X509ChainStatus[] chainStatusArray) { if (chainStatusArray.Length == 1) { X509ChainStatusFlags chainStatus = chainStatusArray.First().Status; return(chainStatus == X509ChainStatusFlags.NoError || chainStatus == X509ChainStatusFlags.UntrustedRoot || chainStatus == X509ChainStatusFlags.PartialChain); } return(false); }
public static void BuildInvalidSignatureTwice() { byte[] bytes = (byte[])TestData.MsCertificate.Clone(); bytes[bytes.Length - 1] ^= 0xFF; using (X509Certificate2 cert = new X509Certificate2(bytes)) using (ChainHolder chainHolder = new ChainHolder()) { X509Chain chain = chainHolder.Chain; chain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2); chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; int iter = 0; void CheckChain() { iter++; bool valid = chain.Build(cert); X509ChainStatusFlags allFlags = chain.AllStatusFlags(); if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { // OSX considers this to be valid because it doesn't report NotSignatureValid, // just PartialChain ("I couldn't find an issuer that made the signature work"), // and PartialChain + AllowUnknownCertificateAuthority == pass. Assert.True(valid, $"Chain is valid on execution {iter}"); Assert.Equal(1, chain.ChainElements.Count); Assert.Equal( X509ChainStatusFlags.PartialChain, allFlags); } else { Assert.False(valid, $"Chain is valid on execution {iter}"); Assert.Equal(3, chain.ChainElements.Count); // Clear UntrustedRoot, if it happened. allFlags &= ~X509ChainStatusFlags.UntrustedRoot; Assert.Equal( X509ChainStatusFlags.NotSignatureValid, allFlags); } chainHolder.DisposeChainElements(); } CheckChain(); CheckChain(); } }
private bool IsValid(X509Certificate cert) { if (!cert.IsCurrent) { this._status = X509ChainStatusFlags.NotTimeNested; return(false); } return(true); }
private void Set(X509ChainStatus[] status, ref int position, X509ChainStatusFlags flags, X509ChainStatusFlags mask) { if ((flags & mask) != 0) { status[position].Status = mask; status[position].StatusInformation = X509ChainStatus.GetInformation(mask); position++; } }
private void CheckRevocationOnChain(X509ChainStatusFlags flag) { bool flag2 = (flag & X509ChainStatusFlags.PartialChain) != X509ChainStatusFlags.NoError; bool online; switch (this.ChainPolicy.RevocationMode) { case X509RevocationMode.NoCheck: return; case X509RevocationMode.Online: online = true; break; case X509RevocationMode.Offline: online = false; break; default: throw new InvalidOperationException(Locale.GetText("Invalid revocation mode.")); } bool flag3 = flag2; for (int i = this.elements.Count - 1; i >= 0; i--) { bool flag4 = true; switch (this.ChainPolicy.RevocationFlag) { case X509RevocationFlag.EndCertificateOnly: flag4 = (i == 0); break; case X509RevocationFlag.EntireChain: flag4 = true; break; case X509RevocationFlag.ExcludeRoot: flag4 = (i != this.elements.Count - 1); break; } X509ChainElement x509ChainElement = this.elements[i]; if (!flag3) { flag3 |= ((x509ChainElement.StatusFlags & X509ChainStatusFlags.NotSignatureValid) != X509ChainStatusFlags.NoError); } if (flag3) { x509ChainElement.StatusFlags |= X509ChainStatusFlags.RevocationStatusUnknown; x509ChainElement.StatusFlags |= X509ChainStatusFlags.OfflineRevocation; } else if (flag4 && !flag2 && !this.IsSelfIssued(x509ChainElement.Certificate)) { x509ChainElement.StatusFlags |= this.CheckRevocation(x509ChainElement.Certificate, i + 1, online); flag3 |= ((x509ChainElement.StatusFlags & X509ChainStatusFlags.Revoked) != X509ChainStatusFlags.NoError); } } }
// this method avoid having a dependance on the order of status public void CheckChainStatus (X509ChainStatusFlags expected, X509ChainStatus[] status, string msg) { if ((expected == X509ChainStatusFlags.NoError) && (status.Length == 0)) return; X509ChainStatusFlags actual = X509ChainStatusFlags.NoError; foreach (X509ChainStatus s in status) { actual |= s.Status; } Assert.AreEqual (expected, actual, msg); }
public static X509Certificate2Collection FilterValidCerts( X509Certificate2Collection certs, X509ChainPolicy policy, X509ChainStatusFlags problemFlags, Action<Exception> notification) { var validCerts = new X509Certificate2Collection(); if (certs == null) return null; foreach (var cert in certs) { X509Chain chainBuilder = new X509Chain(); chainBuilder.ChainPolicy = policy.Clone(); try { // We're using the system class as a helper to merely build the chain // However, we will review each item in the chain ourselves, because we have our own rules... chainBuilder.Build(cert); X509ChainElementCollection chainElements = chainBuilder.ChainElements; // If we don't have a trust chain, then we obviously have a problem... if (chainElements.IsNullOrEmpty()) { notification(new Exception(string.Format("Can't find a trust chain: {0} ", cert.Subject))); return null; } // walk the chain starting at the leaf and see if we hit any issues before the anchor foreach (X509ChainElement chainElement in chainElements) { if (ChainElementHasProblems(chainElement, problemFlags)) { //this.NotifyProblem(chainElement); notification(new Exception(string.Format("Chain Element has problem {0}", Summarize(chainElement, problemFlags)))); // Whoops... problem with at least one cert in the chain. Stop immediately return null; } } } catch (Exception ex) { //this.NotifyError(certificate, ex); // just eat it and drop out to return null notification(ex); return null; } validCerts.Add(cert); } return validCerts; }
private int Count (X509ChainStatusFlags flags) { int size = 0; int n = 0; int f = (int) flags; int m = 0x1; while (n++ < 32) { if ((f & m) == m) size++; m <<= 1; } return size; }
static bool ChainElementHasProblems(X509ChainElement chainElement, X509ChainStatusFlags problemFlags) { // If the builder finds problems with the cert, it will provide a list of "status" flags for the cert X509ChainStatus[] chainElementStatus = chainElement.ChainElementStatus; // If the list is empty or the list is null, then there were NO problems with the cert if (chainElementStatus.IsNullOrEmpty()) { return false; } // Return true if there are any status flags we care about return chainElementStatus.Any(s => (s.Status & problemFlags) != 0); }
/// <summary> /// Creates a new instance of the <see cref="SimplePolicyChecker"/> class. /// </summary> public SimplePolicyChecker() { m_validPolicyErrors = SslPolicyErrors.None; m_validChainFlags = X509ChainStatusFlags.NoError; }
/// <summary> /// Creates an instance, specifying chain policy and problem flags /// </summary> /// <param name="policy">The <see cref="X509ChainPolicy"/> to use for validating trust chains</param> /// <param name="problemFlags">The status flags that will be treated as invalid in trust verification</param> public TrustChainValidator(X509ChainPolicy policy, X509ChainStatusFlags problemFlags) { m_policy = policy; m_problemFlags = problemFlags; }
/// <summary> /// Creates a new instance of the <see cref="CertificatePolicy"/> class. /// </summary> public CertificatePolicy() { m_validPolicyErrors = SslPolicyErrors.None; m_validChainFlags = X509ChainStatusFlags.NoError; }
internal X509ChainStatus (X509ChainStatusFlags flag) { status = flag; info = GetInformation (flag); }
public bool Build (X509Certificate leaf) { _status = X509ChainStatusFlags.NoError; if (_chain == null) { // chain not supplied - we must built it ourselve _chain = new X509CertificateCollection (); X509Certificate x = leaf; X509Certificate tmp = null; while ((x != null) && (!x.IsSelfSigned)) { tmp = FindCertificateParent (x); if (x != null) { _chain.Add (x); x = tmp; // last valid } } // find a trusted root _root = FindCertificateRoot (tmp); } else { // chain supplied - still have to check signatures! int last = _chain.Count; if (last > 0) { if (IsParent (leaf, _chain [0])) { int i = 1; for (; i < last; i++) { if (!IsParent (_chain [i-1], _chain [i])) break; } if (i == last) _root = FindCertificateRoot (_chain [last - 1]); } } else { // is the leaf a root ? (trusted or untrusted) _root = FindCertificateRoot (leaf); } } // validate the chain if ((_chain != null) && (_status == X509ChainStatusFlags.NoError)) { foreach (X509Certificate x in _chain) { // validate dates for each certificate in the chain // note: we DO NOT check for nested date/time if (!IsValid (x)) { return false; } } // check leaf if (!IsValid (leaf)) { // switch status code if the failure is expiration if (_status == X509ChainStatusFlags.NotTimeNested) _status = X509ChainStatusFlags.NotTimeValid; return false; } // check root if ((_root != null) && !IsValid (_root)) { return false; } } return (_status == X509ChainStatusFlags.NoError); }
// private stuff private bool IsValid (X509Certificate cert) { if (!cert.IsCurrent) { // FIXME: nesting isn't very well implemented _status = X509ChainStatusFlags.NotTimeNested; return false; } // TODO - we should check for CRITICAL but unknown extensions // X509ChainStatusFlags.InvalidExtension #if (!NET_1_0 && !INSIDE_CORLIB) if (ServicePointManager.CheckCertificateRevocationList) { // TODO - check revocation (CRL, OCSP ...) // X509ChainStatusFlags.RevocationStatusUnknown // X509ChainStatusFlags.Revoked } #endif return true; }
/// <summary> /// Initializes <see cref="DataSubscriber"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary<string, string> settings = Settings; string setting; OperationalModes operationalModes; CompressionModes compressionModes; int metadataSynchronizationTimeout; double interval; int bufferSize; // Setup connection to data publishing server with or without authentication required if (settings.TryGetValue("requireAuthentication", out setting)) RequireAuthentication = setting.ParseBoolean(); // See if user has opted for different operational modes if (settings.TryGetValue("operationalModes", out setting) && Enum.TryParse(setting, true, out operationalModes)) OperationalModes = operationalModes; // Set the security mode if explicitly defined if (!settings.TryGetValue("securityMode", out setting) || !Enum.TryParse(setting, true, out m_securityMode)) m_securityMode = SecurityMode.None; // Apply gateway compression mode to operational mode flags if (settings.TryGetValue("compressionModes", out setting) && Enum.TryParse(setting, true, out compressionModes)) CompressionModes = compressionModes; if (settings.TryGetValue("useZeroMQChannel", out setting)) m_useZeroMQChannel = setting.ParseBoolean(); // TODO: Remove this exception when CURVE is enabled in GSF ZeroMQ library if (m_useZeroMQChannel && m_securityMode == SecurityMode.TLS) throw new ArgumentException("CURVE security settings are not yet available for GSF ZeroMQ client channel."); // Settings specific to Gateway security if (m_securityMode == SecurityMode.Gateway) { if (!settings.TryGetValue("sharedSecret", out m_sharedSecret) || string.IsNullOrWhiteSpace(m_sharedSecret)) throw new ArgumentException("The \"sharedSecret\" setting must be defined when using Gateway security mode."); if (!settings.TryGetValue("authenticationID", out m_authenticationID) || string.IsNullOrWhiteSpace(m_authenticationID)) throw new ArgumentException("The \"authenticationID\" setting must be defined when using Gateway security mode."); } // Settings specific to Transport Layer Security if (m_securityMode == SecurityMode.TLS) { if (!settings.TryGetValue("localCertificate", out m_localCertificate) || !File.Exists(m_localCertificate)) m_localCertificate = GetLocalCertificate(); if (!settings.TryGetValue("remoteCertificate", out m_remoteCertificate) || !RemoteCertificateExists()) throw new ArgumentException("The \"remoteCertificate\" setting must be defined and certificate file must exist when using TLS security mode."); if (!settings.TryGetValue("validPolicyErrors", out setting) || !Enum.TryParse(setting, out m_validPolicyErrors)) m_validPolicyErrors = SslPolicyErrors.None; if (!settings.TryGetValue("validChainFlags", out setting) || !Enum.TryParse(setting, out m_validChainFlags)) m_validChainFlags = X509ChainStatusFlags.NoError; if (settings.TryGetValue("checkCertificateRevocation", out setting) && !string.IsNullOrWhiteSpace(setting)) m_checkCertificateRevocation = setting.ParseBoolean(); else m_checkCertificateRevocation = true; } // Check if measurements for this connection should be marked as "internal" - i.e., owned and allowed for proxy if (settings.TryGetValue("internal", out setting)) m_internal = setting.ParseBoolean(); // Check if user has explicitly defined the ReceiveInternalMetadata flag if (settings.TryGetValue("receiveInternalMetadata", out setting)) ReceiveInternalMetadata = setting.ParseBoolean(); // Check if user has explicitly defined the ReceiveExternalMetadata flag if (settings.TryGetValue("receiveExternalMetadata", out setting)) ReceiveExternalMetadata = setting.ParseBoolean(); // Check if user has defined a meta-data synchronization timeout if (settings.TryGetValue("metadataSynchronizationTimeout", out setting) && int.TryParse(setting, out metadataSynchronizationTimeout)) m_metadataSynchronizationTimeout = metadataSynchronizationTimeout; // Check if user has defined a flag for using a transaction during meta-data synchronization if (settings.TryGetValue("useTransactionForMetadata", out setting)) m_useTransactionForMetadata = setting.ParseBoolean(); // Check if user wants to request that publisher use millisecond resolution to conserve bandwidth if (settings.TryGetValue("useMillisecondResolution", out setting)) m_useMillisecondResolution = setting.ParseBoolean(); // Check if user wants to request that publisher remove NaN from the data stream to conserve bandwidth if (settings.TryGetValue("requestNaNValueFilter", out setting)) m_requestNaNValueFilter = setting.ParseBoolean(); // Check if user has defined any meta-data filter expressions if (settings.TryGetValue("metadataFilters", out setting)) m_metadataFilters = setting; // Define auto connect setting if (settings.TryGetValue("autoConnect", out setting)) { m_autoConnect = setting.ParseBoolean(); if (m_autoConnect) m_autoSynchronizeMetadata = true; } // Define the maximum allowed exceptions before resetting the connection if (settings.TryGetValue("allowedParsingExceptions", out setting)) m_allowedParsingExceptions = int.Parse(setting); // Define the window of time over which parsing exceptions are tolerated if (settings.TryGetValue("parsingExceptionWindow", out setting)) m_parsingExceptionWindow = Ticks.FromSeconds(double.Parse(setting)); // Check if synchronize meta-data is explicitly enabled or disabled if (settings.TryGetValue("synchronizeMetadata", out setting)) m_autoSynchronizeMetadata = setting.ParseBoolean(); // Define data loss interval if (settings.TryGetValue("dataLossInterval", out setting) && double.TryParse(setting, out interval)) DataLossInterval = interval; // Define buffer size if (!settings.TryGetValue("bufferSize", out setting) || !int.TryParse(setting, out bufferSize)) bufferSize = ClientBase.DefaultReceiveBufferSize; if (settings.TryGetValue("useLocalClockAsRealTime", out setting)) m_useLocalClockAsRealTime = setting.ParseBoolean(); if (m_autoConnect) { // Connect to local events when automatically engaging connection cycle ConnectionAuthenticated += DataSubscriber_ConnectionAuthenticated; MetaDataReceived += DataSubscriber_MetaDataReceived; // Update output measurements to include "subscribed" points UpdateOutputMeasurements(true); } else if (m_autoSynchronizeMetadata) { // Output measurements do not include "subscribed" points, // but should still be filtered if applicable TryFilterOutputMeasurements(); } if (m_securityMode != SecurityMode.TLS) { if (m_useZeroMQChannel) { // Create a new ZeroMQ Dealer ZeroMQClient commandChannel = new ZeroMQClient(); // Initialize default settings commandChannel.PersistSettings = false; commandChannel.MaxConnectionAttempts = 1; commandChannel.ReceiveBufferSize = bufferSize; commandChannel.SendBufferSize = bufferSize; // Assign command channel client reference and attach to needed events CommandChannel = commandChannel; } else { // Create a new TCP client TcpClient commandChannel = new TcpClient(); // Initialize default settings commandChannel.PayloadAware = true; commandChannel.PersistSettings = false; commandChannel.MaxConnectionAttempts = 1; commandChannel.ReceiveBufferSize = bufferSize; commandChannel.SendBufferSize = bufferSize; // Assign command channel client reference and attach to needed events CommandChannel = commandChannel; } } else { if (m_useZeroMQChannel) { // Create a new ZeroMQ Dealer with CURVE security enabled ZeroMQClient commandChannel = new ZeroMQClient(); // Initialize default settings commandChannel.PersistSettings = false; commandChannel.MaxConnectionAttempts = 1; commandChannel.ReceiveBufferSize = bufferSize; commandChannel.SendBufferSize = bufferSize; // TODO: Parse certificate and pass keys to ZeroMQClient for CURVE security // Assign command channel client reference and attach to needed events CommandChannel = commandChannel; } else { // Create a new TLS client and certificate checker TlsClient commandChannel = new TlsClient(); SimpleCertificateChecker certificateChecker = new SimpleCertificateChecker(); // Set up certificate checker certificateChecker.TrustedCertificates.Add(new X509Certificate2(FilePath.GetAbsolutePath(m_remoteCertificate))); certificateChecker.ValidPolicyErrors = m_validPolicyErrors; certificateChecker.ValidChainFlags = m_validChainFlags; // Initialize default settings commandChannel.PayloadAware = true; commandChannel.PersistSettings = false; commandChannel.MaxConnectionAttempts = 1; commandChannel.CertificateFile = FilePath.GetAbsolutePath(m_localCertificate); commandChannel.CheckCertificateRevocation = m_checkCertificateRevocation; commandChannel.CertificateChecker = certificateChecker; commandChannel.ReceiveBufferSize = bufferSize; commandChannel.SendBufferSize = bufferSize; // Assign command channel client reference and attach to needed events CommandChannel = commandChannel; } } // Get proper connection string - either from specified command channel or from base connection string if (settings.TryGetValue("commandChannel", out setting)) m_commandChannel.ConnectionString = setting; else m_commandChannel.ConnectionString = ConnectionString; // Get logging path, if any has been defined if (settings.TryGetValue("loggingPath", out setting)) { setting = FilePath.GetDirectoryName(FilePath.GetAbsolutePath(setting)); if (Directory.Exists(setting)) m_loggingPath = setting; else OnStatusMessage("WARNING: Logging path \"{0}\" not found, defaulting to \"{1}\"...", setting, FilePath.GetAbsolutePath("")); } // Initialize data gap recovery processing, if requested if (settings.TryGetValue("dataGapRecovery", out setting)) { // Make sure setting exists to allow user to by-pass phasor data source validation at startup ConfigurationFile configFile = ConfigurationFile.Current; CategorizedSettingsElementCollection systemSettings = configFile.Settings["systemSettings"]; CategorizedSettingsElement dataGapRecoveryEnabledSetting = systemSettings["DataGapRecoveryEnabled"]; // See if this node should process phasor source validation if ((object)dataGapRecoveryEnabledSetting == null || dataGapRecoveryEnabledSetting.ValueAsBoolean()) { // Example connection string for data gap recovery: // dataGapRecovery={enabled=true; recoveryStartDelay=10.0; minimumRecoverySpan=0.0; maximumRecoverySpan=3600.0} Dictionary<string, string> dataGapSettings = setting.ParseKeyValuePairs(); if (dataGapSettings.TryGetValue("enabled", out setting) && setting.ParseBoolean()) { // Remove dataGapRecovery connection setting from command channel connection string, if defined there. // This will prevent any recursive data gap recovery operations from being established: Dictionary<string, string> connectionSettings = m_commandChannel.ConnectionString.ParseKeyValuePairs(); connectionSettings.Remove("dataGapRecovery"); connectionSettings.Remove("autoConnect"); connectionSettings.Remove("synchronizeMetadata"); connectionSettings.Remove("outputMeasurements"); // Note that the data gap recoverer will connect on the same command channel port as // the real-time subscriber (TCP only) m_dataGapRecoveryEnabled = true; m_dataGapRecoverer = new DataGapRecoverer(); m_dataGapRecoverer.SourceConnectionName = Name; m_dataGapRecoverer.DataSource = DataSource; m_dataGapRecoverer.ConnectionString = string.Join("; ", $"autoConnect=false; synchronizeMetadata=false{(string.IsNullOrWhiteSpace(m_loggingPath) ? "" : "; loggingPath=" + m_loggingPath)}", dataGapSettings.JoinKeyValuePairs(), connectionSettings.JoinKeyValuePairs()); m_dataGapRecoverer.FilterExpression = this.OutputMeasurementKeys().Select(key => key.SignalID.ToString()).ToDelimitedString(';'); m_dataGapRecoverer.RecoveredMeasurements += m_dataGapRecoverer_RecoveredMeasurements; m_dataGapRecoverer.StatusMessage += m_dataGapRecoverer_StatusMessage; m_dataGapRecoverer.ProcessException += m_dataGapRecoverer_ProcessException; m_dataGapRecoverer.Initialize(); } else { m_dataGapRecoveryEnabled = false; } } } else { m_dataGapRecoveryEnabled = false; } // Register subscriber with the statistics engine StatisticsEngine.Register(this, "Subscriber", "SUB"); StatisticsEngine.Calculated += (sender, args) => ResetMeasurementsPerSecondCounters(); Initialized = true; }
// *** certificate chain/path validation stuff *** // Currently a subset of RFC3280 (hopefully a full implementation someday) private void ValidateChain (X509ChainStatusFlags flag) { // 'n' should be the root certificate... int n = elements.Count - 1; X509Certificate2 certificate = elements [n].Certificate; // ... and, if so, must be treated outside the chain... if (((flag & X509ChainStatusFlags.PartialChain) == 0)) { Process (n); // deal with the case where the chain == the root certificate // (which isn't for RFC3280) part of the chain if (n == 0) { elements [0].UncompressFlags (); return; } // skip the root certificate when processing the chain (in 6.1.3) n--; } // ... unless the chain is a partial one (then we start with that one) // 6.1.1 - Inputs // 6.1.1.a - a prospective certificate path of length n (i.e. elements) // 6.1.1.b - the current date/time (i.e. ChainPolicy.VerificationTime) // 6.1.1.c - user-initial-policy-set (i.e. ChainPolicy.CertificatePolicy) // 6.1.1.d - the trust anchor information (i.e. certificate, unless it's a partial chain) // 6.1.1.e - initial-policy-mapping-inhibit (NOT SUPPORTED BY THE API) // 6.1.1.f - initial-explicit-policy (NOT SUPPORTED BY THE API) // 6.1.1.g - initial-any-policy-inhibit (NOT SUPPORTED BY THE API) // 6.1.2 - Initialization (incomplete) // 6.1.2.a-f - policy stuff, some TODO, some not supported // 6.1.2.g - working public key algorithm // working_public_key_algorithm = certificate.PublicKey.Oid.Value; // 6.1.2.h-i - our key contains both the "working public key" and "working public key parameters" data working_public_key = certificate.PublicKey.Key; // 6.1.2.j - working issuer name working_issuer_name = certificate.IssuerName; // 6.1.2.k - this integer is initialized to n, is decremented for each non-self-issued, certificate and // may be reduced to the value in the path length constraint field max_path_length = n; // 6.1.3 - Basic Certificate Processing // note: loop looks reversed (the list is) but we process this part just like RFC3280 does for (int i = n; i > 0; i--) { Process (i); // 6.1.4 - preparation for certificate i+1 (for not with i+1, or i-1 in our loop) PrepareForNextCertificate (i); } Process (0); // 6.1.3.a.3 - revocation checks CheckRevocationOnChain (flag); // 6.1.5 - Wrap-up procedure WrapUp (); }
//this code comes from AgentDiagnostics. Need a better way to hook ino Agent. //Agent hooks TrustChainValidator and the build in DnsCertResolver, but the DnsCertResolver is strongly //linked rather than via interface for notifications and exceptions. static string Summarize(X509ChainElement chainElement, X509ChainStatusFlags problemFlags) { StringBuilder builder = new StringBuilder(); builder.Append(chainElement.Certificate.ExtractEmailNameOrName()); builder.Append(";"); foreach (X509ChainStatus status in chainElement.ChainElementStatus) { if ((status.Status & problemFlags) != 0) { builder.Append(status.Status); } } return builder.ToString(); }
private bool IsParent (X509Certificate child, X509Certificate parent) { if (child.IssuerName != parent.SubjectName) return false; // parent MUST have the Basic Constraint CA=true (except for trusted roots) // see why at http://www.microsoft.com/technet/security/bulletin/MS02-050.asp if ((parent.Version > 2) && (!IsTrusted (parent))) { // TODO: we do not support pathLenConstraint X509Extension ext = parent.Extensions ["2.5.29.19"]; if (ext != null) { BasicConstraintsExtension bc = new BasicConstraintsExtension (ext); if (!bc.CertificateAuthority) _status = X509ChainStatusFlags.InvalidBasicConstraints; } else _status = X509ChainStatusFlags.InvalidBasicConstraints; } if (!child.VerifySignature (parent.RSA)) { _status = X509ChainStatusFlags.NotSignatureValid; return false; } return true; }
private X509Certificate FindCertificateRoot (X509Certificate potentialRoot) { if (potentialRoot == null) { _status = X509ChainStatusFlags.PartialChain; return null; } // if the trusted root is in the chain if (IsTrusted (potentialRoot)) { return potentialRoot; } // if the root isn't in the chain foreach (X509Certificate root in TrustAnchors) { if (IsParent (potentialRoot, root)) { return root; } } // is it a (untrusted) root ? if (potentialRoot.IsSelfSigned) { _status = X509ChainStatusFlags.UntrustedRoot; return potentialRoot; } _status = X509ChainStatusFlags.PartialChain; return null; }
/// <summary> /// Create an LDAP certificate resolver, using timeout and default DNS server for SRV lookup /// </summary> /// <param name="dnsServerIp">An <see cref="IPAddress"/> IP address of the DNS server to use for DNS lookups</param> /// <param name="timeout">Timeout value for DNS and LDAP lookups</param> /// <param name="cacheEnabled">boolean flag indicating whether or not to use the DNS client with cache</param> public LdapCertResolver(IPAddress dnsServerIp, TimeSpan timeout, bool cacheEnabled) { if (dnsServerIp == null) { dnsServerIp = GetLocalServerDns(dnsServerIp); } if (dnsServerIp == null) throw new ArgumentNullException("dnsServerIp"); if (timeout.Ticks < 0) { throw new ArgumentException("timeout value was less than zero", "timeout"); } m_dnsServerIp = dnsServerIp; m_timeout = timeout; m_cacheEnabled = cacheEnabled; m_policy = new X509ChainPolicy(); m_policy.VerificationFlags = (X509VerificationFlags.IgnoreWrongUsage); m_problemFlags = DefaultProblemFlags; }
public X509ChainErrorMapping(CertTrustErrorStatus win32Flag, int win32ErrorCode, X509ChainStatusFlags chainStatusFlag) { Win32Flag = win32Flag; Win32ErrorCode = win32ErrorCode; ChainStatusFlag = chainStatusFlag; }
/// <summary> /// Creates a new instance of the <see cref="SimpleCertificateChecker"/> class. /// </summary> public SimpleCertificateChecker() { m_trustedCertificates = new List<X509Certificate>(); m_validPolicyErrors = SslPolicyErrors.None; m_validChainFlags = X509ChainStatusFlags.NoError; }
private static X509VerificationFlags? GetSuppressionFlag(X509ChainStatusFlags status) { switch (status) { case X509ChainStatusFlags.UntrustedRoot: case X509ChainStatusFlags.PartialChain: return X509VerificationFlags.AllowUnknownCertificateAuthority; case X509ChainStatusFlags.NotValidForUsage: case X509ChainStatusFlags.CtlNotValidForUsage: return X509VerificationFlags.IgnoreWrongUsage; case X509ChainStatusFlags.NotTimeValid: return X509VerificationFlags.IgnoreNotTimeValid; case X509ChainStatusFlags.CtlNotTimeValid: return X509VerificationFlags.IgnoreCtlNotTimeValid; case X509ChainStatusFlags.InvalidNameConstraints: case X509ChainStatusFlags.HasNotSupportedNameConstraint: case X509ChainStatusFlags.HasNotDefinedNameConstraint: case X509ChainStatusFlags.HasNotPermittedNameConstraint: case X509ChainStatusFlags.HasExcludedNameConstraint: return X509VerificationFlags.IgnoreInvalidName; case X509ChainStatusFlags.InvalidPolicyConstraints: case X509ChainStatusFlags.NoIssuanceChainPolicy: return X509VerificationFlags.IgnoreInvalidPolicy; case X509ChainStatusFlags.InvalidBasicConstraints: return X509VerificationFlags.IgnoreInvalidBasicConstraints; case X509ChainStatusFlags.HasNotSupportedCriticalExtension: // This field would be mapped in by AllFlags, but we don't have a name for it currently. return (X509VerificationFlags)0x00002000; case X509ChainStatusFlags.NotTimeNested: return X509VerificationFlags.IgnoreNotTimeNested; } return null; }
private void Set (X509ChainStatus[] status, ref int position, X509ChainStatusFlags flags, X509ChainStatusFlags mask) { if ((flags & mask) != 0) { status [position].Status = mask; status [position].StatusInformation = X509ChainStatus.GetInformation (mask); position++; } }
// public void Reset () { _status = X509ChainStatusFlags.NoError; roots = null; // this force a reload certs.Clear (); if (_chain != null) _chain.Clear (); }
// we check the revocation only once we have built the complete chain private void CheckRevocationOnChain (X509ChainStatusFlags flag) { bool partial = ((flag & X509ChainStatusFlags.PartialChain) != 0); bool online; switch (ChainPolicy.RevocationMode) { case X509RevocationMode.Online: // default online = true; break; case X509RevocationMode.Offline: online = false; break; case X509RevocationMode.NoCheck: return; default: throw new InvalidOperationException (Locale.GetText ("Invalid revocation mode.")); } bool unknown = partial; // from the root down to the end-entity for (int i = elements.Count - 1; i >= 0; i--) { bool check = true; switch (ChainPolicy.RevocationFlag) { case X509RevocationFlag.EndCertificateOnly: check = (i == 0); break; case X509RevocationFlag.EntireChain: check = true; break; case X509RevocationFlag.ExcludeRoot: // default check = (i != (elements.Count - 1)); // anyway, who's gonna sign that the root is invalid ? break; } X509ChainElement element = elements [i]; // we can't assume the revocation status if the certificate is bad (e.g. invalid signature) if (!unknown) unknown |= ((element.StatusFlags & X509ChainStatusFlags.NotSignatureValid) != 0); if (unknown) { // we can skip the revocation checks as we can't be sure of them anyway element.StatusFlags |= X509ChainStatusFlags.RevocationStatusUnknown; element.StatusFlags |= X509ChainStatusFlags.OfflineRevocation; } else if (check && !partial && !IsSelfIssued (element.Certificate)) { // check for revocation (except for the trusted root and self-issued certs) element.StatusFlags |= CheckRevocation (element.Certificate, i+1, online); // if revoked, then all others following in the chain are unknown... unknown |= ((element.StatusFlags & X509ChainStatusFlags.Revoked) != 0); } } }
/// <summary> /// Creates a DNS certificate resolver with a custom timeout and a fallback domain. /// </summary> /// <param name="serverIP">An <see cref="IPAddress"/> instance providing the IP address of the DNS server</param> /// <param name="timeout">Timeout value</param> /// <param name="fallbackDomain">A fallback domain name to try if the main domain name is not resolved.</param> /// <param name="cacheEnabled">boolean flag indicating whether or not to use the client with cache</param> public DnsCertResolver(IPAddress serverIP , TimeSpan timeout , string fallbackDomain , bool cacheEnabled) { if (serverIP == null) { throw new ArgumentNullException("serverIP"); } if (timeout.Ticks < 0) { throw new ArgumentException("timeout value was less than zero", "timeout"); } m_serverIP = serverIP; m_timeout = timeout; m_fallbackDomain = fallbackDomain; m_cacheEnabled = cacheEnabled; m_policy = new X509ChainPolicy(); m_policy.VerificationFlags = (X509VerificationFlags.IgnoreWrongUsage); m_problemFlags = DefaultProblemFlags; }