void Trust_FullChain(SecTrust trust, SecPolicy policy, X509CertificateCollection certs) { // that certificate stopped being valid on September 30th, 2013 so we validate it with a date earlier than that trust.SetVerifyDate(new DateTime(635108745218945450, DateTimeKind.Utc)); SecTrustResult trust_result = SecTrustResult.Unspecified; var ios9 = TestRuntime.CheckXcodeVersion(7, 0); var ios10 = TestRuntime.CheckXcodeVersion(8, 0); var ios11 = TestRuntime.CheckXcodeVersion(9, 0); if (ios10) { trust_result = SecTrustResult.FatalTrustFailure; } // iOS9 is not fully happy with the basic constraints: `SecTrustEvaluate [root AnchorTrusted BasicContraints]` else if (ios9) { trust_result = SecTrustResult.RecoverableTrustFailure; } var result = Evaluate(trust, true); Assert.That(result, Is.EqualTo(trust_result), "Evaluate"); // Evalute must be called prior to Count (Apple documentation) Assert.That(trust.Count, Is.EqualTo(3), "Count"); using (SecCertificate sc1 = trust [0]) { // seems the leaf gets an extra one Assert.That(CFGetRetainCount(sc1.Handle), Is.GreaterThanOrEqualTo((nint)2), "RetainCount(sc1)"); Assert.That(sc1.SubjectSummary, Is.EqualTo("mail.google.com"), "SubjectSummary(sc1)"); } using (SecCertificate sc2 = trust [1]) { Assert.That(CFGetRetainCount(sc2.Handle), Is.GreaterThanOrEqualTo((nint)2), "RetainCount(sc2)"); Assert.That(sc2.SubjectSummary, Is.EqualTo("Thawte SGC CA"), "SubjectSummary(sc2)"); } using (SecCertificate sc3 = trust [2]) { Assert.That(CFGetRetainCount(sc3.Handle), Is.GreaterThanOrEqualTo((nint)2), "RetainCount(sc3)"); Assert.That(sc3.SubjectSummary, Is.EqualTo("Class 3 Public Primary Certification Authority"), "SubjectSummary(sc3)"); } if (TestRuntime.CheckXcodeVersion(5, 0)) { Assert.That(trust.GetTrustResult(), Is.EqualTo(trust_result), "GetTrustResult"); trust.SetAnchorCertificates(certs); Assert.That(trust.GetCustomAnchorCertificates().Length, Is.EqualTo(certs.Count), "GetCustomAnchorCertificates"); if (ios11) { trust_result = SecTrustResult.Unspecified; } else { trust_result = SecTrustResult.Invalid; } // since we modified the `trust` instance it's result was invalidated (marked as unspecified on iOS 11) Assert.That(trust.GetTrustResult(), Is.EqualTo(trust_result), "GetTrustResult-2"); } }
public void Client_Leaf_Only() { X509Certificate x = new X509Certificate(CertificateTest.mail_google_com); using (var policy = SecPolicy.CreateSslPolicy(false, null)) using (var trust = new SecTrust(x, policy)) { // that certificate stopped being valid on September 30th, 2013 so we validate it with a date earlier than that trust.SetVerifyDate(new DateTime(635108745218945450, DateTimeKind.Utc)); // a host name is not meaningful for client certificates Assert.That(Evaluate(trust, true), Is.EqualTo(SecTrustResult.RecoverableTrustFailure), "Evaluate"); if (TestRuntime.CheckXcodeVersion(5, 0)) { // by default there's no *custom* anchors Assert.Null(trust.GetCustomAnchorCertificates(), "GetCustomAnchorCertificates"); using (var results = trust.GetResult()) { Assert.That(CFGetRetainCount(results.Handle), Is.EqualTo((nint)1), "RetainCount"); SecTrustResult value = (SecTrustResult)(int)(NSNumber)results [SecTrustResultKey.ResultValue]; Assert.That(value, Is.EqualTo(SecTrustResult.RecoverableTrustFailure), "ResultValue"); } } } }
public void Basic_Leaf_Only() { X509Certificate x = new X509Certificate(CertificateTest.mail_google_com); using (var policy = SecPolicy.CreateBasicX509Policy()) using (var trust = new SecTrust(x, policy)) { // that certificate stopped being valid on September 30th, 2013 so we validate it with a date earlier than that trust.SetVerifyDate(new DateTime(635108745218945450, DateTimeKind.Utc)); // SSL certs are a superset of the basic X509 profile SecTrustResult result = SecTrustResult.RecoverableTrustFailure; Assert.That(Evaluate(trust, result == SecTrustResult.RecoverableTrustFailure), Is.EqualTo(result), "Evaluate"); if (TestRuntime.CheckXcodeVersion(5, 0)) { // call GetPolicies without a SetPolicy / SetPolicies var policies = trust.GetPolicies(); Assert.That(policies.Length, Is.EqualTo(1), "Policies.Length"); using (var data = new NSData()) { // we do not have an easy way to get the response but the API accepts an empty NSData trust.SetOCSPResponse(data); } } } }
static void TrampolineEvaluate(IntPtr block, IntPtr trust, SecTrustResult trustResult) { var del = BlockLiteral.GetTarget <SecTrustCallback> (block); if (del != null) { var t = trust == IntPtr.Zero ? null : new SecTrust(trust, false); del(t, trustResult); } }
public void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action <NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler) { SecTrustResult result = challenge.ProtectionSpace.ServerSecTrust.Evaluate(); if (result == SecTrustResult.Unspecified || result == SecTrustResult.Proceed) { completionHandler(NSUrlSessionAuthChallengeDisposition.PerformDefaultHandling, null); } else { completionHandler(NSUrlSessionAuthChallengeDisposition.CancelAuthenticationChallenge, null); } }
// SecTrustResult.Unspecified == "Use System Defaults" (valid) // some days it seems iOS timeout just a bit too fast and we get a lot of false positives // this will try again a few times (giving the network request a chance to get back) static SecTrustResult Evaluate(SecTrust trust, bool expect_recoverable = false) { SecTrustResult result = SecTrustResult.Deny; for (int i = 0; i < 8; i++) { result = trust.Evaluate(); if (result != SecTrustResult.RecoverableTrustFailure || expect_recoverable) { return(result); } NSRunLoop.Main.RunUntil(NSDate.Now.AddSeconds(i)); } return(result); }
// SecTrustResult.Unspecified == "Use System Defaults" (valid) // some days it seems iOS timeout just a bit too fast and we get a lot of false positives // this will try again a few times (giving the network request a chance to get back) static SecTrustResult Evaluate(SecTrust trust, bool expect_recoverable = false) { SecTrustResult result = SecTrustResult.Deny; for (int i = 0; i < 8; i++) { result = trust.Evaluate(); if (result != SecTrustResult.RecoverableTrustFailure || expect_recoverable) { return(result); } NSRunLoop.Main.RunUntil(NSDate.Now.AddSeconds(i)); } // we have done our best (it has not failed, but did not confirm either) // still it can't recover (we and expected it could) most likely due to external factors (e.g. network) if (result == SecTrustResult.RecoverableTrustFailure && !expect_recoverable) { Assert.Inconclusive("Cannot recover from RecoverableTrustFailure after 8 attempts"); } return(result); }
extern static /* OSStatus */ int SecTrustEvaluate(IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
static SecTrustResult _TrustEvaluateSsl(X509CertificateCollection certificates, X509CertificateCollection anchors, string hostName) { int certCount = certificates.Count; int anchorCount = anchors != null ? anchors.Count : 0; IntPtr [] secCerts = new IntPtr [certCount]; IntPtr [] secCertAnchors = new IntPtr [anchorCount]; IntPtr certArray = IntPtr.Zero; IntPtr anchorArray = IntPtr.Zero; IntPtr sslsecpolicy = IntPtr.Zero; IntPtr host = IntPtr.Zero; IntPtr sectrust = IntPtr.Zero; SecTrustResult result = SecTrustResult.Deny; try { for (int i = 0; i < certCount; i++) { secCerts [i] = GetCertificate(certificates [i]); if (secCerts [i] == IntPtr.Zero) { return(SecTrustResult.Deny); } } for (int i = 0; i < anchorCount; i++) { secCertAnchors [i] = GetCertificate(anchors [i]); if (secCertAnchors [i] == IntPtr.Zero) { return(SecTrustResult.Deny); } } certArray = FromIntPtrs(secCerts); if (!string.IsNullOrEmpty(hostName)) { host = CFStringCreateWithCharacters(IntPtr.Zero, hostName, (IntPtr)hostName.Length); } sslsecpolicy = SecPolicyCreateSSL(true, host); int code = SecTrustCreateWithCertificates(certArray, sslsecpolicy, out sectrust); if (code != 0) { return(SecTrustResult.Deny); } if (anchorCount > 0) { anchorArray = FromIntPtrs(secCertAnchors); SecTrustSetAnchorCertificates(sectrust, anchorArray); } code = SecTrustEvaluate(sectrust, out result); return(result); } finally { if (certArray != IntPtr.Zero) { CFRelease(certArray); } if (anchorArray != IntPtr.Zero) { CFRelease(anchorArray); } for (int i = 0; i < certCount; i++) { if (secCerts [i] != IntPtr.Zero) { CFRelease(secCerts [i]); } } for (int i = 0; i < anchorCount; i++) { if (secCertAnchors [i] != IntPtr.Zero) { CFRelease(secCertAnchors [i]); } } if (sslsecpolicy != IntPtr.Zero) { CFRelease(sslsecpolicy); } if (host != IntPtr.Zero) { CFRelease(host); } if (sectrust != IntPtr.Zero) { CFRelease(sectrust); } } }
extern static SecStatusCode /* OSStatus */ SecTrustEvaluate(IntPtr /* SecTrustRef */ trust, out /* SecTrustResultType */ SecTrustResult result);
static int SecTrustEvaluate(IntPtr secTrustRef, out SecTrustResult secTrustResultTime) { throw new System.NotImplementedException(); }
static SecTrustResult _TrustEvaluateSsl(MSX.X509CertificateCollection certificates, string hostName) { int certCount = certificates.Count; IntPtr [] cfDataPtrs = new IntPtr [certCount]; IntPtr [] secCerts = new IntPtr [certCount]; IntPtr certArray = IntPtr.Zero; IntPtr sslsecpolicy = IntPtr.Zero; IntPtr host = IntPtr.Zero; IntPtr sectrust = IntPtr.Zero; SecTrustResult result = SecTrustResult.Deny; try { for (int i = 0; i < certCount; i++) { cfDataPtrs [i] = MakeCFData(certificates [i].RawData); } for (int i = 0; i < certCount; i++) { secCerts [i] = SecCertificateCreateWithData(IntPtr.Zero, cfDataPtrs [i]); if (secCerts [i] == IntPtr.Zero) { return(SecTrustResult.Deny); } } certArray = FromIntPtrs(secCerts); host = CFStringCreateWithCharacters(IntPtr.Zero, hostName, hostName.Length); sslsecpolicy = SecPolicyCreateSSL(true, host); int code = SecTrustCreateWithCertificates(certArray, sslsecpolicy, out sectrust); if (code == 0) { code = SecTrustEvaluate(sectrust, out result); } return(result); } finally { for (int i = 0; i < certCount; i++) { if (cfDataPtrs [i] != IntPtr.Zero) { CFRelease(cfDataPtrs [i]); } } if (certArray != IntPtr.Zero) { CFRelease(certArray); } for (int i = 0; i < certCount; i++) { if (secCerts [i] != IntPtr.Zero) { CFRelease(secCerts [i]); } } if (sslsecpolicy != IntPtr.Zero) { CFRelease(sslsecpolicy); } if (host != IntPtr.Zero) { CFRelease(host); } if (sectrust != IntPtr.Zero) { CFRelease(sectrust); } } }
extern static int SecTrustEvaluate (IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
extern static SecStatusCode /* OSStatus */ SecTrustEvaluate (IntPtr /* SecTrustRef */ trust, out /* SecTrustResultType */ SecTrustResult result);
static int SecTrustEvaluate (IntPtr secTrustRef, out SecTrustResult secTrustResultTime) { throw new System.NotImplementedException(); }
private static extern int SecTrustEvaluate(IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
extern static int SecTrustEvaluate(IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
extern static /* OSStatus */ int SecTrustEvaluate (IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
void Trust_FullChain(SecTrust trust, SecPolicy policy, X509CertificateCollection certs) { // that certificate stopped being valid on September 30th, 2013 so we validate it with a date earlier than that trust.SetVerifyDate(new DateTime(635108745218945450, DateTimeKind.Utc)); SecTrustResult trust_result = SecTrustResult.Unspecified; var ios9 = TestRuntime.CheckXcodeVersion(7, 0); var ios10 = TestRuntime.CheckXcodeVersion(8, 0); var ios11 = TestRuntime.CheckXcodeVersion(9, 0); var ios13 = TestRuntime.CheckXcodeVersion(11, 0); if (ios10) { trust_result = SecTrustResult.FatalTrustFailure; } // iOS9 is not fully happy with the basic constraints: `SecTrustEvaluate [root AnchorTrusted BasicContraints]` else if (ios9) { trust_result = SecTrustResult.RecoverableTrustFailure; } var result = Evaluate(trust, true); Assert.That(result, Is.EqualTo(trust_result), "Evaluate"); // Evalute must be called prior to Count (Apple documentation) Assert.That(trust.Count, Is.EqualTo(3), "Count"); using (SecCertificate sc1 = trust [0]) { // seems the leaf gets an extra one Assert.That(CFGetRetainCount(sc1.Handle), Is.GreaterThanOrEqualTo((nint)2), "RetainCount(sc1)"); Assert.That(sc1.SubjectSummary, Is.EqualTo("mail.google.com"), "SubjectSummary(sc1)"); } using (SecCertificate sc2 = trust [1]) { Assert.That(CFGetRetainCount(sc2.Handle), Is.GreaterThanOrEqualTo((nint)2), "RetainCount(sc2)"); Assert.That(sc2.SubjectSummary, Is.EqualTo("Thawte SGC CA"), "SubjectSummary(sc2)"); } using (SecCertificate sc3 = trust [2]) { Assert.That(CFGetRetainCount(sc3.Handle), Is.GreaterThanOrEqualTo((nint)2), "RetainCount(sc3)"); Assert.That(sc3.SubjectSummary, Is.EqualTo("Class 3 Public Primary Certification Authority"), "SubjectSummary(sc3)"); } if (TestRuntime.CheckXcodeVersion(5, 0)) { Assert.That(trust.GetTrustResult(), Is.EqualTo(trust_result), "GetTrustResult"); trust.SetAnchorCertificates(certs); Assert.That(trust.GetCustomAnchorCertificates().Length, Is.EqualTo(certs.Count), "GetCustomAnchorCertificates"); #if __MACOS__ if (TestRuntime.CheckSystemVersion(PlatformName.MacOSX, 10, 15)) { trust_result = SecTrustResult.RecoverableTrustFailure; } else if (TestRuntime.CheckSystemVersion(PlatformName.MacOSX, 10, 13)) { trust_result = SecTrustResult.Unspecified; } else if (TestRuntime.CheckSystemVersion(PlatformName.MacOSX, 10, 12)) { trust_result = SecTrustResult.Invalid; } else if (TestRuntime.CheckSystemVersion(PlatformName.MacOSX, 10, 11)) { trust_result = SecTrustResult.RecoverableTrustFailure; } else { trust_result = SecTrustResult.Unspecified; } #else if (ios13) { trust_result = SecTrustResult.RecoverableTrustFailure; } else if (ios11) { trust_result = SecTrustResult.Unspecified; } else { trust_result = SecTrustResult.Invalid; } #endif // since we modified the `trust` instance it's result was invalidated (marked as unspecified on iOS 11) Assert.That(trust.GetTrustResult(), Is.EqualTo(trust_result), "GetTrustResult-2"); } if (TestRuntime.CheckXcodeVersion(12, 0)) { // old certificate (built in our tests) was not quite up to spec and it eventually became important Assert.False(trust.Evaluate(out var error), "Evaluate"); Assert.NotNull(error, "error"); Assert.That(error.LocalizedDescription, Is.EqualTo("“mail.google.com” certificate is not standards compliant"), "desc"); } else if (TestRuntime.CheckXcodeVersion(11, 0)) { Assert.False(trust.Evaluate(out var error), "Evaluate"); Assert.NotNull(error, "error"); Assert.That(error.LocalizedDescription, Does.Contain("\"mail.google.com\",\"Thawte SGC CA\",\"Class 3 Public Primary Certification Authority\" certificates do not meet pinning requirements")); var underlyingError = (NSError)error.UserInfo [NSError.UnderlyingErrorKey]; // Error is: // Certificate 0 “mail.google.com” has errors: Key size is not permitted for this use, SSL hostname does not match name(s) in certificate, Signature hash algorithm is not permitted for this use;Certificate 1 “Thawte SGC CA” has errors: Key size is not permitted for this use, Signature hash algorithm is not permitted for this use;Certificate 2 “Class 3 Public Primary Certification Authority” has errors: Key size is not permitted for this use; // But the exact format can vary // watchOS reports this: // Certificate 0 “mail.google.com” has errors: Key size is not permitted for this use, Signature hash algorithm is not permitted for this use, SSL hostname does not match name(s) in certificate;Certificate 1 “Thawte SGC CA” has errors: Key size is not permitted for this use, Signature hash algorithm is not permitted for this use;Certificate 2 “Class 3 Public Primary Certification Authority” has errors: Key size is not permitted for this use; Assert.That(underlyingError.LocalizedDescription, Does.Contain("Certificate 0 “mail.google.com” has errors: ")); Assert.That(underlyingError.LocalizedDescription, Does.Contain("Key size is not permitted for this use")); Assert.That(underlyingError.LocalizedDescription, Does.Contain("SSL hostname does not match name(s) in certificate").Or.Contain("Signature hash algorithm is not permitted for this use")); Assert.That(underlyingError.LocalizedDescription, Does.Contain("Certificate 1 “Thawte SGC CA” has errors: Key size is not permitted for this use")); Assert.That(underlyingError.LocalizedDescription, Does.Contain("Certificate 2 “Class 3 Public Primary Certification Authority” has errors:")); } else if (TestRuntime.CheckXcodeVersion(10, 0)) { Assert.True(trust.Evaluate(out var error), "Evaluate"); Assert.Null(error, "error"); } }
extern static SecStatusCode /* OSStatus */ SecTrustGetTrustResult(IntPtr /* SecTrustRef */ trust, out SecTrustResult /* SecTrustResultType */ result);
static extern SecStatusCode SecTrustGetTrustResult(IntPtr /* SecTrustRef */ trust, out SecTrustResult /* SecTrustResultType */ result);