]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_smime/lib/cryptohi.c
Security-57740.51.3.tar.gz
[apple/security.git] / OSX / libsecurity_smime / lib / cryptohi.c
1 /*
2 * crypto.h - public data structures and prototypes for the crypto library
3 *
4 * The contents of this file are subject to the Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file
6 * except in compliance with the License. You may obtain a copy of
7 * the License at http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS
10 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11 * implied. See the License for the specific language governing
12 * rights and limitations under the License.
13 *
14 * The Original Code is the Netscape security libraries.
15 *
16 * The Initial Developer of the Original Code is Netscape
17 * Communications Corporation. Portions created by Netscape are
18 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
19 * Rights Reserved.
20 *
21 * Contributor(s):
22 *
23 * Alternatively, the contents of this file may be used under the
24 * terms of the GNU General Public License Version 2 or later (the
25 * "GPL"), in which case the provisions of the GPL are applicable
26 * instead of those above. If you wish to allow use of your
27 * version of this file only under the terms of the GPL and not to
28 * allow others to use your version of this file under the MPL,
29 * indicate your decision by deleting the provisions above and
30 * replace them with the notice and other provisions required by
31 * the GPL. If you do not delete the provisions above, a recipient
32 * may use your version of this file under either the MPL or the
33 * GPL.
34 */
35
36 #include "cryptohi.h"
37
38 #include "secoid.h"
39 #include "cmspriv.h"
40 #include <security_asn1/secerr.h>
41 #include <Security/cssmapi.h>
42 #include <Security/cssmapi.h>
43 #include <Security/SecKeyPriv.h>
44 #include <Security/cssmapple.h>
45 #include <Security/SecItem.h>
46
47 #ifdef NDEBUG
48 #define CSSM_PERROR(f, r)
49 #define dprintf(args...)
50 #else
51 #define CSSM_PERROR(f, r) cssmPerror(f, r)
52 #define dprintf(args...) fprintf(stderr, args)
53 #endif
54
55 static CSSM_CSP_HANDLE gCsp = 0;
56 static char gCssmInitialized = 0;
57
58 /* @@@ Ugly hack casting, but the extra argument at the end will be ignored. */
59 static CSSM_API_MEMORY_FUNCS memFuncs =
60 {
61 (CSSM_MALLOC)malloc,
62 (CSSM_FREE)free,
63 (CSSM_REALLOC)realloc,
64 (CSSM_CALLOC)calloc,
65 NULL
66 };
67
68 /*
69 *
70 * SecCspHandleForAlgorithm
71 * @@@ This function should get more parameters like keysize and operation required and use mds.
72 *
73 */
74 CSSM_CSP_HANDLE
75 SecCspHandleForAlgorithm(CSSM_ALGORITHMS algorithm)
76 {
77
78 if (!gCsp)
79 {
80 CSSM_VERSION version = { 2, 0 };
81 CSSM_RETURN rv;
82
83 if (!gCssmInitialized)
84 {
85 CSSM_GUID myGuid = { 0xFADE, 0, 0, { 1, 2, 3, 4, 5, 6, 7, 0 } };
86 CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
87
88 rv = CSSM_Init (&version, CSSM_PRIVILEGE_SCOPE_NONE, &myGuid, CSSM_KEY_HIERARCHY_NONE, &pvcPolicy, NULL);
89 if (rv)
90 goto loser;
91 gCssmInitialized = 1;
92 }
93
94 rv = CSSM_ModuleLoad(&gGuidAppleCSP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
95 if (rv)
96 goto loser;
97 rv = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &memFuncs, 0, CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &gCsp);
98 }
99
100 loser:
101 return gCsp;
102 }
103
104 OSStatus cmsNullWrapKey(SecKeyRef refKey,
105 CSSM_KEY_PTR rawKey)
106 {
107 CSSM_DATA descData = {0, 0};
108 CSSM_RETURN crtn;
109 CSSM_CC_HANDLE ccHand;
110 CSSM_ACCESS_CREDENTIALS creds;
111 CSSM_CSP_HANDLE refCspHand = CSSM_INVALID_HANDLE;
112 const CSSM_KEY *cssmKey = NULL;
113 uint32 keyAttr;
114
115 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
116 memset(rawKey, 0, sizeof(CSSM_KEY));
117
118 crtn = SecKeyGetCSSMKey(refKey, &cssmKey);
119 if(crtn) {
120 CSSM_PERROR("SecKeyGetCSSMKey", crtn);
121 goto loser;
122 }
123 crtn = SecKeyGetCSPHandle(refKey, &refCspHand);
124 if(crtn) {
125 CSSM_PERROR("SecKeyGetCSPHandle", crtn);
126 goto loser;
127 }
128
129 crtn = CSSM_CSP_CreateSymmetricContext(refCspHand,
130 CSSM_ALGID_NONE,
131 CSSM_ALGMODE_NONE,
132 &creds,
133 NULL, // unwrappingKey
134 NULL, // initVector
135 CSSM_PADDING_NONE,
136 0, // Params
137 &ccHand);
138 if(crtn) {
139 CSSM_PERROR("CSSM_CSP_CreateSymmetricContext", crtn);
140 return crtn;
141 }
142
143 keyAttr = rawKey->KeyHeader.KeyAttr;
144 keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE |
145 CSSM_KEYATTR_MODIFIABLE);
146 keyAttr |= CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
147 crtn = CSSM_WrapKey(ccHand,
148 &creds,
149 cssmKey,
150 &descData,
151 rawKey);
152 if(crtn != CSSM_OK) {
153 CSSM_PERROR("CSSM_WrapKey", crtn);
154 }
155 CSSM_DeleteContext(ccHand);
156
157 loser:
158 return crtn;
159 }
160
161 CSSM_ALGORITHMS
162 SECOID_FindyCssmAlgorithmByTag(SECOidTag algTag)
163 {
164 const SECOidData *oidData = SECOID_FindOIDByTag(algTag);
165 return oidData ? oidData->cssmAlgorithm : CSSM_ALGID_NONE;
166 }
167
168
169 static void SEC_PrintCFError(CFErrorRef CF_RELEASES_ARGUMENT error) {
170 if (error) {
171 CFStringRef errorDesc = CFErrorCopyDescription(error);
172 dprintf("SecKey API returned: %ld, %s", CFErrorGetCode(error),
173 errorDesc ? CFStringGetCStringPtr(errorDesc, kCFStringEncodingUTF8) : "");
174 CFRelease(error);
175 if (errorDesc) { CFRelease(errorDesc); }
176 }
177
178 }
179
180 /* The new SecKey API has made this very painful */
181 static SecKeyAlgorithm SECOID_FindSecKeyAlgorithmByTags(SECOidTag sigAlgTag, SECOidTag digAlgTag, bool isDigest) {
182 switch(sigAlgTag) {
183 case(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION):
184 if (digAlgTag == SEC_OID_MD5) {
185 return ((isDigest) ? kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5 :
186 kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5);
187 }
188 break;
189 case(SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION):
190 if (digAlgTag == SEC_OID_SHA1) {
191 return ((isDigest) ? kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
192 : kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1);
193 }
194 break;
195 case(SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION):
196 if (digAlgTag == SEC_OID_SHA256) {
197 return ((isDigest) ? kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
198 : kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256);
199 }
200 break;
201 case(SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION):
202 if (digAlgTag == SEC_OID_SHA384) {
203 return ((isDigest) ? kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
204 : kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384);
205 }
206 break;
207 case(SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION):
208 if (digAlgTag == SEC_OID_SHA512) {
209 return ((isDigest) ? kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
210 : kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512);
211 }
212 break;
213 case(SEC_OID_PKCS1_RSA_ENCRYPTION):
214 switch (digAlgTag) {
215 case (SEC_OID_MD5):
216 return ((isDigest) ? kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5 :
217 kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5);
218 case(SEC_OID_SHA1):
219 return ((isDigest) ? kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
220 : kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1);
221 case(SEC_OID_SHA256):
222 return ((isDigest) ? kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
223 : kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256);
224 case(SEC_OID_SHA384):
225 return ((isDigest) ? kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
226 : kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384);
227 case(SEC_OID_SHA512):
228 return ((isDigest) ? kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
229 : kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512);
230 default:
231 return NULL;
232 }
233 case(SEC_OID_ECDSA_WithSHA1):
234 if (digAlgTag == SEC_OID_SHA1) {
235 return ((isDigest) ? kSecKeyAlgorithmECDSASignatureDigestX962
236 : kSecKeyAlgorithmECDSASignatureMessageX962SHA1);
237 }
238 break;
239 case(SEC_OID_ECDSA_WITH_SHA256):
240 if (digAlgTag == SEC_OID_SHA256) {
241 return ((isDigest) ? kSecKeyAlgorithmECDSASignatureDigestX962
242 : kSecKeyAlgorithmECDSASignatureMessageX962SHA256);
243 }
244 break;
245 case(SEC_OID_ECDSA_WITH_SHA384):
246 if (digAlgTag == SEC_OID_SHA384) {
247 return ((isDigest) ? kSecKeyAlgorithmECDSASignatureDigestX962
248 : kSecKeyAlgorithmECDSASignatureMessageX962SHA384);
249 }
250 break;
251 case(SEC_OID_ECDSA_WITH_SHA512):
252 if (digAlgTag == SEC_OID_SHA512) {
253 return ((isDigest) ? kSecKeyAlgorithmECDSASignatureDigestX962
254 : kSecKeyAlgorithmECDSASignatureMessageX962SHA512);
255 }
256 break;
257 case(SEC_OID_EC_PUBLIC_KEY):
258 case(SEC_OID_SECP_256_R1):
259 case(SEC_OID_SECP_384_R1):
260 case(SEC_OID_SECP_521_R1):
261 switch (digAlgTag) {
262 case(SEC_OID_SHA1):
263 return ((isDigest) ? kSecKeyAlgorithmECDSASignatureDigestX962
264 : kSecKeyAlgorithmECDSASignatureMessageX962SHA1);
265 case(SEC_OID_SHA256):
266 return ((isDigest) ? kSecKeyAlgorithmECDSASignatureDigestX962
267 : kSecKeyAlgorithmECDSASignatureMessageX962SHA256);
268 case(SEC_OID_SHA384):
269 return ((isDigest) ? kSecKeyAlgorithmECDSASignatureDigestX962
270 : kSecKeyAlgorithmECDSASignatureMessageX962SHA384);
271 case(SEC_OID_SHA512):
272 return ((isDigest) ? kSecKeyAlgorithmECDSASignatureDigestX962
273 : kSecKeyAlgorithmECDSASignatureMessageX962SHA512);
274 default:
275 return NULL;
276 }
277 default:
278 return NULL;
279 }
280 return NULL;
281 }
282
283 CFStringRef SECOID_CopyKeyTypeByTag(SECOidTag tag) {
284 CFStringRef keyType = NULL;
285
286 switch(tag) {
287 case(SEC_OID_RC2_CBC):
288 case(SEC_OID_CMS_RC2_KEY_WRAP):
289 keyType = kSecAttrKeyTypeRC2;
290 break;
291 case(SEC_OID_RC4):
292 keyType = kSecAttrKeyTypeRC4;
293 break;
294 case(SEC_OID_DES_ECB):
295 case(SEC_OID_DES_CBC):
296 case(SEC_OID_DES_OFB):
297 case(SEC_OID_DES_CFB):
298 keyType = kSecAttrKeyTypeDES;
299 break;
300 case(SEC_OID_DES_EDE):
301 case(SEC_OID_DES_EDE3_CBC):
302 case(SEC_OID_CMS_3DES_KEY_WRAP):
303 keyType = kSecAttrKeyType3DES;
304 break;
305 case(SEC_OID_AES_128_ECB):
306 case(SEC_OID_AES_128_CBC):
307 case(SEC_OID_AES_192_ECB):
308 case(SEC_OID_AES_192_CBC):
309 case(SEC_OID_AES_256_ECB):
310 case(SEC_OID_AES_256_CBC):
311 case(SEC_OID_AES_128_KEY_WRAP):
312 case(SEC_OID_AES_192_KEY_WRAP):
313 case(SEC_OID_AES_256_KEY_WRAP):
314 keyType = kSecAttrKeyTypeAES;
315 break;
316 default:
317 keyType = NULL;
318 }
319
320 return keyType;
321 }
322
323 static SECStatus SGN_SignAll(uint8_t *buf, size_t len,
324 SecPrivateKeyRef pk, SECItem *resultSignature,
325 SECOidTag digAlgTag, SECOidTag sigAlgTag,
326 bool isDigest) {
327 OSStatus rv = SECFailure;
328 CFDataRef signature = NULL, dataToSign = NULL;
329 CFErrorRef error = NULL;
330 SecKeyAlgorithm keyAlg = NULL;
331
332 keyAlg = SECOID_FindSecKeyAlgorithmByTags(sigAlgTag, digAlgTag, isDigest);
333
334 /* we no longer support signing with MD5 */
335 if (keyAlg == kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5 ||
336 keyAlg == kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5) {
337 dprintf("CMS signature failed: MD5 algorithm is disallowed for generating signatures.");
338 rv = SEC_ERROR_INVALID_ALGORITHM;
339 goto out;
340 }
341
342 if (keyAlg == NULL) {
343 rv = SEC_ERROR_INVALID_ALGORITHM;
344 goto out;
345 }
346
347 dataToSign = CFDataCreate(NULL, buf, len);
348 if (!dataToSign) {
349 goto out;
350 }
351
352 signature = SecKeyCreateSignature(pk, keyAlg, dataToSign, &error);
353 if (!signature) {
354 goto out;
355 }
356
357 CFIndex signatureLength = CFDataGetLength(signature);
358 if (signatureLength < 0 || signatureLength > 1024) {
359 goto out;
360 }
361 resultSignature->Data = (uint8_t *)malloc(signatureLength);
362 if (!resultSignature->Data) {
363 goto out;
364 }
365
366 memcpy(resultSignature->Data, CFDataGetBytePtr(signature), signatureLength);
367 resultSignature->Length = signatureLength;
368 rv = SECSuccess;
369
370 out:
371 if (signature) { CFRelease(signature); }
372 if (dataToSign) {CFRelease(dataToSign); }
373 SEC_PrintCFError(error);
374 if (rv) {
375 PORT_SetError(rv);
376 }
377 return rv;
378 }
379
380 SECStatus
381 SEC_SignData(SECItem *result, unsigned char *buf, int len,
382 SecPrivateKeyRef pk, SECOidTag digAlgTag, SECOidTag sigAlgTag)
383 {
384 return SGN_SignAll(buf, len, pk, result, digAlgTag, sigAlgTag, false);
385 }
386
387 SECStatus
388 SGN_Digest(SecPrivateKeyRef pk, SECOidTag digAlgTag, SECOidTag sigAlgTag, SECItem *result, SECItem *digest)
389 {
390 return SGN_SignAll(digest->Data, digest->Length, pk, result, digAlgTag, sigAlgTag, true);
391 }
392
393 static SECStatus VFY_VerifyAll(uint8_t *buf, size_t len,
394 SecPublicKeyRef pk, SECItem *sig,
395 SECOidTag digAlgTag, SECOidTag sigAlgTag,
396 bool isDigest) {
397 OSStatus rv = SECFailure;
398 CFDataRef signature = NULL, data = NULL;
399 CFErrorRef error = NULL;
400 SecKeyAlgorithm keyAlg = NULL;
401
402 signature = CFDataCreate(NULL, sig->Data, sig->Length);
403 data = CFDataCreate(NULL, buf, len);
404 if (!signature || !data) {
405 goto out;
406 }
407
408 keyAlg = SECOID_FindSecKeyAlgorithmByTags(sigAlgTag, digAlgTag, isDigest);
409 if (keyAlg == NULL) {
410 rv = SEC_ERROR_INVALID_ALGORITHM;
411 goto out;
412 }
413
414 if(SecKeyVerifySignature(pk, keyAlg, data, signature, &error)) {
415 rv = SECSuccess;
416 }
417
418 out:
419 if (signature) { CFRelease(signature); }
420 if (data) { CFRelease(data); }
421 SEC_PrintCFError(error);
422 if (rv) {
423 PORT_SetError(rv);
424 }
425 return rv;
426 }
427
428 SECStatus
429 VFY_VerifyData(unsigned char *buf, int len,
430 SecPublicKeyRef pk, SECItem *sig,
431 SECOidTag digAlgTag, SECOidTag sigAlgTag, void *wincx)
432 {
433 return VFY_VerifyAll(buf, len, pk, sig,
434 digAlgTag, sigAlgTag, false);
435 }
436
437 SECStatus
438 VFY_VerifyDigest(SECItem *digest, SecPublicKeyRef pk,
439 SECItem *sig, SECOidTag digAlgTag, SECOidTag sigAlgTag, void *wincx)
440 {
441 return VFY_VerifyAll(digest->Data, digest->Length, pk, sig,
442 digAlgTag, sigAlgTag, true);
443 }
444
445 SECStatus
446 WRAP_PubWrapSymKey(SecPublicKeyRef publickey,
447 SecSymmetricKeyRef bulkkey,
448 CSSM_DATA_PTR encKey)
449 {
450 OSStatus rv;
451 CSSM_KEY bk;
452
453 rv = cmsNullWrapKey(bulkkey, &bk);
454 if (rv) {
455 return rv;
456 }
457
458 return SecKeyEncrypt(publickey, kSecPaddingPKCS1,
459 bk.KeyData.Data, bk.KeyData.Length,
460 encKey->Data, &encKey->Length);
461 }
462
463
464 SecSymmetricKeyRef
465 WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, CSSM_DATA_PTR encKey, SECOidTag bulkalgtag)
466 {
467 CFDataRef encryptedKey = NULL, bulkkey = NULL;
468 CFMutableDictionaryRef keyparams = NULL;
469 CFStringRef keyType = NULL;
470 CFErrorRef error = NULL;
471 SecSymmetricKeyRef bk = NULL;
472
473 /* decrypt the key */
474 encryptedKey = CFDataCreate(NULL, encKey->Data, encKey->Length);
475 if (!encryptedKey) {
476 goto out;
477 }
478
479 bulkkey = SecKeyCreateDecryptedData(privkey, kSecKeyAlgorithmRSAEncryptionPKCS1, encryptedKey, &error);
480 if (!bulkkey) {
481 goto out;
482 }
483
484 /* create the SecSymmetricKeyRef */
485 keyType = SECOID_CopyKeyTypeByTag(bulkalgtag);
486 if (!keyType) {
487 goto out;
488 }
489
490 keyparams = CFDictionaryCreateMutable(NULL, 1,
491 &kCFTypeDictionaryKeyCallBacks,
492 &kCFTypeDictionaryValueCallBacks);
493 if (!keyparams) {
494 goto out;
495 }
496
497 CFDictionaryAddValue(keyparams, kSecAttrKeyType, keyType);
498 bk = SecKeyCreateFromData(keyparams, bulkkey, NULL);
499
500 out:
501 if (encryptedKey) { CFRelease(encryptedKey); }
502 if (bulkkey) { CFRelease(bulkkey); }
503 if (keyparams) { CFRelease(keyparams); }
504 if (keyType) { CFRelease(keyType); }
505 SEC_PrintCFError(error);
506 return bk;
507 }