]>
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> | |
b54c578e | 47 | #include <Security/SecItemPriv.h> |
b1ab9ed8 A |
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 | 80 | if (key->key) { |
866f8763 A |
81 | ccrsa_pub_ctx_t pubkey = key->key; |
82 | cc_clear(ccrsa_pub_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(pubkey))), pubkey); | |
5c19dc3a A |
83 | free(key->key); |
84 | key->key = NULL; | |
85 | } | |
b1ab9ed8 A |
86 | } |
87 | ||
88 | #define cc_skip_zeros(size, ptr) { while (size > 0 && *ptr == 0) { ++ptr; --size; } } | |
89 | ||
90 | // | |
91 | // pubkey is initilaized with an n which is the maximum it can hold | |
92 | // We set the n to its correct value given m. | |
93 | // | |
94 | static int ccrsa_pub_init(ccrsa_pub_ctx_t pubkey, | |
95 | size_t m_size, const uint8_t* m, | |
96 | size_t e_size, const uint8_t* e) | |
97 | { | |
98 | cc_skip_zeros(m_size, m); | |
5c19dc3a | 99 | |
b1ab9ed8 A |
100 | cc_size nm = ccn_nof_size(m_size); |
101 | if (nm > ccrsa_ctx_n(pubkey)) | |
102 | return -1; | |
5c19dc3a | 103 | |
b1ab9ed8 | 104 | ccrsa_ctx_n(pubkey) = nm; |
5c19dc3a | 105 | |
b1ab9ed8 A |
106 | ccn_read_uint(nm, ccrsa_ctx_m(pubkey), m_size, m); |
107 | cczp_init(ccrsa_ctx_zm(pubkey)); | |
5c19dc3a | 108 | |
b1ab9ed8 A |
109 | return ccn_read_uint(nm, ccrsa_ctx_e(pubkey), e_size, e); |
110 | } | |
111 | ||
112 | ||
b1ab9ed8 A |
113 | static OSStatus ccrsa_pub_decode_apple(ccrsa_pub_ctx_t pubkey, size_t pkcs1_size, const uint8_t* pkcs1) |
114 | { | |
115 | OSStatus result = errSecParam; | |
5c19dc3a | 116 | |
b1ab9ed8 A |
117 | DERItem keyItem = {(DERByte *)pkcs1, pkcs1_size}; |
118 | DERRSAPubKeyApple decodedKey; | |
5c19dc3a | 119 | |
fa7225c8 A |
120 | require_noerr_action_quiet(DERParseSequence(&keyItem, |
121 | DERNumRSAPubKeyAppleItemSpecs, DERRSAPubKeyAppleItemSpecs, | |
122 | &decodedKey, sizeof(decodedKey)), | |
123 | errOut, result = errSecDecode); | |
5c19dc3a | 124 | |
fa7225c8 | 125 | // We could honor the reciprocal, but we don't think this is used enough to care. |
b1ab9ed8 | 126 | // Don't bother exploding the below function to try to handle this case, it computes. |
5c19dc3a | 127 | |
fa7225c8 A |
128 | require_noerr_quiet(ccrsa_pub_init(pubkey, |
129 | decodedKey.modulus.length, decodedKey.modulus.data, | |
130 | decodedKey.pubExponent.length, decodedKey.pubExponent.data), | |
131 | errOut); | |
5c19dc3a | 132 | |
b1ab9ed8 | 133 | result = errSecSuccess; |
5c19dc3a | 134 | |
b1ab9ed8 A |
135 | errOut: |
136 | return result; | |
137 | } | |
138 | ||
139 | ||
140 | static void ccasn_encode_int(cc_size n, const cc_unit*s, size_t s_size, uint8_t **buffer) | |
141 | { | |
142 | **buffer = ASN1_INTEGER; | |
143 | *buffer += 1; | |
5c19dc3a | 144 | |
b1ab9ed8 A |
145 | DERSize itemLength = 4; |
146 | DEREncodeLength(s_size, *buffer, &itemLength); | |
147 | *buffer += itemLength; | |
5c19dc3a | 148 | |
b1ab9ed8 | 149 | ccn_write_int(n, s, s_size, *buffer); |
5c19dc3a | 150 | |
b1ab9ed8 A |
151 | *buffer += s_size; |
152 | } | |
153 | ||
154 | ||
155 | static OSStatus SecRSAPublicKeyInit(SecKeyRef key, | |
427c49bc | 156 | const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { |
5c19dc3a | 157 | |
b1ab9ed8 | 158 | OSStatus result = errSecParam; |
b1ab9ed8 | 159 | ccrsa_pub_ctx_t pubkey; |
5c19dc3a A |
160 | size_t size_n = 0; |
161 | ||
b1ab9ed8 | 162 | switch (encoding) { |
427c49bc | 163 | case kSecKeyEncodingBytes: // Octets is PKCS1 |
5c19dc3a | 164 | case kSecKeyEncodingPkcs1: { |
fa7225c8 A |
165 | size_n = ccrsa_import_pub_n(keyDataLength, keyData); |
166 | require_quiet(size_n != 0, errOut); | |
167 | require_quiet(size_n <= ccn_nof(kMaximumRSAKeyBits), errOut); | |
5c19dc3a A |
168 | |
169 | key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 170 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a | 171 | |
866f8763 | 172 | pubkey = key->key; |
5c19dc3a A |
173 | ccrsa_ctx_n(pubkey) = size_n; |
174 | ||
fa7225c8 | 175 | require_noerr_quiet(ccrsa_import_pub(pubkey, keyDataLength, keyData), errOut); |
5c19dc3a A |
176 | |
177 | result = errSecSuccess; | |
178 | ||
427c49bc | 179 | break; |
5c19dc3a | 180 | } |
427c49bc | 181 | case kSecKeyEncodingApplePkcs1: |
5c19dc3a A |
182 | /* for the few uses (I can't find any) that uses kSecKeyEncodingApplePkcs1, force largest keys */ |
183 | size_n = ccn_nof(kMaximumRSAKeyBits); | |
184 | ||
185 | key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 186 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a | 187 | |
866f8763 | 188 | pubkey = key->key; |
5c19dc3a A |
189 | ccrsa_ctx_n(pubkey) = size_n; |
190 | ||
427c49bc A |
191 | result = ccrsa_pub_decode_apple(pubkey, keyDataLength, keyData); |
192 | break; | |
193 | case kSecKeyEncodingRSAPublicParams: | |
194 | { | |
195 | SecRSAPublicKeyParams *params = (SecRSAPublicKeyParams *)keyData; | |
5c19dc3a A |
196 | |
197 | size_n = ccn_nof_size(params->modulusLength); | |
198 | ||
199 | key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 200 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a | 201 | |
866f8763 | 202 | pubkey = key->key; |
5c19dc3a A |
203 | ccrsa_ctx_n(pubkey) = size_n; |
204 | ||
fa7225c8 A |
205 | require_noerr_quiet(ccrsa_pub_init(pubkey, |
206 | params->modulusLength, params->modulus, | |
207 | params->exponentLength, params->exponent), errOut); | |
5c19dc3a | 208 | |
427c49bc A |
209 | result = errSecSuccess; |
210 | break; | |
211 | } | |
212 | case kSecExtractPublicFromPrivate: | |
213 | { | |
866f8763 A |
214 | ccrsa_full_ctx_t fullKey = (ccrsa_full_ctx_t) keyData; |
215 | ||
5c19dc3a A |
216 | size_n = ccrsa_ctx_n(fullKey); |
217 | ||
218 | key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 219 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a | 220 | |
866f8763 | 221 | pubkey = key->key; |
5c19dc3a A |
222 | ccrsa_ctx_n(pubkey) = size_n; |
223 | ||
866f8763 | 224 | memcpy(pubkey, ccrsa_ctx_public(fullKey), ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); |
427c49bc A |
225 | result = errSecSuccess; |
226 | break; | |
227 | } | |
228 | default: | |
229 | break; | |
b1ab9ed8 | 230 | } |
5c19dc3a | 231 | |
b1ab9ed8 A |
232 | errOut: |
233 | return result; | |
234 | } | |
235 | ||
fa7225c8 A |
236 | static CFTypeRef SecRSAPublicKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, |
237 | CFArrayRef allAlgorithms, SecKeyOperationMode mode, | |
238 | CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { | |
239 | CFTypeRef result; | |
240 | require_action_quiet(CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRawCCUnit), out, result = kCFNull); | |
5c19dc3a | 241 | |
866f8763 | 242 | ccrsa_pub_ctx_t pubkey = key->key; |
fa7225c8 | 243 | result = kCFBooleanTrue; |
6b200bc3 | 244 | int ccerr = 0; |
fa7225c8 A |
245 | switch (operation) { |
246 | case kSecKeyOperationTypeEncrypt: | |
247 | if (mode == kSecKeyOperationModePerform) { | |
b54c578e A |
248 | // Input buffer length must be cc_unit aligned, otherwise it is not a valid cc_unit buffer. |
249 | CFIndex bufferSize = CFDataGetLength(in1); | |
250 | require_action_quiet(bufferSize == ccn_sizeof_size(ccrsa_block_size(pubkey)), out, | |
251 | (result = NULL, | |
252 | SecError(errSecParam, error, CFSTR("%@: sign - input buffer bad size (%d bytes)"), key, | |
253 | (int)bufferSize))); | |
254 | ||
6b200bc3 A |
255 | // Verify that plaintext is smaller than modulus. Note that since we already verified that input algorithm |
256 | // is kSecKeyAlgorithmRSAEncryptionRawCCUnit, we can safely access in1 CFDataRef contents as cc_unit *. | |
fa7225c8 A |
257 | require_action_quiet(ccn_cmpn(ccn_nof_size(CFDataGetLength(in1)), (const cc_unit *)CFDataGetBytePtr(in1), |
258 | ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)) < 0, out, | |
259 | (result = NULL, | |
260 | SecError(errSecParam, error, CFSTR("RSApubkey wrong size of buffer to encrypt")))); | |
261 | ||
262 | // Encrypt into output buffer. | |
b54c578e | 263 | result = CFDataCreateMutableWithScratch(NULL, bufferSize); |
6b200bc3 A |
264 | ccerr = ccrsa_pub_crypt(pubkey, (cc_unit *)CFDataGetMutableBytePtr((CFMutableDataRef)result), |
265 | (const cc_unit *)CFDataGetBytePtr(in1)); | |
b1ab9ed8 | 266 | } |
b1ab9ed8 | 267 | break; |
fa7225c8 A |
268 | case kSecKeyOperationTypeDecrypt: |
269 | if (mode == kSecKeyOperationModePerform) { | |
b54c578e A |
270 | // Input buffer length must be cc_unit aligned, otherwise it is not a valid cc_unit buffer. |
271 | CFIndex bufferSize = CFDataGetLength(in1); | |
272 | require_action_quiet(bufferSize == ccn_sizeof_size(ccrsa_block_size(pubkey)), out, | |
273 | (result = NULL, | |
274 | SecError(errSecParam, error, CFSTR("%@: sign - input buffer bad size (%d bytes)"), key, | |
275 | (int)bufferSize))); | |
276 | ||
fa7225c8 | 277 | // Decrypt into output buffer. |
b54c578e | 278 | result = CFDataCreateMutableWithScratch(NULL, bufferSize); |
6b200bc3 A |
279 | ccerr = ccrsa_pub_crypt(pubkey, (cc_unit *)CFDataGetMutableBytePtr((CFMutableDataRef)result), |
280 | (const cc_unit *)CFDataGetBytePtr(in1)); | |
b1ab9ed8 | 281 | } |
427c49bc | 282 | break; |
b1ab9ed8 | 283 | default: |
fa7225c8 | 284 | result = kCFNull; |
b1ab9ed8 | 285 | break; |
b1ab9ed8 | 286 | } |
5c19dc3a | 287 | |
6b200bc3 | 288 | require_noerr_action_quiet(ccerr, out, (CFReleaseNull(result), |
866f8763 | 289 | SecError(errSecParam, error, CFSTR("rsa_pub_crypt failed, ccerr=%d"), ccerr))); |
fa7225c8 | 290 | out: |
b1ab9ed8 A |
291 | return result; |
292 | } | |
293 | ||
294 | static size_t SecRSAPublicKeyBlockSize(SecKeyRef key) { | |
866f8763 | 295 | ccrsa_pub_ctx_t pubkey = key->key; |
fa7225c8 | 296 | return ccrsa_block_size(pubkey); |
b1ab9ed8 A |
297 | } |
298 | ||
299 | ||
300 | static CFDataRef SecRSAPublicKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_pub_ctx_t pubkey) | |
301 | { | |
302 | size_t m_size = ccn_write_int_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); | |
303 | size_t e_size = ccn_write_int_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); | |
5c19dc3a | 304 | |
b1ab9ed8 | 305 | const size_t seq_size = DERLengthOfItem(ASN1_INTEGER, m_size) + |
427c49bc | 306 | DERLengthOfItem(ASN1_INTEGER, e_size); |
5c19dc3a | 307 | |
b1ab9ed8 | 308 | const size_t result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size); |
5c19dc3a | 309 | |
fa7225c8 | 310 | CFMutableDataRef pkcs1 = CFDataCreateMutableWithScratch(allocator, result_size); |
b1ab9ed8 | 311 | uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); |
5c19dc3a | 312 | |
fa7225c8 | 313 | *bytes++ = ONE_BYTE_ASN1_CONSTR_SEQUENCE; |
5c19dc3a | 314 | |
b1ab9ed8 A |
315 | DERSize itemLength = 4; |
316 | DEREncodeLength(seq_size, bytes, &itemLength); | |
317 | bytes += itemLength; | |
5c19dc3a | 318 | |
b1ab9ed8 A |
319 | ccasn_encode_int(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, &bytes); |
320 | ccasn_encode_int(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey), e_size, &bytes); | |
5c19dc3a | 321 | |
b1ab9ed8 A |
322 | return pkcs1; |
323 | } | |
324 | ||
325 | static OSStatus SecRSAPublicKeyCopyPublicSerialization(SecKeyRef key, CFDataRef* serialized) | |
326 | { | |
866f8763 | 327 | ccrsa_pub_ctx_t pubkey = key->key; |
5c19dc3a | 328 | |
b1ab9ed8 A |
329 | CFAllocatorRef allocator = CFGetAllocator(key); |
330 | *serialized = SecRSAPublicKeyCreatePKCS1(allocator, pubkey); | |
5c19dc3a | 331 | |
b1ab9ed8 A |
332 | if (NULL == *serialized) |
333 | return errSecDecode; | |
334 | else | |
335 | return errSecSuccess; | |
336 | } | |
337 | ||
338 | static CFDictionaryRef SecRSAPublicKeyCopyAttributeDictionary(SecKeyRef key) { | |
fa7225c8 A |
339 | CFDictionaryRef dict = SecKeyGeneratePublicAttributeDictionary(key, kSecAttrKeyTypeRSA); |
340 | CFMutableDictionaryRef mutableDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); | |
341 | CFDictionarySetValue(mutableDict, kSecAttrCanDecrypt, kCFBooleanTrue); | |
342 | CFDictionarySetValue(mutableDict, kSecAttrCanDerive, kCFBooleanFalse); | |
343 | CFAssignRetained(dict, mutableDict); | |
344 | return dict; | |
345 | } | |
346 | ||
347 | static CFDataRef SecRSAPublicKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { | |
866f8763 | 348 | ccrsa_pub_ctx_t pubkey = key->key; |
fa7225c8 | 349 | return SecRSAPublicKeyCreatePKCS1(CFGetAllocator(key), pubkey); |
b1ab9ed8 A |
350 | } |
351 | ||
427c49bc | 352 | static CFStringRef SecRSAPublicKeyCopyDescription(SecKeyRef key) { |
5c19dc3a | 353 | |
427c49bc A |
354 | CFStringRef keyDescription = NULL; |
355 | CFDataRef modRef = SecKeyCopyModulus(key); | |
5c19dc3a | 356 | |
866f8763 | 357 | ccrsa_pub_ctx_t pubkey = key->key; |
5c19dc3a | 358 | |
427c49bc | 359 | CFStringRef modulusString = CFDataCopyHexString(modRef); |
fa7225c8 | 360 | require_quiet(modulusString, fail); |
5c19dc3a A |
361 | |
362 | 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); | |
363 | ||
427c49bc A |
364 | fail: |
365 | CFReleaseSafe(modRef); | |
366 | CFReleaseSafe(modulusString); | |
367 | if(!keyDescription) | |
5c19dc3a A |
368 | 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); |
369 | ||
427c49bc A |
370 | return keyDescription; |
371 | } | |
372 | ||
b1ab9ed8 | 373 | SecKeyDescriptor kSecRSAPublicKeyDescriptor = { |
fa7225c8 A |
374 | .version = kSecKeyDescriptorVersion, |
375 | .name = "RSAPublicKey", | |
376 | ||
377 | .init = SecRSAPublicKeyInit, | |
378 | .destroy = SecRSAPublicKeyDestroy, | |
379 | .blockSize = SecRSAPublicKeyBlockSize, | |
380 | .copyDictionary = SecRSAPublicKeyCopyAttributeDictionary, | |
381 | .copyExternalRepresentation = SecRSAPublicKeyCopyExternalRepresentation, | |
382 | .describe = SecRSAPublicKeyCopyDescription, | |
383 | .copyPublic = SecRSAPublicKeyCopyPublicSerialization, | |
384 | .copyOperationResult = SecRSAPublicKeyCopyOperationResult, | |
b1ab9ed8 A |
385 | }; |
386 | ||
387 | /* Public Key API functions. */ | |
fa7225c8 | 388 | SecKeyRef SecKeyCreateRSAPublicKey_ios(CFAllocatorRef allocator, |
427c49bc A |
389 | const uint8_t *keyData, CFIndex keyDataLength, |
390 | SecKeyEncoding encoding) { | |
b1ab9ed8 | 391 | return SecKeyCreate(allocator, &kSecRSAPublicKeyDescriptor, keyData, |
427c49bc | 392 | keyDataLength, encoding); |
b1ab9ed8 A |
393 | } |
394 | ||
fa7225c8 A |
395 | SecKeyRef SecKeyCreateRSAPublicKey(CFAllocatorRef allocator, |
396 | const uint8_t *keyData, CFIndex keyDataLength, | |
397 | SecKeyEncoding encoding) { | |
398 | return SecKeyCreateRSAPublicKey_ios(allocator, keyData, | |
399 | keyDataLength, encoding); | |
400 | } | |
401 | ||
b1ab9ed8 | 402 | CFDataRef SecKeyCopyModulus(SecKeyRef key) { |
fa7225c8 A |
403 | CFDataRef modulus = NULL; |
404 | if (key->key_class == &kSecRSAPublicKeyDescriptor) { | |
866f8763 | 405 | ccrsa_pub_ctx_t pubkey = key->key; |
5c19dc3a | 406 | |
fa7225c8 | 407 | size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); |
5c19dc3a | 408 | |
fa7225c8 A |
409 | CFAllocatorRef allocator = CFGetAllocator(key); |
410 | CFMutableDataRef modulusData = CFDataCreateMutable(allocator, m_size); | |
5c19dc3a | 411 | |
fa7225c8 A |
412 | if (modulusData == NULL) |
413 | return NULL; | |
5c19dc3a | 414 | |
fa7225c8 | 415 | CFDataSetLength(modulusData, m_size); |
5c19dc3a | 416 | |
fa7225c8 A |
417 | ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, CFDataGetMutableBytePtr(modulusData)); |
418 | modulus = modulusData; | |
419 | } else if (key->key_class->copyDictionary != NULL) { | |
420 | CFDictionaryRef dict = key->key_class->copyDictionary(key); | |
421 | if (dict != NULL) { | |
422 | modulus = CFRetainSafe(CFDictionaryGetValue(dict, CFSTR("_rsam"))); | |
423 | CFRelease(dict); | |
424 | } | |
425 | } | |
5c19dc3a | 426 | |
fa7225c8 | 427 | return modulus; |
b1ab9ed8 A |
428 | } |
429 | ||
430 | CFDataRef SecKeyCopyExponent(SecKeyRef key) { | |
fa7225c8 A |
431 | CFDataRef exponent = NULL; |
432 | if (key->key_class == &kSecRSAPublicKeyDescriptor) { | |
866f8763 | 433 | ccrsa_pub_ctx_t pubkey = key->key; |
5c19dc3a | 434 | |
fa7225c8 | 435 | size_t e_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); |
5c19dc3a | 436 | |
fa7225c8 A |
437 | CFAllocatorRef allocator = CFGetAllocator(key); |
438 | CFMutableDataRef exponentData = CFDataCreateMutable(allocator, e_size); | |
5c19dc3a | 439 | |
fa7225c8 A |
440 | if (exponentData == NULL) |
441 | return NULL; | |
5c19dc3a | 442 | |
fa7225c8 | 443 | CFDataSetLength(exponentData, e_size); |
5c19dc3a | 444 | |
fa7225c8 A |
445 | ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey), e_size, CFDataGetMutableBytePtr(exponentData)); |
446 | exponent = exponentData; | |
447 | } else if (key->key_class->copyDictionary != NULL) { | |
448 | CFDictionaryRef dict = key->key_class->copyDictionary(key); | |
449 | if (dict != NULL) { | |
450 | exponent = CFRetainSafe(CFDictionaryGetValue(dict, CFSTR("_rsae"))); | |
451 | CFRelease(dict); | |
452 | } | |
453 | } | |
5c19dc3a | 454 | |
fa7225c8 | 455 | return exponent; |
b1ab9ed8 A |
456 | } |
457 | ||
458 | ||
459 | /* | |
460 | * | |
461 | * Private Key | |
462 | * | |
463 | */ | |
464 | ||
465 | /* Private key static functions. */ | |
466 | static void SecRSAPrivateKeyDestroy(SecKeyRef key) { | |
467 | /* Zero out the public key */ | |
5c19dc3a | 468 | if (key->key) { |
866f8763 A |
469 | ccrsa_full_ctx_t fullkey = key->key; |
470 | cc_clear(ccrsa_full_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(fullkey))), fullkey); | |
5c19dc3a A |
471 | free(key->key); |
472 | key->key = NULL; | |
b1ab9ed8 | 473 | } |
b1ab9ed8 A |
474 | } |
475 | ||
5c19dc3a | 476 | static OSStatus SecRSAPrivateKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { |
b1ab9ed8 | 477 | OSStatus result = errSecParam; |
b1ab9ed8 | 478 | ccrsa_full_ctx_t fullkey; |
5c19dc3a A |
479 | cc_size size_n = 0; |
480 | ||
b1ab9ed8 A |
481 | switch (encoding) { |
482 | case kSecKeyEncodingBytes: // Octets is PKCS1 | |
483 | case kSecKeyEncodingPkcs1: | |
5c19dc3a | 484 | { |
fa7225c8 A |
485 | size_n = ccrsa_import_priv_n(keyDataLength,keyData); |
486 | require_quiet(size_n != 0, errOut); | |
487 | require_quiet(size_n <= ccn_nof(kMaximumRSAKeyBits), errOut); | |
5c19dc3a A |
488 | |
489 | key->key = calloc(1, ccrsa_full_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 490 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a | 491 | |
866f8763 | 492 | fullkey = key->key; |
5c19dc3a A |
493 | ccrsa_ctx_n(fullkey) = size_n; |
494 | ||
fa7225c8 | 495 | require_quiet(ccrsa_import_priv(fullkey, keyDataLength, keyData)==0, errOut); |
5c19dc3a A |
496 | |
497 | result = errSecSuccess; | |
b1ab9ed8 | 498 | break; |
5c19dc3a | 499 | } |
b1ab9ed8 A |
500 | case kSecGenerateKey: |
501 | { | |
502 | CFDictionaryRef parameters = (CFDictionaryRef) keyData; | |
5c19dc3a | 503 | |
b1ab9ed8 A |
504 | CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits); |
505 | CFIndex keyLengthInBits = getIntValue(ksize); | |
5c19dc3a A |
506 | |
507 | if (keyLengthInBits < 512 || keyLengthInBits > kMaximumRSAKeyBits) { | |
b1ab9ed8 | 508 | secwarning("Invalid or missing key size in: %@", parameters); |
5c19dc3a A |
509 | result = errSecKeySizeNotAllowed; |
510 | goto errOut; | |
b1ab9ed8 | 511 | } |
5c19dc3a A |
512 | |
513 | size_n = ccn_nof(keyLengthInBits); | |
514 | ||
515 | key->key = calloc(1, ccrsa_full_ctx_size(ccn_sizeof_n(size_n))); | |
fa7225c8 | 516 | require_action_quiet(key->key, errOut, result = errSecAllocate); |
5c19dc3a | 517 | |
866f8763 | 518 | fullkey = key->key; |
5c19dc3a A |
519 | ccrsa_ctx_n(fullkey) = size_n; |
520 | ||
b1ab9ed8 A |
521 | /* TODO: Add support for kSecPublicExponent parameter. */ |
522 | static uint8_t e[] = { 0x01, 0x00, 0x01 }; // Default is 65537 | |
866f8763 | 523 | if (!ccrsa_generate_fips186_key(keyLengthInBits, fullkey, sizeof(e), e, ccrng_seckey,ccrng_seckey)) |
b1ab9ed8 A |
524 | result = errSecSuccess; |
525 | break; | |
526 | } | |
527 | default: | |
528 | break; | |
529 | } | |
5c19dc3a | 530 | errOut: |
b1ab9ed8 A |
531 | return result; |
532 | } | |
533 | ||
fa7225c8 A |
534 | static CFTypeRef SecRSAPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, |
535 | CFArrayRef allAlgorithms, SecKeyOperationMode mode, | |
536 | CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { | |
537 | CFTypeRef result = kCFNull; | |
538 | ||
866f8763 | 539 | ccrsa_full_ctx_t fullkey = key->key; |
6b200bc3 | 540 | int ccerr = 0; |
fa7225c8 A |
541 | switch (operation) { |
542 | case kSecKeyOperationTypeSign: | |
543 | if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureRawCCUnit)) { | |
544 | if (mode == kSecKeyOperationModePerform) { | |
b54c578e A |
545 | // Input buffer length must be cc_unit aligned, otherwise it is not a valid cc_unit buffer. |
546 | CFIndex bufferSize = CFDataGetLength(in1); | |
547 | require_action_quiet(bufferSize == ccn_sizeof_size(ccrsa_block_size(ccrsa_ctx_public(fullkey))), out, | |
548 | (result = NULL, | |
549 | SecError(errSecParam, error, CFSTR("%@: sign - input buffer bad size (%d bytes)"), key, | |
550 | (int)bufferSize))); | |
551 | ||
6b200bc3 A |
552 | // Verify that data is smaller than modulus. Note that since we already verified that input algorithm |
553 | // is kSecKeyAlgorithmRSASignatureRawCCUnit, we can safely access in1 CFDataRef contents as cc_unit *. | |
fa7225c8 A |
554 | require_action_quiet(ccn_cmpn(ccn_nof_size(CFDataGetLength(in1)), (const cc_unit *)CFDataGetBytePtr(in1), |
555 | ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)) < 0, out, | |
556 | (result = NULL, | |
866f8763 | 557 | SecError(errSecParam, error, CFSTR("%@: sign - digest too big (%d bytes)"), key, |
fa7225c8 A |
558 | (int)CFDataGetLength(in1)))); |
559 | ||
560 | // Encrypt buffer and write it to output data. | |
b54c578e | 561 | result = CFDataCreateMutableWithScratch(kCFAllocatorDefault, bufferSize); |
6b200bc3 A |
562 | ccerr = ccrsa_priv_crypt(fullkey, (cc_unit *)CFDataGetMutableBytePtr((CFMutableDataRef)result), |
563 | (const cc_unit *)CFDataGetBytePtr(in1)); | |
fa7225c8 A |
564 | } else { |
565 | // Operation is supported. | |
566 | result = kCFBooleanTrue; | |
567 | } | |
b1ab9ed8 | 568 | } |
b1ab9ed8 | 569 | break; |
fa7225c8 A |
570 | case kSecKeyOperationTypeDecrypt: |
571 | if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRawCCUnit)) { | |
572 | if (mode == kSecKeyOperationModePerform) { | |
b54c578e A |
573 | // Input buffer length must be cc_unit aligned, otherwise it is not a valid cc_unit buffer. |
574 | CFIndex bufferSize = CFDataGetLength(in1); | |
575 | require_action_quiet(bufferSize == ccn_sizeof_size(ccrsa_block_size(ccrsa_ctx_public(fullkey))), out, | |
576 | (result = NULL, | |
577 | SecError(errSecParam, error, CFSTR("%@: sign - input buffer bad size (%d bytes)"), key, | |
578 | (int)bufferSize))); | |
579 | ||
fa7225c8 | 580 | // Decrypt buffer and write it to output data. |
b54c578e | 581 | result = CFDataCreateMutableWithScratch(NULL, bufferSize); |
6b200bc3 A |
582 | ccerr = ccrsa_priv_crypt(fullkey, (cc_unit *)CFDataGetMutableBytePtr((CFMutableDataRef)result), |
583 | (const cc_unit *)CFDataGetBytePtr(in1)); | |
fa7225c8 A |
584 | } else { |
585 | // Operation is supported. | |
586 | result = kCFBooleanTrue; | |
587 | } | |
588 | } | |
b1ab9ed8 | 589 | break; |
b1ab9ed8 | 590 | default: |
fa7225c8 | 591 | break; |
b1ab9ed8 | 592 | } |
5c19dc3a | 593 | |
6b200bc3 | 594 | require_noerr_action_quiet(ccerr, out, (CFReleaseNull(result), |
866f8763 | 595 | SecError(errSecParam, error, CFSTR("rsa_priv_crypt failed, ccerr=%d"), ccerr))); |
fa7225c8 | 596 | out: |
b1ab9ed8 A |
597 | return result; |
598 | } | |
599 | ||
600 | static size_t SecRSAPrivateKeyBlockSize(SecKeyRef key) { | |
866f8763 | 601 | ccrsa_full_ctx_t fullkey = key->key; |
5c19dc3a | 602 | |
b1ab9ed8 A |
603 | return ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); |
604 | } | |
605 | ||
606 | static CFDataRef SecRSAPrivateKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_full_ctx_t fullkey) | |
607 | { | |
fa7225c8 | 608 | const size_t result_size = ccrsa_export_priv_size(fullkey); |
5c19dc3a | 609 | |
d64be36e | 610 | CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size); |
5c19dc3a | 611 | |
d64be36e | 612 | if (pkcs1 == NULL) { |
b1ab9ed8 | 613 | return NULL; |
d64be36e | 614 | } |
5c19dc3a | 615 | |
d64be36e | 616 | CFDataSetLength(pkcs1, result_size); |
5c19dc3a | 617 | |
b1ab9ed8 | 618 | uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); |
5c19dc3a | 619 | |
fa7225c8 A |
620 | if (ccrsa_export_priv(fullkey,result_size,bytes)!=0) { |
621 | /* Decoding failed */ | |
622 | CFReleaseNull(pkcs1); | |
623 | return NULL; | |
624 | } | |
5c19dc3a | 625 | |
b1ab9ed8 A |
626 | return pkcs1; |
627 | } | |
628 | ||
629 | static CFDataRef SecRSAPrivateKeyCopyPKCS1(SecKeyRef key) | |
630 | { | |
866f8763 | 631 | ccrsa_full_ctx_t fullkey = key->key; |
5c19dc3a | 632 | |
b1ab9ed8 A |
633 | CFAllocatorRef allocator = CFGetAllocator(key); |
634 | return SecRSAPrivateKeyCreatePKCS1(allocator, fullkey); | |
635 | } | |
636 | ||
637 | static OSStatus SecRSAPrivateKeyCopyPublicSerialization(SecKeyRef key, CFDataRef* serialized) | |
638 | { | |
866f8763 | 639 | ccrsa_full_ctx_t fullkey = key->key; |
5c19dc3a | 640 | |
b1ab9ed8 | 641 | CFAllocatorRef allocator = CFGetAllocator(key); |
866f8763 | 642 | *serialized = SecRSAPublicKeyCreatePKCS1(allocator, ccrsa_ctx_public(fullkey)); |
5c19dc3a | 643 | |
b1ab9ed8 A |
644 | if (NULL == *serialized) |
645 | return errSecDecode; | |
646 | else | |
647 | return errSecSuccess; | |
648 | } | |
649 | ||
650 | ||
651 | static CFDictionaryRef SecRSAPrivateKeyCopyAttributeDictionary(SecKeyRef key) { | |
652 | CFDictionaryRef dict = NULL; | |
653 | CFDataRef fullKeyBlob = NULL; | |
5c19dc3a | 654 | |
b1ab9ed8 A |
655 | /* PKCS1 encode the key pair. */ |
656 | fullKeyBlob = SecRSAPrivateKeyCopyPKCS1(key); | |
fa7225c8 | 657 | require_quiet(fullKeyBlob, errOut); |
5c19dc3a | 658 | |
b1ab9ed8 | 659 | dict = SecKeyGeneratePrivateAttributeDictionary(key, kSecAttrKeyTypeRSA, fullKeyBlob); |
fa7225c8 A |
660 | CFMutableDictionaryRef mutableDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); |
661 | CFDictionarySetValue(mutableDict, kSecAttrCanDerive, kCFBooleanFalse); | |
662 | CFAssignRetained(dict, mutableDict); | |
5c19dc3a | 663 | |
b1ab9ed8 A |
664 | errOut: |
665 | CFReleaseSafe(fullKeyBlob); | |
5c19dc3a | 666 | |
b1ab9ed8 A |
667 | return dict; |
668 | } | |
669 | ||
fa7225c8 A |
670 | static CFDataRef SecRSAPrivateKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { |
671 | return SecRSAPrivateKeyCopyPKCS1(key); | |
672 | } | |
673 | ||
427c49bc | 674 | static CFStringRef SecRSAPrivateKeyCopyDescription(SecKeyRef key){ |
5c19dc3a A |
675 | |
676 | 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); | |
677 | ||
427c49bc | 678 | } |
fa7225c8 | 679 | |
b1ab9ed8 | 680 | SecKeyDescriptor kSecRSAPrivateKeyDescriptor = { |
fa7225c8 A |
681 | .version = kSecKeyDescriptorVersion, |
682 | .name = "RSAPrivateKey", | |
683 | ||
684 | .init = SecRSAPrivateKeyInit, | |
685 | .destroy = SecRSAPrivateKeyDestroy, | |
686 | .blockSize = SecRSAPrivateKeyBlockSize, | |
687 | .copyExternalRepresentation = SecRSAPrivateKeyCopyExternalRepresentation, | |
688 | .copyDictionary = SecRSAPrivateKeyCopyAttributeDictionary, | |
689 | .describe = SecRSAPrivateKeyCopyDescription, | |
690 | .copyPublic = SecRSAPrivateKeyCopyPublicSerialization, | |
691 | .copyOperationResult = SecRSAPrivateKeyCopyOperationResult, | |
b1ab9ed8 A |
692 | }; |
693 | ||
694 | /* Private Key API functions. */ | |
695 | SecKeyRef SecKeyCreateRSAPrivateKey(CFAllocatorRef allocator, | |
427c49bc A |
696 | const uint8_t *keyData, CFIndex keyDataLength, |
697 | SecKeyEncoding encoding) { | |
b1ab9ed8 | 698 | return SecKeyCreate(allocator, &kSecRSAPrivateKeyDescriptor, keyData, |
427c49bc | 699 | keyDataLength, encoding); |
b1ab9ed8 A |
700 | } |
701 | ||
702 | ||
703 | OSStatus SecRSAKeyGeneratePair(CFDictionaryRef parameters, | |
427c49bc | 704 | SecKeyRef *rsaPublicKey, SecKeyRef *rsaPrivateKey) { |
b1ab9ed8 | 705 | OSStatus status = errSecParam; |
5c19dc3a | 706 | |
b1ab9ed8 | 707 | CFAllocatorRef allocator = NULL; /* @@@ get from parameters. */ |
5c19dc3a | 708 | |
b1ab9ed8 A |
709 | SecKeyRef pubKey = NULL; |
710 | SecKeyRef privKey = SecKeyCreate(allocator, &kSecRSAPrivateKeyDescriptor, | |
711 | (const void*) parameters, 0, kSecGenerateKey); | |
5c19dc3a | 712 | |
fa7225c8 | 713 | require_quiet(privKey, errOut); |
5c19dc3a | 714 | |
b1ab9ed8 A |
715 | /* Create SecKeyRef's from the pkcs1 encoded keys. */ |
716 | pubKey = SecKeyCreate(allocator, &kSecRSAPublicKeyDescriptor, | |
717 | privKey->key, 0, kSecExtractPublicFromPrivate); | |
5c19dc3a | 718 | |
fa7225c8 | 719 | require_quiet(pubKey, errOut); |
5c19dc3a | 720 | |
b1ab9ed8 A |
721 | if (rsaPublicKey) { |
722 | *rsaPublicKey = pubKey; | |
723 | pubKey = NULL; | |
724 | } | |
725 | if (rsaPrivateKey) { | |
726 | *rsaPrivateKey = privKey; | |
727 | privKey = NULL; | |
728 | } | |
5c19dc3a | 729 | |
b1ab9ed8 | 730 | status = errSecSuccess; |
5c19dc3a | 731 | |
b1ab9ed8 A |
732 | errOut: |
733 | CFReleaseSafe(pubKey); | |
734 | CFReleaseSafe(privKey); | |
5c19dc3a | 735 | |
b1ab9ed8 A |
736 | return status; |
737 | } |