2016-11-10 13:04:39 +00:00
|
|
|
|
//
|
|
|
|
|
// MonoBtlsProvider.cs
|
|
|
|
|
//
|
|
|
|
|
// Author:
|
|
|
|
|
// Martin Baulig <martin.baulig@xamarin.com>
|
|
|
|
|
//
|
|
|
|
|
// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
|
|
|
|
|
//
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
|
//
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
|
//
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
|
// THE SOFTWARE.
|
|
|
|
|
#if SECURITY_DEP && MONO_FEATURE_BTLS
|
|
|
|
|
#if MONO_SECURITY_ALIAS
|
|
|
|
|
extern alias MonoSecurity;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
2017-08-21 15:34:15 +00:00
|
|
|
|
using System.Net.Security;
|
2018-08-23 08:19:07 +00:00
|
|
|
|
using System.Security.Cryptography;
|
2016-11-10 13:04:39 +00:00
|
|
|
|
using System.Security.Cryptography.X509Certificates;
|
|
|
|
|
using System.Security.Authentication;
|
2018-10-09 08:20:59 +00:00
|
|
|
|
using Microsoft.Win32.SafeHandles;
|
2016-11-10 13:04:39 +00:00
|
|
|
|
|
|
|
|
|
#if MONO_SECURITY_ALIAS
|
|
|
|
|
using MonoSecurity::Mono.Security.Interface;
|
|
|
|
|
using MX = MonoSecurity::Mono.Security.X509;
|
|
|
|
|
#else
|
|
|
|
|
using Mono.Security.Interface;
|
|
|
|
|
using MX = Mono.Security.X509;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
using MNS = Mono.Net.Security;
|
|
|
|
|
|
|
|
|
|
namespace Mono.Btls
|
|
|
|
|
{
|
|
|
|
|
class MonoBtlsProvider : MonoTlsProvider
|
|
|
|
|
{
|
|
|
|
|
public override Guid ID {
|
2017-08-21 15:34:15 +00:00
|
|
|
|
get { return MNS.MonoTlsProviderFactory.BtlsId; }
|
2016-11-10 13:04:39 +00:00
|
|
|
|
}
|
|
|
|
|
public override string Name {
|
|
|
|
|
get { return "btls"; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal MonoBtlsProvider ()
|
|
|
|
|
{
|
|
|
|
|
if (!MNS.MonoTlsProviderFactory.IsBtlsSupported ())
|
|
|
|
|
throw new NotSupportedException ("BTLS is not supported in this runtime.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool SupportsSslStream {
|
|
|
|
|
get { return true; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool SupportsMonoExtensions {
|
|
|
|
|
get { return true; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool SupportsConnectionInfo {
|
|
|
|
|
get { return true; }
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-19 20:04:20 +00:00
|
|
|
|
internal override bool SupportsCleanShutdown {
|
|
|
|
|
get { return true; }
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-10 13:04:39 +00:00
|
|
|
|
public override SslProtocols SupportedProtocols {
|
|
|
|
|
get { return SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override IMonoSslStream CreateSslStream (
|
|
|
|
|
Stream innerStream, bool leaveInnerStreamOpen,
|
|
|
|
|
MonoTlsSettings settings = null)
|
2017-08-21 15:34:15 +00:00
|
|
|
|
{
|
|
|
|
|
return SslStream.CreateMonoSslStream (innerStream, leaveInnerStreamOpen, this, settings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal override IMonoSslStream CreateSslStreamInternal (
|
|
|
|
|
SslStream sslStream, Stream innerStream, bool leaveInnerStreamOpen,
|
|
|
|
|
MonoTlsSettings settings)
|
2016-11-10 13:04:39 +00:00
|
|
|
|
{
|
|
|
|
|
return new MonoBtlsStream (
|
2017-08-21 15:34:15 +00:00
|
|
|
|
innerStream, leaveInnerStreamOpen, sslStream, settings, this);
|
2016-11-10 13:04:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal override bool HasNativeCertificates {
|
|
|
|
|
get { return true; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal override X509Certificate2Impl GetNativeCertificate (
|
|
|
|
|
byte[] data, string password, X509KeyStorageFlags flags)
|
|
|
|
|
{
|
2018-10-09 08:20:59 +00:00
|
|
|
|
using (var handle = new SafePasswordHandle (password))
|
|
|
|
|
return GetNativeCertificate (data, handle, flags);
|
2016-11-10 13:04:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal override X509Certificate2Impl GetNativeCertificate (
|
|
|
|
|
X509Certificate certificate)
|
|
|
|
|
{
|
|
|
|
|
var impl = certificate.Impl as X509CertificateImplBtls;
|
|
|
|
|
if (impl != null)
|
|
|
|
|
return (X509Certificate2Impl)impl.Clone ();
|
|
|
|
|
|
|
|
|
|
var data = certificate.GetRawCertData ();
|
2019-04-12 14:10:50 +00:00
|
|
|
|
return new X509CertificateImplBtls (data, MonoBtlsX509Format.DER);
|
2016-11-10 13:04:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-09 08:20:59 +00:00
|
|
|
|
internal X509Certificate2Impl GetNativeCertificate (
|
|
|
|
|
byte[] data, SafePasswordHandle password, X509KeyStorageFlags flags)
|
|
|
|
|
{
|
2019-04-12 14:10:50 +00:00
|
|
|
|
return new X509CertificateImplBtls (data, password, flags);
|
2018-10-09 08:20:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-21 15:34:15 +00:00
|
|
|
|
internal static MonoBtlsX509VerifyParam GetVerifyParam (MonoTlsSettings settings, string targetHost, bool serverMode)
|
2016-11-10 13:04:39 +00:00
|
|
|
|
{
|
|
|
|
|
MonoBtlsX509VerifyParam param;
|
|
|
|
|
if (serverMode)
|
|
|
|
|
param = MonoBtlsX509VerifyParam.GetSslClient ();
|
|
|
|
|
else
|
|
|
|
|
param = MonoBtlsX509VerifyParam.GetSslServer ();
|
|
|
|
|
|
2017-08-21 15:34:15 +00:00
|
|
|
|
if (targetHost == null && settings?.CertificateValidationTime == null)
|
2016-11-10 13:04:39 +00:00
|
|
|
|
return param;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
var copy = param.Copy ();
|
2017-08-21 15:34:15 +00:00
|
|
|
|
if (targetHost != null)
|
|
|
|
|
copy.SetHost (targetHost);
|
|
|
|
|
if (settings?.CertificateValidationTime != null)
|
|
|
|
|
copy.SetTime (settings.CertificateValidationTime.Value);
|
2016-11-10 13:04:39 +00:00
|
|
|
|
return copy;
|
|
|
|
|
} finally {
|
|
|
|
|
param.Dispose ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal override bool ValidateCertificate (
|
|
|
|
|
ICertificateValidator2 validator, string targetHost, bool serverMode,
|
|
|
|
|
X509CertificateCollection certificates, bool wantsChain, ref X509Chain chain,
|
|
|
|
|
ref MonoSslPolicyErrors errors, ref int status11)
|
|
|
|
|
{
|
|
|
|
|
if (chain != null) {
|
|
|
|
|
var chainImpl = (X509ChainImplBtls)chain.Impl;
|
|
|
|
|
var success = chainImpl.StoreCtx.VerifyResult == 1;
|
|
|
|
|
CheckValidationResult (
|
|
|
|
|
validator, targetHost, serverMode, certificates,
|
|
|
|
|
wantsChain, chain, chainImpl.StoreCtx,
|
|
|
|
|
success, ref errors, ref status11);
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using (var store = new MonoBtlsX509Store ())
|
|
|
|
|
using (var nativeChain = MonoBtlsProvider.GetNativeChain (certificates))
|
2017-08-21 15:34:15 +00:00
|
|
|
|
using (var param = GetVerifyParam (validator.Settings, targetHost, serverMode))
|
2016-11-10 13:04:39 +00:00
|
|
|
|
using (var storeCtx = new MonoBtlsX509StoreCtx ()) {
|
2017-02-22 17:45:59 +00:00
|
|
|
|
SetupCertificateStore (store, validator.Settings, serverMode);
|
2016-11-10 13:04:39 +00:00
|
|
|
|
|
|
|
|
|
storeCtx.Initialize (store, nativeChain);
|
|
|
|
|
|
|
|
|
|
storeCtx.SetVerifyParam (param);
|
|
|
|
|
|
|
|
|
|
var ret = storeCtx.Verify ();
|
|
|
|
|
|
|
|
|
|
var success = ret == 1;
|
|
|
|
|
|
|
|
|
|
if (wantsChain && chain == null) {
|
|
|
|
|
chain = GetManagedChain (nativeChain);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CheckValidationResult (
|
|
|
|
|
validator, targetHost, serverMode, certificates,
|
|
|
|
|
wantsChain, null, storeCtx,
|
|
|
|
|
success, ref errors, ref status11);
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static bool ValidateCertificate (MonoBtlsX509Chain chain, MonoBtlsX509VerifyParam param)
|
|
|
|
|
{
|
|
|
|
|
using (var store = new MonoBtlsX509Store ())
|
|
|
|
|
using (var storeCtx = new MonoBtlsX509StoreCtx ()) {
|
2017-08-21 15:34:15 +00:00
|
|
|
|
/*
|
|
|
|
|
* We're called from X509Certificate2.Verify() via X509CertificateImplBtls.Verify().
|
|
|
|
|
*
|
|
|
|
|
* Use the default settings and assume client-mode.
|
|
|
|
|
*/
|
|
|
|
|
SetupCertificateStore (store, MonoTlsSettings.DefaultSettings, false);
|
2016-11-10 13:04:39 +00:00
|
|
|
|
|
|
|
|
|
storeCtx.Initialize (store, chain);
|
|
|
|
|
|
|
|
|
|
if (param != null)
|
|
|
|
|
storeCtx.SetVerifyParam (param);
|
|
|
|
|
|
|
|
|
|
var ret = storeCtx.Verify ();
|
|
|
|
|
|
|
|
|
|
return ret == 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CheckValidationResult (
|
|
|
|
|
ICertificateValidator validator, string targetHost, bool serverMode,
|
|
|
|
|
X509CertificateCollection certificates, bool wantsChain,
|
|
|
|
|
X509Chain chain, MonoBtlsX509StoreCtx storeCtx,
|
|
|
|
|
bool success, ref MonoSslPolicyErrors errors, ref int status11)
|
|
|
|
|
{
|
2018-08-23 08:19:07 +00:00
|
|
|
|
status11 = unchecked((int)0);
|
2018-09-05 08:26:42 +00:00
|
|
|
|
if (success)
|
|
|
|
|
return;
|
|
|
|
|
errors = MonoSslPolicyErrors.RemoteCertificateChainErrors;
|
|
|
|
|
if (!wantsChain || storeCtx == null || chain == null) {
|
|
|
|
|
status11 = unchecked((int)0x800B010B);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-12 14:10:50 +00:00
|
|
|
|
var error = storeCtx.GetError ();
|
|
|
|
|
switch (error) {
|
|
|
|
|
case Mono.Btls.MonoBtlsX509Error.OK:
|
|
|
|
|
errors = MonoSslPolicyErrors.None;
|
|
|
|
|
break;
|
|
|
|
|
case Mono.Btls.MonoBtlsX509Error.CRL_NOT_YET_VALID:
|
|
|
|
|
break;
|
|
|
|
|
case MonoBtlsX509Error.HOSTNAME_MISMATCH:
|
|
|
|
|
errors = MonoSslPolicyErrors.RemoteCertificateNameMismatch;
|
|
|
|
|
chain.Impl.AddStatus (X509ChainStatusFlags.UntrustedRoot);
|
|
|
|
|
status11 = unchecked ((int)0x800B010B);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
chain.Impl.AddStatus (MapVerifyErrorToChainStatus (error));
|
|
|
|
|
status11 = unchecked ((int)0x800B010B);
|
|
|
|
|
break;
|
2016-11-10 13:04:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-05 08:26:42 +00:00
|
|
|
|
internal static X509ChainStatusFlags MapVerifyErrorToChainStatus (MonoBtlsX509Error code)
|
2018-08-23 08:19:07 +00:00
|
|
|
|
{
|
2018-09-05 08:26:42 +00:00
|
|
|
|
switch (code) {
|
2019-04-12 14:10:50 +00:00
|
|
|
|
case MonoBtlsX509Error.OK:
|
2018-09-05 08:26:42 +00:00
|
|
|
|
return X509ChainStatusFlags.NoError;
|
|
|
|
|
|
2019-04-12 14:10:50 +00:00
|
|
|
|
case MonoBtlsX509Error.CERT_NOT_YET_VALID:
|
2018-09-05 08:26:42 +00:00
|
|
|
|
case MonoBtlsX509Error.CERT_HAS_EXPIRED:
|
|
|
|
|
case MonoBtlsX509Error.ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
|
|
|
|
case MonoBtlsX509Error.ERROR_IN_CERT_NOT_AFTER_FIELD:
|
|
|
|
|
return X509ChainStatusFlags.NotTimeValid;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.CERT_REVOKED:
|
|
|
|
|
return X509ChainStatusFlags.Revoked;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
|
|
|
|
|
case MonoBtlsX509Error.CERT_SIGNATURE_FAILURE:
|
|
|
|
|
return X509ChainStatusFlags.NotSignatureValid;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.CERT_UNTRUSTED:
|
|
|
|
|
case MonoBtlsX509Error.DEPTH_ZERO_SELF_SIGNED_CERT:
|
|
|
|
|
case MonoBtlsX509Error.SELF_SIGNED_CERT_IN_CHAIN:
|
|
|
|
|
return X509ChainStatusFlags.UntrustedRoot;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.CRL_HAS_EXPIRED:
|
|
|
|
|
return X509ChainStatusFlags.OfflineRevocation;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.CRL_NOT_YET_VALID:
|
|
|
|
|
case MonoBtlsX509Error.CRL_SIGNATURE_FAILURE:
|
|
|
|
|
case MonoBtlsX509Error.ERROR_IN_CRL_LAST_UPDATE_FIELD:
|
|
|
|
|
case MonoBtlsX509Error.ERROR_IN_CRL_NEXT_UPDATE_FIELD:
|
|
|
|
|
case MonoBtlsX509Error.KEYUSAGE_NO_CRL_SIGN:
|
|
|
|
|
case MonoBtlsX509Error.UNABLE_TO_DECRYPT_CRL_SIGNATURE:
|
|
|
|
|
case MonoBtlsX509Error.UNABLE_TO_GET_CRL:
|
|
|
|
|
case MonoBtlsX509Error.UNABLE_TO_GET_CRL_ISSUER:
|
|
|
|
|
case MonoBtlsX509Error.UNHANDLED_CRITICAL_CRL_EXTENSION:
|
|
|
|
|
return X509ChainStatusFlags.RevocationStatusUnknown;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.INVALID_EXTENSION:
|
|
|
|
|
return X509ChainStatusFlags.InvalidExtension;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.UNABLE_TO_GET_ISSUER_CERT:
|
|
|
|
|
case MonoBtlsX509Error.UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
|
|
|
|
case MonoBtlsX509Error.UNABLE_TO_VERIFY_LEAF_SIGNATURE:
|
|
|
|
|
return X509ChainStatusFlags.PartialChain;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.INVALID_PURPOSE:
|
|
|
|
|
return X509ChainStatusFlags.NotValidForUsage;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.INVALID_CA:
|
|
|
|
|
case MonoBtlsX509Error.INVALID_NON_CA:
|
|
|
|
|
case MonoBtlsX509Error.PATH_LENGTH_EXCEEDED:
|
|
|
|
|
case MonoBtlsX509Error.KEYUSAGE_NO_CERTSIGN:
|
|
|
|
|
case MonoBtlsX509Error.KEYUSAGE_NO_DIGITAL_SIGNATURE:
|
|
|
|
|
return X509ChainStatusFlags.InvalidBasicConstraints;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.INVALID_POLICY_EXTENSION:
|
|
|
|
|
case MonoBtlsX509Error.NO_EXPLICIT_POLICY:
|
|
|
|
|
return X509ChainStatusFlags.InvalidPolicyConstraints;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.CERT_REJECTED:
|
|
|
|
|
return X509ChainStatusFlags.ExplicitDistrust;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.UNHANDLED_CRITICAL_EXTENSION:
|
|
|
|
|
return X509ChainStatusFlags.HasNotSupportedCriticalExtension;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.HOSTNAME_MISMATCH:
|
|
|
|
|
// FIXME: we should have a better error flag for this.
|
|
|
|
|
return X509ChainStatusFlags.UntrustedRoot;
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.CERT_CHAIN_TOO_LONG:
|
|
|
|
|
throw new CryptographicException ();
|
|
|
|
|
|
|
|
|
|
case MonoBtlsX509Error.OUT_OF_MEM:
|
|
|
|
|
throw new OutOfMemoryException ();
|
2018-08-23 08:19:07 +00:00
|
|
|
|
|
|
|
|
|
default:
|
2018-09-05 08:26:42 +00:00
|
|
|
|
throw new CryptographicException ("Unrecognized X509VerifyStatusCode:" + code);
|
|
|
|
|
}
|
2018-08-23 08:19:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-22 17:45:59 +00:00
|
|
|
|
internal static void SetupCertificateStore (MonoBtlsX509Store store, MonoTlsSettings settings, bool server)
|
|
|
|
|
{
|
2017-08-21 15:34:15 +00:00
|
|
|
|
/*
|
|
|
|
|
* In server-mode, we only add certificates which are explicitly trusted via
|
|
|
|
|
* MonoTlsSettings.TrustAnchors.
|
|
|
|
|
*
|
|
|
|
|
* MonoTlsSettings.CertificateSearchPaths is ignored on Android.
|
|
|
|
|
*
|
|
|
|
|
*/
|
2017-06-07 13:16:24 +00:00
|
|
|
|
|
|
|
|
|
#if MONODROID
|
2017-08-21 15:34:15 +00:00
|
|
|
|
AddTrustedRoots (store, settings, server);
|
|
|
|
|
if (!server)
|
|
|
|
|
SetupDefaultCertificateStore (store);
|
2017-06-07 13:16:24 +00:00
|
|
|
|
return;
|
|
|
|
|
#else
|
2017-08-21 15:34:15 +00:00
|
|
|
|
if (server || settings?.CertificateSearchPaths == null) {
|
|
|
|
|
AddTrustedRoots (store, settings, server);
|
|
|
|
|
if (!server)
|
|
|
|
|
SetupDefaultCertificateStore (store);
|
2017-06-07 13:16:24 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var path in settings.CertificateSearchPaths) {
|
2017-08-21 15:34:15 +00:00
|
|
|
|
switch (path) {
|
|
|
|
|
case "@default":
|
2017-06-07 13:16:24 +00:00
|
|
|
|
AddTrustedRoots (store, settings, server);
|
|
|
|
|
AddUserStore (store);
|
|
|
|
|
AddMachineStore (store);
|
2017-08-21 15:34:15 +00:00
|
|
|
|
break;
|
|
|
|
|
case "@trusted":
|
|
|
|
|
AddTrustedRoots (store, settings, server);
|
|
|
|
|
break;
|
|
|
|
|
case "@user":
|
2017-06-07 13:16:24 +00:00
|
|
|
|
AddUserStore (store);
|
2017-08-21 15:34:15 +00:00
|
|
|
|
break;
|
|
|
|
|
case "@machine":
|
2017-06-07 13:16:24 +00:00
|
|
|
|
AddMachineStore (store);
|
2017-08-21 15:34:15 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (path.StartsWith ("@pem:")) {
|
|
|
|
|
var realPath = path.Substring (5);
|
|
|
|
|
if (Directory.Exists (realPath))
|
|
|
|
|
store.AddDirectoryLookup (realPath, MonoBtlsX509FileType.PEM);
|
|
|
|
|
break;
|
|
|
|
|
} else if (path.StartsWith ("@der:")) {
|
|
|
|
|
var realPath = path.Substring (5);
|
|
|
|
|
if (Directory.Exists (realPath))
|
|
|
|
|
store.AddDirectoryLookup (realPath, MonoBtlsX509FileType.ASN1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
throw new NotSupportedException (string.Format ("Invalid item `{0}' in MonoTlsSettings.CertificateSearchPaths.", path));
|
2017-06-07 13:16:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2017-02-22 17:45:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-21 15:34:15 +00:00
|
|
|
|
static void SetupDefaultCertificateStore (MonoBtlsX509Store store)
|
2016-11-10 13:04:39 +00:00
|
|
|
|
{
|
|
|
|
|
#if MONODROID
|
|
|
|
|
store.SetDefaultPaths ();
|
|
|
|
|
store.AddAndroidLookup ();
|
|
|
|
|
#else
|
2017-02-22 17:45:59 +00:00
|
|
|
|
AddUserStore (store);
|
|
|
|
|
AddMachineStore (store);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if !MONODROID
|
|
|
|
|
static void AddUserStore (MonoBtlsX509Store store)
|
|
|
|
|
{
|
2016-11-10 13:04:39 +00:00
|
|
|
|
var userPath = MonoBtlsX509StoreManager.GetStorePath (MonoBtlsX509StoreType.UserTrustedRoots);
|
|
|
|
|
if (Directory.Exists (userPath))
|
|
|
|
|
store.AddDirectoryLookup (userPath, MonoBtlsX509FileType.PEM);
|
2017-02-22 17:45:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void AddMachineStore (MonoBtlsX509Store store)
|
|
|
|
|
{
|
2016-11-10 13:04:39 +00:00
|
|
|
|
var machinePath = MonoBtlsX509StoreManager.GetStorePath (MonoBtlsX509StoreType.MachineTrustedRoots);
|
|
|
|
|
if (Directory.Exists (machinePath))
|
|
|
|
|
store.AddDirectoryLookup (machinePath, MonoBtlsX509FileType.PEM);
|
2017-02-22 17:45:59 +00:00
|
|
|
|
}
|
2016-11-10 13:04:39 +00:00
|
|
|
|
#endif
|
2017-02-22 17:45:59 +00:00
|
|
|
|
|
|
|
|
|
static void AddTrustedRoots (MonoBtlsX509Store store, MonoTlsSettings settings, bool server)
|
|
|
|
|
{
|
|
|
|
|
if (settings?.TrustAnchors == null)
|
|
|
|
|
return;
|
|
|
|
|
var trust = server ? MonoBtlsX509TrustKind.TRUST_CLIENT : MonoBtlsX509TrustKind.TRUST_SERVER;
|
|
|
|
|
store.AddCollection (settings.TrustAnchors, trust);
|
2016-11-10 13:04:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string GetSystemStoreLocation ()
|
|
|
|
|
{
|
2017-01-19 14:22:10 +00:00
|
|
|
|
#if MONODROID
|
2016-11-10 13:04:39 +00:00
|
|
|
|
return "/system/etc/security/cacerts";
|
|
|
|
|
#else
|
2017-01-19 14:22:10 +00:00
|
|
|
|
return MonoBtlsX509StoreManager.GetStorePath (MonoBtlsX509StoreType.MachineTrustedRoots);
|
2016-11-10 13:04:39 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-12 14:10:50 +00:00
|
|
|
|
public static X509Certificate2 CreateCertificate (byte[] data, MonoBtlsX509Format format)
|
2016-11-10 13:04:39 +00:00
|
|
|
|
{
|
2019-04-12 14:10:50 +00:00
|
|
|
|
using (var impl = new X509CertificateImplBtls (data, format)) {
|
2016-11-10 13:04:39 +00:00
|
|
|
|
return new X509Certificate2 (impl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-12 14:10:50 +00:00
|
|
|
|
public static X509Certificate2 CreateCertificate (byte[] data, string password, bool disallowFallback = false)
|
2016-11-10 13:04:39 +00:00
|
|
|
|
{
|
2019-04-12 14:10:50 +00:00
|
|
|
|
using (var handle = new SafePasswordHandle (password))
|
|
|
|
|
using (var impl = new X509CertificateImplBtls (data, handle, X509KeyStorageFlags.DefaultKeySet))
|
2016-11-10 13:04:39 +00:00
|
|
|
|
return new X509Certificate2 (impl);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-12 14:10:50 +00:00
|
|
|
|
public static X509Certificate2 CreateCertificate (MonoBtlsX509 x509)
|
2016-11-10 13:04:39 +00:00
|
|
|
|
{
|
2019-04-12 14:10:50 +00:00
|
|
|
|
using (var impl = new X509CertificateImplBtls (x509))
|
|
|
|
|
return new X509Certificate2 (impl);
|
2016-11-10 13:04:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static X509Chain CreateChain ()
|
|
|
|
|
{
|
|
|
|
|
using (var impl = new X509ChainImplBtls ())
|
|
|
|
|
return new X509Chain (impl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static X509Chain GetManagedChain (MonoBtlsX509Chain chain)
|
|
|
|
|
{
|
|
|
|
|
var impl = new X509ChainImplBtls (chain);
|
|
|
|
|
return new X509Chain (impl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MonoBtlsX509 GetBtlsCertificate (X509Certificate certificate)
|
|
|
|
|
{
|
|
|
|
|
var impl = certificate.Impl as X509CertificateImplBtls;
|
|
|
|
|
if (impl != null)
|
|
|
|
|
return impl.X509.Copy ();
|
|
|
|
|
|
|
|
|
|
return MonoBtlsX509.LoadFromData (certificate.GetRawCertData (), MonoBtlsX509Format.DER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MonoBtlsX509Chain GetNativeChain (X509CertificateCollection certificates)
|
|
|
|
|
{
|
|
|
|
|
var chain = new MonoBtlsX509Chain ();
|
|
|
|
|
try {
|
|
|
|
|
foreach (var cert in certificates) {
|
|
|
|
|
using (var x509 = GetBtlsCertificate (cert))
|
|
|
|
|
chain.AddCertificate (x509);
|
|
|
|
|
}
|
|
|
|
|
return chain;
|
|
|
|
|
} catch {
|
|
|
|
|
chain.Dispose ();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|