internal static SafeTemporaryKeychainHandle CreateTemporaryKeychain() { string tmpKeychainPath = Path.Combine( Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".keychain"); // Use a distinct GUID so that if a keychain is abandoned it isn't recoverable. string tmpKeychainPassphrase = Guid.NewGuid().ToString("N"); byte[] utf8Passphrase = System.Text.Encoding.UTF8.GetBytes(tmpKeychainPassphrase); SafeTemporaryKeychainHandle keychain; int osStatus = AppleCryptoNative_SecKeychainCreateTemporary( tmpKeychainPath, utf8Passphrase.Length, utf8Passphrase, out keychain); SafeTemporaryKeychainHandle.TrackKeychain(keychain); if (osStatus == 0) { osStatus = AppleCryptoNative_SetKeychainNeverLock(keychain); } if (osStatus != 0) { keychain.Dispose(); throw CreateExceptionForOSStatus(osStatus); } return(keychain); }
internal static unsafe SafeTemporaryKeychainHandle CreateTemporaryKeychain() { const int randomSize = 256; string tmpKeychainPath = Path.Combine( Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".keychain"); // Use a random password so that if a keychain is abandoned it isn't recoverable. // We use stack to minimize lingering Span <byte> random = stackalloc byte[randomSize]; RandomNumberGenerator.Fill(random); // Create hex-like UTF8 string. Span <byte> utf8Passphrase = stackalloc byte[randomSize * 2 + 1]; utf8Passphrase[randomSize * 2] = 0; // null termination for C string. for (int i = 0; i < random.Length; i++) { // Instead of true hexadecimal, we simply take lower and upper 4 bits and we offset them from ASCII 'A' // to get printable form. We dont use managed string to avoid lingering copies. utf8Passphrase[i * 2] = (byte)((random[i] & 0x0F) + 65); utf8Passphrase[i * 2 + 1] = (byte)((random[i] >> 4) & 0x0F + 65); } // clear the binary bits. CryptographicOperations.ZeroMemory(random); SafeTemporaryKeychainHandle keychain; int osStatus; fixed(byte *ptr = utf8Passphrase) { osStatus = AppleCryptoNative_SecKeychainCreateTemporary( tmpKeychainPath, utf8Passphrase.Length, ptr, out keychain); } CryptographicOperations.ZeroMemory(utf8Passphrase); SafeTemporaryKeychainHandle.TrackKeychain(keychain); if (osStatus == 0) { osStatus = AppleCryptoNative_SetKeychainNeverLock(keychain); } if (osStatus != 0) { keychain.Dispose(); throw CreateExceptionForOSStatus(osStatus); } return(keychain); }
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 static SafeSecKeyRefHandle X509GetPrivateKeyFromIdentity(SafeSecIdentityHandle identity) { SafeSecKeyRefHandle key; int osStatus = AppleCryptoNative_X509CopyPrivateKeyFromIdentity(identity, out key); SafeTemporaryKeychainHandle.TrackItem(key); if (osStatus != 0) { key.Dispose(); throw CreateExceptionForOSStatus(osStatus); } if (key.IsInvalid) { key.Dispose(); throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); } return(key); }
internal static SafeSecCertificateHandle X509GetCertFromIdentity(SafeSecIdentityHandle identity) { SafeSecCertificateHandle cert; int osStatus = AppleCryptoNative_X509CopyCertFromIdentity(identity, out cert); SafeTemporaryKeychainHandle.TrackItem(cert); if (osStatus != 0) { cert.Dispose(); throw CreateExceptionForOSStatus(osStatus); } if (cert.IsInvalid) { cert.Dispose(); throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); } return(cert); }
internal static void RsaGenerateKey( int keySizeInBits, out SafeSecKeyRefHandle pPublicKey, out SafeSecKeyRefHandle pPrivateKey) { using (SafeTemporaryKeychainHandle tempKeychain = CreateTemporaryKeychain()) { SafeSecKeyRefHandle keychainPublic; SafeSecKeyRefHandle keychainPrivate; int osStatus; int result = AppleCryptoNative_RsaGenerateKey( keySizeInBits, tempKeychain, out keychainPublic, out keychainPrivate, out osStatus); if (result == 1) { pPublicKey = keychainPublic; pPrivateKey = keychainPrivate; return; } using (keychainPrivate) using (keychainPublic) { if (result == 0) { throw CreateExceptionForOSStatus(osStatus); } Debug.Fail($"Unexpected result from AppleCryptoNative_RsaGenerateKey: {result}"); throw new CryptographicException(); } } }
internal static bool X509DemuxAndRetainHandle( IntPtr handle, out SafeSecCertificateHandle certHandle, out SafeSecIdentityHandle identityHandle) { int result = AppleCryptoNative_X509DemuxAndRetainHandle(handle, out certHandle, out identityHandle); SafeTemporaryKeychainHandle.TrackItem(certHandle); SafeTemporaryKeychainHandle.TrackItem(identityHandle); switch (result) { case 1: return(true); case 0: return(false); default: Debug.Fail($"AppleCryptoNative_X509DemuxAndRetainHandle returned {result}"); throw new CryptographicException(); } }
internal static SafeSecKeyRefHandle X509GetPublicKey(SafeSecCertificateHandle cert) { SafeSecKeyRefHandle publicKey; int osStatus; int ret = AppleCryptoNative_X509GetPublicKey(cert, out publicKey, out osStatus); SafeTemporaryKeychainHandle.TrackItem(publicKey); if (ret == 1) { return(publicKey); } publicKey.Dispose(); if (ret == 0) { throw CreateExceptionForOSStatus(osStatus); } Debug.Fail($"Unexpected return value {ret}"); throw new CryptographicException(); }
private static unsafe partial int AppleCryptoNative_SecKeychainCreateTemporary( string path, int utf8PassphraseLength, byte *utf8Passphrase, out SafeTemporaryKeychainHandle keychain);
private static extern int AppleCryptoNative_SecKeychainCreateTemporary( string path, int utf8PassphraseLength, byte[] utf8Passphrase, out SafeTemporaryKeychainHandle keychain);
public AppleCertLoader(SafeCFArrayHandle collectionHandle, SafeTemporaryKeychainHandle tmpKeychain) { _collectionHandle = collectionHandle; _tmpKeychain = tmpKeychain; }
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(); } }