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 46static CSSM_CSP_HANDLE gCsp = 0; 47static char gCssmInitialized = 0; 48 49/* @@@ Ugly hack casting, but the extra argument at the end will be ignored. */ 50static 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 */ 65CSSM_CSP_HANDLE 66SecCspHandleForAlgorithm(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 91loser: 92 return gCsp; 93} 94 95CSSM_ALGORITHMS 96SECOID_FindyCssmAlgorithmByTag(SECOidTag algTag) 97{ 98 const SECOidData *oidData = SECOID_FindOIDByTag(algTag); 99 return oidData ? oidData->cssmAlgorithm : CSSM_ALGID_NONE; 100} 101 102static 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 120SECStatus 121SEC_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 173loser: 174 if (cc) 175 CSSM_DeleteContext(cc); 176 177 return rv; 178} 179 180SECStatus 181SGN_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 232loser: 233 if (cc) 234 CSSM_DeleteContext(cc); 235 236 return rv; 237} 238 239SECStatus 240VFY_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 273loser: 274 if (cc) 275 CSSM_DeleteContext(cc); 276 277 return rv; 278} 279 280SECStatus 281VFY_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 311loser: 312 if (cc) 313 CSSM_DeleteContext(cc); 314 315 return rv; 316} 317 318SECStatus 319WRAP_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 442loser: 443 if (cc) 444 CSSM_DeleteContext(cc); 445 446 return rv; 447} 448 449SecSymmetricKeyRef 450WRAP_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 544loser: 545 if (rv) 546 PORT_SetError(rv); 547 548 if (cc) 549 CSSM_DeleteContext(cc); 550 551 return bulkkey; 552} 553