]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
5c19dc3a | 2 | * Copyright (c) 2006-2010,2012-2015 Apple Inc. All Rights Reserved. |
427c49bc | 3 | * |
b1ab9ed8 | 4 | * @APPLE_LICENSE_HEADER_START@ |
5c19dc3a | 5 | * |
b1ab9ed8 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
5c19dc3a | 12 | * |
b1ab9ed8 A |
13 | * The Original Code and all software distributed under the License are |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
5c19dc3a | 20 | * |
b1ab9ed8 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
427c49bc | 24 | /* |
b1ab9ed8 A |
25 | * SecRSAKey.c - CoreFoundation based rsa key object |
26 | */ | |
27 | ||
28 | ||
29 | #include "SecRSAKey.h" | |
30 | #include "SecRSAKeyPriv.h" | |
31 | #include <Security/SecKeyInternal.h> | |
32 | #include <Security/SecItem.h> | |
33 | #include <Security/SecBasePriv.h> | |
34 | #include <AssertMacros.h> | |
35 | #include <Security/SecureTransport.h> /* For error codes. */ | |
36 | #include <CoreFoundation/CFData.h> /* For error codes. */ | |
37 | #include <fcntl.h> | |
38 | #include <sys/types.h> | |
39 | #include <unistd.h> | |
40 | #include <CoreFoundation/CFNumber.h> | |
41 | #include <Security/SecFramework.h> | |
42 | #include <Security/SecRandom.h> | |
427c49bc A |
43 | #include <utilities/debugging.h> |
44 | #include <utilities/SecCFWrappers.h> | |
fa7225c8 A |
45 | #include <utilities/SecCFError.h> |
46 | #include <utilities/array_size.h> | |
b1ab9ed8 A |
47 | #include "SecItemPriv.h" |
48 | #include <Security/SecInternal.h> | |
49 | ||
50 | #include <corecrypto/ccn.h> | |
51 | #include <corecrypto/ccrsa.h> | |
52 | #include <corecrypto/ccsha1.h> | |
fa7225c8 | 53 | #include <corecrypto/ccsha2.h> |
b1ab9ed8 A |
54 | |
55 | #include <libDER/asn1Types.h> | |
56 | #include <libDER/DER_Keys.h> | |
57 | #include <libDER/DER_Encode.h> | |
58 | ||
59 | #include <CommonCrypto/CommonDigest.h> | |
60 | ||
61 | #include <corecrypto/ccrsa_priv.h> | |
62 | ||
63 | #include <stdint.h> | |
64 | #include <string.h> | |
65 | ||
5c19dc3a | 66 | #define kMaximumRSAKeyBits (1024 * 8) |
b1ab9ed8 A |
67 | |
68 | #define RSA_PKCS1_PAD_SIGN 0x01 | |
69 | #define RSA_PKCS1_PAD_ENCRYPT 0x02 | |
70 | ||
b1ab9ed8 A |
71 | /* |
72 | * | |
73 | * Public Key | |
74 | * | |
75 | */ | |
76 | ||
77 | /* Public key static functions. */ | |
78 | static void SecRSAPublicKeyDestroy(SecKeyRef key) { | |
79 | /* Zero out the public key */ | |
5c19dc3a A |
80 | if (key->key) { |
81 | ccrsa_pub_ctx_t pubkey; | |
82 | pubkey.pub = key->key; | |
83 | cc_clear(ccrsa_pub_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(pubkey))), pubkey.pub); | |
84 | free(key->key); | |
85 | key->key = NULL; | |
86 | } | |
b1ab9ed8 A |
87 | } |
88 | ||
89 | #define cc_skip_zeros(size, ptr) { while (size > 0 && *ptr == 0) { ++ptr; --size; } } | |
90 | ||
91 | // | |
92 | // pubkey is initilaized with an n which is the maximum it can hold | |
93 | // We set the n to its correct value given m. | |
94 | // | |
95 | static int ccrsa_pub_init(ccrsa_pub_ctx_t pubkey, | |
96 | size_t m_size, const uint8_t* m, | |
97 | size_t e_size, const uint8_t* e) | |
98 | { | |
99 | cc_skip_zeros(m_size, m); | |
5c19dc3a | 100 | |
b1ab9ed8 A |
101 | cc_size nm = ccn_nof_size(m_size); |
102 | if (nm > ccrsa_ctx_n(pubkey)) | |
103 | return -1; | |
5c19dc3a | 104 | |
b1ab9ed8 | 105 | ccrsa_ctx_n(pubkey) = nm; |
5c19dc3a | 106 | |
b1ab9ed8 A |
107 | ccn_read_uint(nm, ccrsa_ctx_m(pubkey), m_size, m); |
108 | cczp_init(ccrsa_ctx_zm(pubkey)); | |
5c19dc3a | 109 | |
b1ab9ed8 A |
110 | return ccn_read_uint(nm, ccrsa_ctx_e(pubkey), e_size, e); |
111 | } | |
112 | ||
113 | ||
b1ab9ed8 A |
114 | static OSStatus ccrsa_pub_decode_apple(ccrsa_pub_ctx_t pubkey, size_t pkcs1_size, const uint8_t* pkcs1) |
115 | { | |
116 | OSStatus result = errSecParam; | |
5c19dc3a | 117 | |
b1ab9ed8 A |
118 | DERItem keyItem = {(DERByte *)pkcs1, pkcs1_size}; |
119 | DERRSAPubKeyApple decodedKey; | |
5c19dc3a | 120 | |
fa7225c8 A |
121 | require_noerr_action_quiet(DERParseSequence(&keyItem, |
122 | DERNumRSAPubKeyAppleItemSpecs, DERRSAPubKeyAppleItemSpecs, | |
123 | &decodedKey, sizeof(decodedKey)), | |
124 | errOut, result = errSecDecode); | |
5c19dc3a | 125 | |
fa7225c8 | 126 | // We could honor the reciprocal, but we don't think this is used enough to care. |
b1ab9ed8 | 127 | // Don't bother exploding the below function to try to handle this case, it computes. |
5c19dc3a | 128 | |
fa7225c8 A |
129 | require_noerr_quiet(ccrsa_pub_init(pubkey, |
130 | decodedKey.modulus.length, decodedKey.modulus.data, | |
131 | decodedKey.pubExponent.length, decodedKey.pubExponent.data), | |
132 | errOut); | |
5c19dc3a | 133 | |
b1ab9ed8 | 134 | result = errSecSuccess; |
5c19dc3a | 135 | |
b1ab9ed8 A |
136 | errOut: |
137 | return result; | |
138 | } | |
139 | ||
140 | ||
141 | static void ccasn_encode_int(cc_size n, const cc_unit*s, size_t s_size, uint8_t **buffer) | |
142 | { | |
143 | **buffer = ASN1_INTEGER; | |
144 | *buffer += 1; | |
5c19dc3a | 145 | |
b1ab9ed8 A |
146 | DERSize itemLength = 4; |
147 | DEREncodeLength(s_size, *buffer, &itemLength); | |
148 | *buffer += itemLength; | |
5c19dc3a | 149 | |
b1ab9ed8 | 150 | ccn_write_int(n, s, s_size, *buffer); |
5c19dc3a | 151 | |
b1ab9ed8 A |
152 | *buffer += s_size; |
153 | } | |
154 | ||
155 | ||
156 | static OSStatus SecRSAPublicKeyInit(SecKeyRef key, | |
427c49bc | 157 | const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { |
5c19dc3a | 158 | |
b1ab9ed8 | 159 | OSStatus result = errSecParam; |
b1ab9ed8 | 160 | ccrsa_pub_ctx_t pubkey; |
5c19dc3a A |
161 | size_t size_n = 0; |
162 | ||
b1ab9ed8 | 163 | switch (encoding) { |
427c49bc | 164 | case kSecKeyEncodingBytes: // Octets is PKCS1 |
5c19dc3a | 165 | case kSecKeyEncodingPkcs1: { |
fa7225c8 A |
166 | size_n = ccrsa_import_pub_n(keyDataLength, keyData); |
167 | require_quiet(size_n != 0, errOut); | |
168 | require_quiet(size_n <= ccn_nof(kMaximumRSAKeyBits), errOut); | |
5c19dc3a A |
169 | |
170 | key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 171 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a A |
172 | |
173 | pubkey.pub = key->key; | |
174 | ccrsa_ctx_n(pubkey) = size_n; | |
175 | ||
fa7225c8 | 176 | require_noerr_quiet(ccrsa_import_pub(pubkey, keyDataLength, keyData), errOut); |
5c19dc3a A |
177 | |
178 | result = errSecSuccess; | |
179 | ||
427c49bc | 180 | break; |
5c19dc3a | 181 | } |
427c49bc | 182 | case kSecKeyEncodingApplePkcs1: |
5c19dc3a A |
183 | /* for the few uses (I can't find any) that uses kSecKeyEncodingApplePkcs1, force largest keys */ |
184 | size_n = ccn_nof(kMaximumRSAKeyBits); | |
185 | ||
186 | key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 187 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a A |
188 | |
189 | pubkey.pub = key->key; | |
190 | ccrsa_ctx_n(pubkey) = size_n; | |
191 | ||
427c49bc A |
192 | result = ccrsa_pub_decode_apple(pubkey, keyDataLength, keyData); |
193 | break; | |
194 | case kSecKeyEncodingRSAPublicParams: | |
195 | { | |
196 | SecRSAPublicKeyParams *params = (SecRSAPublicKeyParams *)keyData; | |
5c19dc3a A |
197 | |
198 | size_n = ccn_nof_size(params->modulusLength); | |
199 | ||
200 | key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 201 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a A |
202 | |
203 | pubkey.pub = key->key; | |
204 | ccrsa_ctx_n(pubkey) = size_n; | |
205 | ||
fa7225c8 A |
206 | require_noerr_quiet(ccrsa_pub_init(pubkey, |
207 | params->modulusLength, params->modulus, | |
208 | params->exponentLength, params->exponent), errOut); | |
5c19dc3a | 209 | |
427c49bc A |
210 | result = errSecSuccess; |
211 | break; | |
212 | } | |
213 | case kSecExtractPublicFromPrivate: | |
214 | { | |
215 | ccrsa_full_ctx_t fullKey; | |
216 | fullKey.full = (ccrsa_full_ctx*) keyData; | |
217 | ||
5c19dc3a A |
218 | size_n = ccrsa_ctx_n(fullKey); |
219 | ||
220 | key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 221 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a A |
222 | |
223 | pubkey.pub = key->key; | |
224 | ccrsa_ctx_n(pubkey) = size_n; | |
225 | ||
226 | memcpy(pubkey.pub, ccrsa_ctx_public(fullKey).pub, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); | |
427c49bc A |
227 | result = errSecSuccess; |
228 | break; | |
229 | } | |
230 | default: | |
231 | break; | |
b1ab9ed8 | 232 | } |
5c19dc3a | 233 | |
b1ab9ed8 A |
234 | errOut: |
235 | return result; | |
236 | } | |
237 | ||
fa7225c8 A |
238 | static CFTypeRef SecRSAPublicKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, |
239 | CFArrayRef allAlgorithms, SecKeyOperationMode mode, | |
240 | CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { | |
241 | CFTypeRef result; | |
242 | require_action_quiet(CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRawCCUnit), out, result = kCFNull); | |
5c19dc3a | 243 | |
b1ab9ed8 A |
244 | ccrsa_pub_ctx_t pubkey; |
245 | pubkey.pub = key->key; | |
fa7225c8 A |
246 | result = kCFBooleanTrue; |
247 | switch (operation) { | |
248 | case kSecKeyOperationTypeEncrypt: | |
249 | if (mode == kSecKeyOperationModePerform) { | |
250 | // Verify that plaintext is smaller than modulus. | |
251 | require_action_quiet(ccn_cmpn(ccn_nof_size(CFDataGetLength(in1)), (const cc_unit *)CFDataGetBytePtr(in1), | |
252 | ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)) < 0, out, | |
253 | (result = NULL, | |
254 | SecError(errSecParam, error, CFSTR("RSApubkey wrong size of buffer to encrypt")))); | |
255 | ||
256 | // Encrypt into output buffer. | |
257 | result = CFDataCreateMutableWithScratch(NULL, ccrsa_block_size(pubkey)); | |
258 | ccrsa_pub_crypt(pubkey, (cc_unit *)CFDataGetMutableBytePtr((CFMutableDataRef)result), | |
259 | (const cc_unit *)CFDataGetBytePtr(in1)); | |
b1ab9ed8 | 260 | } |
b1ab9ed8 | 261 | break; |
fa7225c8 A |
262 | case kSecKeyOperationTypeDecrypt: |
263 | if (mode == kSecKeyOperationModePerform) { | |
264 | // Decrypt into output buffer. | |
265 | result = CFDataCreateMutableWithScratch(NULL, ccrsa_block_size(pubkey)); | |
266 | ccrsa_pub_crypt(pubkey, (cc_unit *)CFDataGetMutableBytePtr((CFMutableDataRef)result), | |
267 | (const cc_unit *)CFDataGetBytePtr(in1)); | |
b1ab9ed8 | 268 | } |
427c49bc | 269 | break; |
b1ab9ed8 | 270 | default: |
fa7225c8 | 271 | result = kCFNull; |
b1ab9ed8 | 272 | break; |
b1ab9ed8 | 273 | } |
5c19dc3a | 274 | |
fa7225c8 | 275 | out: |
b1ab9ed8 A |
276 | return result; |
277 | } | |
278 | ||
279 | static size_t SecRSAPublicKeyBlockSize(SecKeyRef key) { | |
280 | ccrsa_pub_ctx_t pubkey; | |
281 | pubkey.pub = key->key; | |
fa7225c8 | 282 | return ccrsa_block_size(pubkey); |
b1ab9ed8 A |
283 | } |
284 | ||
285 | ||
286 | static CFDataRef SecRSAPublicKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_pub_ctx_t pubkey) | |
287 | { | |
288 | size_t m_size = ccn_write_int_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); | |
289 | size_t e_size = ccn_write_int_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); | |
5c19dc3a | 290 | |
b1ab9ed8 | 291 | const size_t seq_size = DERLengthOfItem(ASN1_INTEGER, m_size) + |
427c49bc | 292 | DERLengthOfItem(ASN1_INTEGER, e_size); |
5c19dc3a | 293 | |
b1ab9ed8 | 294 | const size_t result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size); |
5c19dc3a | 295 | |
fa7225c8 | 296 | CFMutableDataRef pkcs1 = CFDataCreateMutableWithScratch(allocator, result_size); |
b1ab9ed8 | 297 | uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); |
5c19dc3a | 298 | |
fa7225c8 | 299 | *bytes++ = ONE_BYTE_ASN1_CONSTR_SEQUENCE; |
5c19dc3a | 300 | |
b1ab9ed8 A |
301 | DERSize itemLength = 4; |
302 | DEREncodeLength(seq_size, bytes, &itemLength); | |
303 | bytes += itemLength; | |
5c19dc3a | 304 | |
b1ab9ed8 A |
305 | ccasn_encode_int(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, &bytes); |
306 | ccasn_encode_int(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey), e_size, &bytes); | |
5c19dc3a | 307 | |
b1ab9ed8 A |
308 | return pkcs1; |
309 | } | |
310 | ||
311 | static OSStatus SecRSAPublicKeyCopyPublicSerialization(SecKeyRef key, CFDataRef* serialized) | |
312 | { | |
313 | ccrsa_pub_ctx_t pubkey; | |
314 | pubkey.pub = key->key; | |
5c19dc3a | 315 | |
b1ab9ed8 A |
316 | CFAllocatorRef allocator = CFGetAllocator(key); |
317 | *serialized = SecRSAPublicKeyCreatePKCS1(allocator, pubkey); | |
5c19dc3a | 318 | |
b1ab9ed8 A |
319 | if (NULL == *serialized) |
320 | return errSecDecode; | |
321 | else | |
322 | return errSecSuccess; | |
323 | } | |
324 | ||
325 | static CFDictionaryRef SecRSAPublicKeyCopyAttributeDictionary(SecKeyRef key) { | |
fa7225c8 A |
326 | CFDictionaryRef dict = SecKeyGeneratePublicAttributeDictionary(key, kSecAttrKeyTypeRSA); |
327 | CFMutableDictionaryRef mutableDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); | |
328 | CFDictionarySetValue(mutableDict, kSecAttrCanDecrypt, kCFBooleanTrue); | |
329 | CFDictionarySetValue(mutableDict, kSecAttrCanDerive, kCFBooleanFalse); | |
330 | CFAssignRetained(dict, mutableDict); | |
331 | return dict; | |
332 | } | |
333 | ||
334 | static CFDataRef SecRSAPublicKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { | |
335 | ccrsa_pub_ctx_t pubkey; | |
336 | pubkey.pub = key->key; | |
337 | return SecRSAPublicKeyCreatePKCS1(CFGetAllocator(key), pubkey); | |
b1ab9ed8 A |
338 | } |
339 | ||
427c49bc | 340 | static CFStringRef SecRSAPublicKeyCopyDescription(SecKeyRef key) { |
5c19dc3a | 341 | |
427c49bc A |
342 | CFStringRef keyDescription = NULL; |
343 | CFDataRef modRef = SecKeyCopyModulus(key); | |
5c19dc3a | 344 | |
427c49bc A |
345 | ccrsa_pub_ctx_t pubkey; |
346 | pubkey.pub = key->key; | |
5c19dc3a | 347 | |
427c49bc | 348 | CFStringRef modulusString = CFDataCopyHexString(modRef); |
fa7225c8 | 349 | require_quiet(modulusString, fail); |
5c19dc3a A |
350 | |
351 | keyDescription = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR( "<SecKeyRef algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, exponent: {hex: %llx, decimal: %lld}, modulus: %@, addr: %p>"), SecKeyGetAlgorithmId(key), key->key_class->name, key->key_class->version, (8*SecKeyGetBlockSize(key)), (long long)*ccrsa_ctx_e(pubkey), (long long)*ccrsa_ctx_e(pubkey), modulusString, key); | |
352 | ||
427c49bc A |
353 | fail: |
354 | CFReleaseSafe(modRef); | |
355 | CFReleaseSafe(modulusString); | |
356 | if(!keyDescription) | |
5c19dc3a A |
357 | keyDescription = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecKeyRef algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, addr: %p>"), (long)SecKeyGetAlgorithmId(key), key->key_class->name, key->key_class->version, (8*SecKeyGetBlockSize(key)), key); |
358 | ||
427c49bc A |
359 | return keyDescription; |
360 | } | |
361 | ||
b1ab9ed8 | 362 | SecKeyDescriptor kSecRSAPublicKeyDescriptor = { |
fa7225c8 A |
363 | .version = kSecKeyDescriptorVersion, |
364 | .name = "RSAPublicKey", | |
365 | ||
366 | .init = SecRSAPublicKeyInit, | |
367 | .destroy = SecRSAPublicKeyDestroy, | |
368 | .blockSize = SecRSAPublicKeyBlockSize, | |
369 | .copyDictionary = SecRSAPublicKeyCopyAttributeDictionary, | |
370 | .copyExternalRepresentation = SecRSAPublicKeyCopyExternalRepresentation, | |
371 | .describe = SecRSAPublicKeyCopyDescription, | |
372 | .copyPublic = SecRSAPublicKeyCopyPublicSerialization, | |
373 | .copyOperationResult = SecRSAPublicKeyCopyOperationResult, | |
b1ab9ed8 A |
374 | }; |
375 | ||
376 | /* Public Key API functions. */ | |
fa7225c8 | 377 | SecKeyRef SecKeyCreateRSAPublicKey_ios(CFAllocatorRef allocator, |
427c49bc A |
378 | const uint8_t *keyData, CFIndex keyDataLength, |
379 | SecKeyEncoding encoding) { | |
b1ab9ed8 | 380 | return SecKeyCreate(allocator, &kSecRSAPublicKeyDescriptor, keyData, |
427c49bc | 381 | keyDataLength, encoding); |
b1ab9ed8 A |
382 | } |
383 | ||
fa7225c8 A |
384 | SecKeyRef SecKeyCreateRSAPublicKey(CFAllocatorRef allocator, |
385 | const uint8_t *keyData, CFIndex keyDataLength, | |
386 | SecKeyEncoding encoding) { | |
387 | return SecKeyCreateRSAPublicKey_ios(allocator, keyData, | |
388 | keyDataLength, encoding); | |
389 | } | |
390 | ||
b1ab9ed8 | 391 | CFDataRef SecKeyCopyModulus(SecKeyRef key) { |
fa7225c8 A |
392 | CFDataRef modulus = NULL; |
393 | if (key->key_class == &kSecRSAPublicKeyDescriptor) { | |
394 | ccrsa_pub_ctx_t pubkey; | |
395 | pubkey.pub = key->key; | |
5c19dc3a | 396 | |
fa7225c8 | 397 | size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); |
5c19dc3a | 398 | |
fa7225c8 A |
399 | CFAllocatorRef allocator = CFGetAllocator(key); |
400 | CFMutableDataRef modulusData = CFDataCreateMutable(allocator, m_size); | |
5c19dc3a | 401 | |
fa7225c8 A |
402 | if (modulusData == NULL) |
403 | return NULL; | |
5c19dc3a | 404 | |
fa7225c8 | 405 | CFDataSetLength(modulusData, m_size); |
5c19dc3a | 406 | |
fa7225c8 A |
407 | ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, CFDataGetMutableBytePtr(modulusData)); |
408 | modulus = modulusData; | |
409 | } else if (key->key_class->copyDictionary != NULL) { | |
410 | CFDictionaryRef dict = key->key_class->copyDictionary(key); | |
411 | if (dict != NULL) { | |
412 | modulus = CFRetainSafe(CFDictionaryGetValue(dict, CFSTR("_rsam"))); | |
413 | CFRelease(dict); | |
414 | } | |
415 | } | |
5c19dc3a | 416 | |
fa7225c8 | 417 | return modulus; |
b1ab9ed8 A |
418 | } |
419 | ||
420 | CFDataRef SecKeyCopyExponent(SecKeyRef key) { | |
fa7225c8 A |
421 | CFDataRef exponent = NULL; |
422 | if (key->key_class == &kSecRSAPublicKeyDescriptor) { | |
423 | ccrsa_pub_ctx_t pubkey; | |
424 | pubkey.pub = key->key; | |
5c19dc3a | 425 | |
fa7225c8 | 426 | size_t e_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); |
5c19dc3a | 427 | |
fa7225c8 A |
428 | CFAllocatorRef allocator = CFGetAllocator(key); |
429 | CFMutableDataRef exponentData = CFDataCreateMutable(allocator, e_size); | |
5c19dc3a | 430 | |
fa7225c8 A |
431 | if (exponentData == NULL) |
432 | return NULL; | |
5c19dc3a | 433 | |
fa7225c8 | 434 | CFDataSetLength(exponentData, e_size); |
5c19dc3a | 435 | |
fa7225c8 A |
436 | ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey), e_size, CFDataGetMutableBytePtr(exponentData)); |
437 | exponent = exponentData; | |
438 | } else if (key->key_class->copyDictionary != NULL) { | |
439 | CFDictionaryRef dict = key->key_class->copyDictionary(key); | |
440 | if (dict != NULL) { | |
441 | exponent = CFRetainSafe(CFDictionaryGetValue(dict, CFSTR("_rsae"))); | |
442 | CFRelease(dict); | |
443 | } | |
444 | } | |
5c19dc3a | 445 | |
fa7225c8 | 446 | return exponent; |
b1ab9ed8 A |
447 | } |
448 | ||
449 | ||
450 | /* | |
451 | * | |
452 | * Private Key | |
453 | * | |
454 | */ | |
455 | ||
456 | /* Private key static functions. */ | |
457 | static void SecRSAPrivateKeyDestroy(SecKeyRef key) { | |
458 | /* Zero out the public key */ | |
5c19dc3a A |
459 | if (key->key) { |
460 | ccrsa_full_ctx_t fullkey; | |
461 | fullkey.full = key->key; | |
462 | cc_clear(ccrsa_full_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(fullkey))), fullkey.full); | |
463 | free(key->key); | |
464 | key->key = NULL; | |
b1ab9ed8 | 465 | } |
b1ab9ed8 A |
466 | } |
467 | ||
5c19dc3a | 468 | static OSStatus SecRSAPrivateKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { |
b1ab9ed8 | 469 | OSStatus result = errSecParam; |
b1ab9ed8 | 470 | ccrsa_full_ctx_t fullkey; |
5c19dc3a A |
471 | cc_size size_n = 0; |
472 | ||
b1ab9ed8 A |
473 | switch (encoding) { |
474 | case kSecKeyEncodingBytes: // Octets is PKCS1 | |
475 | case kSecKeyEncodingPkcs1: | |
5c19dc3a | 476 | { |
fa7225c8 A |
477 | size_n = ccrsa_import_priv_n(keyDataLength,keyData); |
478 | require_quiet(size_n != 0, errOut); | |
479 | require_quiet(size_n <= ccn_nof(kMaximumRSAKeyBits), errOut); | |
5c19dc3a A |
480 | |
481 | key->key = calloc(1, ccrsa_full_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 482 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a A |
483 | |
484 | fullkey.full = key->key; | |
485 | ccrsa_ctx_n(fullkey) = size_n; | |
486 | ||
fa7225c8 | 487 | require_quiet(ccrsa_import_priv(fullkey, keyDataLength, keyData)==0, errOut); |
5c19dc3a A |
488 | |
489 | result = errSecSuccess; | |
b1ab9ed8 | 490 | break; |
5c19dc3a | 491 | } |
b1ab9ed8 A |
492 | case kSecGenerateKey: |
493 | { | |
494 | CFDictionaryRef parameters = (CFDictionaryRef) keyData; | |
5c19dc3a | 495 | |
b1ab9ed8 A |
496 | CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits); |
497 | CFIndex keyLengthInBits = getIntValue(ksize); | |
5c19dc3a A |
498 | |
499 | if (keyLengthInBits < 512 || keyLengthInBits > kMaximumRSAKeyBits) { | |
b1ab9ed8 | 500 | secwarning("Invalid or missing key size in: %@", parameters); |
5c19dc3a A |
501 | result = errSecKeySizeNotAllowed; |
502 | goto errOut; | |
b1ab9ed8 | 503 | } |
5c19dc3a A |
504 | |
505 | size_n = ccn_nof(keyLengthInBits); | |
506 | ||
507 | key->key = calloc(1, ccrsa_full_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 508 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a A |
509 | |
510 | fullkey.full = key->key; | |
511 | ccrsa_ctx_n(fullkey) = size_n; | |
512 | ||
b1ab9ed8 A |
513 | /* TODO: Add support for kSecPublicExponent parameter. */ |
514 | static uint8_t e[] = { 0x01, 0x00, 0x01 }; // Default is 65537 | |
fa7225c8 | 515 | if (!ccrsa_generate_fips186_key(keyLengthInBits, fullkey.full, sizeof(e), e, ccrng_seckey,ccrng_seckey)) |
b1ab9ed8 A |
516 | result = errSecSuccess; |
517 | break; | |
518 | } | |
519 | default: | |
520 | break; | |
521 | } | |
5c19dc3a | 522 | errOut: |
b1ab9ed8 A |
523 | return result; |
524 | } | |
525 | ||
fa7225c8 A |
526 | static CFTypeRef SecRSAPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, |
527 | CFArrayRef allAlgorithms, SecKeyOperationMode mode, | |
528 | CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { | |
529 | CFTypeRef result = kCFNull; | |
530 | ||
531 | ccrsa_full_ctx_t fullkey = { .full = key->key }; | |
532 | switch (operation) { | |
533 | case kSecKeyOperationTypeSign: | |
534 | if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureRawCCUnit)) { | |
535 | if (mode == kSecKeyOperationModePerform) { | |
536 | // Verify that data is smaller than modulus. | |
537 | require_action_quiet(ccn_cmpn(ccn_nof_size(CFDataGetLength(in1)), (const cc_unit *)CFDataGetBytePtr(in1), | |
538 | ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)) < 0, out, | |
539 | (result = NULL, | |
540 | SecError(errSecParam, error, CFSTR("%@: sign - digest too big (%d bytes)"), | |
541 | (int)CFDataGetLength(in1)))); | |
542 | ||
543 | // Encrypt buffer and write it to output data. | |
544 | result = CFDataCreateMutableWithScratch(kCFAllocatorDefault, ccrsa_block_size(ccrsa_ctx_public(fullkey))); | |
545 | ccrsa_priv_crypt(fullkey, (cc_unit *)CFDataGetMutableBytePtr((CFMutableDataRef)result), | |
546 | (const cc_unit *)CFDataGetBytePtr(in1)); | |
547 | } else { | |
548 | // Operation is supported. | |
549 | result = kCFBooleanTrue; | |
550 | } | |
b1ab9ed8 | 551 | } |
b1ab9ed8 | 552 | break; |
fa7225c8 A |
553 | case kSecKeyOperationTypeDecrypt: |
554 | if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRawCCUnit)) { | |
555 | if (mode == kSecKeyOperationModePerform) { | |
556 | // Decrypt buffer and write it to output data. | |
557 | result = CFDataCreateMutableWithScratch(NULL, ccrsa_block_size(fullkey)); | |
558 | ccrsa_priv_crypt(fullkey, (cc_unit *)CFDataGetMutableBytePtr((CFMutableDataRef)result), | |
559 | (const cc_unit *)CFDataGetBytePtr(in1)); | |
560 | } else { | |
561 | // Operation is supported. | |
562 | result = kCFBooleanTrue; | |
563 | } | |
564 | } | |
b1ab9ed8 | 565 | break; |
b1ab9ed8 | 566 | default: |
fa7225c8 | 567 | break; |
b1ab9ed8 | 568 | } |
5c19dc3a | 569 | |
fa7225c8 | 570 | out: |
b1ab9ed8 A |
571 | return result; |
572 | } | |
573 | ||
574 | static size_t SecRSAPrivateKeyBlockSize(SecKeyRef key) { | |
575 | ccrsa_full_ctx_t fullkey; | |
576 | fullkey.full = key->key; | |
5c19dc3a | 577 | |
b1ab9ed8 A |
578 | return ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); |
579 | } | |
580 | ||
581 | static CFDataRef SecRSAPrivateKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_full_ctx_t fullkey) | |
582 | { | |
fa7225c8 | 583 | const size_t result_size = ccrsa_export_priv_size(fullkey); |
5c19dc3a | 584 | |
b1ab9ed8 | 585 | CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size); |
5c19dc3a | 586 | |
b1ab9ed8 A |
587 | if (pkcs1 == NULL) |
588 | return NULL; | |
5c19dc3a | 589 | |
b1ab9ed8 | 590 | CFDataSetLength(pkcs1, result_size); |
5c19dc3a | 591 | |
b1ab9ed8 | 592 | uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); |
5c19dc3a | 593 | |
fa7225c8 A |
594 | if (ccrsa_export_priv(fullkey,result_size,bytes)!=0) { |
595 | /* Decoding failed */ | |
596 | CFReleaseNull(pkcs1); | |
597 | return NULL; | |
598 | } | |
5c19dc3a | 599 | |
b1ab9ed8 A |
600 | return pkcs1; |
601 | } | |
602 | ||
603 | static CFDataRef SecRSAPrivateKeyCopyPKCS1(SecKeyRef key) | |
604 | { | |
605 | ccrsa_full_ctx_t fullkey; | |
606 | fullkey.full = key->key; | |
5c19dc3a | 607 | |
b1ab9ed8 A |
608 | CFAllocatorRef allocator = CFGetAllocator(key); |
609 | return SecRSAPrivateKeyCreatePKCS1(allocator, fullkey); | |
610 | } | |
611 | ||
612 | static OSStatus SecRSAPrivateKeyCopyPublicSerialization(SecKeyRef key, CFDataRef* serialized) | |
613 | { | |
614 | ccrsa_full_ctx_t fullkey; | |
615 | fullkey.full = key->key; | |
5c19dc3a | 616 | |
b1ab9ed8 A |
617 | CFAllocatorRef allocator = CFGetAllocator(key); |
618 | *serialized = SecRSAPublicKeyCreatePKCS1(allocator, fullkey); | |
5c19dc3a | 619 | |
b1ab9ed8 A |
620 | if (NULL == *serialized) |
621 | return errSecDecode; | |
622 | else | |
623 | return errSecSuccess; | |
624 | } | |
625 | ||
626 | ||
627 | static CFDictionaryRef SecRSAPrivateKeyCopyAttributeDictionary(SecKeyRef key) { | |
628 | CFDictionaryRef dict = NULL; | |
629 | CFDataRef fullKeyBlob = NULL; | |
5c19dc3a | 630 | |
b1ab9ed8 A |
631 | /* PKCS1 encode the key pair. */ |
632 | fullKeyBlob = SecRSAPrivateKeyCopyPKCS1(key); | |
fa7225c8 | 633 | require_quiet(fullKeyBlob, errOut); |
5c19dc3a | 634 | |
b1ab9ed8 | 635 | dict = SecKeyGeneratePrivateAttributeDictionary(key, kSecAttrKeyTypeRSA, fullKeyBlob); |
fa7225c8 A |
636 | CFMutableDictionaryRef mutableDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); |
637 | CFDictionarySetValue(mutableDict, kSecAttrCanDerive, kCFBooleanFalse); | |
638 | CFAssignRetained(dict, mutableDict); | |
5c19dc3a | 639 | |
b1ab9ed8 A |
640 | errOut: |
641 | CFReleaseSafe(fullKeyBlob); | |
5c19dc3a | 642 | |
b1ab9ed8 A |
643 | return dict; |
644 | } | |
645 | ||
fa7225c8 A |
646 | static CFDataRef SecRSAPrivateKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { |
647 | return SecRSAPrivateKeyCopyPKCS1(key); | |
648 | } | |
649 | ||
427c49bc | 650 | static CFStringRef SecRSAPrivateKeyCopyDescription(SecKeyRef key){ |
5c19dc3a A |
651 | |
652 | return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR( "<SecKeyRef algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, addr: %p>"), SecKeyGetAlgorithmId(key), key->key_class->name, key->key_class->version, (8*SecKeyGetBlockSize(key)), key); | |
653 | ||
427c49bc | 654 | } |
fa7225c8 | 655 | |
b1ab9ed8 | 656 | SecKeyDescriptor kSecRSAPrivateKeyDescriptor = { |
fa7225c8 A |
657 | .version = kSecKeyDescriptorVersion, |
658 | .name = "RSAPrivateKey", | |
659 | ||
660 | .init = SecRSAPrivateKeyInit, | |
661 | .destroy = SecRSAPrivateKeyDestroy, | |
662 | .blockSize = SecRSAPrivateKeyBlockSize, | |
663 | .copyExternalRepresentation = SecRSAPrivateKeyCopyExternalRepresentation, | |
664 | .copyDictionary = SecRSAPrivateKeyCopyAttributeDictionary, | |
665 | .describe = SecRSAPrivateKeyCopyDescription, | |
666 | .copyPublic = SecRSAPrivateKeyCopyPublicSerialization, | |
667 | .copyOperationResult = SecRSAPrivateKeyCopyOperationResult, | |
b1ab9ed8 A |
668 | }; |
669 | ||
670 | /* Private Key API functions. */ | |
671 | SecKeyRef SecKeyCreateRSAPrivateKey(CFAllocatorRef allocator, | |
427c49bc A |
672 | const uint8_t *keyData, CFIndex keyDataLength, |
673 | SecKeyEncoding encoding) { | |
b1ab9ed8 | 674 | return SecKeyCreate(allocator, &kSecRSAPrivateKeyDescriptor, keyData, |
427c49bc | 675 | keyDataLength, encoding); |
b1ab9ed8 A |
676 | } |
677 | ||
678 | ||
679 | OSStatus SecRSAKeyGeneratePair(CFDictionaryRef parameters, | |
427c49bc | 680 | SecKeyRef *rsaPublicKey, SecKeyRef *rsaPrivateKey) { |
b1ab9ed8 | 681 | OSStatus status = errSecParam; |
5c19dc3a | 682 | |
b1ab9ed8 | 683 | CFAllocatorRef allocator = NULL; /* @@@ get from parameters. */ |
5c19dc3a | 684 | |
b1ab9ed8 A |
685 | SecKeyRef pubKey = NULL; |
686 | SecKeyRef privKey = SecKeyCreate(allocator, &kSecRSAPrivateKeyDescriptor, | |
687 | (const void*) parameters, 0, kSecGenerateKey); | |
5c19dc3a | 688 | |
fa7225c8 | 689 | require_quiet(privKey, errOut); |
5c19dc3a | 690 | |
b1ab9ed8 A |
691 | /* Create SecKeyRef's from the pkcs1 encoded keys. */ |
692 | pubKey = SecKeyCreate(allocator, &kSecRSAPublicKeyDescriptor, | |
693 | privKey->key, 0, kSecExtractPublicFromPrivate); | |
5c19dc3a | 694 | |
fa7225c8 | 695 | require_quiet(pubKey, errOut); |
5c19dc3a | 696 | |
b1ab9ed8 A |
697 | if (rsaPublicKey) { |
698 | *rsaPublicKey = pubKey; | |
699 | pubKey = NULL; | |
700 | } | |
701 | if (rsaPrivateKey) { | |
702 | *rsaPrivateKey = privKey; | |
703 | privKey = NULL; | |
704 | } | |
5c19dc3a | 705 | |
b1ab9ed8 | 706 | status = errSecSuccess; |
5c19dc3a | 707 | |
b1ab9ed8 A |
708 | errOut: |
709 | CFReleaseSafe(pubKey); | |
710 | CFReleaseSafe(privKey); | |
5c19dc3a | 711 | |
b1ab9ed8 A |
712 | return status; |
713 | } |