From 90328c5d46d0f079b32e9c09c24d7cef7ea20da4 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Wed, 28 Sep 2022 12:13:58 -0400 Subject: [PATCH 1/9] Implement managed pieces for macOS ChaCha20Poly1305. Co-authored-by: Filip Navara --- .../Interop.Aead.cs | 109 ++++++++++++++++++ .../src/System.Security.Cryptography.csproj | 5 +- .../Cryptography/ChaCha20Poly1305.macOS.cs | 72 ++++++++++++ 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs create mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs new file mode 100644 index 00000000000000..681838c2e23a40 --- /dev/null +++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs @@ -0,0 +1,109 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Security.Cryptography.Apple; + +internal static partial class Interop +{ + internal static partial class AppleCrypto + { + internal static unsafe void ChaCha20Poly1305Encrypt( + ReadOnlySpan key, + ReadOnlySpan nonce, + ReadOnlySpan plaintext, + Span ciphertext, + Span tag, + ReadOnlySpan aad) + { + fixed (byte* keyPtr = key) + fixed (byte* noncePtr = nonce) + fixed (byte* plaintextPtr = plaintext) + fixed (byte* ciphertextPtr = ciphertext) + fixed (byte* tagPtr = tag) + fixed (byte* aadPtr = aad) + { + const int Success = 1; + int result = AppleCryptoNative_ChaCha20Poly1305Encrypt( + keyPtr, key.Length, + noncePtr, nonce.Length, + plaintextPtr, plaintext.Length, + ciphertextPtr, ciphertext.Length, + tagPtr, tag.Length, + aadPtr, aad.Length); + + if (result != Success) + { + CryptographicOperations.ZeroMemory(ciphertext); + CryptographicOperations.ZeroMemory(tag); + throw new CryptographicException(); + } + } + } + + internal static unsafe void ChaCha20Poly1305Decrypt( + ReadOnlySpan key, + ReadOnlySpan nonce, + ReadOnlySpan ciphertext, + ReadOnlySpan tag, + Span plaintext, + ReadOnlySpan aad) + { + fixed (byte* keyPtr = key) + fixed (byte* noncePtr = nonce) + fixed (byte* ciphertextPtr = ciphertext) + fixed (byte* tagPtr = tag) + fixed (byte* plaintextPtr = plaintext) + fixed (byte* aadPtr = aad) + { + const int Success = 1; + int result = AppleCryptoNative_ChaCha20Poly1305Decrypt( + keyPtr, key.Length, + noncePtr, nonce.Length, + ciphertextPtr, ciphertext.Length, + tagPtr, tag.Length, + plaintextPtr, plaintext.Length, + aadPtr, aad.Length); + + // TODO: Need to throw the AuthenticationTagMismatchException when it gets merged. + if (result != Success) + { + CryptographicOperations.ZeroMemory(plaintext); + throw new CryptographicException(); + } + } + } + + [LibraryImport(Libraries.AppleCryptoNative)] + private static unsafe partial int AppleCryptoNative_ChaCha20Poly1305Encrypt( + byte* keyPtr, + int keyLength, + byte* noncePtr, + int nonceLength, + byte* plaintextPtr, + int plaintextLength, + byte* ciphertextPtr, + int ciphertextLength, + byte* tagPtr, + int tagLength, + byte* aadPtr, + int aadLength); + + [LibraryImport(Libraries.AppleCryptoNative)] + private static unsafe partial int AppleCryptoNative_ChaCha20Poly1305Decrypt( + byte* keyPtr, + int keyLength, + byte* noncePtr, + int nonceLength, + byte* ciphertextPtr, + int ciphertextLength, + byte* tagPtr, + int tagLength, + byte* plaintextPtr, + int plaintextLength, + byte* aadPtr, + int aadLength); + } +} diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index ed68d33a835db9..f390480bce452c 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -788,6 +788,7 @@ + @@ -868,7 +869,6 @@ Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.Cipher.cs" /> - @@ -1257,6 +1257,8 @@ Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Rsa.cs" /> + + diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs new file mode 100644 index 00000000000000..82f1633c1882e1 --- /dev/null +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace System.Security.Cryptography +{ + public sealed partial class ChaCha20Poly1305 + { + // CryptoKit added ChaCha20Poly1305 in macOS 10.15, which is our minimum target for macOS. + public static bool IsSupported => true; + private byte[]? _key; + + [MemberNotNull(nameof(_key))] + private void ImportKey(ReadOnlySpan key) + { + // We should only be calling this in the constructor, so there shouldn't be a previous key. + Debug.Assert(_key is null); + + // Pin the array on the POH so that the GC doesn't move it around to allow zeroing to be more effective. + _key = GC.AllocateArray(key.Length, pinned: true); + key.CopyTo(_key); + } + + private void EncryptCore( + ReadOnlySpan nonce, + ReadOnlySpan plaintext, + Span ciphertext, + Span tag, + ReadOnlySpan associatedData = default) + { + CheckDisposed(); + Interop.AppleCrypto.ChaCha20Poly1305Encrypt( + _key, + nonce, + plaintext, + ciphertext, + tag, + associatedData); + } + + private void DecryptCore( + ReadOnlySpan nonce, + ReadOnlySpan ciphertext, + ReadOnlySpan tag, + Span plaintext, + ReadOnlySpan associatedData = default) + { + CheckDisposed(); + Interop.AppleCrypto.ChaCha20Poly1305Decrypt( + _key, + nonce, + ciphertext, + tag, + plaintext, + associatedData); + } + + public void Dispose() + { + CryptographicOperations.ZeroMemory(_key); + _key = null; + } + + [MemberNotNull(nameof(_key))] + private void CheckDisposed() + { + ObjectDisposedException.ThrowIf(_key is null, this); + } + } +} From 0f7ec62504e3586a8592884bb5e0a35bdef946e2 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Wed, 28 Sep 2022 13:05:15 -0400 Subject: [PATCH 2/9] Implement native ChaCha20Poly1305 on macOS. Co-authored-by: Filip Navara --- .../Interop.Aead.cs | 1 + .../CMakeLists.txt | 30 +++++++ .../entrypoints.c | 3 + .../extra_libs.cmake | 6 ++ .../pal_aead.h | 35 ++++++++ .../pal_aead.swift | 88 +++++++++++++++++++ 6 files changed, 163 insertions(+) create mode 100644 src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.h create mode 100644 src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs index 681838c2e23a40..a68aff0752e9a4 100644 --- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs +++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs @@ -68,6 +68,7 @@ internal static unsafe void ChaCha20Poly1305Decrypt( aadPtr, aad.Length); // TODO: Need to throw the AuthenticationTagMismatchException when it gets merged. + // When there is an auth tag mismatch, -2 is returned. if (result != Success) { CryptographicOperations.ZeroMemory(plaintext); diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt index 77aa423237c358..ee1dd2e77d33a6 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt @@ -30,6 +30,7 @@ if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVO else() set(NATIVECRYPTO_SOURCES ${NATIVECRYPTO_SOURCES} + pal_aead.o pal_keychain_macos.c pal_keyderivation_macos.c pal_seckey_macos.c @@ -38,6 +39,35 @@ else() ) endif() +# As of CMake 3.20.2 support for Swift only works with the Ninja and XCode +# generators so we cannot rely on it. Even with the Ninja generator it doesn't +# work in combination with other languages within the same library. +# +# We need to compile the Swift file in a slightly special way to target +# only the Swift-in-OS runtime and fallback to weak linking on downlevel +# platforms where Swift runtime is not available. +if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_OSX) + set(SWIFT_PLATFORM "macosx") + set(SWIFT_PLATFORM_SUFFIX "") + set(SWIFT_DEFAULT_DEPLOYMENT_TARGET "10.15") + + if(CMAKE_OSX_DEPLOYMENT_TARGET) + set(SWIFT_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET}) + else() + set(SWIFT_DEPLOYMENT_TARGET ${SWIFT_DEFAULT_DEPLOYMENT_TARGET}) + endif() + + set(SWIFT_COMPILER_TARGET "${CMAKE_OSX_ARCHITECTURES}-apple-${SWIFT_PLATFORM}${SWIFT_DEPLOYMENT_TARGET}${SWIFT_PLATFORM_SUFFIX}") +endif() + +add_custom_command( + OUTPUT pal_aead.o + COMMAND xcrun swiftc -emit-object -static -parse-as-library -runtime-compatibility-version none -sdk ${CMAKE_OSX_SYSROOT} -target ${SWIFT_COMPILER_TARGET} ${CMAKE_CURRENT_SOURCE_DIR}/pal_aead.swift -o pal_aead.o + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/pal_aead.swift + COMMENT "Compiling Swift file pal_aead.swift" +) +set_source_files_properties(pal_aead.o PROPERTIES EXTERNAL_OBJECT true GENERATED true) + if (CLR_CMAKE_TARGET_MACCATALYST) add_definitions(-DTARGET_MACCATALYST) endif() diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c b/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c index 16e1efe9d25d1d..37ca21c8efac7b 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c @@ -4,6 +4,7 @@ #include // Include System.Security.Cryptography.Native.Apple headers +#include "pal_aead.h" #include "pal_digest.h" #include "pal_ecc.h" #include "pal_hmac.h" @@ -25,6 +26,8 @@ static const Entry s_cryptoAppleNative[] = { + DllImportEntry(AppleCryptoNative_ChaCha20Poly1305Encrypt) + DllImportEntry(AppleCryptoNative_ChaCha20Poly1305Decrypt) DllImportEntry(AppleCryptoNative_DigestFree) DllImportEntry(AppleCryptoNative_DigestCreate) DllImportEntry(AppleCryptoNative_DigestUpdate) diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/extra_libs.cmake b/src/native/libs/System.Security.Cryptography.Native.Apple/extra_libs.cmake index 9ed82cd31bc29e..07b595bd6e4c2b 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/extra_libs.cmake +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/extra_libs.cmake @@ -4,4 +4,10 @@ macro(append_extra_cryptography_apple_libs NativeLibsExtra) find_library(SECURITY_LIBRARY Security) list(APPEND ${NativeLibsExtra} ${COREFOUNDATION_LIBRARY} ${SECURITY_LIBRARY}) + + if (CLR_CMAKE_TARGET_OSX) + find_library(CRYPTOKIT_LIBRARY CryptoKit) + + list(APPEND ${NativeLibsExtra} ${CRYPTOKIT_LIBRARY} -L/usr/lib/swift -lobjc -lswiftCore -lswiftFoundation) + endif() endmacro() diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.h b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.h new file mode 100644 index 00000000000000..42e3c22e7dad6c --- /dev/null +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.h @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma once + +#include "pal_types.h" +#include "pal_compiler.h" + +PALEXPORT int32_t AppleCryptoNative_ChaCha20Poly1305Encrypt( + uint8_t* keyPtr, + int32_t keyLength, + uint8_t* noncePtr, + int32_t nonceLength, + uint8_t* plaintextPtr, + int32_t plaintextLength, + uint8_t* ciphertextBuffer, + int32_t ciphertextBufferLength, + uint8_t* tagBuffer, + int32_t tagBufferLength, + uint8_t* aadPtr, + int32_t aadLength); + +PALEXPORT int32_t AppleCryptoNative_ChaCha20Poly1305Decrypt( + uint8_t* keyPtr, + int32_t keyLength, + uint8_t* noncePtr, + int32_t nonceLength, + uint8_t* ciphertextPtr, + int32_t ciphertextLength, + uint8_t* tagPtr, + int32_t tagLength, + uint8_t* plaintextBuffer, + int32_t plaintextBufferLength, + uint8_t* aadPtr, + int32_t aadLength); diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift new file mode 100644 index 00000000000000..2d969f08a67c38 --- /dev/null +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import CryptoKit +import Foundation + +@_cdecl("AppleCryptoNative_ChaCha20Poly1305Encrypt") +public func AppleCryptoNative_ChaCha20Poly1305Encrypt( + keyPtr: UnsafeMutableRawPointer, + keyLength: Int32, + noncePtr: UnsafeMutableRawPointer, + nonceLength: Int32, + plaintextPtr: UnsafeMutableRawPointer, + plaintextLength: Int32, + ciphertextBuffer: UnsafeMutablePointer, + ciphertextBufferLength: Int32, + tagBuffer: UnsafeMutablePointer, + tagBufferLength: Int32, + aadPtr: UnsafeMutableRawPointer, + aadLength: Int32 + ) -> Int32 { + let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) + let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) + let plaintext = Data(bytesNoCopy: plaintextPtr, count: Int(plaintextLength), deallocator: Data.Deallocator.none) + let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) + let symmetricKey = SymmetricKey(data: key) + + guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { + return 0 + } + + guard let result = try? ChaChaPoly.seal(plaintext, using: symmetricKey, nonce: nonce, authenticating: aad) else { + return 0 + } + + assert(ciphertextBufferLength >= result.ciphertext.count) + assert(tagBufferLength >= result.tag.count) + + result.ciphertext.copyBytes(to: ciphertextBuffer, count: result.ciphertext.count) + result.tag.copyBytes(to: tagBuffer, count: result.tag.count) + return 1 + } + +@_cdecl("AppleCryptoNative_ChaCha20Poly1305Decrypt") +public func AppleCryptoNative_ChaCha20Poly1305Decrypt( + keyPtr: UnsafeMutableRawPointer, + keyLength: Int32, + noncePtr: UnsafeMutableRawPointer, + nonceLength: Int32, + ciphertextPtr: UnsafeMutableRawPointer, + ciphertextLength: Int32, + tagPtr: UnsafeMutableRawPointer, + tagLength: Int32, + plaintextBuffer: UnsafeMutablePointer, + plaintextBufferLength: Int32, + aadPtr: UnsafeMutableRawPointer, + aadLength: Int32 +) -> Int32 +{ + let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) + let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) + let ciphertext = Data(bytesNoCopy: ciphertextPtr, count: Int(ciphertextLength), deallocator: Data.Deallocator.none) + let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) + let tag = Data(bytesNoCopy: tagPtr, count: Int(tagLength), deallocator: Data.Deallocator.none) + let symmetricKey = SymmetricKey(data: key) + + guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { + return 0 + } + + guard let sealedBoxRestored = try? ChaChaPoly.SealedBox(nonce: nonce, ciphertext: ciphertext, tag: tag) else { + return 0 + } + + do { + let result = try ChaChaPoly.open(sealedBoxRestored, using: symmetricKey, authenticating: aad) + + assert(plaintextBufferLength >= result.count) + result.copyBytes(to: plaintextBuffer, count: result.count) + return 1 + } + catch CryptoKitError.authenticationFailure { + return -2 + } + catch { + return 0 + } +} From dc9fb132582c4800eb594f860b972feb96f75350 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Wed, 28 Sep 2022 13:30:10 -0400 Subject: [PATCH 3/9] Remove outdated comment --- .../System.Security.Cryptography.Native.Apple/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt index ee1dd2e77d33a6..83a6387efce40b 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt @@ -42,10 +42,6 @@ endif() # As of CMake 3.20.2 support for Swift only works with the Ninja and XCode # generators so we cannot rely on it. Even with the Ninja generator it doesn't # work in combination with other languages within the same library. -# -# We need to compile the Swift file in a slightly special way to target -# only the Swift-in-OS runtime and fallback to weak linking on downlevel -# platforms where Swift runtime is not available. if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_OSX) set(SWIFT_PLATFORM "macosx") set(SWIFT_PLATFORM_SUFFIX "") From 271ce72fc3d18bd6a949f3fb3d4668e729622c85 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Wed, 28 Sep 2022 14:00:16 -0400 Subject: [PATCH 4/9] Fix indentation --- .../pal_aead.swift | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift index 2d969f08a67c38..247a5d984fdeba 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift @@ -19,26 +19,26 @@ public func AppleCryptoNative_ChaCha20Poly1305Encrypt( aadPtr: UnsafeMutableRawPointer, aadLength: Int32 ) -> Int32 { - let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) - let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) - let plaintext = Data(bytesNoCopy: plaintextPtr, count: Int(plaintextLength), deallocator: Data.Deallocator.none) - let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) - let symmetricKey = SymmetricKey(data: key) + let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) + let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) + let plaintext = Data(bytesNoCopy: plaintextPtr, count: Int(plaintextLength), deallocator: Data.Deallocator.none) + let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) + let symmetricKey = SymmetricKey(data: key) - guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { - return 0 - } + guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { + return 0 + } - guard let result = try? ChaChaPoly.seal(plaintext, using: symmetricKey, nonce: nonce, authenticating: aad) else { - return 0 - } + guard let result = try? ChaChaPoly.seal(plaintext, using: symmetricKey, nonce: nonce, authenticating: aad) else { + return 0 + } - assert(ciphertextBufferLength >= result.ciphertext.count) - assert(tagBufferLength >= result.tag.count) + assert(ciphertextBufferLength >= result.ciphertext.count) + assert(tagBufferLength >= result.tag.count) - result.ciphertext.copyBytes(to: ciphertextBuffer, count: result.ciphertext.count) - result.tag.copyBytes(to: tagBuffer, count: result.tag.count) - return 1 + result.ciphertext.copyBytes(to: ciphertextBuffer, count: result.ciphertext.count) + result.tag.copyBytes(to: tagBuffer, count: result.tag.count) + return 1 } @_cdecl("AppleCryptoNative_ChaCha20Poly1305Decrypt") From 8fdbe249c9152284dd8807ff0045ab8c9c3857ec Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Wed, 28 Sep 2022 14:31:00 -0400 Subject: [PATCH 5/9] Add runtime checks back --- .../pal_aead.swift | 86 ++++++++++--------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift index 247a5d984fdeba..ea6ff59cc57324 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift @@ -19,26 +19,30 @@ public func AppleCryptoNative_ChaCha20Poly1305Encrypt( aadPtr: UnsafeMutableRawPointer, aadLength: Int32 ) -> Int32 { - let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) - let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) - let plaintext = Data(bytesNoCopy: plaintextPtr, count: Int(plaintextLength), deallocator: Data.Deallocator.none) - let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) - let symmetricKey = SymmetricKey(data: key) + if #available(macOS 10.15, *) { + let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) + let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) + let plaintext = Data(bytesNoCopy: plaintextPtr, count: Int(plaintextLength), deallocator: Data.Deallocator.none) + let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) + let symmetricKey = SymmetricKey(data: key) - guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { - return 0 - } + guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { + return 0 + } - guard let result = try? ChaChaPoly.seal(plaintext, using: symmetricKey, nonce: nonce, authenticating: aad) else { - return 0 - } + guard let result = try? ChaChaPoly.seal(plaintext, using: symmetricKey, nonce: nonce, authenticating: aad) else { + return 0 + } + + assert(ciphertextBufferLength >= result.ciphertext.count) + assert(tagBufferLength >= result.tag.count) - assert(ciphertextBufferLength >= result.ciphertext.count) - assert(tagBufferLength >= result.tag.count) + result.ciphertext.copyBytes(to: ciphertextBuffer, count: result.ciphertext.count) + result.tag.copyBytes(to: tagBuffer, count: result.tag.count) + return 1 + } - result.ciphertext.copyBytes(to: ciphertextBuffer, count: result.ciphertext.count) - result.tag.copyBytes(to: tagBuffer, count: result.tag.count) - return 1 + return -1 } @_cdecl("AppleCryptoNative_ChaCha20Poly1305Decrypt") @@ -57,32 +61,36 @@ public func AppleCryptoNative_ChaCha20Poly1305Decrypt( aadLength: Int32 ) -> Int32 { - let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) - let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) - let ciphertext = Data(bytesNoCopy: ciphertextPtr, count: Int(ciphertextLength), deallocator: Data.Deallocator.none) - let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) - let tag = Data(bytesNoCopy: tagPtr, count: Int(tagLength), deallocator: Data.Deallocator.none) - let symmetricKey = SymmetricKey(data: key) + if #available(macOS 10.15, *) { + let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) + let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) + let ciphertext = Data(bytesNoCopy: ciphertextPtr, count: Int(ciphertextLength), deallocator: Data.Deallocator.none) + let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) + let tag = Data(bytesNoCopy: tagPtr, count: Int(tagLength), deallocator: Data.Deallocator.none) + let symmetricKey = SymmetricKey(data: key) - guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { - return 0 - } + guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { + return 0 + } - guard let sealedBoxRestored = try? ChaChaPoly.SealedBox(nonce: nonce, ciphertext: ciphertext, tag: tag) else { - return 0 - } + guard let sealedBoxRestored = try? ChaChaPoly.SealedBox(nonce: nonce, ciphertext: ciphertext, tag: tag) else { + return 0 + } - do { - let result = try ChaChaPoly.open(sealedBoxRestored, using: symmetricKey, authenticating: aad) + do { + let result = try ChaChaPoly.open(sealedBoxRestored, using: symmetricKey, authenticating: aad) - assert(plaintextBufferLength >= result.count) - result.copyBytes(to: plaintextBuffer, count: result.count) - return 1 - } - catch CryptoKitError.authenticationFailure { - return -2 - } - catch { - return 0 + assert(plaintextBufferLength >= result.count) + result.copyBytes(to: plaintextBuffer, count: result.count) + return 1 + } + catch CryptoKitError.authenticationFailure { + return -2 + } + catch { + return 0 + } } + + return -1 } From fa6c5f90b93ce4d5cdd165d885d6ced93b38688f Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Wed, 28 Sep 2022 14:35:45 -0400 Subject: [PATCH 6/9] Code review feedback --- .../CMakeLists.txt | 12 ++++++------ .../entrypoints.c | 2 +- .../{pal_aead.h => pal_swiftbindings.h} | 0 .../{pal_aead.swift => pal_swiftbindings.swift} | 0 4 files changed, 7 insertions(+), 7 deletions(-) rename src/native/libs/System.Security.Cryptography.Native.Apple/{pal_aead.h => pal_swiftbindings.h} (100%) rename src/native/libs/System.Security.Cryptography.Native.Apple/{pal_aead.swift => pal_swiftbindings.swift} (100%) diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt index 83a6387efce40b..dff4680af57602 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt @@ -30,7 +30,7 @@ if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVO else() set(NATIVECRYPTO_SOURCES ${NATIVECRYPTO_SOURCES} - pal_aead.o + pal_swiftbindings.o pal_keychain_macos.c pal_keyderivation_macos.c pal_seckey_macos.c @@ -57,12 +57,12 @@ if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_OSX) endif() add_custom_command( - OUTPUT pal_aead.o - COMMAND xcrun swiftc -emit-object -static -parse-as-library -runtime-compatibility-version none -sdk ${CMAKE_OSX_SYSROOT} -target ${SWIFT_COMPILER_TARGET} ${CMAKE_CURRENT_SOURCE_DIR}/pal_aead.swift -o pal_aead.o - MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/pal_aead.swift - COMMENT "Compiling Swift file pal_aead.swift" + OUTPUT pal_swiftbindings.o + COMMAND xcrun swiftc -emit-object -static -parse-as-library -runtime-compatibility-version none -sdk ${CMAKE_OSX_SYSROOT} -target ${SWIFT_COMPILER_TARGET} ${CMAKE_CURRENT_SOURCE_DIR}/pal_swiftbindings.swift -o pal_swiftbindings.o + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/pal_swiftbindings.swift + COMMENT "Compiling Swift file pal_swiftbindings.swift" ) -set_source_files_properties(pal_aead.o PROPERTIES EXTERNAL_OBJECT true GENERATED true) +set_source_files_properties(pal_swiftbindings.o PROPERTIES EXTERNAL_OBJECT true GENERATED true) if (CLR_CMAKE_TARGET_MACCATALYST) add_definitions(-DTARGET_MACCATALYST) diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c b/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c index 37ca21c8efac7b..4f013c4cf74843 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c @@ -4,7 +4,6 @@ #include // Include System.Security.Cryptography.Native.Apple headers -#include "pal_aead.h" #include "pal_digest.h" #include "pal_ecc.h" #include "pal_hmac.h" @@ -18,6 +17,7 @@ #include "pal_seckey_macos.h" #include "pal_signverify.h" #include "pal_ssl.h" +#include "pal_swiftbindings.h" #include "pal_symmetric.h" #include "pal_trust_macos.h" #include "pal_x509.h" diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.h b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.h similarity index 100% rename from src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.h rename to src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.h diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.swift similarity index 100% rename from src/native/libs/System.Security.Cryptography.Native.Apple/pal_aead.swift rename to src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.swift From 6e3ba362b167eceb56e397f608c44fe6b63b163c Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Wed, 28 Sep 2022 16:28:08 -0400 Subject: [PATCH 7/9] Try raising the deployment target --- eng/native/configurecompiler.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake index da893f7da616ba..93d0f9c5ad54d3 100644 --- a/eng/native/configurecompiler.cmake +++ b/eng/native/configurecompiler.cmake @@ -509,7 +509,7 @@ if (CLR_CMAKE_HOST_UNIX) set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0") add_compile_options(-arch arm64) elseif(CLR_CMAKE_HOST_ARCH_AMD64) - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15") add_compile_options(-arch x86_64) else() clr_unknown_arch() From 5f578bab33e8b878a1b95ed1d038ec996f747e0f Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Fri, 30 Sep 2022 09:06:20 -0400 Subject: [PATCH 8/9] Implement AuthenticationTagMismatchException --- .../Interop.Aead.cs | 16 +++- .../tests/ChaCha20Poly1305Tests.cs | 8 +- .../pal_swiftbindings.swift | 86 +++++++++---------- 3 files changed, 58 insertions(+), 52 deletions(-) diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs index a68aff0752e9a4..62102ac0a5939f 100644 --- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs +++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.Apple; @@ -36,6 +37,7 @@ internal static unsafe void ChaCha20Poly1305Encrypt( if (result != Success) { + Debug.Assert(result == 0); CryptographicOperations.ZeroMemory(ciphertext); CryptographicOperations.ZeroMemory(tag); throw new CryptographicException(); @@ -59,6 +61,7 @@ internal static unsafe void ChaCha20Poly1305Decrypt( fixed (byte* aadPtr = aad) { const int Success = 1; + const int AuthTagMismatch = -1; int result = AppleCryptoNative_ChaCha20Poly1305Decrypt( keyPtr, key.Length, noncePtr, nonce.Length, @@ -67,12 +70,19 @@ internal static unsafe void ChaCha20Poly1305Decrypt( plaintextPtr, plaintext.Length, aadPtr, aad.Length); - // TODO: Need to throw the AuthenticationTagMismatchException when it gets merged. - // When there is an auth tag mismatch, -2 is returned. if (result != Success) { CryptographicOperations.ZeroMemory(plaintext); - throw new CryptographicException(); + + if (result == AuthTagMismatch) + { + throw new AuthenticationTagMismatchException(); + } + else + { + Debug.Assert(result == 0); + throw new CryptographicException(); + } } } } diff --git a/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs b/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs index f381e17e73d190..40f17690cdffcc 100644 --- a/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs @@ -457,8 +457,12 @@ public static void CheckIsSupported() // OpenSSL is present, and a high enough version, // but the distro build options turned off ChaCha/Poly. } - else if (PlatformDetection.OpenSslPresentOnSystem && - (PlatformDetection.IsOSX || PlatformDetection.IsOpenSslSupported)) + else if (PlatformDetection.IsOSX) + { + // CryptoKit is supported on macOS 10.15+, which is our minimum target. + expectedIsSupported = true; + } + else if (PlatformDetection.OpenSslPresentOnSystem && PlatformDetection.IsOpenSslSupported) { const int OpenSslChaChaMinimumVersion = 0x1_01_00_00_F; //major_minor_fix_patch_status expectedIsSupported = SafeEvpPKeyHandle.OpenSslVersion >= OpenSslChaChaMinimumVersion; diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.swift b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.swift index ea6ff59cc57324..7d54df744b1f70 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.swift +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.swift @@ -19,30 +19,26 @@ public func AppleCryptoNative_ChaCha20Poly1305Encrypt( aadPtr: UnsafeMutableRawPointer, aadLength: Int32 ) -> Int32 { - if #available(macOS 10.15, *) { - let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) - let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) - let plaintext = Data(bytesNoCopy: plaintextPtr, count: Int(plaintextLength), deallocator: Data.Deallocator.none) - let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) - let symmetricKey = SymmetricKey(data: key) + let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) + let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) + let plaintext = Data(bytesNoCopy: plaintextPtr, count: Int(plaintextLength), deallocator: Data.Deallocator.none) + let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) + let symmetricKey = SymmetricKey(data: key) - guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { - return 0 - } - - guard let result = try? ChaChaPoly.seal(plaintext, using: symmetricKey, nonce: nonce, authenticating: aad) else { - return 0 - } - - assert(ciphertextBufferLength >= result.ciphertext.count) - assert(tagBufferLength >= result.tag.count) + guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { + return 0 + } - result.ciphertext.copyBytes(to: ciphertextBuffer, count: result.ciphertext.count) - result.tag.copyBytes(to: tagBuffer, count: result.tag.count) - return 1 + guard let result = try? ChaChaPoly.seal(plaintext, using: symmetricKey, nonce: nonce, authenticating: aad) else { + return 0 } - return -1 + assert(ciphertextBufferLength >= result.ciphertext.count) + assert(tagBufferLength >= result.tag.count) + + result.ciphertext.copyBytes(to: ciphertextBuffer, count: result.ciphertext.count) + result.tag.copyBytes(to: tagBuffer, count: result.tag.count) + return 1 } @_cdecl("AppleCryptoNative_ChaCha20Poly1305Decrypt") @@ -61,36 +57,32 @@ public func AppleCryptoNative_ChaCha20Poly1305Decrypt( aadLength: Int32 ) -> Int32 { - if #available(macOS 10.15, *) { - let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) - let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) - let ciphertext = Data(bytesNoCopy: ciphertextPtr, count: Int(ciphertextLength), deallocator: Data.Deallocator.none) - let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) - let tag = Data(bytesNoCopy: tagPtr, count: Int(tagLength), deallocator: Data.Deallocator.none) - let symmetricKey = SymmetricKey(data: key) + let nonceData = Data(bytesNoCopy: noncePtr, count: Int(nonceLength), deallocator: Data.Deallocator.none) + let key = Data(bytesNoCopy: keyPtr, count: Int(keyLength), deallocator: Data.Deallocator.none) + let ciphertext = Data(bytesNoCopy: ciphertextPtr, count: Int(ciphertextLength), deallocator: Data.Deallocator.none) + let aad = Data(bytesNoCopy: aadPtr, count: Int(aadLength), deallocator: Data.Deallocator.none) + let tag = Data(bytesNoCopy: tagPtr, count: Int(tagLength), deallocator: Data.Deallocator.none) + let symmetricKey = SymmetricKey(data: key) - guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { - return 0 - } + guard let nonce = try? ChaChaPoly.Nonce(data: nonceData) else { + return 0 + } - guard let sealedBoxRestored = try? ChaChaPoly.SealedBox(nonce: nonce, ciphertext: ciphertext, tag: tag) else { - return 0 - } + guard let sealedBoxRestored = try? ChaChaPoly.SealedBox(nonce: nonce, ciphertext: ciphertext, tag: tag) else { + return 0 + } - do { - let result = try ChaChaPoly.open(sealedBoxRestored, using: symmetricKey, authenticating: aad) + do { + let result = try ChaChaPoly.open(sealedBoxRestored, using: symmetricKey, authenticating: aad) - assert(plaintextBufferLength >= result.count) - result.copyBytes(to: plaintextBuffer, count: result.count) - return 1 - } - catch CryptoKitError.authenticationFailure { - return -2 - } - catch { - return 0 - } + assert(plaintextBufferLength >= result.count) + result.copyBytes(to: plaintextBuffer, count: result.count) + return 1 + } + catch CryptoKitError.authenticationFailure { + return -1 + } + catch { + return 0 } - - return -1 } From 1ca9b7ffc15f59a775f41e8abd559bbe029664b8 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Fri, 30 Sep 2022 16:13:11 -0400 Subject: [PATCH 9/9] Simplify some cmake logic --- .../CMakeLists.txt | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt index dff4680af57602..0c288067d1148a 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt @@ -45,15 +45,8 @@ endif() if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_OSX) set(SWIFT_PLATFORM "macosx") set(SWIFT_PLATFORM_SUFFIX "") - set(SWIFT_DEFAULT_DEPLOYMENT_TARGET "10.15") - - if(CMAKE_OSX_DEPLOYMENT_TARGET) - set(SWIFT_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET}) - else() - set(SWIFT_DEPLOYMENT_TARGET ${SWIFT_DEFAULT_DEPLOYMENT_TARGET}) - endif() - - set(SWIFT_COMPILER_TARGET "${CMAKE_OSX_ARCHITECTURES}-apple-${SWIFT_PLATFORM}${SWIFT_DEPLOYMENT_TARGET}${SWIFT_PLATFORM_SUFFIX}") + set(SWIFT_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET}) + set(SWIFT_COMPILER_TARGET "${CMAKE_OSX_ARCHITECTURES}-apple-${SWIFT_PLATFORM}${SWIFT_DEPLOYMENT_TARGET}${SWIFT_PLATFORM_SUFFIX}") endif() add_custom_command(