Initial implementation of X509Certificates, HttpClient, and SslStream for macOS #15970
Conversation
This is a bit of a Work In Progress. But I'd gone on long enough that I wanted to get something out for review. X509Certificates should fully pass tests. HttpClient will probably explode due to a TODO I left myself, and SslClient I'm trying to see what places the official tests are having trouble with in case my machine is behaving oddly. My current remaining cleanup notes (aside from "implement deferred functionality"):
Part of what I'm looking for at this juncture is macro-comments; things that might take a day or two of restructuring to fix. Micro-comments are also quite welcome. |
@dotnet-bot Test Outerloop OSX Debug please |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cursory review done. Will do a detailed review when we pull things back
return -2; | ||
} | ||
|
||
//*pOSStatus = SecTrustSetNetworkFetchAllowed(chain, allowNetwork); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debugging?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, good catch.
} | ||
|
||
CFDictionaryRef detailsAndStuff = SecTrustCopyResult(chain); | ||
CFTypeRef detailsPtr = CFDictionaryGetValue(detailsAndStuff, CFSTR("TrustResultDetails")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No error checking against detailsAndStuff and detailsPtr here
CFRetain(details); | ||
CFRelease(detailsAndStuff); | ||
|
||
printf("Just the details:\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More debugging? (I'll stop mentioning that regarding printfs)
PAL_X509ChainCtlNotTimeValid = 0x00020000, | ||
PAL_X509ChainCtlNotSignatureValid = 0x00040000, | ||
PAL_X509ChainCtlNotValidForUsage = 0x00080000, | ||
PAL_X509ChainOfflineRevocation = 0x01000000, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went from 80000 to 1000000 (an extra 0)?
PAL_X509ChainNoIssuanceChainPolicy = 0x02000000, | ||
PAL_X509ChainExplicitDistrust = 0x04000000, | ||
PAL_X509ChainHasNotSupportedCriticalExtension = 0x08000000, | ||
PAL_X509ChainHasWeakSignature = 0x00100000, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PAL_X509ChainHasWeakSignature out of order or need extra 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Values and ordering should be the same as they are in X509ChainStatusFlags.
{ | ||
// This is as likely as anything. No error conditions are defined for | ||
// the OS function, and our shim only adds a NULL if isServer isn't a normalized bool. | ||
throw new OutOfMemoryException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we can have something better.... Just raw Exception?
|
||
private unsafe int WriteToConnection(void* connection, byte* data, void** dataLength) | ||
{ | ||
ulong toWrite = (ulong)*dataLength; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
verify connection == _toConnection?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
connection will be NULL since we don't give them one. (It's their callback's way of maintaining object notions; but we got that captured in the delegate)
X509ChainElementCollection elements = chain.ChainElements; | ||
|
||
// We need to leave off the EE (first) and root (last) certificate from the intermediates. | ||
X509Certificate2[] intermediateCerts = elements.Count < 3 ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does <3 guarantee that we need to remove the first and last? Vs. 4, 5, etc.?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If 1, it's just the first cert.
If 2, it's a cert directly from a root.
In both 1 and 2 we've removed the items we care about by being Array.Empty. At 3 we have things left over after we remove up to two.
And, really, it's because we're about to do Count - 2
as an array size.
@@ -0,0 +1,363 @@ | |||
// Licensed to the .NET Foundation under one or more agreements. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't review. Refactoring of OpenSslCertificateFinder.cs ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep
@@ -2,12 +2,14 @@ | |||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I'm working on cleaning up the .props, test .csproj because most of our newer tests are not running due build changes and renaming of netstandard :(
fdb3ed5
to
8cf6f2c
Compare
… for macOS Broken by this change: * X509Store has no implementation yet on macOS. * Exporting as a PFX is not yet implemented on macOS. * A lot of TLS CipherSuites have no metadata defined. * macOS does not support version skipping in TLS. So `Tls | Tls12` is an invalid choice. In this change: General: * All OSStatus related exceptions now look up the error message. X509Certificates: * X509Certificate moves to using SecCertificateRef from OpenSSL's X509. * X509 metadata comes from a managed reader after being loaded by Security.framework, due to the significant amount of data that has no public export in Apple's libraries. * Significant code was factored out to be shared by OpenSSL and Apple implementations for X500DistinguishedName and X509Certficate2Collection.Find. * Loading a PFX (or, rather, the private keys from a PFX) via Apple's platform requires importing into a Keychain, and a Keychain requires a file on disk. A temporary keychain is created during cert loading and erased when safe. Like the perphemeral key load on Windows this can leak files due to abnormal program termination. HttpClient: * Initialization no longer wakes up OpenSSL SslStream: * New implementation based on Apple SecureTransport. * Currently has support for SNI (for AuthenticateAsClient)
8cf6f2c
to
071d141
Compare
Arg_InvalidHandle takes an argument name. Cryptography_OpenInvalidHandle just describes the state of things.
Okay, it seems that Sierra (10.12) fixed some bugs in SecTrustEvaluate. On El Capitan (10.11) it segfaults 50% of the time when the evaluation doesn't involve the SSL policy (the other 50% it reports a corrupt keychain when no keychain should be involved). Hmm. |
Enough changed that I made a completely new PR (#16445). To get an idea of the changes: bartonjs/corefx@apple_x509_part1...bartonjs:apple_x509_part2 |
Broken by this change:
Tls | Tls12
is an invalid choice.In this change:
General:
X509Certificates:
due to the significant amount of data that has no public export in Apple's libraries.
requires importing into a Keychain, and a Keychain requires a file on disk.
A temporary keychain is created during cert loading and erased when safe.
Like the perphemeral key load on Windows this can leak files due to
abnormal program termination.
HttpClient:
SslStream: