]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_smime/lib/cryptohi.c
Security-57337.20.44.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
46 static CSSM_CSP_HANDLE gCsp = 0;
47 static char gCssmInitialized = 0;
48
49 /* @@@ Ugly hack casting, but the extra argument at the end will be ignored. */
50 static CSSM_API_MEMORY_FUNCS memFuncs =
51 {
52 (CSSM_MALLOC)malloc,
53 (CSSM_FREE)free,
54 (CSSM_REALLOC)realloc,
55 (CSSM_CALLOC)calloc,
56 NULL
57 };
58
59 /*
60 *
61 * SecCspHandleForAlgorithm
62 * @@@ This function should get more parameters like keysize and operation required and use mds.
63 *
64 */
65 CSSM_CSP_HANDLE
66 SecCspHandleForAlgorithm(CSSM_ALGORITHMS algorithm)
67 {
68
69 if (!gCsp)
70 {
71 CSSM_VERSION version = { 2, 0 };
72 CSSM_RETURN rv;
73
74 if (!gCssmInitialized)
75 {
76 CSSM_GUID myGuid = { 0xFADE, 0, 0, { 1, 2, 3, 4, 5, 6, 7, 0 } };
77 CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
78
79 rv = CSSM_Init (&version, CSSM_PRIVILEGE_SCOPE_NONE, &myGuid, CSSM_KEY_HIERARCHY_NONE, &pvcPolicy, NULL);
80 if (rv)
81 goto loser;
82 gCssmInitialized = 1;
83 }
84
85 rv = CSSM_ModuleLoad(&gGuidAppleCSP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
86 if (rv)
87 goto loser;
88 rv = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &memFuncs, 0, CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &gCsp);
89 }
90
91 loser:
92 return gCsp;
93 }
94
95 CSSM_ALGORITHMS
96 SECOID_FindyCssmAlgorithmByTag(SECOidTag algTag)
97 {
98 const SECOidData *oidData = SECOID_FindOIDByTag(algTag);
99 return oidData ? oidData->cssmAlgorithm : CSSM_ALGID_NONE;
100 }
101
102 static SECStatus SEC_CssmRtnToSECStatus(CSSM_RETURN rv)
103 {
104 CSSM_RETURN crtn = CSSM_ERRCODE(rv);
105 switch(crtn) {
106 case CSSM_ERRCODE_USER_CANCELED:
107 case CSSM_ERRCODE_OPERATION_AUTH_DENIED:
108 case CSSM_ERRCODE_OBJECT_USE_AUTH_DENIED:
109 return SEC_ERROR_USER_CANCELLED;
110 case CSSM_ERRCODE_NO_USER_INTERACTION:
111 return SEC_ERROR_NO_USER_INTERACTION;
112 case CSSMERR_CSP_KEY_USAGE_INCORRECT:
113 return SEC_ERROR_INADEQUATE_KEY_USAGE;
114 default:
115 fprintf(stderr, "CSSM_SignData returned: %08X\n", (uint32_t)rv);
116 return SEC_ERROR_LIBRARY_FAILURE;
117 }
118 }
119
120 SECStatus
121 SEC_SignData(SECItem *result, unsigned char *buf, int len,
122 SecPrivateKeyRef pk, SECOidTag digAlgTag, SECOidTag sigAlgTag)
123 {
124 const CSSM_ACCESS_CREDENTIALS *accessCred;
125 CSSM_ALGORITHMS algorithm;
126 CSSM_CC_HANDLE cc = 0;
127 CSSM_CSP_HANDLE csp;
128 OSStatus rv;
129 CSSM_DATA dataBuf = { (uint32)len, (uint8 *)buf };
130 CSSM_DATA sig = {};
131 const CSSM_KEY *key;
132
133 algorithm = SECOID_FindyCssmAlgorithmByTag(SecCmsUtilMakeSignatureAlgorithm(digAlgTag, sigAlgTag));
134 if (!algorithm)
135 {
136 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
137 rv = SECFailure;
138 goto loser;
139 }
140
141 rv = SecKeyGetCSPHandle(pk, &csp);
142 if (rv) {
143 PORT_SetError(SEC_ERROR_BAD_KEY);
144 goto loser;
145 }
146 rv = SecKeyGetCSSMKey(pk, &key);
147 if (rv) {
148 PORT_SetError(SEC_ERROR_BAD_KEY);
149 goto loser;
150 }
151 rv = SecKeyGetCredentials(pk, CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault, &accessCred);
152 if (rv) {
153 PORT_SetError(SEC_ERROR_BAD_KEY);
154 goto loser;
155 }
156
157 rv = CSSM_CSP_CreateSignatureContext(csp, algorithm, accessCred, key, &cc);
158 if (rv) {
159 PORT_SetError(SEC_ERROR_NO_MEMORY);
160 goto loser;
161 }
162
163 rv = CSSM_SignData(cc, &dataBuf, 1, CSSM_ALGID_NONE, &sig);
164 if (rv) {
165 SECErrorCodes code = SEC_CssmRtnToSECStatus(rv);
166 PORT_SetError(code);
167 goto loser;
168 }
169
170 result->Length = sig.Length;
171 result->Data = sig.Data;
172
173 loser:
174 if (cc)
175 CSSM_DeleteContext(cc);
176
177 return rv;
178 }
179
180 SECStatus
181 SGN_Digest(SecPrivateKeyRef pk, SECOidTag digAlgTag, SECOidTag sigAlgTag, SECItem *result, SECItem *digest)
182 {
183 const CSSM_ACCESS_CREDENTIALS *accessCred;
184 CSSM_ALGORITHMS digalg, sigalg;
185 CSSM_CC_HANDLE cc = 0;
186 CSSM_CSP_HANDLE csp;
187 const CSSM_KEY *key;
188 CSSM_DATA sig = {};
189 OSStatus rv;
190
191 digalg = SECOID_FindyCssmAlgorithmByTag(digAlgTag);
192 sigalg = SECOID_FindyCssmAlgorithmByTag(sigAlgTag);
193 if (!digalg || !sigalg)
194 {
195 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
196 rv = SECFailure;
197 goto loser;
198 }
199
200 rv = SecKeyGetCSPHandle(pk, &csp);
201 if (rv) {
202 PORT_SetError(SEC_ERROR_BAD_KEY);
203 goto loser;
204 }
205 rv = SecKeyGetCSSMKey(pk, &key);
206 if (rv) {
207 PORT_SetError(SEC_ERROR_BAD_KEY);
208 goto loser;
209 }
210 rv = SecKeyGetCredentials(pk, CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault, &accessCred);
211 if (rv) {
212 PORT_SetError(SEC_ERROR_BAD_KEY);
213 goto loser;
214 }
215
216 rv = CSSM_CSP_CreateSignatureContext(csp, sigalg, accessCred, key, &cc);
217 if (rv) {
218 PORT_SetError(SEC_ERROR_NO_MEMORY);
219 goto loser;
220 }
221
222 rv = CSSM_SignData(cc, digest, 1, digalg, &sig);
223 if (rv) {
224 SECErrorCodes code = SEC_CssmRtnToSECStatus(rv);
225 PORT_SetError(code);
226 goto loser;
227 }
228
229 result->Length = sig.Length;
230 result->Data = sig.Data;
231
232 loser:
233 if (cc)
234 CSSM_DeleteContext(cc);
235
236 return rv;
237 }
238
239 SECStatus
240 VFY_VerifyData(unsigned char *buf, int len,
241 SecPublicKeyRef pk, SECItem *sig,
242 SECOidTag digAlgTag, SECOidTag sigAlgTag, void *wincx)
243 {
244 SECOidTag algTag;
245 CSSM_ALGORITHMS algorithm;
246 CSSM_CC_HANDLE cc = 0;
247 CSSM_CSP_HANDLE csp;
248 OSStatus rv = SECFailure;
249 CSSM_DATA dataBuf = { (uint32)len, (uint8 *)buf };
250 const CSSM_KEY *key;
251
252 algTag = SecCmsUtilMakeSignatureAlgorithm(digAlgTag, sigAlgTag);
253 algorithm = SECOID_FindyCssmAlgorithmByTag(algTag);
254 if (!algorithm)
255 {
256 rv = algTag == SEC_OID_UNKNOWN ? SecCmsVSSignatureAlgorithmUnknown : SecCmsVSSignatureAlgorithmUnsupported;
257 goto loser;
258 }
259
260 rv = SecKeyGetCSPHandle(pk, &csp);
261 if (rv)
262 goto loser;
263 rv = SecKeyGetCSSMKey(pk, &key);
264 if (rv)
265 goto loser;
266
267 rv = CSSM_CSP_CreateSignatureContext(csp, algorithm, NULL, key, &cc);
268 if (rv)
269 goto loser;
270
271 rv = CSSM_VerifyData(cc, &dataBuf, 1, CSSM_ALGID_NONE, sig);
272
273 loser:
274 if (cc)
275 CSSM_DeleteContext(cc);
276
277 return rv;
278 }
279
280 SECStatus
281 VFY_VerifyDigest(SECItem *digest, SecPublicKeyRef pk,
282 SECItem *sig, SECOidTag digAlgTag, SECOidTag sigAlgTag, void *wincx)
283 {
284 CSSM_ALGORITHMS sigalg, digalg;
285 CSSM_CC_HANDLE cc = 0;
286 CSSM_CSP_HANDLE csp;
287 const CSSM_KEY *key;
288 OSStatus rv;
289
290 digalg = SECOID_FindyCssmAlgorithmByTag(digAlgTag);
291 sigalg = SECOID_FindyCssmAlgorithmByTag(sigAlgTag);
292 if (!digalg || !sigalg)
293 {
294 rv = digAlgTag == SEC_OID_UNKNOWN || sigAlgTag == SEC_OID_UNKNOWN ? SecCmsVSSignatureAlgorithmUnknown : SecCmsVSSignatureAlgorithmUnsupported;
295 goto loser;
296 }
297
298 rv = SecKeyGetCSPHandle(pk, &csp);
299 if (rv)
300 goto loser;
301 rv = SecKeyGetCSSMKey(pk, &key);
302 if (rv)
303 goto loser;
304
305 rv = CSSM_CSP_CreateSignatureContext(csp, sigalg, NULL, key, &cc);
306 if (rv)
307 goto loser;
308
309 rv = CSSM_VerifyData(cc, digest, 1, digalg, sig);
310
311 loser:
312 if (cc)
313 CSSM_DeleteContext(cc);
314
315 return rv;
316 }
317
318 SECStatus
319 WRAP_PubWrapSymKey(SecPublicKeyRef publickey,
320 SecSymmetricKeyRef bulkkey,
321 CSSM_DATA_PTR encKey)
322 {
323 CSSM_WRAP_KEY wrappedKey = {};
324 //CSSM_WRAP_KEY wrappedPk = {}
325 //CSSM_KEY upk = {};
326 CSSM_CC_HANDLE cc = 0;
327 CSSM_CSP_HANDLE pkCsp, bkCsp;
328 const CSSM_KEY *pk, *bk, *pubkey;
329 OSStatus rv;
330 CSSM_ACCESS_CREDENTIALS accessCred = {};
331
332 rv = SecKeyGetCSPHandle(publickey, &pkCsp);
333 if (rv)
334 goto loser;
335 rv = SecKeyGetCSSMKey(publickey, &pk);
336 if (rv)
337 goto loser;
338
339 rv = SecKeyGetCSPHandle(bulkkey, &bkCsp);
340 if (rv)
341 goto loser;
342 rv = SecKeyGetCSSMKey(bulkkey, &bk);
343 if (rv)
344 goto loser;
345
346 #if 1
347 pubkey = pk;
348 #else
349 /* We need to get the publickey out of it's pkCsp and into the bkCsp so we can operate with it. */
350
351 /* Make a NULL wrap symmetric context to extract the public key from pkCsp. */
352 rv = CSSM_CSP_CreateSymmetricContext(pkCsp,
353 CSSM_ALGID_NONE,
354 CSSM_MODE_NONE,
355 NULL, /* accessCred */
356 NULL, /* key */
357 NULL, /* iv */
358 CSSM_PADDING_NONE,
359 NULL, /* reserved */
360 &cc);
361 if (rv)
362 goto loser;
363 rv = CSSM_WrapKey(cc,
364 NULL /* accessCred */,
365 pk,
366 NULL /* descriptiveData */,
367 &wrappedPk);
368 CSSM_DeleteContext(cc);
369 cc = 0;
370
371 /* Make a NULL unwrap symmetric context to import the public key into bkCsp. */
372 rv = CSSM_CSP_CreateSymmetricContext(bkCsp,
373 CSSM_ALGID_NONE,
374 CSSM_MODE_NONE,
375 NULL, /* accessCred */
376 NULL, /* key */
377 NULL, /* iv */
378 CSSM_PADDING_NONE,
379 NULL, /* reserved */
380 &cc);
381 if (rv)
382 goto loser;
383 rv = CSSM_UnwrapKey(cc, NULL, &wrappedPk, usage, attr, NULL /* label */, NULL /* rcc */, &upk, NULL /* descriptiveData */);
384 CSSM_DeleteContext(cc);
385 cc = 0;
386
387 pubkey = &upk;
388 #endif
389
390 rv = CSSM_CSP_CreateAsymmetricContext(bkCsp,
391 pubkey->KeyHeader.AlgorithmId,
392 &accessCred,
393 pubkey,
394 CSSM_PADDING_PKCS1,
395 &cc);
396 if (rv)
397 goto loser;
398
399 {
400 /* Set the wrapped key format to indicate we want just the raw bits encrypted. */
401 CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, sizeof(uint32) };
402 contextAttribute.Attribute.Uint32 = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
403 rv = CSSM_UpdateContextAttributes(cc, 1, &contextAttribute);
404 if (rv)
405 goto loser;
406 }
407
408 {
409 /* Set the mode to CSSM_ALGMODE_PKCS1_EME_V15. */
410 CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_MODE, sizeof(uint32) };
411 contextAttribute.Attribute.Uint32 = CSSM_ALGMODE_NONE; /* CSSM_ALGMODE_PKCS1_EME_V15 */
412 rv = CSSM_UpdateContextAttributes(cc, 1, &contextAttribute);
413 if (rv)
414 goto loser;
415 }
416
417 {
418 // @@@ Stick in an empty initVector to work around a csp bug.
419 CSSM_DATA initVector = {};
420 CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(CSSM_DATA_PTR) };
421 contextAttribute.Attribute.Data = &initVector;
422 rv = CSSM_UpdateContextAttributes(cc, 1, &contextAttribute);
423 if (rv)
424 goto loser;
425 }
426
427 rv = CSSM_WrapKey(cc,
428 &accessCred,
429 bk,
430 NULL, /* descriptiveData */
431 &wrappedKey);
432 if (rv)
433 goto loser;
434
435 // @@@ Fix leaks!
436 if (encKey->Length < wrappedKey.KeyData.Length)
437 abort();
438 encKey->Length = wrappedKey.KeyData.Length;
439 memcpy(encKey->Data, wrappedKey.KeyData.Data, encKey->Length);
440 CSSM_FreeKey(bkCsp, NULL /* credentials */, &wrappedKey, FALSE);
441
442 loser:
443 if (cc)
444 CSSM_DeleteContext(cc);
445
446 return rv;
447 }
448
449 SecSymmetricKeyRef
450 WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, CSSM_DATA_PTR encKey, SECOidTag bulkalgtag)
451 {
452 SecSymmetricKeyRef bulkkey = NULL;
453 CSSM_WRAP_KEY wrappedKey = {};
454 CSSM_CC_HANDLE cc = 0;
455 CSSM_CSP_HANDLE pkCsp;
456 const CSSM_KEY *pk;
457 CSSM_KEY unwrappedKey = {};
458 const CSSM_ACCESS_CREDENTIALS *accessCred;
459 CSSM_DATA descriptiveData = {};
460 CSSM_ALGORITHMS bulkalg;
461 OSStatus rv;
462
463 rv = SecKeyGetCSPHandle(privkey, &pkCsp);
464 if (rv)
465 goto loser;
466 rv = SecKeyGetCSSMKey(privkey, &pk);
467 if (rv)
468 goto loser;
469 rv = SecKeyGetCredentials(privkey,
470 CSSM_ACL_AUTHORIZATION_DECRYPT, /* @@@ Should be UNWRAP */
471 kSecCredentialTypeDefault,
472 &accessCred);
473 if (rv)
474 goto loser;
475
476 bulkalg = SECOID_FindyCssmAlgorithmByTag(bulkalgtag);
477 if (!bulkalg)
478 {
479 rv = SEC_ERROR_INVALID_ALGORITHM;
480 goto loser;
481 }
482
483 rv = CSSM_CSP_CreateAsymmetricContext(pkCsp,
484 pk->KeyHeader.AlgorithmId,
485 accessCred,
486 pk,
487 CSSM_PADDING_PKCS1,
488 &cc);
489 if (rv)
490 goto loser;
491
492 {
493 // @@@ Stick in an empty initvector to work around a csp bug.
494 CSSM_DATA initVector = {};
495 CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(CSSM_DATA_PTR) };
496 contextAttribute.Attribute.Data = &initVector;
497 rv = CSSM_UpdateContextAttributes(cc, 1, &contextAttribute);
498 if (rv)
499 goto loser;
500 }
501
502 wrappedKey.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
503 wrappedKey.KeyHeader.BlobType = CSSM_KEYBLOB_WRAPPED;
504 wrappedKey.KeyHeader.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
505 wrappedKey.KeyHeader.AlgorithmId = bulkalg;
506 wrappedKey.KeyHeader.KeyClass = CSSM_KEYCLASS_SESSION_KEY;
507 wrappedKey.KeyHeader.WrapAlgorithmId = pk->KeyHeader.AlgorithmId;
508 wrappedKey.KeyHeader.WrapMode = CSSM_ALGMODE_NONE; /* CSSM_ALGMODE_PKCS1_EME_V15 */
509 wrappedKey.KeyData = *encKey;
510
511 rv = CSSM_UnwrapKey(cc,
512 NULL, /* publicKey */
513 &wrappedKey,
514 CSSM_KEYUSE_DECRYPT,
515 CSSM_KEYATTR_EXTRACTABLE /* | CSSM_KEYATTR_RETURN_DATA */,
516 NULL, /* keyLabel */
517 NULL, /* rcc */
518 &unwrappedKey,
519 &descriptiveData);
520 if (rv) {
521 SECErrorCodes code;
522 if (CSSM_ERRCODE(rv) == CSSM_ERRCODE_USER_CANCELED
523 || CSSM_ERRCODE(rv) == CSSM_ERRCODE_OPERATION_AUTH_DENIED
524 || CSSM_ERRCODE(rv) == CSSM_ERRCODE_OBJECT_USE_AUTH_DENIED)
525 code = SEC_ERROR_USER_CANCELLED;
526 else if (CSSM_ERRCODE(rv) == CSSM_ERRCODE_NO_USER_INTERACTION
527 || rv == CSSMERR_CSP_KEY_USAGE_INCORRECT)
528 code = SEC_ERROR_INADEQUATE_KEY_USAGE;
529 else
530 {
531 fprintf(stderr, "CSSM_UnwrapKey returned: %08X\n", (uint32_t)rv);
532 code = SEC_ERROR_LIBRARY_FAILURE;
533 }
534
535 PORT_SetError(code);
536 goto loser;
537 }
538
539 // @@@ Export this key from the csp/dl and import it to the standard csp
540 rv = SecKeyCreateWithCSSMKey(&unwrappedKey, &bulkkey);
541 if (rv)
542 goto loser;
543
544 loser:
545 if (rv)
546 PORT_SetError(rv);
547
548 if (cc)
549 CSSM_DeleteContext(cc);
550
551 return bulkkey;
552 }