diff --git a/mcs/class/System/Mono.UnityTls/UnityTlsConversions.cs b/mcs/class/System/Mono.UnityTls/UnityTlsConversions.cs index e72f8e623c294dbfc76f34e50a62f04512f52328..59aff9bd45e735a41e90110070f099e6ba1df635 100644 --- a/mcs/class/System/Mono.UnityTls/UnityTlsConversions.cs +++ b/mcs/class/System/Mono.UnityTls/UnityTlsConversions.cs @@ -8,6 +8,7 @@ using Mono.Security.Interface; #endif using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; namespace Mono.Unity { @@ -102,6 +103,30 @@ namespace Mono.Unity error |= MonoSslPolicyErrors.RemoteCertificateChainErrors; return error; } + + public static X509ChainStatusFlags VerifyResultToChainStatus (UnityTls.unitytls_x509verify_result verifyResult) + { + // First, check "non-flags" + if (verifyResult == UnityTls.unitytls_x509verify_result.UNITYTLS_X509VERIFY_SUCCESS) + return X509ChainStatusFlags.NoError; + else if (verifyResult == UnityTls.unitytls_x509verify_result.UNITYTLS_X509VERIFY_FATAL_ERROR) + return X509ChainStatusFlags.UntrustedRoot; // Inaccurate, throw exception instead? + + // Yes, we ignore user error flags here. They still affect if a chain is accepted, but they are not status flags of the chain! + X509ChainStatusFlags error = X509ChainStatusFlags.NoError; + if (verifyResult.HasFlag (UnityTls.unitytls_x509verify_result.UNITYTLS_X509VERIFY_FLAG_EXPIRED)) + error |= X509ChainStatusFlags.NotTimeValid; + if (verifyResult.HasFlag (UnityTls.unitytls_x509verify_result.UNITYTLS_X509VERIFY_FLAG_REVOKED)) + error |= X509ChainStatusFlags.Revoked; + if (verifyResult.HasFlag (UnityTls.unitytls_x509verify_result.UNITYTLS_X509VERIFY_FLAG_CN_MISMATCH)) + // Unclear what to return, behaving like Mono's BTLS impl + // https://github.com/mono/mono/blob/1553889bc54f87060158febca7e6b8b9910975f8/mcs/class/System/Mono.Btls/MonoBtlsProvider.cs#L312 + error |= X509ChainStatusFlags.UntrustedRoot; + if (verifyResult.HasFlag (UnityTls.unitytls_x509verify_result.UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED)) + error |= X509ChainStatusFlags.UntrustedRoot; + + return error; + } } } #endif \ No newline at end of file diff --git a/mcs/class/System/Mono.UnityTls/UnityTlsProvider.cs b/mcs/class/System/Mono.UnityTls/UnityTlsProvider.cs index 2cc1a1ab2543a96ab4d53a39e5a524011ed71f2d..877ca24a86426fd98287e2c2f4f0306545759fd6 100644 --- a/mcs/class/System/Mono.UnityTls/UnityTlsProvider.cs +++ b/mcs/class/System/Mono.UnityTls/UnityTlsProvider.cs @@ -131,6 +131,12 @@ namespace Mono.Unity } errors = UnityTlsConversions.VerifyResultToPolicyErrror(result); + // There should be a status per certificate, but once again we're following closely the BTLS implementation + // https://github.com/mono/mono/blob/1553889bc54f87060158febca7e6b8b9910975f8/mcs/class/System/Mono.Btls/MonoBtlsProvider.cs#L180 + // which also provides only a single status for the entire chain. + // It is notoriously tricky to implement in OpenSSL to get a status for all invididual certificates without finishing the handshake in the process. + // This is partially the reason why unitytls_x509verify_X doesn't expose it (TODO!) and likely the reason Mono's BTLS impl ignores this. + unityTlsChainImpl?.AddStatus(UnityTlsConversions.VerifyResultToChainStatus(result)); return result == UnityTls.unitytls_x509verify_result.UNITYTLS_X509VERIFY_SUCCESS && errorState.code == UnityTls.unitytls_error_code.UNITYTLS_SUCCESS; } diff --git a/mcs/class/System/Mono.UnityTls/X509ChainImplUnityTls.cs b/mcs/class/System/Mono.UnityTls/X509ChainImplUnityTls.cs index 8a14497e2169c2832def535890b0921ce29ad007..f3b120b39275d855993579373c87c0ccc54e0dee 100644 --- a/mcs/class/System/Mono.UnityTls/X509ChainImplUnityTls.cs +++ b/mcs/class/System/Mono.UnityTls/X509ChainImplUnityTls.cs @@ -1,6 +1,7 @@ #if SECURITY_DEP using System; +using System.Collections.Generic; using System.Text; using System.Security; using System.Security.Cryptography; @@ -12,9 +13,10 @@ namespace Mono.Unity // Follows mostly X509ChainImplBtls class X509ChainImplUnityTls : X509ChainImpl { - X509ChainElementCollection elements; - UnityTls.unitytls_x509list_ref nativeCertificateChain; - X509ChainPolicy policy = new X509ChainPolicy (); + private X509ChainElementCollection elements; + private UnityTls.unitytls_x509list_ref nativeCertificateChain; + private X509ChainPolicy policy = new X509ChainPolicy (); + private List chainStatusList; internal X509ChainImplUnityTls (UnityTls.unitytls_x509list_ref nativeCertificateChain) { @@ -64,8 +66,13 @@ namespace Mono.Unity set { policy = value; } } - public override X509ChainStatus[] ChainStatus { - get { throw new NotImplementedException (); } + public override X509ChainStatus[] ChainStatus => chainStatusList?.ToArray() ?? new X509ChainStatus[0]; + + public void AddStatus (X509ChainStatusFlags errorCode) + { + if (chainStatusList == null) + chainStatusList = new List(); + chainStatusList.Add (new X509ChainStatus(errorCode)); } public override bool Build (X509Certificate2 certificate)