2018-10-09 08:20:59 +00:00
|
|
|
//
|
|
|
|
// MonoCertificatePal.OSX.cs
|
2014-08-13 10:39:27 +01:00
|
|
|
//
|
|
|
|
// Authors:
|
2018-10-09 08:20:59 +00:00
|
|
|
// Miguel de Icaza
|
|
|
|
// Sebastien Pouliot <sebastien@xamarin.com>
|
|
|
|
// Martin Baulig <mabaul@microsoft.com>
|
|
|
|
//
|
|
|
|
// Copyright 2010 Novell, Inc
|
2017-04-10 11:41:01 +00:00
|
|
|
// Copyright 2011-2014 Xamarin Inc.
|
2018-10-09 08:20:59 +00:00
|
|
|
// Copyright (c) 2018 Xamarin Inc. (http://www.xamarin.com)
|
2014-08-13 10:39:27 +01:00
|
|
|
//
|
2018-10-09 08:20:59 +00:00
|
|
|
// 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:
|
2014-08-13 10:39:27 +01:00
|
|
|
//
|
2018-10-09 08:20:59 +00:00
|
|
|
// 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.
|
2019-02-04 20:11:37 +00:00
|
|
|
|
|
|
|
#if !MONO_FEATURE_BTLS
|
|
|
|
#if MONO_SECURITY_ALIAS
|
|
|
|
extern alias MonoSecurity;
|
|
|
|
using MonoSecurity::Mono.Security.Cryptography;
|
|
|
|
#else
|
|
|
|
using Mono.Security.Cryptography;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2014-08-13 10:39:27 +01:00
|
|
|
using System;
|
2018-10-09 08:20:59 +00:00
|
|
|
using System.Threading;
|
2014-08-13 10:39:27 +01:00
|
|
|
using System.Runtime.InteropServices;
|
2017-04-19 15:52:01 +00:00
|
|
|
using System.Security.Cryptography;
|
2018-10-09 08:20:59 +00:00
|
|
|
using System.Security.Cryptography.Apple;
|
2017-04-19 15:52:01 +00:00
|
|
|
using System.Security.Cryptography.X509Certificates;
|
2018-10-09 08:20:59 +00:00
|
|
|
using Microsoft.Win32.SafeHandles;
|
2017-04-10 11:41:01 +00:00
|
|
|
using Mono.Net;
|
2014-08-13 10:39:27 +01:00
|
|
|
|
2017-04-19 15:52:01 +00:00
|
|
|
#if MONO_FEATURE_BTLS
|
|
|
|
using Mono.Btls;
|
|
|
|
#endif
|
|
|
|
|
2018-10-09 08:20:59 +00:00
|
|
|
namespace Mono.AppleTls
|
|
|
|
{
|
|
|
|
static partial class MonoCertificatePal
|
|
|
|
{
|
|
|
|
public static SafeSecIdentityHandle ImportIdentity (X509Certificate2 certificate)
|
2017-04-10 11:41:01 +00:00
|
|
|
{
|
2018-10-09 08:20:59 +00:00
|
|
|
if (certificate == null)
|
|
|
|
throw new ArgumentNullException (nameof (certificate));
|
|
|
|
if (!certificate.HasPrivateKey)
|
|
|
|
throw new InvalidOperationException ("Need X509Certificate2 with a private key.");
|
2014-08-13 10:39:27 +01:00
|
|
|
|
2018-10-09 08:20:59 +00:00
|
|
|
return ItemImport (certificate) ?? new SafeSecIdentityHandle ();
|
2017-04-10 11:41:01 +00:00
|
|
|
}
|
2017-04-19 15:52:01 +00:00
|
|
|
|
|
|
|
[DllImport (AppleTlsContext.SecurityLibrary)]
|
|
|
|
extern static SecStatusCode SecItemImport (
|
|
|
|
/* CFDataRef */ IntPtr importedData,
|
|
|
|
/* CFStringRef */ IntPtr fileNameOrExtension, // optional
|
|
|
|
/* SecExternalFormat* */ ref SecExternalFormat inputFormat, // optional, IN/OUT
|
|
|
|
/* SecExternalItemType* */ ref SecExternalItemType itemType, // optional, IN/OUT
|
|
|
|
/* SecItemImportExportFlags */ SecItemImportExportFlags flags,
|
|
|
|
/* const SecItemImportExportKeyParameters* */ IntPtr keyParams, // optional
|
|
|
|
/* SecKeychainRef */ IntPtr importKeychain, // optional
|
|
|
|
/* CFArrayRef* */ out IntPtr outItems);
|
|
|
|
|
|
|
|
static public CFArray ItemImport (byte[] buffer, string password)
|
|
|
|
{
|
|
|
|
using (var data = CFData.FromData (buffer))
|
|
|
|
using (var pwstring = CFString.Create (password)) {
|
|
|
|
SecItemImportExportKeyParameters keyParams = new SecItemImportExportKeyParameters ();
|
|
|
|
keyParams.passphrase = pwstring.Handle;
|
|
|
|
|
|
|
|
return ItemImport (data, SecExternalFormat.PKCS12, SecExternalItemType.Aggregate, SecItemImportExportFlags.None, keyParams);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static CFArray ItemImport (CFData data, SecExternalFormat format, SecExternalItemType itemType,
|
2018-10-09 08:20:59 +00:00
|
|
|
SecItemImportExportFlags flags = SecItemImportExportFlags.None,
|
|
|
|
SecItemImportExportKeyParameters? keyParams = null)
|
2017-04-19 15:52:01 +00:00
|
|
|
{
|
|
|
|
return ItemImport (data, ref format, ref itemType, flags, keyParams);
|
|
|
|
}
|
|
|
|
|
|
|
|
static CFArray ItemImport (CFData data, ref SecExternalFormat format, ref SecExternalItemType itemType,
|
2018-10-09 08:20:59 +00:00
|
|
|
SecItemImportExportFlags flags = SecItemImportExportFlags.None,
|
|
|
|
SecItemImportExportKeyParameters? keyParams = null)
|
2017-04-19 15:52:01 +00:00
|
|
|
{
|
|
|
|
IntPtr keyParamsPtr = IntPtr.Zero;
|
|
|
|
if (keyParams != null) {
|
|
|
|
keyParamsPtr = Marshal.AllocHGlobal (Marshal.SizeOf (keyParams.Value));
|
|
|
|
if (keyParamsPtr == IntPtr.Zero)
|
|
|
|
throw new OutOfMemoryException ();
|
|
|
|
Marshal.StructureToPtr (keyParams.Value, keyParamsPtr, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
IntPtr result;
|
|
|
|
var status = SecItemImport (data.Handle, IntPtr.Zero, ref format, ref itemType, flags, keyParamsPtr, IntPtr.Zero, out result);
|
|
|
|
|
|
|
|
if (keyParamsPtr != IntPtr.Zero)
|
|
|
|
Marshal.FreeHGlobal (keyParamsPtr);
|
|
|
|
|
|
|
|
if (status != SecStatusCode.Success)
|
|
|
|
throw new NotSupportedException (status.ToString ());
|
|
|
|
|
|
|
|
return new CFArray (result, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
[DllImport (AppleTlsContext.SecurityLibrary)]
|
|
|
|
extern static /* SecIdentityRef */ IntPtr SecIdentityCreate (
|
|
|
|
/* CFAllocatorRef */ IntPtr allocator,
|
|
|
|
/* SecCertificateRef */ IntPtr certificate,
|
|
|
|
/* SecKeyRef */ IntPtr privateKey);
|
|
|
|
|
2018-10-09 08:20:59 +00:00
|
|
|
static public SafeSecIdentityHandle ItemImport (X509Certificate2 certificate)
|
2017-04-19 15:52:01 +00:00
|
|
|
{
|
|
|
|
if (!certificate.HasPrivateKey)
|
|
|
|
throw new NotSupportedException ();
|
|
|
|
|
|
|
|
using (var key = ImportPrivateKey (certificate))
|
2018-10-09 08:20:59 +00:00
|
|
|
using (var cert = MonoCertificatePal.FromOtherCertificate (certificate)) {
|
|
|
|
var identity = SecIdentityCreate (IntPtr.Zero, cert.DangerousGetHandle (), key.DangerousGetHandle ());
|
|
|
|
if (!MonoCertificatePal.IsSecIdentity (identity))
|
2017-04-19 15:52:01 +00:00
|
|
|
throw new InvalidOperationException ();
|
|
|
|
|
2018-10-09 08:20:59 +00:00
|
|
|
return new SafeSecIdentityHandle (identity, true);
|
2017-04-19 15:52:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static byte[] ExportKey (RSA key)
|
|
|
|
{
|
|
|
|
#if MONO_FEATURE_BTLS
|
|
|
|
using (var btlsKey = MonoBtlsKey.CreateFromRSAPrivateKey (key))
|
|
|
|
return btlsKey.GetBytes (true);
|
|
|
|
#else
|
|
|
|
return PKCS8.PrivateKeyInfo.Encode (key);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-10-09 08:20:59 +00:00
|
|
|
static SafeSecKeyRefHandle ImportPrivateKey (X509Certificate2 certificate)
|
2017-04-19 15:52:01 +00:00
|
|
|
{
|
|
|
|
if (!certificate.HasPrivateKey)
|
|
|
|
throw new NotSupportedException ();
|
|
|
|
|
|
|
|
CFArray items;
|
|
|
|
using (var data = CFData.FromData (ExportKey ((RSA)certificate.PrivateKey)))
|
|
|
|
items = ItemImport (data, SecExternalFormat.OpenSSL, SecExternalItemType.PrivateKey);
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (items.Count != 1)
|
|
|
|
throw new InvalidOperationException ("Private key import failed.");
|
|
|
|
|
|
|
|
var imported = items[0];
|
2018-10-09 08:20:59 +00:00
|
|
|
if (!MonoCertificatePal.IsSecKey (imported))
|
2017-04-19 15:52:01 +00:00
|
|
|
throw new InvalidOperationException ("Private key import doesn't return SecKey.");
|
|
|
|
|
2018-10-09 08:20:59 +00:00
|
|
|
return new SafeSecKeyRefHandle (imported, items.Handle);
|
2017-04-19 15:52:01 +00:00
|
|
|
} finally {
|
|
|
|
items.Dispose ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const int SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION = 0;
|
|
|
|
|
|
|
|
// Native enum; don't change.
|
2018-10-09 08:20:59 +00:00
|
|
|
enum SecExternalFormat : int
|
|
|
|
{
|
2017-04-19 15:52:01 +00:00
|
|
|
Unknown = 0,
|
|
|
|
OpenSSL = 1,
|
|
|
|
X509Cert = 9,
|
|
|
|
PEMSequence = 10,
|
|
|
|
PKCS7 = 11,
|
|
|
|
PKCS12 = 12
|
|
|
|
}
|
|
|
|
|
|
|
|
// Native enum; don't change.
|
2018-10-09 08:20:59 +00:00
|
|
|
enum SecExternalItemType : int
|
|
|
|
{
|
2017-04-19 15:52:01 +00:00
|
|
|
Unknown = 0,
|
|
|
|
PrivateKey = 1,
|
|
|
|
PublicKey = 2,
|
|
|
|
SessionKey = 3,
|
|
|
|
Certificate = 4,
|
|
|
|
Aggregate = 5
|
|
|
|
}
|
|
|
|
|
|
|
|
// Native enum; don't change
|
2018-10-09 08:20:59 +00:00
|
|
|
enum SecItemImportExportFlags : int
|
|
|
|
{
|
2017-04-19 15:52:01 +00:00
|
|
|
None,
|
|
|
|
PemArmour = 0x00000001, /* exported blob is PEM formatted */
|
|
|
|
}
|
|
|
|
|
|
|
|
// Native struct; don't change
|
|
|
|
[StructLayout (LayoutKind.Sequential)]
|
2018-10-09 08:20:59 +00:00
|
|
|
struct SecItemImportExportKeyParameters
|
|
|
|
{
|
2017-04-19 15:52:01 +00:00
|
|
|
public int version; /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */
|
|
|
|
public int flags; /* SecKeyImportExportFlags bits */
|
|
|
|
public IntPtr passphrase; /* SecExternalFormat.PKCS12 only. Legal types are CFStringRef and CFDataRef. */
|
|
|
|
|
|
|
|
IntPtr alertTitle;
|
|
|
|
IntPtr alertPrompt;
|
|
|
|
|
|
|
|
public IntPtr accessRef; /* SecAccessRef */
|
|
|
|
|
|
|
|
IntPtr keyUsage;
|
|
|
|
IntPtr keyAttributes;
|
|
|
|
}
|
2017-04-10 11:41:01 +00:00
|
|
|
}
|
|
|
|
}
|