Skip to content

Commit d68afd6

Browse files
committed
[iOS] Implement DSA, RSA, EC key import/export
1 parent d1fed28 commit d68afd6

36 files changed

+1534
-782
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.Security.Cryptography;
7+
8+
namespace Internal.Cryptography
9+
{
10+
internal static partial class AsymmetricAlgorithmHelpers
11+
{
12+
// Encodes a EC key as an uncompressed set of concatenated scalars,
13+
// optionally including the private key. To omit the private parameter,
14+
// "d" must have a length of zero.
15+
public static void EncodeToUncompressedAnsiX963Key(
16+
ReadOnlySpan<byte> x,
17+
ReadOnlySpan<byte> y,
18+
ReadOnlySpan<byte> d,
19+
Span<byte> destination)
20+
{
21+
const byte UncompressedKeyPrefix = 0x04;
22+
if (x.Length != y.Length || (d.Length > 0 && d.Length != y.Length))
23+
throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
24+
25+
int size = 1 + x.Length + y.Length + d.Length; // 0x04 || X || Y { || D }
26+
27+
if (destination.Length < size)
28+
{
29+
Debug.Fail("destination.Length < size");
30+
throw new CryptographicException();
31+
}
32+
33+
destination[0] = UncompressedKeyPrefix;
34+
x.CopyTo(destination.Slice(1));
35+
y.CopyTo(destination.Slice(1 + x.Length));
36+
d.CopyTo(destination.Slice(1 + x.Length + y.Length));
37+
}
38+
39+
public static void DecodeFromUncompressedAnsiX963Key(
40+
ReadOnlySpan<byte> ansiKey,
41+
bool hasPrivateKey,
42+
out ECParameters ret)
43+
{
44+
ret = default;
45+
46+
const byte UncompressedKeyPrefix = 0x04;
47+
if (ansiKey.Length < 1 || ansiKey[0] != UncompressedKeyPrefix)
48+
throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
49+
50+
int fieldCount = hasPrivateKey ? 3 : 2;
51+
int fieldSize = (ansiKey.Length - 1) / fieldCount;
52+
53+
if (ansiKey.Length != 1 + fieldSize * fieldCount)
54+
throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
55+
56+
ret.Q = new ECPoint {
57+
X = ansiKey.Slice(1, fieldSize).ToArray(),
58+
Y = ansiKey.Slice(1 + fieldSize, fieldSize).ToArray()
59+
};
60+
61+
if (hasPrivateKey)
62+
{
63+
ret.D = ansiKey.Slice(1 + fieldSize + fieldSize, fieldSize).ToArray();
64+
}
65+
}
66+
}
67+
}

src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Keychain.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ private static extern int AppleCryptoNative_SecKeychainEnumerateIdentities(
6666
out SafeCFArrayHandle matches,
6767
out int pOSStatus);
6868

69-
internal static SafeKeychainHandle SecKeychainItemCopyKeychain(SafeKeychainItemHandle item)
69+
private static SafeKeychainHandle SecKeychainItemCopyKeychain(SafeHandle item)
7070
{
7171
bool addedRef = false;
7272

@@ -85,6 +85,12 @@ internal static SafeKeychainHandle SecKeychainItemCopyKeychain(SafeKeychainItemH
8585
}
8686
}
8787

88+
internal static SafeKeychainHandle SecKeychainItemCopyKeychain(SafeKeychainItemHandle item)
89+
=> SecKeychainItemCopyKeychain((SafeHandle)item);
90+
91+
internal static SafeKeychainHandle SecKeychainItemCopyKeychain(SafeSecKeyRefHandle item)
92+
=> SecKeychainItemCopyKeychain((SafeHandle)item);
93+
8894
internal static SafeKeychainHandle SecKeychainItemCopyKeychain(IntPtr item)
8995
{
9096
SafeKeychainHandle keychain;

src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.cs

+15-48
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,6 @@ internal static partial class AppleCrypto
1616
private const int kErrorSeeError = -2;
1717
private const int kPlatformNotSupported = -5;
1818

19-
private static int AppleCryptoNative_SecKeyImportEphemeral(
20-
ReadOnlySpan<byte> pbKeyBlob,
21-
int isPrivateKey,
22-
out SafeSecKeyRefHandle ppKeyOut,
23-
out int pOSStatus) =>
24-
AppleCryptoNative_SecKeyImportEphemeral(
25-
ref MemoryMarshal.GetReference(pbKeyBlob),
26-
pbKeyBlob.Length,
27-
isPrivateKey,
28-
out ppKeyOut,
29-
out pOSStatus);
30-
31-
[DllImport(Libraries.AppleCryptoNative)]
32-
private static extern int AppleCryptoNative_SecKeyImportEphemeral(
33-
ref byte pbKeyBlob,
34-
int cbKeyBlob,
35-
int isPrivateKey,
36-
out SafeSecKeyRefHandle ppKeyOut,
37-
out int pOSStatus);
38-
3919
[DllImport(Libraries.AppleCryptoNative)]
4020
private static extern ulong AppleCryptoNative_SecKeyGetSimpleKeySizeInBytes(SafeSecKeyRefHandle publicKey);
4121

@@ -102,40 +82,27 @@ internal static int GetSimpleKeySizeInBits(SafeSecKeyRefHandle publicKey)
10282
return (int)(keySizeInBytes * 8);
10383
}
10484
}
105-
106-
internal static SafeSecKeyRefHandle ImportEphemeralKey(ReadOnlySpan<byte> keyBlob, bool hasPrivateKey)
107-
{
108-
Debug.Assert(keyBlob != null);
109-
110-
SafeSecKeyRefHandle keyHandle;
111-
int osStatus;
112-
113-
int ret = AppleCryptoNative_SecKeyImportEphemeral(
114-
keyBlob,
115-
hasPrivateKey ? 1 : 0,
116-
out keyHandle,
117-
out osStatus);
118-
119-
if (ret == 1 && !keyHandle.IsInvalid)
120-
{
121-
return keyHandle;
122-
}
123-
124-
if (ret == 0)
125-
{
126-
throw CreateExceptionForOSStatus(osStatus);
127-
}
128-
129-
Debug.Fail($"SecKeyImportEphemeral returned {ret}");
130-
throw new CryptographicException();
131-
}
13285
}
13386
}
13487

13588
namespace System.Security.Cryptography.Apple
13689
{
137-
internal sealed class SafeSecKeyRefHandle : SafeKeychainItemHandle
90+
internal sealed class SafeSecKeyRefHandle : SafeHandle
13891
{
92+
public SafeSecKeyRefHandle()
93+
: base(IntPtr.Zero, ownsHandle: true)
94+
{
95+
}
96+
97+
protected override bool ReleaseHandle()
98+
{
99+
Interop.CoreFoundation.CFRelease(handle);
100+
SetHandle(IntPtr.Zero);
101+
return true;
102+
}
103+
104+
public override bool IsInvalid => handle == IntPtr.Zero;
105+
139106
protected override void Dispose(bool disposing)
140107
{
141108
if (disposing && SafeHandleCache<SafeSecKeyRefHandle>.IsCachedInvalidHandle(this))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.Runtime.InteropServices;
7+
using System.Security.Cryptography;
8+
using System.Security.Cryptography.Apple;
9+
using Microsoft.Win32.SafeHandles;
10+
11+
internal static partial class Interop
12+
{
13+
internal static partial class AppleCrypto
14+
{
15+
internal enum PAL_KeyAlgorithm : uint
16+
{
17+
Unknown = 0,
18+
EC = 1,
19+
RSA = 2,
20+
}
21+
22+
internal static unsafe SafeSecKeyRefHandle CreateDataKey(
23+
ReadOnlySpan<byte> keyData,
24+
PAL_KeyAlgorithm keyAlgorithm,
25+
bool isPublic)
26+
{
27+
fixed (byte* pKey = keyData)
28+
{
29+
int result = AppleCryptoNative_SecKeyCreateWithData(
30+
pKey,
31+
keyData.Length,
32+
keyAlgorithm,
33+
isPublic ? 1 : 0,
34+
out SafeSecKeyRefHandle dataKey,
35+
out SafeCFErrorHandle errorHandle);
36+
37+
using (errorHandle)
38+
{
39+
return result switch
40+
{
41+
kSuccess => dataKey,
42+
kErrorSeeError => throw CreateExceptionForCFError(errorHandle),
43+
_ => throw new CryptographicException { HResult = result }
44+
};
45+
}
46+
}
47+
}
48+
49+
internal static byte[] SecKeyCopyExternalRepresentation(
50+
SafeSecKeyRefHandle key)
51+
{
52+
int result = AppleCryptoNative_SecKeyCopyExternalRepresentation(
53+
key,
54+
out SafeCFDataHandle data,
55+
out SafeCFErrorHandle errorHandle);
56+
57+
using (errorHandle)
58+
using (data)
59+
{
60+
return result switch
61+
{
62+
kSuccess => CoreFoundation.CFGetData(data),
63+
kErrorSeeError => throw CreateExceptionForCFError(errorHandle),
64+
_ => throw new CryptographicException { HResult = result }
65+
};
66+
}
67+
}
68+
69+
[DllImport(Libraries.AppleCryptoNative)]
70+
private static unsafe extern int AppleCryptoNative_SecKeyCreateWithData(
71+
byte* pKey,
72+
int cbKey,
73+
PAL_KeyAlgorithm keyAlgorithm,
74+
int isPublic,
75+
out SafeSecKeyRefHandle pDataKey,
76+
out SafeCFErrorHandle pErrorOut);
77+
78+
[DllImport(Libraries.AppleCryptoNative)]
79+
private static unsafe extern int AppleCryptoNative_SecKeyCopyExternalRepresentation(
80+
SafeSecKeyRefHandle key,
81+
out SafeCFDataHandle pDataOut,
82+
out SafeCFErrorHandle pErrorOut);
83+
84+
[DllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_SecKeyCopyPublicKey")]
85+
internal static unsafe extern SafeSecKeyRefHandle CopyPublicKey(SafeSecKeyRefHandle privateKey);
86+
}
87+
}

src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.Export.cs src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.SecKeyRef.macOS.cs

+47
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,53 @@ internal static partial class AppleCrypto
1414
{
1515
private static readonly SafeCreateHandle s_nullExportString = new SafeCreateHandle();
1616

17+
private static int AppleCryptoNative_SecKeyImportEphemeral(
18+
ReadOnlySpan<byte> pbKeyBlob,
19+
int isPrivateKey,
20+
out SafeSecKeyRefHandle ppKeyOut,
21+
out int pOSStatus) =>
22+
AppleCryptoNative_SecKeyImportEphemeral(
23+
ref MemoryMarshal.GetReference(pbKeyBlob),
24+
pbKeyBlob.Length,
25+
isPrivateKey,
26+
out ppKeyOut,
27+
out pOSStatus);
28+
29+
[DllImport(Libraries.AppleCryptoNative)]
30+
private static extern int AppleCryptoNative_SecKeyImportEphemeral(
31+
ref byte pbKeyBlob,
32+
int cbKeyBlob,
33+
int isPrivateKey,
34+
out SafeSecKeyRefHandle ppKeyOut,
35+
out int pOSStatus);
36+
37+
internal static SafeSecKeyRefHandle ImportEphemeralKey(ReadOnlySpan<byte> keyBlob, bool hasPrivateKey)
38+
{
39+
Debug.Assert(keyBlob != null);
40+
41+
SafeSecKeyRefHandle keyHandle;
42+
int osStatus;
43+
44+
int ret = AppleCryptoNative_SecKeyImportEphemeral(
45+
keyBlob,
46+
hasPrivateKey ? 1 : 0,
47+
out keyHandle,
48+
out osStatus);
49+
50+
if (ret == 1 && !keyHandle.IsInvalid)
51+
{
52+
return keyHandle;
53+
}
54+
55+
if (ret == 0)
56+
{
57+
throw CreateExceptionForOSStatus(osStatus);
58+
}
59+
60+
Debug.Fail($"SecKeyImportEphemeral returned {ret}");
61+
throw new CryptographicException();
62+
}
63+
1764
[DllImport(Libraries.AppleCryptoNative)]
1865
private static extern int AppleCryptoNative_SecKeyExport(
1966
SafeSecKeyRefHandle? key,

0 commit comments

Comments
 (0)