private static byte[] X509Export(X509ContentType contentType, SafeCreateHandle cfPassphrase, IntPtr[] certHandles) { Debug.Assert(contentType == X509ContentType.Pkcs7 || contentType == X509ContentType.Pkcs12); using (SafeCreateHandle handlesArray = CoreFoundation.CFArrayCreate(certHandles, (UIntPtr)certHandles.Length)) { SafeCFDataHandle exportData; int osStatus; int result = AppleCryptoNative_X509ExportData( handlesArray, contentType, cfPassphrase, out exportData, out osStatus); using (exportData) { if (result != 1) { if (result == 0) { throw CreateExceptionForOSStatus(osStatus); } Debug.Fail($"Unexpected result from AppleCryptoNative_X509ExportData: {result}"); throw new CryptographicException(); } Debug.Assert(!exportData.IsInvalid, "Successful export yielded no data"); return(CoreFoundation.CFGetData(exportData)); } } }
internal static byte[] X509GetRawData(SafeSecCertificateHandle cert) { int osStatus; SafeCFDataHandle data; int ret = AppleCryptoNative_X509GetRawData( cert, out data, out osStatus); using (data) { if (ret == 1) { return(CoreFoundation.CFGetData(data)); } if (ret == 0) { throw CreateExceptionForOSStatus(osStatus); } Debug.Fail($"Unexpected return value {ret}"); throw new CryptographicException(); } }
private static byte[] ExecuteTransform(ReadOnlySpan <byte> source, SecKeyTransform transform) { const int Success = 1; const int kErrorSeeError = -2; SafeCFDataHandle data; SafeCFErrorHandle error; int ret = transform(source, out data, out error); using (error) using (data) { if (ret == Success) { return(CoreFoundation.CFGetData(data)); } if (ret == kErrorSeeError) { throw CreateExceptionForCFError(error); } Debug.Fail($"transform returned {ret}"); throw new CryptographicException(); } }
internal static bool TrySecKeyCopyExternalRepresentation( SafeSecKeyRefHandle key, out byte[] externalRepresentation) { const int errSecPassphraseRequired = -25260; int result = AppleCryptoNative_SecKeyCopyExternalRepresentation( key, out SafeCFDataHandle data, out SafeCFErrorHandle errorHandle); using (errorHandle) using (data) { switch (result) { case kSuccess: externalRepresentation = CoreFoundation.CFGetData(data); return(true); case kErrorSeeError: if (Interop.CoreFoundation.GetErrorCode(errorHandle) == errSecPassphraseRequired) { externalRepresentation = Array.Empty <byte>(); return(false); } throw CreateExceptionForCFError(errorHandle); default: Debug.Fail($"SecKeyCopyExternalRepresentation returned {result}"); throw new CryptographicException(); } } }
internal static byte[] SecKeyExport( SafeSecKeyRefHandle?key, bool exportPrivate, string password) { using (SafeCFDataHandle cfData = SecKeyExportData(key, exportPrivate, password)) { return(CoreFoundation.CFGetData(cfData)); } }
internal static byte[] CreateSignature( SafeSecKeyRefHandle privateKey, ReadOnlySpan <byte> dataHash, PAL_HashAlgorithm hashAlgorithm, PAL_SignatureAlgorithm signatureAlgorithm) { using (SafeCFDataHandle signature = NativeCreateSignature(privateKey, dataHash, hashAlgorithm, signatureAlgorithm)) { return(CoreFoundation.CFGetData(signature)); } }
internal static byte[] SecKeyExport( SafeSecKeyRefHandle key, bool exportPrivate, string password) { SafeCreateHandle exportPassword = exportPrivate ? CoreFoundation.CFStringCreateWithCString(password) : s_nullExportString; int ret; SafeCFDataHandle cfData; int osStatus; try { ret = AppleCryptoNative_SecKeyExport( key, exportPrivate ? 1 : 0, exportPassword, out cfData, out osStatus); } finally { if (exportPassword != s_nullExportString) { exportPassword.Dispose(); } } byte[] exportedData; using (cfData) { if (ret == 0) { throw CreateExceptionForOSStatus(osStatus); } if (ret != 1) { Debug.Fail($"AppleCryptoNative_SecKeyExport returned {ret}"); throw new CryptographicException(); } exportedData = CoreFoundation.CFGetData(cfData); } return(exportedData); }
internal static byte[]? EcdhKeyAgree( SafeSecKeyRefHandle privateKey, SafeSecKeyRefHandle publicKey, Span <byte> opportunisticDestination, out int bytesWritten) { const int Success = 1; const int kErrorSeeError = -2; SafeCFDataHandle data; SafeCFErrorHandle error; int status = AppleCryptoNative_EcdhKeyAgree(privateKey, publicKey, out data, out error); using (data) using (error) { if (status == kErrorSeeError) { throw CreateExceptionForCFError(error); } if (status == Success && !data.IsInvalid) { if (CoreFoundation.TryCFWriteData(data, opportunisticDestination, out bytesWritten)) { return(null); } bytesWritten = 0; return(CoreFoundation.CFGetData(data)); } Debug.Fail($"Unexpected status ({status})"); throw new CryptographicException(); } }
internal static DerSequenceReader SecKeyExport( SafeSecKeyRefHandle key, bool exportPrivate) { // Apple requires all private keys to be exported encrypted, but since we're trying to export // as parsed structures we will need to decrypt it for the user. const string ExportPassword = "******"; SafeCreateHandle exportPassword = exportPrivate ? CoreFoundation.CFStringCreateWithCString(ExportPassword) : s_nullExportString; int ret; SafeCFDataHandle cfData; int osStatus; try { ret = AppleCryptoNative_SecKeyExport( key, exportPrivate ? 1 : 0, exportPassword, out cfData, out osStatus); } finally { if (exportPassword != s_nullExportString) { exportPassword.Dispose(); } } byte[] exportedData; using (cfData) { if (ret == 0) { throw CreateExceptionForOSStatus(osStatus); } if (ret != 1) { Debug.Fail($"AppleCryptoNative_SecKeyExport returned {ret}"); throw new CryptographicException(); } exportedData = CoreFoundation.CFGetData(cfData); } DerSequenceReader reader = new DerSequenceReader(exportedData); if (!exportPrivate) { return(reader); } byte tag = reader.PeekTag(); // PKCS#8 defines two structures, PrivateKeyInfo, which starts with an integer, // and EncryptedPrivateKey, which starts with an encryption algorithm (DER sequence). if (tag == (byte)DerSequenceReader.DerTag.Integer) { return(reader); } const byte ConstructedSequence = DerSequenceReader.ConstructedFlag | (byte)DerSequenceReader.DerTag.Sequence; if (tag == ConstructedSequence) { return(ReadEncryptedPkcs8Blob(ExportPassword, reader)); } Debug.Fail($"Data was neither PrivateKey or EncryptedPrivateKey: {tag:X2}"); throw new CryptographicException(); }