-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Re-enable asymmetric key generation on macOS. #16588
Re-enable asymmetric key generation on macOS. #16588
Conversation
Generate RSA and ECDSA keys via a temporary keychain. When no keychain is given, SecKeyGeneratePair will generate the keys into the default/login keychain. Since the keys were not expected to have been in the keychain, they permanently leak out and the keychain grows over time. Instead, have the managed code provide a temporary keychain into which the keys will be created. Then, export them and re-import them to the NULL keychain. The temporary keychain can then be deleted, and the hard problem of delayed cleanup is avoided. Files on disk will still leak if the process terminates during the key generation phase, but that is a much smaller window than other 'temporary file on disk' solutions.
} | ||
|
||
Debug.Fail($"Unexpected result from AppleCryptoNative_EccGenerateKey: {result}"); | ||
throw new CryptographicException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use the osStatus regardless? i.e.
Debug.Assert(result == 0, $"Unexpected result from {nameof(AppleCryptoNative_EccGenerateKey)}: {result}");
throw CreateExceptionForOSStatus(osStatus);
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A non-boolean value should mean that we don't trust osStatus to report the true cause of the error (it might even still be noErr
).
} | ||
|
||
Debug.Fail($"Unexpected result from AppleCryptoNative_RsaGenerateKey: {result}"); | ||
throw new CryptographicException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question
@@ -4,8 +4,8 @@ | |||
|
|||
#include "pal_ecc.h" | |||
|
|||
extern "C" int | |||
AppleCryptoNative_EccGenerateKey(int32_t keySizeBits, SecKeyRef* pPublicKey, SecKeyRef* pPrivateKey, int32_t* pOSStatus) | |||
extern "C" int AppleCryptoNative_EccGenerateKey( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return type should be changed from int
to int32_t
@@ -7,8 +7,8 @@ | |||
static int32_t ExecuteCFDataTransform( | |||
SecTransformRef xform, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut); | |||
|
|||
extern "C" int | |||
AppleCryptoNative_RsaGenerateKey(int32_t keySizeBits, SecKeyRef* pPublicKey, SecKeyRef* pPrivateKey, int32_t* pOSStatus) | |||
extern "C" int AppleCryptoNative_RsaGenerateKey( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int
=> int32_t
... maybe search and replace in these files in case there are more of 'em
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed these two int
=> int32_t
s. There are others, which is causing clang-format to have a conniption; I'll do that as a style only change after this one goes in.
|
||
SecItemImportExportKeyParameters keyParams = {}; | ||
keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; | ||
keyParams.passphrase = CFSTR("ExportImportPassphrase"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this string? Is it part of the spec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does CFSTR allocate anything, and if so, does it need to be freed somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apple's export API doesn't (under most circumstances) allow plaintext export. So I have to give it a non-null value for the export passphrase (and the same value on import to decrypt the blob).
CFSTR has the following behaviors:
The returned CFString has the following semantics:
- Because CFSTR is not a Create or Copy function, you are not responsible for releasing the string when you no longer need it.
- The string is not released by CFString. In other words, CFString guarantees its validity until the program terminates.
- I assume the docs meant "not released by CFRelease", since that's the only thing that makes sense.
- The string can be retained and released in a balanced fashion, like any other CFString.
That said, I've usually been calling CFRelease (because point 2 says it doesn't hurt), so I'll do so here, too.
@@ -43,7 +43,7 @@ public bool SupportsSha2Oaep | |||
get { return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); } | |||
} | |||
|
|||
public bool SupportsKeyGeneration => !RuntimeInformation.IsOSPlatform(OSPlatform.OSX); | |||
public bool SupportsKeyGeneration => true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there platforms now that don't support key generation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apple doesn't support DSA. But RSA and ECDSA are full on again now, so I'll go ahead and remove the conditionals.
Generate RSA and ECDSA keys via a temporary keychain. When no keychain is given, SecKeyGeneratePair will generate the keys into the default/login keychain. Since the keys were not expected to have been in the keychain, they permanently leak out and the keychain grows over time. Instead, have the managed code provide a temporary keychain into which the keys will be created. Then, export them and re-import them to the NULL keychain. The temporary keychain can then be deleted, and the hard problem of delayed cleanup is avoided. Files on disk will still leak if the process terminates during the key generation phase, but that is a much smaller window than other 'temporary file on disk' solutions. Commit migrated from dotnet/corefx@37ddcd3
Generate RSA and ECDSA keys via a temporary keychain.
When no keychain is given, SecKeyGeneratePair will generate the keys into the
default/login keychain. Since the keys were not expected to have been in the
keychain, they permanently leak out and the keychain grows over time.
Instead, have the managed code provide a temporary keychain into which the keys
will be created. Then, export them and re-import them to the NULL keychain. The
temporary keychain can then be deleted, and the hard problem of delayed cleanup is
avoided.
Files on disk will still leak if the process terminates during the key generation
phase, but that is a much smaller window than other 'temporary file on disk' solutions.