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 // See the LICENSE file in the project root for more information.
4
5 #include "pal_signverify.h"
6
7 static int32_t ExecuteSignTransform(SecTransformRef signer, CFDataRef* pSignatureOut, CFErrorRef* pErrorOut);
8 static int32_t ExecuteVerifyTransform(SecTransformRef verifier, CFErrorRef* pErrorOut);
9
10 static int32_t ConfigureSignVerifyTransform(
11 SecTransformRef xform, CFDataRef cfDataHash, PAL_HashAlgorithm, bool useDigestAlgorithm, CFErrorRef* pErrorOut);
12
GenerateSignature(SecKeyRef privateKey,uint8_t * pbDataHash,int32_t cbDataHash,PAL_HashAlgorithm hashAlgorithm,bool useHashAlgorithm,CFDataRef * pSignatureOut,CFErrorRef * pErrorOut)13 static int32_t GenerateSignature(SecKeyRef privateKey,
14 uint8_t* pbDataHash,
15 int32_t cbDataHash,
16 PAL_HashAlgorithm hashAlgorithm,
17 bool useHashAlgorithm,
18 CFDataRef* pSignatureOut,
19 CFErrorRef* pErrorOut)
20 {
21 if (pSignatureOut != nullptr)
22 *pSignatureOut = nullptr;
23 if (pErrorOut != nullptr)
24 *pErrorOut = nullptr;
25
26 if (privateKey == nullptr || pbDataHash == nullptr || cbDataHash < 0 || pSignatureOut == nullptr ||
27 pErrorOut == nullptr)
28 {
29 return kErrorBadInput;
30 }
31
32 CFDataRef dataHash = CFDataCreateWithBytesNoCopy(nullptr, pbDataHash, cbDataHash, kCFAllocatorNull);
33
34 if (dataHash == nullptr)
35 {
36 return kErrorUnknownState;
37 }
38
39 int32_t ret = kErrorSeeError;
40 SecTransformRef signer = SecSignTransformCreate(privateKey, pErrorOut);
41
42 if (signer != nullptr)
43 {
44 if (*pErrorOut == nullptr)
45 {
46 if (ConfigureSignVerifyTransform(signer, dataHash, hashAlgorithm, useHashAlgorithm, pErrorOut))
47 {
48 ret = ExecuteSignTransform(signer, pSignatureOut, pErrorOut);
49 }
50 }
51
52 CFRelease(signer);
53 }
54
55 CFRelease(dataHash);
56 return ret;
57 }
58
AppleCryptoNative_GenerateSignature(SecKeyRef privateKey,uint8_t * pbDataHash,int32_t cbDataHash,CFDataRef * pSignatureOut,CFErrorRef * pErrorOut)59 extern "C" int32_t AppleCryptoNative_GenerateSignature(
60 SecKeyRef privateKey, uint8_t* pbDataHash, int32_t cbDataHash, CFDataRef* pSignatureOut, CFErrorRef* pErrorOut)
61 {
62 return GenerateSignature(privateKey, pbDataHash, cbDataHash, PAL_Unknown, false, pSignatureOut, pErrorOut);
63 }
64
AppleCryptoNative_GenerateSignatureWithHashAlgorithm(SecKeyRef privateKey,uint8_t * pbDataHash,int32_t cbDataHash,PAL_HashAlgorithm hashAlgorithm,CFDataRef * pSignatureOut,CFErrorRef * pErrorOut)65 extern "C" int32_t AppleCryptoNative_GenerateSignatureWithHashAlgorithm(SecKeyRef privateKey,
66 uint8_t* pbDataHash,
67 int32_t cbDataHash,
68 PAL_HashAlgorithm hashAlgorithm,
69 CFDataRef* pSignatureOut,
70 CFErrorRef* pErrorOut)
71 {
72 return GenerateSignature(privateKey, pbDataHash, cbDataHash, hashAlgorithm, true, pSignatureOut, pErrorOut);
73 }
74
VerifySignature(SecKeyRef publicKey,uint8_t * pbDataHash,int32_t cbDataHash,uint8_t * pbSignature,int32_t cbSignature,PAL_HashAlgorithm hashAlgorithm,bool useHashAlgorithm,CFErrorRef * pErrorOut)75 static int32_t VerifySignature(SecKeyRef publicKey,
76 uint8_t* pbDataHash,
77 int32_t cbDataHash,
78 uint8_t* pbSignature,
79 int32_t cbSignature,
80 PAL_HashAlgorithm hashAlgorithm,
81 bool useHashAlgorithm,
82 CFErrorRef* pErrorOut)
83 {
84 if (pErrorOut != nullptr)
85 *pErrorOut = nullptr;
86
87 if (publicKey == nullptr || pbDataHash == nullptr || cbDataHash < 0 || pbSignature == nullptr || cbSignature < 0 ||
88 pErrorOut == nullptr)
89 return kErrorBadInput;
90
91 CFDataRef dataHash = CFDataCreateWithBytesNoCopy(nullptr, pbDataHash, cbDataHash, kCFAllocatorNull);
92
93 if (dataHash == nullptr)
94 {
95 return kErrorUnknownState;
96 }
97
98 CFDataRef signature = CFDataCreateWithBytesNoCopy(nullptr, pbSignature, cbSignature, kCFAllocatorNull);
99
100 if (signature == nullptr)
101 {
102 CFRelease(dataHash);
103 return kErrorUnknownState;
104 }
105
106 int32_t ret = kErrorSeeError;
107 SecTransformRef verifier = SecVerifyTransformCreate(publicKey, signature, pErrorOut);
108
109 if (verifier != nullptr)
110 {
111 if (*pErrorOut == nullptr)
112 {
113 if (ConfigureSignVerifyTransform(verifier, dataHash, hashAlgorithm, useHashAlgorithm, pErrorOut))
114 {
115 ret = ExecuteVerifyTransform(verifier, pErrorOut);
116 }
117 }
118
119 CFRelease(verifier);
120 }
121
122 CFRelease(dataHash);
123 CFRelease(signature);
124
125 return ret;
126 }
127
AppleCryptoNative_VerifySignatureWithHashAlgorithm(SecKeyRef publicKey,uint8_t * pbDataHash,int32_t cbDataHash,uint8_t * pbSignature,int32_t cbSignature,PAL_HashAlgorithm hashAlgorithm,CFErrorRef * pErrorOut)128 extern "C" int32_t AppleCryptoNative_VerifySignatureWithHashAlgorithm(SecKeyRef publicKey,
129 uint8_t* pbDataHash,
130 int32_t cbDataHash,
131 uint8_t* pbSignature,
132 int32_t cbSignature,
133 PAL_HashAlgorithm hashAlgorithm,
134 CFErrorRef* pErrorOut)
135 {
136 return VerifySignature(publicKey, pbDataHash, cbDataHash, pbSignature, cbSignature, hashAlgorithm, true, pErrorOut);
137 }
138
AppleCryptoNative_VerifySignature(SecKeyRef publicKey,uint8_t * pbDataHash,int32_t cbDataHash,uint8_t * pbSignature,int32_t cbSignature,CFErrorRef * pErrorOut)139 extern "C" int32_t AppleCryptoNative_VerifySignature(SecKeyRef publicKey,
140 uint8_t* pbDataHash,
141 int32_t cbDataHash,
142 uint8_t* pbSignature,
143 int32_t cbSignature,
144 CFErrorRef* pErrorOut)
145 {
146 return VerifySignature(publicKey, pbDataHash, cbDataHash, pbSignature, cbSignature, PAL_Unknown, false, pErrorOut);
147 }
148
ExecuteSignTransform(SecTransformRef signer,CFDataRef * pSignatureOut,CFErrorRef * pErrorOut)149 static int32_t ExecuteSignTransform(SecTransformRef signer, CFDataRef* pSignatureOut, CFErrorRef* pErrorOut)
150 {
151 assert(signer != nullptr);
152 assert(pSignatureOut != nullptr);
153 assert(pErrorOut != nullptr);
154
155 int32_t ret = INT_MIN;
156 CFTypeRef signerResponse = SecTransformExecute(signer, pErrorOut);
157 CFDataRef signature = nullptr;
158
159 if (signerResponse == nullptr || *pErrorOut != nullptr)
160 {
161 ret = kErrorSeeError;
162 goto cleanup;
163 }
164
165 if (CFGetTypeID(signerResponse) != CFDataGetTypeID())
166 {
167 ret = kErrorUnknownState;
168 goto cleanup;
169 }
170
171 signature = reinterpret_cast<CFDataRef>(const_cast<void*>(signerResponse));
172
173 if (CFDataGetLength(signature) > 0)
174 {
175 // We're going to call CFRelease in cleanup, so this keeps it alive
176 // to be interpreted by the managed code.
177 CFRetain(signature);
178 *pSignatureOut = signature;
179 ret = 1;
180 }
181 else
182 {
183 ret = kErrorUnknownState;
184 *pSignatureOut = nullptr;
185 }
186
187 cleanup:
188 if (signerResponse != nullptr)
189 {
190 CFRelease(signerResponse);
191 }
192
193 return ret;
194 }
195
ExecuteVerifyTransform(SecTransformRef verifier,CFErrorRef * pErrorOut)196 static int32_t ExecuteVerifyTransform(SecTransformRef verifier, CFErrorRef* pErrorOut)
197 {
198 assert(verifier != nullptr);
199 assert(pErrorOut != nullptr);
200
201 int32_t ret = kErrorSeeError;
202 CFTypeRef verifierResponse = SecTransformExecute(verifier, pErrorOut);
203
204 if (verifierResponse != nullptr)
205 {
206 if (*pErrorOut == nullptr)
207 {
208 ret = (verifierResponse == kCFBooleanTrue);
209 }
210
211 CFRelease(verifierResponse);
212 }
213
214 return ret;
215 }
216
ConfigureSignVerifyTransform(SecTransformRef xform,CFDataRef cfDataHash,PAL_HashAlgorithm hashAlgorithm,bool includeHashAlgorithm,CFErrorRef * pErrorOut)217 static int32_t ConfigureSignVerifyTransform(SecTransformRef xform,
218 CFDataRef cfDataHash,
219 PAL_HashAlgorithm hashAlgorithm,
220 bool includeHashAlgorithm,
221 CFErrorRef* pErrorOut)
222 {
223 if (!SecTransformSetAttribute(xform, kSecInputIsAttributeName, kSecInputIsDigest, pErrorOut))
224 {
225 return 0;
226 }
227
228 if (!SecTransformSetAttribute(xform, kSecTransformInputAttributeName, cfDataHash, pErrorOut))
229 {
230 return 0;
231 }
232
233 if (includeHashAlgorithm)
234 {
235 CFStringRef cfHashName = nullptr;
236 int32_t hashSize = 0;
237
238 switch (hashAlgorithm)
239 {
240 case PAL_MD5:
241 cfHashName = kSecDigestMD5;
242 break;
243 case PAL_SHA1:
244 cfHashName = kSecDigestSHA1;
245 break;
246 case PAL_SHA256:
247 cfHashName = kSecDigestSHA2;
248 hashSize = 256;
249 break;
250 case PAL_SHA384:
251 cfHashName = kSecDigestSHA2;
252 hashSize = 384;
253 break;
254 case PAL_SHA512:
255 cfHashName = kSecDigestSHA2;
256 hashSize = 512;
257 break;
258 default:
259 return kErrorUnknownAlgorithm;
260 }
261
262 if (!SecTransformSetAttribute(xform, kSecDigestTypeAttribute, cfHashName, pErrorOut))
263 {
264 return 0;
265 }
266
267 if (hashSize != 0)
268 {
269 CFNumberRef cfHashSize = CFNumberCreate(nullptr, kCFNumberIntType, &hashSize);
270
271 if (cfHashSize == nullptr)
272 {
273 return 0;
274 }
275
276 if (!SecTransformSetAttribute(xform, kSecDigestLengthAttribute, cfHashSize, pErrorOut))
277 {
278 CFRelease(cfHashSize);
279 return 0;
280 }
281
282 CFRelease(cfHashSize);
283 }
284 }
285
286 return 1;
287 }
288