Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[macOS] Implement RSA, ECC through new macOS 10.12 APIs #51620

Merged
merged 5 commits into from
Apr 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.Apple;
using Microsoft.Win32.SafeHandles;

internal static partial class Interop
{
Expand All @@ -13,10 +14,9 @@ internal static partial class AppleCrypto
[DllImport(Libraries.AppleCryptoNative)]
private static extern int AppleCryptoNative_EccGenerateKey(
int keySizeInBits,
SafeKeychainHandle tempKeychain,
out SafeSecKeyRefHandle pPublicKey,
out SafeSecKeyRefHandle pPrivateKey,
out int pOSStatus);
out SafeCFErrorHandle pErrorOut);

[DllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_EccGetKeySizeInBits")]
internal static extern long EccGetKeySizeInBits(SafeSecKeyRefHandle publicKey);
Expand All @@ -26,20 +26,19 @@ internal static void EccGenerateKey(
out SafeSecKeyRefHandle pPublicKey,
out SafeSecKeyRefHandle pPrivateKey)
{
using (SafeTemporaryKeychainHandle tempKeychain = CreateTemporaryKeychain())
SafeSecKeyRefHandle keychainPublic;
SafeSecKeyRefHandle keychainPrivate;
SafeCFErrorHandle error;

int result = AppleCryptoNative_EccGenerateKey(
keySizeInBits,
out keychainPublic,
out keychainPrivate,
out error);

using (error)
{
SafeSecKeyRefHandle keychainPublic;
SafeSecKeyRefHandle keychainPrivate;
int osStatus;

int result = AppleCryptoNative_EccGenerateKey(
keySizeInBits,
tempKeychain,
out keychainPublic,
out keychainPrivate,
out osStatus);

if (result == 1)
if (result == kSuccess)
{
pPublicKey = keychainPublic;
pPrivateKey = keychainPrivate;
Expand All @@ -49,9 +48,9 @@ internal static void EccGenerateKey(
using (keychainPrivate)
using (keychainPublic)
{
if (result == 0)
if (result == kErrorSeeError)
{
throw CreateExceptionForOSStatus(osStatus);
throw CreateExceptionForCFError(error);
}

Debug.Fail($"Unexpected result from AppleCryptoNative_EccGenerateKey: {result}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ internal static partial class AppleCrypto
[DllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_RsaGenerateKey")]
private static extern int AppleCryptoNative_RsaGenerateKey(
int keySizeInBits,
SafeKeychainHandle keychain,
out SafeSecKeyRefHandle pPublicKey,
out SafeSecKeyRefHandle pPrivateKey,
out int pOSStatus);
out SafeCFErrorHandle pErrorOut);

[DllImport(Libraries.AppleCryptoNative)]
private static extern int AppleCryptoNative_RsaSignaturePrimitive(
Expand Down Expand Up @@ -125,20 +124,19 @@ internal static void RsaGenerateKey(
out SafeSecKeyRefHandle pPublicKey,
out SafeSecKeyRefHandle pPrivateKey)
{
using (SafeTemporaryKeychainHandle tempKeychain = CreateTemporaryKeychain())
SafeSecKeyRefHandle keychainPublic;
SafeSecKeyRefHandle keychainPrivate;
Comment on lines +127 to +128
Copy link
Member

@bartonjs bartonjs Apr 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these are not keychains (or even bound to them) the variables could probably use a better name.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I will fix it up in a follow up PR.

SafeCFErrorHandle error;

int result = AppleCryptoNative_RsaGenerateKey(
keySizeInBits,
out keychainPublic,
out keychainPrivate,
out error);

using (error)
{
SafeSecKeyRefHandle keychainPublic;
SafeSecKeyRefHandle keychainPrivate;
int osStatus;

int result = AppleCryptoNative_RsaGenerateKey(
keySizeInBits,
tempKeychain,
out keychainPublic,
out keychainPrivate,
out osStatus);

if (result == 1)
if (result == kSuccess)
{
pPublicKey = keychainPublic;
pPrivateKey = keychainPrivate;
Expand All @@ -148,9 +146,9 @@ internal static void RsaGenerateKey(
using (keychainPrivate)
using (keychainPublic)
{
if (result == 0)
if (result == kErrorSeeError)
{
throw CreateExceptionForOSStatus(osStatus);
throw CreateExceptionForCFError(error);
}

Debug.Fail($"Unexpected result from AppleCryptoNative_RsaGenerateKey: {result}");
Expand Down Expand Up @@ -258,9 +256,6 @@ private static bool ProcessPrimitiveResponse(
Span<byte> destination,
out int bytesWritten)
{
const int kErrorSeeError = -2;
const int kSuccess = 1;

if (returnValue == kErrorSeeError)
{
throw CreateExceptionForCFError(cfError);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ internal static partial class Interop
{
internal static partial class AppleCrypto
{
private const int kSuccess = 1;
private const int kErrorSeeError = -2;

private static int AppleCryptoNative_SecKeyImportEphemeral(
ReadOnlySpan<byte> pbKeyBlob,
int isPrivateKey,
Expand Down Expand Up @@ -129,9 +132,6 @@ private static extern int AppleCryptoNative_VerifySignatureWithHashAlgorithm(

private static byte[] ExecuteTransform(ReadOnlySpan<byte> source, SecKeyTransform transform)
{
const int Success = 1;
const int kErrorSeeError = -2;

SafeCFDataHandle data;
SafeCFErrorHandle error;

Expand All @@ -140,7 +140,7 @@ private static byte[] ExecuteTransform(ReadOnlySpan<byte> source, SecKeyTransfor
using (error)
using (data)
{
if (ret == Success)
if (ret == kSuccess)
{
return CoreFoundation.CFGetData(data);
}
Expand Down Expand Up @@ -169,11 +169,9 @@ private static bool TryExecuteTransform(
using (errorHandle)
using (outputHandle)
{
const int Success = 1;
const int kErrorSeeError = -2;
switch (ret)
{
case Success:
case kSuccess:
return CoreFoundation.TryCFWriteData(outputHandle, destination, out bytesWritten);
case kErrorSeeError:
throw CreateExceptionForCFError(errorHandle);
Expand Down Expand Up @@ -292,7 +290,6 @@ internal static bool VerifySignature(

const int True = 1;
const int False = 0;
const int kErrorSeeError = -2;

using (error)
{
Expand Down Expand Up @@ -331,7 +328,6 @@ internal static bool VerifySignature(

const int True = 1;
const int False = 0;
const int kErrorSeeError = -2;

using (error)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,47 @@

#include "pal_ecc.h"

#if !defined(TARGET_MACCATALYST) && !defined(TARGET_IOS) && !defined(TARGET_TVOS)
int32_t AppleCryptoNative_EccGenerateKey(
int32_t keySizeBits, SecKeychainRef tempKeychain, SecKeyRef* pPublicKey, SecKeyRef* pPrivateKey, int32_t* pOSStatus)
int32_t AppleCryptoNative_EccGenerateKey(int32_t keySizeBits,
SecKeyRef* pPublicKey,
SecKeyRef* pPrivateKey,
CFErrorRef* pErrorOut)
{
if (pPublicKey != NULL)
*pPublicKey = NULL;
if (pPrivateKey != NULL)
*pPrivateKey = NULL;

if (pPublicKey == NULL || pPrivateKey == NULL || pOSStatus == NULL)
if (pPublicKey == NULL || pPrivateKey == NULL || pErrorOut == NULL)
return kErrorBadInput;

int32_t ret = kErrorSeeError;
CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(NULL, 3, &kCFTypeDictionaryKeyCallBacks, NULL);

CFNumberRef cfKeySizeValue = CFNumberCreate(NULL, kCFNumberIntType, &keySizeBits);
OSStatus status;

if (attributes != NULL && cfKeySizeValue != NULL)
{
CFDictionaryAddValue(attributes, kSecAttrKeyType, kSecAttrKeyTypeEC);
CFDictionaryAddValue(attributes, kSecAttrKeySizeInBits, cfKeySizeValue);
CFDictionaryAddValue(attributes, kSecUseKeychain, tempKeychain);
bartonjs marked this conversation as resolved.
Show resolved Hide resolved

status = SecKeyGeneratePair(attributes, pPublicKey, pPrivateKey);

if (status == noErr)
{
status = ExportImportKey(pPublicKey, kSecItemTypePublicKey);
}

if (status == noErr)
*pPrivateKey = SecKeyCreateRandomKey(attributes, pErrorOut);
if (*pPrivateKey != NULL)
{
status = ExportImportKey(pPrivateKey, kSecItemTypePrivateKey);
*pPublicKey = SecKeyCopyPublicKey(*pPrivateKey);
ret = 1;
}
}
else
{
status = errSecAllocate;
ret = errSecAllocate;
}

if (attributes != NULL)
CFRelease(attributes);
if (cfKeySizeValue != NULL)
CFRelease(cfKeySizeValue);

*pOSStatus = status;
return status == noErr;
return ret;
}
#endif

uint64_t AppleCryptoNative_EccGetKeySizeInBits(SecKeyRef publicKey)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,15 @@

#include <Security/Security.h>

#if !defined(TARGET_MACCATALYST) && !defined(TARGET_IOS) && !defined(TARGET_TVOS)
/*
Generate an ECC keypair of the specified size.

Returns 1 on success, 0 on failure. On failure, *pOSStatus should carry the OS failure code.
Follows pal_seckey return conventions.
*/
PALEXPORT int32_t AppleCryptoNative_EccGenerateKey(int32_t keySizeBits,
SecKeychainRef tempKeychain,
SecKeyRef* pPublicKey,
SecKeyRef* pPrivateKey,
int32_t* pOSStatus);
#endif
CFErrorRef* pErrorOut);

/*
Get the keysize, in bits, of an ECC key.
Expand Down
Loading