Skip to content

Commit ab0dd26

Browse files
authored
Merge pull request #1401 from Unity-Technologies/unity-master-include-system-store-certificates-in-callback
Unity master include system store certificates in callback
2 parents 3ffa57d + 82c89ab commit ab0dd26

File tree

2 files changed

+35
-8
lines changed

2 files changed

+35
-8
lines changed

mcs/class/System/Mono.UnityTls/UnityTlsProvider.cs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ internal override IMonoSslStream CreateSslStreamInternal (
4848
return new UnityTlsStream (innerStream, leaveInnerStreamOpen, sslStream, settings, this);
4949
}
5050

51+
static UnityTls.unitytls_x509verify_result x509verify_callback(void* userData, UnityTls.unitytls_x509_ref cert, UnityTls.unitytls_x509verify_result result, UnityTls.unitytls_errorstate* errorState)
52+
{
53+
if (userData != null)
54+
UnityTls.NativeInterface.unitytls_x509list_append ((UnityTls.unitytls_x509list*)userData, cert, errorState);
55+
return result;
56+
}
57+
5158
internal override bool ValidateCertificate (
5259
ICertificateValidator2 validator, string targetHost, bool serverMode,
5360
X509CertificateCollection certificates, bool wantsChain, ref X509Chain chain,
@@ -62,9 +69,6 @@ internal override bool ValidateCertificate (
6269
errors |= MonoSslPolicyErrors.RemoteCertificateNotAvailable;
6370
return false;
6471
}
65-
66-
if (wantsChain)
67-
chain = MNS.SystemCertificateValidator.CreateX509Chain (certificates);
6872
}
6973
else
7074
{
@@ -85,6 +89,7 @@ internal override bool ValidateCertificate (
8589
// convert cert to native or extract from unityTlsChainImpl.
8690
var result = UnityTls.unitytls_x509verify_result.UNITYTLS_X509VERIFY_NOT_DONE;
8791
UnityTls.unitytls_x509list* certificatesNative = null;
92+
UnityTls.unitytls_x509list* finalCertificateChainNative = UnityTls.NativeInterface.unitytls_x509list_create (&errorState);
8893
try
8994
{
9095
// Things the validator provides that we might want to make use of here:
@@ -114,29 +119,42 @@ internal override bool ValidateCertificate (
114119
var trustCAnativeRef = UnityTls.NativeInterface.unitytls_x509list_get_ref (trustCAnative, &errorState);
115120

116121
fixed (byte* targetHostUtf8Ptr = targetHostUtf8) {
117-
result = UnityTls.NativeInterface.unitytls_x509verify_explicit_ca (certificatesNativeRef, trustCAnativeRef, targetHostUtf8Ptr, (size_t)targetHostUtf8.Length, null, null, &errorState);
122+
result = UnityTls.NativeInterface.unitytls_x509verify_explicit_ca (
123+
certificatesNativeRef, trustCAnativeRef, targetHostUtf8Ptr, (size_t)targetHostUtf8.Length, x509verify_callback, finalCertificateChainNative, &errorState);
118124
}
119125
}
120126
finally {
121127
UnityTls.NativeInterface.unitytls_x509list_free (trustCAnative);
122128
}
123129
} else {
124130
fixed (byte* targetHostUtf8Ptr = targetHostUtf8) {
125-
result = UnityTls.NativeInterface.unitytls_x509verify_default_ca (certificatesNativeRef, targetHostUtf8Ptr, (size_t)targetHostUtf8.Length, null, null, &errorState);
131+
result = UnityTls.NativeInterface.unitytls_x509verify_default_ca (
132+
certificatesNativeRef, targetHostUtf8Ptr, (size_t)targetHostUtf8.Length, x509verify_callback, finalCertificateChainNative, &errorState);
126133
}
127134
}
128135
}
136+
catch {
137+
UnityTls.NativeInterface.unitytls_x509list_free (finalCertificateChainNative);
138+
throw;
139+
}
129140
finally {
130141
UnityTls.NativeInterface.unitytls_x509list_free (certificatesNative);
131142
}
132143

144+
chain?.Dispose();
145+
var chainImpl = new X509ChainImplUnityTls(
146+
UnityTls.NativeInterface.unitytls_x509list_get_ref (finalCertificateChainNative, &errorState),
147+
reverseOrder: true // the verify callback starts with the root and ends with the leaf. That's the opposite of chain ordering.
148+
);
149+
chain = new X509Chain(chainImpl);
150+
133151
errors = UnityTlsConversions.VerifyResultToPolicyErrror(result);
134152
// There should be a status per certificate, but once again we're following closely the BTLS implementation
135153
// https://github.com/mono/mono/blob/1553889bc54f87060158febca7e6b8b9910975f8/mcs/class/System/Mono.Btls/MonoBtlsProvider.cs#L180
136154
// which also provides only a single status for the entire chain.
137155
// It is notoriously tricky to implement in OpenSSL to get a status for all invididual certificates without finishing the handshake in the process.
138156
// This is partially the reason why unitytls_x509verify_X doesn't expose it (TODO!) and likely the reason Mono's BTLS impl ignores this.
139-
unityTlsChainImpl?.AddStatus(UnityTlsConversions.VerifyResultToChainStatus(result));
157+
chainImpl.AddStatus(UnityTlsConversions.VerifyResultToChainStatus(result));
140158
return result == UnityTls.unitytls_x509verify_result.UNITYTLS_X509VERIFY_SUCCESS &&
141159
errorState.code == UnityTls.unitytls_error_code.UNITYTLS_SUCCESS;
142160
}

mcs/class/System/Mono.UnityTls/X509ChainImplUnityTls.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ class X509ChainImplUnityTls : X509ChainImpl
1717
private UnityTls.unitytls_x509list_ref nativeCertificateChain;
1818
private X509ChainPolicy policy = new X509ChainPolicy ();
1919
private List<X509ChainStatus> chainStatusList;
20+
private bool reverseOrder;
2021

21-
internal X509ChainImplUnityTls (UnityTls.unitytls_x509list_ref nativeCertificateChain)
22+
internal X509ChainImplUnityTls (UnityTls.unitytls_x509list_ref nativeCertificateChain, bool reverseOrder = false)
2223
{
2324
this.elements = null;
2425
this.nativeCertificateChain = nativeCertificateChain;
26+
this.reverseOrder = reverseOrder;
2527
}
2628

2729
public override bool IsValid {
@@ -45,7 +47,7 @@ public override X509ChainElementCollection ChainElements {
4547
elements = new X509ChainElementCollection ();
4648
UnityTls.unitytls_errorstate errorState = UnityTls.NativeInterface.unitytls_errorstate_create ();
4749
var cert = UnityTls.NativeInterface.unitytls_x509list_get_x509 (nativeCertificateChain, (size_t)0, &errorState);
48-
for (int i = 0; cert.handle != UnityTls.NativeInterface.UNITYTLS_INVALID_HANDLE; ++i) {
50+
for (int i = 1; cert.handle != UnityTls.NativeInterface.UNITYTLS_INVALID_HANDLE; ++i) {
4951
size_t certBufferSize = UnityTls.NativeInterface.unitytls_x509_export_der (cert, null, (size_t)0, &errorState);
5052
var certBuffer = new byte[(int)certBufferSize]; // Need to reallocate every time since X509Certificate constructor takes no length but only a byte array.
5153
fixed(byte* certBufferPtr = certBuffer) {
@@ -57,6 +59,13 @@ public override X509ChainElementCollection ChainElements {
5759
}
5860
}
5961

62+
if (reverseOrder) {
63+
var reversed = new X509ChainElementCollection ();
64+
for (int i=elements.Count - 1; i>=0; --i)
65+
reversed.Add(elements[i].Certificate);
66+
elements = reversed;
67+
}
68+
6069
return elements;
6170
}
6271
}

0 commit comments

Comments
 (0)