Skip to content
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 @@ -132,6 +132,14 @@ if (GEN_SHARED_LIB)
${NATIVE_LIBS_EXTRA}
)

add_custom_command(TARGET System.Security.Cryptography.Native.Apple POST_BUILD
COMMENT "Verifying System.Security.Cryptography.Native.Apple has no Swift ObjC classes"
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../verify-no-swift-objc-classes.sh
$<TARGET_FILE:System.Security.Cryptography.Native.Apple>
${CMAKE_NM}
VERBATIM
)

if (NOT CLR_CMAKE_TARGET_APPLE_MOBILE)
add_custom_command(TARGET System.Security.Cryptography.Native.Apple POST_BUILD
COMMENT "Verifying System.Security.Cryptography.Native.Apple points against entrypoints.c "
Expand All @@ -144,6 +152,14 @@ if (GEN_SHARED_LIB)
endif()
endif()

add_custom_command(TARGET System.Security.Cryptography.Native.Apple-Static POST_BUILD
COMMENT "Verifying System.Security.Cryptography.Native.Apple static archive has no Swift ObjC classes"
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../verify-no-swift-objc-classes.sh
$<TARGET_FILE:System.Security.Cryptography.Native.Apple-Static>
${CMAKE_NM}
VERBATIM
)

if (GEN_SHARED_LIB)
install_with_stripped_symbols (System.Security.Cryptography.Native.Apple PROGRAMS .)
endif()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@
import CryptoKit
import Foundation

final class HashBox {
struct HashBox {
var value: any HashFunction
init(_ value: any HashFunction) {
self.value = value
}
}

enum X25519Key {
Expand All @@ -23,13 +20,6 @@ enum X25519Key {
}
}

final class X25519KeyBox {
var value: X25519Key
init(_ value: X25519Key) {
self.value = value
}
}

protocol NonceProtocol {
init<D>(data: D) throws where D : DataProtocol
}
Expand Down Expand Up @@ -72,6 +62,18 @@ extension ChaChaPoly.SealedBox: SealedBoxProtocol {

extension ChaChaPoly: AEADSymmetricAlgorithm {}

private func allocatePointer<T>(to value: T) -> UnsafeMutableRawPointer {
let pointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
pointer.initialize(to: value)
return UnsafeMutableRawPointer(pointer)
}

private func deallocatePointer<T>(_ pointer: UnsafeMutableRawPointer, to type: T.Type) {
let typedPointer = pointer.assumingMemoryBound(to: type)
typedPointer.deinitialize(count: 1)
typedPointer.deallocate()
}

func encrypt<Algorithm>(
_ algorithm: Algorithm.Type,
key: UnsafeBufferPointer<UInt8>,
Expand Down Expand Up @@ -422,24 +424,19 @@ public func AppleCryptoNative_DigestCreate(algorithm: Int32, pcbDigest: UnsafeMu
switch hashAlgorithm {
case .md5:
pcbDigest.pointee = Int32(Insecure.MD5.byteCount)
let box = HashBox(Insecure.MD5())
return Unmanaged.passRetained(box).toOpaque()
return allocatePointer(to: HashBox(value: Insecure.MD5()))
case .sha1:
pcbDigest.pointee = Int32(Insecure.SHA1.byteCount)
let box = HashBox(Insecure.SHA1())
return Unmanaged.passRetained(box).toOpaque()
return allocatePointer(to: HashBox(value: Insecure.SHA1()))
case .sha256:
pcbDigest.pointee = Int32(SHA256.byteCount)
let box = HashBox(SHA256())
return Unmanaged.passRetained(box).toOpaque()
return allocatePointer(to: HashBox(value: SHA256()))
case .sha384:
pcbDigest.pointee = Int32(SHA384.byteCount)
let box = HashBox(SHA384())
return Unmanaged.passRetained(box).toOpaque()
return allocatePointer(to: HashBox(value: SHA384()))
case .sha512:
pcbDigest.pointee = Int32(SHA512.byteCount)
let box = HashBox(SHA512())
return Unmanaged.passRetained(box).toOpaque()
return allocatePointer(to: HashBox(value: SHA512()))
default:
pcbDigest.pointee = 0
return nil
Expand All @@ -456,11 +453,11 @@ public func AppleCryptoNative_DigestUpdate(ctx: UnsafeMutableRawPointer?, pBuf:
return -1
}

let box = Unmanaged<HashBox>.fromOpaque(ctx).takeUnretainedValue()
let box = ctx.assumingMemoryBound(to: HashBox.self)
let source = Data(bytesNoCopy: pBuf, count: Int(cBuf), deallocator: Data.Deallocator.none)
var hash = box.value
var hash = box.pointee.value
hash.update(data: source)
box.value = hash
box.pointee.value = hash
return 1
}

Expand All @@ -470,23 +467,23 @@ public func AppleCryptoNative_DigestReset(ctx: UnsafeMutableRawPointer?) -> Int3
return -1
}

let box = Unmanaged<HashBox>.fromOpaque(ctx).takeUnretainedValue()
let box = ctx.assumingMemoryBound(to: HashBox.self)

switch box.value {
switch box.pointee.value {
case is Insecure.MD5:
box.value = Insecure.MD5()
box.pointee.value = Insecure.MD5()
return 1
case is Insecure.SHA1:
box.value = Insecure.SHA1()
box.pointee.value = Insecure.SHA1()
return 1
case is SHA256:
box.value = SHA256()
box.pointee.value = SHA256()
return 1
case is SHA384:
box.value = SHA384()
box.pointee.value = SHA384()
return 1
case is SHA512:
box.value = SHA512()
box.pointee.value = SHA512()
return 1
default:
return -2
Expand All @@ -499,10 +496,10 @@ public func AppleCryptoNative_DigestFinal(ctx: UnsafeMutableRawPointer?, pOutput
return -1
}

let box = Unmanaged<HashBox>.fromOpaque(ctx).takeUnretainedValue()
let box = ctx.assumingMemoryBound(to: HashBox.self)
let destination = UnsafeMutableRawBufferPointer(start: pOutput, count: Int(cbOutput))

let hash = box.value.finalize()
let hash = box.pointee.value.finalize()
let copied = hash.withUnsafeBytes { digest in
return digest.copyBytes(to: destination) == digest.count
}
Expand All @@ -517,7 +514,7 @@ public func AppleCryptoNative_DigestFinal(ctx: UnsafeMutableRawPointer?, pOutput
@_silgen_name("AppleCryptoNative_DigestFree")
public func AppleCryptoNative_DigestFree(ptr: UnsafeMutableRawPointer?) {
if let ptr {
Unmanaged<HashBox>.fromOpaque(ptr).release()
deallocatePointer(ptr, to: HashBox.self)
}
}

Expand All @@ -527,11 +524,10 @@ public func AppleCryptoNative_DigestClone(ctx: UnsafeMutableRawPointer?) -> Unsa
return nil
}

let box = Unmanaged<HashBox>.fromOpaque(ctx).takeUnretainedValue()
let digest = box.value
let box = ctx.assumingMemoryBound(to: HashBox.self)
let digest = box.pointee.value
let clone = digest
let cloneBox = HashBox(clone)
return Unmanaged.passRetained(cloneBox).toOpaque()
return allocatePointer(to: HashBox(value: clone))
}

@_silgen_name("AppleCryptoNative_DigestCurrent")
Expand All @@ -540,9 +536,9 @@ public func AppleCryptoNative_DigestCurrent(ctx: UnsafeMutableRawPointer?, pOutp
return -1
}

let box = Unmanaged<HashBox>.fromOpaque(ctx).takeUnretainedValue()
let box = ctx.assumingMemoryBound(to: HashBox.self)
let destination = UnsafeMutableRawBufferPointer(start: pOutput, count: Int(cbOutput))
let unboxed = box.value
let unboxed = box.pointee.value
let clone = unboxed
let hash = clone.finalize()
let copied = hash.withUnsafeBytes { digest in
Expand Down Expand Up @@ -593,14 +589,14 @@ public func AppleCryptoNative_X25519DeriveRawSecretAgreement(
return -1
}

let keyBox = Unmanaged<X25519KeyBox>.fromOpaque(keyPtr).takeUnretainedValue()
let peerBox = Unmanaged<X25519KeyBox>.fromOpaque(peerKeyPtr).takeUnretainedValue()
let keyBox = keyPtr.assumingMemoryBound(to: X25519Key.self)
let peerBox = peerKeyPtr.assumingMemoryBound(to: X25519Key.self)

guard case .privateKey(let key) = keyBox.value else {
guard case .privateKey(let key) = keyBox.pointee else {
return -1
}

let peerKey = peerBox.value.getPublic()
let peerKey = peerBox.pointee.getPublic()
return deriveRawSecretAgreement(key: key, peerKey: peerKey, pOutput: pOutput, cbOutput: cbOutput)
}

Expand All @@ -615,9 +611,9 @@ public func AppleCryptoNative_X25519DeriveRawSecretAgreementWithBytes(
return -1
}

let keyBox = Unmanaged<X25519KeyBox>.fromOpaque(keyPtr).takeUnretainedValue()
let keyBox = keyPtr.assumingMemoryBound(to: X25519Key.self)

guard case .privateKey(let key) = keyBox.value else {
guard case .privateKey(let key) = keyBox.pointee else {
return -1
}

Expand All @@ -633,7 +629,7 @@ public func AppleCryptoNative_X25519DeriveRawSecretAgreementWithBytes(
@_silgen_name("AppleCryptoNative_X25519FreeKey")
public func AppleCryptoNative_X25519FreeKey(ptr: UnsafeMutableRawPointer?) {
if let ptr {
Unmanaged<X25519KeyBox>.fromOpaque(ptr).release()
deallocatePointer(ptr, to: X25519Key.self)
}
}

Expand All @@ -646,9 +642,9 @@ public func AppleCryptoNative_X25519ExportPrivateKey(
return -1
}

let box = Unmanaged<X25519KeyBox>.fromOpaque(keyPtr).takeUnretainedValue()
let box = keyPtr.assumingMemoryBound(to: X25519Key.self)

guard case .privateKey(let key) = box.value else {
guard case .privateKey(let key) = box.pointee else {
return -1
}

Expand All @@ -673,8 +669,8 @@ public func AppleCryptoNative_X25519ExportPublicKey(
return -1
}

let box = Unmanaged<X25519KeyBox>.fromOpaque(keyPtr).takeUnretainedValue()
let key = box.value.getPublic()
let box = keyPtr.assumingMemoryBound(to: X25519Key.self)
let key = box.pointee.getPublic()
let destination = UnsafeMutableRawBufferPointer(start: pOutput, count: Int(cbOutput))

let copied = key.rawRepresentation.withUnsafeBytes { pubKey in
Expand All @@ -691,8 +687,7 @@ public func AppleCryptoNative_X25519ExportPublicKey(
@_silgen_name("AppleCryptoNative_X25519GenerateKey")
public func AppleCryptoNative_X25519GenerateKey() -> UnsafeMutableRawPointer? {
let key = Curve25519.KeyAgreement.PrivateKey.init()
let box = X25519KeyBox(X25519Key.privateKey(key))
return Unmanaged.passRetained(box).toOpaque()
return allocatePointer(to: X25519Key.privateKey(key))
}

@_silgen_name("AppleCryptoNative_X25519ImportPrivateKey")
Expand All @@ -707,8 +702,7 @@ public func AppleCryptoNative_X25519ImportPrivateKey(pKey: UnsafeMutableRawPoint
return nil
}

let box = X25519KeyBox(X25519Key.privateKey(key))
return Unmanaged.passRetained(box).toOpaque()
return allocatePointer(to: X25519Key.privateKey(key))
}

@_silgen_name("AppleCryptoNative_X25519ImportPublicKey")
Expand All @@ -723,6 +717,5 @@ public func AppleCryptoNative_X25519ImportPublicKey(pKey: UnsafeMutableRawPointe
return nil
}

let box = X25519KeyBox(X25519Key.publicKey(key))
return Unmanaged.passRetained(box).toOpaque()
return allocatePointer(to: X25519Key.publicKey(key))
}
32 changes: 32 additions & 0 deletions src/native/libs/verify-no-swift-objc-classes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env bash

if (( $# != 2 )); then
echo "Usage:"
echo "verify-no-swift-objc-classes.sh <path to library> <path to NM command>"
exit 1
fi

library=$1
nmCommand=$2

if ! nmOutput=$("$nmCommand" -m "$library"); then
echo "ERROR: failed to inspect $library for Swift ObjC class definitions." >&2
exit 2
fi

swiftObjCClasses=()
while IFS= read -r line; do
# Swift classes are registered as ObjC classes with process-global names. Local
# definitions in this library can collide if another copy is loaded into the
# same process, so keep Swift bindings limited to value types and functions.
if [[ $line != *"(undefined)"* && $line =~ (__DATA__TtC|__METACLASS_DATA__TtC|__IVARS__TtC|_OBJC_CLASS_\$__TtC) ]]; then
swiftObjCClasses+=("$line")
fi
done <<< "$nmOutput"

if (( ${#swiftObjCClasses[@]} != 0 )); then
echo "ERROR: $library contains Swift ObjC class definitions." >&2
echo "Swift classes have process-global ObjC runtime names and must not be used in this native library." >&2
printf '%s\n' "${swiftObjCClasses[@]}" >&2
exit 2
fi
Loading