private static SafeSecCertificateHandle X509ImportCertificate( ReadOnlySpan <byte> bytes, X509ContentType contentType, SafeCreateHandle?importPassword, out SafeSecIdentityHandle identityHandle) { SafeSecCertificateHandle certHandle; SafeCreateHandle cfPassphrase = importPassword ?? s_emptyExportString; int osStatus = AppleCryptoNative_X509ImportCertificate( bytes, contentType, cfPassphrase, out certHandle, out identityHandle); if (osStatus == 0) { return(certHandle); } certHandle.Dispose(); identityHandle.Dispose(); throw CreateExceptionForOSStatus(osStatus); }
private static partial int AppleCryptoNative_X509ImportCertificate( ref byte pbKeyBlob, int cbKeyBlob, X509ContentType contentType, SafeCreateHandle cfPfxPassphrase, out SafeSecCertificateHandle pCertOut, out SafeSecIdentityHandle pPrivateKeyOut);
internal static SafeSecCertificateHandle X509ImportCertificate( ReadOnlySpan <byte> bytes, X509ContentType contentType, SafePasswordHandle importPassword, out SafeSecIdentityHandle identityHandle) { SafeCreateHandle?cfPassphrase = null; bool releasePassword = false; try { if (!importPassword.IsInvalid) { importPassword.DangerousAddRef(ref releasePassword); cfPassphrase = CoreFoundation.CFStringCreateFromSpan(importPassword.DangerousGetSpan()); } return(X509ImportCertificate( bytes, contentType, cfPassphrase, out identityHandle)); } finally { if (releasePassword) { importPassword.DangerousRelease(); } cfPassphrase?.Dispose(); } }
internal AppleCertificatePal(SafeSecIdentityHandle identityHandle) { Debug.Assert(!identityHandle.IsInvalid); _identityHandle = identityHandle; _certHandle = Interop.AppleCrypto.X509GetCertFromIdentity(identityHandle); }
void SetCertificate(SafeSecIdentityHandle identify, IList <SafeSecCertificateHandle> certificates) { using (var array = Bundle(identify, certificates)) { var result = SSLSetCertificate(Handle, array.Handle); CheckStatusAndThrow(result); } }
private ICertificatePal CopyWithPrivateKey(SecKeyPair keyPair) { if (keyPair.PrivateKey == null) { // Both Windows and Linux/OpenSSL are unaware if they bound a public or private key. // Here, we do know. So throw if we can't do what they asked. throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); } SafeKeychainHandle keychain = Interop.AppleCrypto.SecKeychainItemCopyKeychain(keyPair.PrivateKey); if (keychain.IsInvalid) { keychain = Interop.AppleCrypto.CreateTemporaryKeychain(); } using (keychain) { SafeSecIdentityHandle identityHandle = Interop.AppleCrypto.X509CopyWithPrivateKey( _certHandle, keyPair.PrivateKey, keychain); AppleCertificatePal newPal = new AppleCertificatePal(identityHandle); newPal.HoldPrivateKey(); return(newPal); } }
public void Dispose() { _certHandle?.Dispose(); _identityHandle?.Dispose(); _certHandle = null; _identityHandle = null; }
private static extern int AppleCryptoNative_X509ImportCertificate( byte[] pbKeyBlob, int cbKeyBlob, X509ContentType contentType, SafeCreateHandle cfPfxPassphrase, SafeKeychainHandle tmpKeychain, int exportable, out SafeSecCertificateHandle pCertOut, out SafeSecIdentityHandle pPrivateKeyOut, out int pOSStatus);
public void Dispose() { _certHandle?.Dispose(); _identityHandle?.Dispose(); _privateKeyHolder?.Dispose(); _certHandle = null; _identityHandle = null; _privateKeyHolder = null; }
internal static SafeSecCertificateHandle X509ImportCertificate( byte[] bytes, X509ContentType contentType, SafeCreateHandle importPassword, SafeKeychainHandle keychain, bool exportable, out SafeSecIdentityHandle identityHandle) { SafeSecCertificateHandle certHandle; int osStatus; SafeCreateHandle cfPassphrase = importPassword ?? s_nullExportString; int ret = AppleCryptoNative_X509ImportCertificate( bytes, bytes.Length, contentType, cfPassphrase, keychain, exportable ? 1 : 0, out certHandle, out identityHandle, out osStatus); SafeTemporaryKeychainHandle.TrackItem(certHandle); SafeTemporaryKeychainHandle.TrackItem(identityHandle); if (ret == 1) { return(certHandle); } certHandle.Dispose(); identityHandle.Dispose(); const int SeeOSStatus = 0; const int ImportReturnedEmpty = -2; const int ImportReturnedNull = -3; switch (ret) { case SeeOSStatus: throw CreateExceptionForOSStatus(osStatus); case ImportReturnedNull: case ImportReturnedEmpty: throw new CryptographicException(); default: Debug.Fail($"Unexpected return value {ret}"); throw new CryptographicException(); } }
internal AppleCertificatePal MoveToKeychain(SafeKeychainHandle keychain, SafeSecKeyRefHandle privateKey) { SafeSecIdentityHandle identity = Interop.AppleCrypto.X509MoveToKeychain( _certHandle, keychain, privateKey); if (identity != null) { return(new AppleCertificatePal(identity)); } return(null); }
public static SafeSecCertificateHandle GetCertificate(SafeSecIdentityHandle identity) { if (identity == null || identity.IsInvalid) { throw new ArgumentNullException(nameof(identity)); } var result = SecIdentityCopyCertificate(identity.DangerousGetHandle(), out var cert); if (result != SecStatusCode.Success) { throw new InvalidOperationException(result.ToString()); } return(new SafeSecCertificateHandle(cert, true)); }
public override void StartHandshake() { Debug("StartHandshake: {0}", IsServer); if (Interlocked.CompareExchange(ref handshakeStarted, 1, 1) != 0) { throw new InvalidOperationException(); } InitializeConnection(); /* * SecureTransport is bugged OS X 10.5.8+ - renegotiation after * calling SetCertificate() will not work. * * We also cannot change options after the handshake has started, * so if you want to request a client certificate, it will happen * both during the initial handshake and during renegotiation. * * You may check 'SslStream.IsAuthenticated' (which will be false * during the initial handshake) from within your * 'LocalCertificateSelectionCallback' and return null to have the * callback invoked again during renegotiation. * * However, the first time your selection callback returns a client * certificate, that certificate will be used for the rest of the * session. */ SetSessionOption(SslSessionOption.BreakOnCertRequested, true); SetSessionOption(SslSessionOption.BreakOnClientAuth, true); SetSessionOption(SslSessionOption.BreakOnServerAuth, true); if (IsServer) { SafeSecCertificateHandle[] intermediateCerts; serverIdentity = AppleCertificateHelper.GetIdentity(LocalServerCertificate, out intermediateCerts); if (serverIdentity.IsInvalid) { throw new SSA.AuthenticationException("Unable to get server certificate from keychain."); } SetCertificate(serverIdentity, intermediateCerts); for (int i = 0; i < intermediateCerts.Length; i++) { intermediateCerts [i].Dispose(); } } }
private static int AppleCryptoNative_X509ImportCertificate( ReadOnlySpan <byte> keyBlob, X509ContentType contentType, SafeCreateHandle cfPfxPassphrase, out SafeSecCertificateHandle pCertOut, out SafeSecIdentityHandle pPrivateKeyOut) { return(AppleCryptoNative_X509ImportCertificate( ref MemoryMarshal.GetReference(keyBlob), keyBlob.Length, contentType, cfPfxPassphrase, out pCertOut, out pPrivateKeyOut)); }
void ClientCertificateRequested() { EvaluateTrust(); var acceptableIssuers = CopyDistinguishedNames(); localClientCertificate = SelectClientCertificate(acceptableIssuers); if (localClientCertificate == null) { return; } clientIdentity = AppleCertificateHelper.GetIdentity(localClientCertificate); if (clientIdentity.IsInvalid) { throw new TlsException(AlertDescription.CertificateUnknown); } SetCertificate(clientIdentity, new SafeSecCertificateHandle [0]); }
internal static SafeSecKeyRefHandle X509GetPrivateKeyFromIdentity(SafeSecIdentityHandle identity) { SafeSecKeyRefHandle key; int osStatus = AppleCryptoNative_X509CopyPrivateKeyFromIdentity(identity, out key); if (osStatus != 0) { key.Dispose(); throw CreateExceptionForOSStatus(osStatus); } if (key.IsInvalid) { key.Dispose(); throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); } return(key); }
static SafeSecIdentityHandle FindIdentity(Predicate <SafeSecCertificateHandle> filter) { Initialize(); /* * Unfortunately, SecItemCopyMatching() does not allow any search * filters when looking up an identity. * * The following lookup will return all identities from the keychain - * we then need need to find the right one. */ using (var query = CFMutableDictionary.Create()) { query.SetValue(SecClassKey, SecClassIdentity); query.SetValue(CFBoolean.True.Handle, ReturnRef); query.SetValue(MatchLimitAll, MatchLimit); var status = SecItemCopyMatching(query.Handle, out var ptr); if (status != SecStatusCode.Success || ptr == IntPtr.Zero) { return(null); } using (var array = new CFArray(ptr, false)) { for (int i = 0; i < array.Count; i++) { var item = array[i]; if (!MonoCertificatePal.IsSecIdentity(item)) { throw new InvalidOperationException(); } using (var identity = new SafeSecIdentityHandle(item)) using (var certificate = MonoCertificatePal.GetCertificate(identity)) { if (filter(certificate)) { return(new SafeSecIdentityHandle(item)); } } } } } return(null); }
internal static SafeSecCertificateHandle X509GetCertFromIdentity(SafeSecIdentityHandle identity) { SafeSecCertificateHandle cert; int osStatus = AppleCryptoNative_X509CopyCertFromIdentity(identity, out cert); if (osStatus != 0) { cert.Dispose(); throw CreateExceptionForOSStatus(osStatus); } if (cert.IsInvalid) { cert.Dispose(); throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); } return(cert); }
internal static bool X509DemuxAndRetainHandle( IntPtr handle, out SafeSecCertificateHandle certHandle, out SafeSecIdentityHandle identityHandle) { int result = AppleCryptoNative_X509DemuxAndRetainHandle(handle, out certHandle, out identityHandle); switch (result) { case 1: return(true); case 0: return(false); default: Debug.Fail($"AppleCryptoNative_X509DemuxAndRetainHandle returned {result}"); throw new CryptographicException(); } }
CFArray Bundle(SafeSecIdentityHandle identity, IList <SafeSecCertificateHandle> certificates) { if (identity == null || identity.IsInvalid) { throw new ArgumentNullException(nameof(identity)); } if (certificates == null) { throw new ArgumentNullException(nameof(certificates)); } var ptrs = new IntPtr [certificates.Count + 1]; ptrs [0] = identity.DangerousGetHandle(); for (int i = 0; i < certificates.Count; i++) { ptrs [i + 1] = certificates [i].DangerousGetHandle(); } return(CFArray.CreateArray(ptrs)); }
protected override void Dispose(bool disposing) { try { if (disposed) { return; } if (disposing) { disposed = true; if (serverIdentity != null) { serverIdentity.Dispose(); serverIdentity = null; } if (clientIdentity != null) { clientIdentity.Dispose(); clientIdentity = null; } if (remoteCertificate != null) { remoteCertificate.Dispose(); remoteCertificate = null; } } } finally { disposed = true; if (context != IntPtr.Zero) { CFObject.CFRelease(context); context = IntPtr.Zero; } base.Dispose(disposing); } }
private ICertificatePal CopyWithPrivateKey(SecKeyPair keyPair) { if (keyPair.PrivateKey == null) { // Both Windows and Linux/OpenSSL are unaware if they bound a public or private key. // Here, we do know. So throw if we can't do what they asked. throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); } SafeKeychainHandle keychain = Interop.AppleCrypto.SecKeychainItemCopyKeychain(keyPair.PrivateKey); // If we're using a key already in a keychain don't add the certificate to that keychain here, // do it in the temporary add/remove in the shim. SafeKeychainHandle cloneKeychain = SafeTemporaryKeychainHandle.InvalidHandle; if (keychain.IsInvalid) { keychain = Interop.AppleCrypto.CreateTemporaryKeychain(); cloneKeychain = keychain; } // Because SecIdentityRef only has private constructors we need to have the cert and the key // in the same keychain. That almost certainly means we're going to need to add this cert to a // keychain, and when a cert that isn't part of a keychain gets added to a keychain then the // interior pointer of "what keychain did I come from?" used by SecKeychainItemCopyKeychain gets // set. That makes this function have side effects, which is not desired. // // It also makes reference tracking on temporary keychains broken, since the cert can // DangerousRelease a handle it didn't DangerousAddRef on. And so CopyWithPrivateKey makes // a temporary keychain, then deletes it before anyone has a chance to (e.g.) export the // new identity as a PKCS#12 blob. // // Solution: Clone the cert, like we do in Windows. SafeSecCertificateHandle tempHandle; { byte[] export = RawData; const bool exportable = false; SafeSecIdentityHandle identityHandle; tempHandle = Interop.AppleCrypto.X509ImportCertificate( export, X509ContentType.Cert, SafePasswordHandle.InvalidHandle, cloneKeychain, exportable, out identityHandle); Debug.Assert(identityHandle.IsInvalid, "identityHandle should be IsInvalid"); identityHandle.Dispose(); Debug.Assert(!tempHandle.IsInvalid, "tempHandle should not be IsInvalid"); } using (keychain) using (tempHandle) { SafeSecIdentityHandle identityHandle = Interop.AppleCrypto.X509CopyWithPrivateKey( tempHandle, keyPair.PrivateKey, keychain); AppleCertificatePal newPal = new AppleCertificatePal(identityHandle); return(newPal); } }
private static extern int AppleCryptoNative_X509DemuxAndRetainHandle( IntPtr handle, out SafeSecCertificateHandle certHandle, out SafeSecIdentityHandle identityHandle);
private static extern int AppleCryptoNative_X509CopyCertFromIdentity( SafeSecIdentityHandle identity, out SafeSecCertificateHandle cert);
private static extern int AppleCryptoNative_X509MoveToKeychain( SafeSecCertificateHandle certHandle, SafeKeychainHandle targetKeychain, SafeSecKeyRefHandle privateKeyHandle, out SafeSecIdentityHandle pIdentityHandleOut, out int pOSStatus);
private static partial int AppleCryptoNative_X509CopyWithPrivateKey( SafeSecCertificateHandle certHandle, SafeSecKeyRefHandle privateKeyHandle, SafeKeychainHandle targetKeychain, out SafeSecIdentityHandle pIdentityHandleOut, out int pOSStatus);
internal static SafeSecCertificateHandle X509ImportCertificate( byte[] bytes, X509ContentType contentType, SafePasswordHandle importPassword, SafeKeychainHandle keychain, bool exportable, out SafeSecIdentityHandle identityHandle) { SafeSecCertificateHandle certHandle; int osStatus; int ret; SafeCreateHandle cfPassphrase = s_nullExportString; bool releasePassword = false; try { if (!importPassword.IsInvalid) { importPassword.DangerousAddRef(ref releasePassword); IntPtr passwordHandle = importPassword.DangerousGetHandle(); if (passwordHandle != IntPtr.Zero) { cfPassphrase = CoreFoundation.CFStringCreateWithCString(passwordHandle); } } ret = AppleCryptoNative_X509ImportCertificate( bytes, bytes.Length, contentType, cfPassphrase, keychain, exportable ? 1 : 0, out certHandle, out identityHandle, out osStatus); SafeTemporaryKeychainHandle.TrackItem(certHandle); SafeTemporaryKeychainHandle.TrackItem(identityHandle); } finally { if (releasePassword) { importPassword.DangerousRelease(); } if (cfPassphrase != s_nullExportString) { cfPassphrase.Dispose(); } } if (ret == 1) { return(certHandle); } certHandle.Dispose(); identityHandle.Dispose(); const int SeeOSStatus = 0; const int ImportReturnedEmpty = -2; const int ImportReturnedNull = -3; switch (ret) { case SeeOSStatus: throw CreateExceptionForOSStatus(osStatus); case ImportReturnedNull: case ImportReturnedEmpty: throw new CryptographicException(); default: Debug.Fail($"Unexpected return value {ret}"); throw new CryptographicException(); } }
private static extern int AppleCryptoNative_X509CopyPrivateKeyFromIdentity( SafeSecIdentityHandle identity, out SafeSecKeyRefHandle key);