@@ -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 }
0 commit comments