security/nss/lib/pk11wrap/pk11nobj.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 /*
michael@0 5 * This file manages Netscape specific PKCS #11 objects (CRLs, Trust objects,
michael@0 6 * etc).
michael@0 7 */
michael@0 8
michael@0 9 #include "secport.h"
michael@0 10 #include "seccomon.h"
michael@0 11 #include "secmod.h"
michael@0 12 #include "secmodi.h"
michael@0 13 #include "secmodti.h"
michael@0 14 #include "pkcs11.h"
michael@0 15 #include "pk11func.h"
michael@0 16 #include "cert.h"
michael@0 17 #include "certi.h"
michael@0 18 #include "secitem.h"
michael@0 19 #include "sechash.h"
michael@0 20 #include "secoid.h"
michael@0 21
michael@0 22 #include "certdb.h"
michael@0 23 #include "secerr.h"
michael@0 24 #include "sslerr.h"
michael@0 25
michael@0 26 #include "pki3hack.h"
michael@0 27 #include "dev3hack.h"
michael@0 28
michael@0 29 #include "devm.h"
michael@0 30 #include "pki.h"
michael@0 31 #include "pkim.h"
michael@0 32
michael@0 33 extern const NSSError NSS_ERROR_NOT_FOUND;
michael@0 34
michael@0 35 CK_TRUST
michael@0 36 pk11_GetTrustField(PK11SlotInfo *slot, PLArenaPool *arena,
michael@0 37 CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type)
michael@0 38 {
michael@0 39 CK_TRUST rv = 0;
michael@0 40 SECItem item;
michael@0 41
michael@0 42 item.data = NULL;
michael@0 43 item.len = 0;
michael@0 44
michael@0 45 if( SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item) ) {
michael@0 46 PORT_Assert(item.len == sizeof(CK_TRUST));
michael@0 47 PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST));
michael@0 48 /* Damn, is there an endian problem here? */
michael@0 49 return rv;
michael@0 50 }
michael@0 51
michael@0 52 return 0;
michael@0 53 }
michael@0 54
michael@0 55 PRBool
michael@0 56 pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust)
michael@0 57 {
michael@0 58 PLArenaPool *arena;
michael@0 59
michael@0 60 CK_ATTRIBUTE tobjTemplate[] = {
michael@0 61 { CKA_CLASS, NULL, 0 },
michael@0 62 { CKA_CERT_SHA1_HASH, NULL, 0 },
michael@0 63 };
michael@0 64
michael@0 65 CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
michael@0 66 CK_OBJECT_HANDLE tobjID;
michael@0 67 unsigned char sha1_hash[SHA1_LENGTH];
michael@0 68
michael@0 69 CK_TRUST serverAuth, codeSigning, emailProtection, clientAuth;
michael@0 70
michael@0 71 PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len);
michael@0 72
michael@0 73 PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc));
michael@0 74 PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash,
michael@0 75 SHA1_LENGTH);
michael@0 76
michael@0 77 tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate,
michael@0 78 sizeof(tobjTemplate)/sizeof(tobjTemplate[0]));
michael@0 79 if( CK_INVALID_HANDLE == tobjID ) {
michael@0 80 return PR_FALSE;
michael@0 81 }
michael@0 82
michael@0 83 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 84 if( NULL == arena ) return PR_FALSE;
michael@0 85
michael@0 86 /* Unfortunately, it seems that PK11_GetAttributes doesn't deal
michael@0 87 * well with nonexistent attributes. I guess we have to check
michael@0 88 * the trust info fields one at a time.
michael@0 89 */
michael@0 90
michael@0 91 /* We could verify CKA_CERT_HASH here */
michael@0 92
michael@0 93 /* We could verify CKA_EXPIRES here */
michael@0 94
michael@0 95
michael@0 96 /* "Purpose" trust information */
michael@0 97 serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH);
michael@0 98 clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH);
michael@0 99 codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING);
michael@0 100 emailProtection = pk11_GetTrustField(slot, arena, tobjID,
michael@0 101 CKA_TRUST_EMAIL_PROTECTION);
michael@0 102 /* Here's where the fun logic happens. We have to map back from the
michael@0 103 * key usage, extended key usage, purpose, and possibly other trust values
michael@0 104 * into the old trust-flags bits. */
michael@0 105
michael@0 106 /* First implementation: keep it simple for testing. We can study what other
michael@0 107 * mappings would be appropriate and add them later.. fgmr 20000724 */
michael@0 108
michael@0 109 if ( serverAuth == CKT_NSS_TRUSTED ) {
michael@0 110 trust->sslFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
michael@0 111 }
michael@0 112
michael@0 113 if ( serverAuth == CKT_NSS_TRUSTED_DELEGATOR ) {
michael@0 114 trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA |
michael@0 115 CERTDB_NS_TRUSTED_CA;
michael@0 116 }
michael@0 117 if ( clientAuth == CKT_NSS_TRUSTED_DELEGATOR ) {
michael@0 118 trust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA ;
michael@0 119 }
michael@0 120
michael@0 121 if ( emailProtection == CKT_NSS_TRUSTED ) {
michael@0 122 trust->emailFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
michael@0 123 }
michael@0 124
michael@0 125 if ( emailProtection == CKT_NSS_TRUSTED_DELEGATOR ) {
michael@0 126 trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
michael@0 127 }
michael@0 128
michael@0 129 if( codeSigning == CKT_NSS_TRUSTED ) {
michael@0 130 trust->objectSigningFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
michael@0 131 }
michael@0 132
michael@0 133 if( codeSigning == CKT_NSS_TRUSTED_DELEGATOR ) {
michael@0 134 trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
michael@0 135 }
michael@0 136
michael@0 137 /* There's certainly a lot more logic that can go here.. */
michael@0 138
michael@0 139 PORT_FreeArena(arena, PR_FALSE);
michael@0 140
michael@0 141 return PR_TRUE;
michael@0 142 }
michael@0 143
michael@0 144 static SECStatus
michael@0 145 pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg)
michael@0 146 {
michael@0 147 SECItem derCrl;
michael@0 148 CERTCrlHeadNode *head = (CERTCrlHeadNode *) arg;
michael@0 149 CERTCrlNode *new_node = NULL;
michael@0 150 CK_ATTRIBUTE fetchCrl[3] = {
michael@0 151 { CKA_VALUE, NULL, 0},
michael@0 152 { CKA_NETSCAPE_KRL, NULL, 0},
michael@0 153 { CKA_NETSCAPE_URL, NULL, 0},
michael@0 154 };
michael@0 155 const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]);
michael@0 156 CK_RV crv;
michael@0 157 SECStatus rv = SECFailure;
michael@0 158
michael@0 159 crv = PK11_GetAttributes(head->arena,slot,crlID,fetchCrl,fetchCrlSize);
michael@0 160 if (CKR_OK != crv) {
michael@0 161 PORT_SetError(PK11_MapError(crv));
michael@0 162 goto loser;
michael@0 163 }
michael@0 164
michael@0 165 if (!fetchCrl[1].pValue) {
michael@0 166 PORT_SetError(SEC_ERROR_CRL_INVALID);
michael@0 167 goto loser;
michael@0 168 }
michael@0 169
michael@0 170 new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode));
michael@0 171 if (new_node == NULL) {
michael@0 172 goto loser;
michael@0 173 }
michael@0 174
michael@0 175 if (*((CK_BBOOL *)fetchCrl[1].pValue))
michael@0 176 new_node->type = SEC_KRL_TYPE;
michael@0 177 else
michael@0 178 new_node->type = SEC_CRL_TYPE;
michael@0 179
michael@0 180 derCrl.type = siBuffer;
michael@0 181 derCrl.data = (unsigned char *)fetchCrl[0].pValue;
michael@0 182 derCrl.len = fetchCrl[0].ulValueLen;
michael@0 183 new_node->crl=CERT_DecodeDERCrl(head->arena,&derCrl,new_node->type);
michael@0 184 if (new_node->crl == NULL) {
michael@0 185 goto loser;
michael@0 186 }
michael@0 187
michael@0 188 if (fetchCrl[2].pValue) {
michael@0 189 int nnlen = fetchCrl[2].ulValueLen;
michael@0 190 new_node->crl->url = (char *)PORT_ArenaAlloc(head->arena, nnlen+1);
michael@0 191 if ( !new_node->crl->url ) {
michael@0 192 goto loser;
michael@0 193 }
michael@0 194 PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
michael@0 195 new_node->crl->url[nnlen] = 0;
michael@0 196 } else {
michael@0 197 new_node->crl->url = NULL;
michael@0 198 }
michael@0 199
michael@0 200
michael@0 201 new_node->next = NULL;
michael@0 202 if (head->last) {
michael@0 203 head->last->next = new_node;
michael@0 204 head->last = new_node;
michael@0 205 } else {
michael@0 206 head->first = head->last = new_node;
michael@0 207 }
michael@0 208 rv = SECSuccess;
michael@0 209
michael@0 210 loser:
michael@0 211 return(rv);
michael@0 212 }
michael@0 213
michael@0 214 /*
michael@0 215 * Return a list of all the CRLs .
michael@0 216 * CRLs are allocated in the list's arena.
michael@0 217 */
michael@0 218 SECStatus
michael@0 219 PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx) {
michael@0 220 pk11TraverseSlot creater;
michael@0 221 CK_ATTRIBUTE theTemplate[2];
michael@0 222 CK_ATTRIBUTE *attrs;
michael@0 223 CK_OBJECT_CLASS certClass = CKO_NETSCAPE_CRL;
michael@0 224 CK_BBOOL isKrl = CK_FALSE;
michael@0 225
michael@0 226 attrs = theTemplate;
michael@0 227 PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); attrs++;
michael@0 228 if (type != -1) {
michael@0 229 isKrl = (CK_BBOOL) (type == SEC_KRL_TYPE);
michael@0 230 PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, &isKrl, sizeof(isKrl)); attrs++;
michael@0 231 }
michael@0 232
michael@0 233 creater.callback = pk11_CollectCrls;
michael@0 234 creater.callbackArg = (void *) nodes;
michael@0 235 creater.findTemplate = theTemplate;
michael@0 236 creater.templateCount = (attrs - theTemplate);
michael@0 237
michael@0 238 return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
michael@0 239 }
michael@0 240
michael@0 241 struct crlOptionsStr {
michael@0 242 CERTCrlHeadNode* head;
michael@0 243 PRInt32 decodeOptions;
michael@0 244 };
michael@0 245
michael@0 246 typedef struct crlOptionsStr crlOptions;
michael@0 247
michael@0 248 static SECStatus
michael@0 249 pk11_RetrieveCrlsCallback(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID,
michael@0 250 void *arg)
michael@0 251 {
michael@0 252 SECItem* derCrl = NULL;
michael@0 253 crlOptions* options = (crlOptions*) arg;
michael@0 254 CERTCrlHeadNode *head = options->head;
michael@0 255 CERTCrlNode *new_node = NULL;
michael@0 256 CK_ATTRIBUTE fetchCrl[3] = {
michael@0 257 { CKA_VALUE, NULL, 0},
michael@0 258 { CKA_NETSCAPE_KRL, NULL, 0},
michael@0 259 { CKA_NETSCAPE_URL, NULL, 0},
michael@0 260 };
michael@0 261 const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]);
michael@0 262 CK_RV crv;
michael@0 263 SECStatus rv = SECFailure;
michael@0 264 PRBool adopted = PR_FALSE; /* whether the CRL adopted the DER memory
michael@0 265 successfully */
michael@0 266 int i;
michael@0 267
michael@0 268 crv = PK11_GetAttributes(NULL,slot,crlID,fetchCrl,fetchCrlSize);
michael@0 269 if (CKR_OK != crv) {
michael@0 270 PORT_SetError(PK11_MapError(crv));
michael@0 271 goto loser;
michael@0 272 }
michael@0 273
michael@0 274 if (!fetchCrl[1].pValue) {
michael@0 275 /* reject KRLs */
michael@0 276 PORT_SetError(SEC_ERROR_CRL_INVALID);
michael@0 277 goto loser;
michael@0 278 }
michael@0 279
michael@0 280 new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena,
michael@0 281 sizeof(CERTCrlNode));
michael@0 282 if (new_node == NULL) {
michael@0 283 goto loser;
michael@0 284 }
michael@0 285
michael@0 286 new_node->type = SEC_CRL_TYPE;
michael@0 287
michael@0 288 derCrl = SECITEM_AllocItem(NULL, NULL, 0);
michael@0 289 if (!derCrl) {
michael@0 290 goto loser;
michael@0 291 }
michael@0 292 derCrl->type = siBuffer;
michael@0 293 derCrl->data = (unsigned char *)fetchCrl[0].pValue;
michael@0 294 derCrl->len = fetchCrl[0].ulValueLen;
michael@0 295 new_node->crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl,new_node->type,
michael@0 296 options->decodeOptions);
michael@0 297 if (new_node->crl == NULL) {
michael@0 298 goto loser;
michael@0 299 }
michael@0 300 adopted = PR_TRUE; /* now that the CRL has adopted the DER memory,
michael@0 301 we won't need to free it upon exit */
michael@0 302
michael@0 303 if (fetchCrl[2].pValue && fetchCrl[2].ulValueLen) {
michael@0 304 /* copy the URL if there is one */
michael@0 305 int nnlen = fetchCrl[2].ulValueLen;
michael@0 306 new_node->crl->url = (char *)PORT_ArenaAlloc(new_node->crl->arena,
michael@0 307 nnlen+1);
michael@0 308 if ( !new_node->crl->url ) {
michael@0 309 goto loser;
michael@0 310 }
michael@0 311 PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
michael@0 312 new_node->crl->url[nnlen] = 0;
michael@0 313 } else {
michael@0 314 new_node->crl->url = NULL;
michael@0 315 }
michael@0 316
michael@0 317 new_node->next = NULL;
michael@0 318 if (head->last) {
michael@0 319 head->last->next = new_node;
michael@0 320 head->last = new_node;
michael@0 321 } else {
michael@0 322 head->first = head->last = new_node;
michael@0 323 }
michael@0 324 rv = SECSuccess;
michael@0 325 new_node->crl->slot = PK11_ReferenceSlot(slot);
michael@0 326 new_node->crl->pkcs11ID = crlID;
michael@0 327
michael@0 328 loser:
michael@0 329 /* free attributes that weren't adopted by the CRL */
michael@0 330 for (i=1;i<fetchCrlSize;i++) {
michael@0 331 if (fetchCrl[i].pValue) {
michael@0 332 PORT_Free(fetchCrl[i].pValue);
michael@0 333 }
michael@0 334 }
michael@0 335 /* free the DER if the CRL object didn't adopt it */
michael@0 336 if (fetchCrl[0].pValue && PR_FALSE == adopted) {
michael@0 337 PORT_Free(fetchCrl[0].pValue);
michael@0 338 }
michael@0 339 if (derCrl && !adopted) {
michael@0 340 /* clear the data fields, which we already took care of above */
michael@0 341 derCrl->data = NULL;
michael@0 342 derCrl->len = 0;
michael@0 343 /* free the memory for the SECItem structure itself */
michael@0 344 SECITEM_FreeItem(derCrl, PR_TRUE);
michael@0 345 }
michael@0 346 return(rv);
michael@0 347 }
michael@0 348
michael@0 349 /*
michael@0 350 * Return a list of CRLs matching specified issuer and type
michael@0 351 * CRLs are not allocated in the list's arena, but rather in their own,
michael@0 352 * arena, so that they can be used individually in the CRL cache .
michael@0 353 * CRLs are always partially decoded for efficiency.
michael@0 354 */
michael@0 355 SECStatus pk11_RetrieveCrls(CERTCrlHeadNode *nodes, SECItem* issuer,
michael@0 356 void *wincx)
michael@0 357 {
michael@0 358 pk11TraverseSlot creater;
michael@0 359 CK_ATTRIBUTE theTemplate[2];
michael@0 360 CK_ATTRIBUTE *attrs;
michael@0 361 CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL;
michael@0 362 crlOptions options;
michael@0 363
michael@0 364 attrs = theTemplate;
michael@0 365 PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++;
michael@0 366
michael@0 367 options.head = nodes;
michael@0 368
michael@0 369 /* - do a partial decoding - we don't need to decode the entries while
michael@0 370 fetching
michael@0 371 - don't copy the DER for optimal performance - CRL can be very large
michael@0 372 - have the CRL objects adopt the DER, so SEC_DestroyCrl will free it
michael@0 373 - keep bad CRL objects. The CRL cache is interested in them, for
michael@0 374 security purposes. Bad CRL objects are a sign of something amiss.
michael@0 375 */
michael@0 376
michael@0 377 options.decodeOptions = CRL_DECODE_SKIP_ENTRIES | CRL_DECODE_DONT_COPY_DER |
michael@0 378 CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_KEEP_BAD_CRL;
michael@0 379 if (issuer)
michael@0 380 {
michael@0 381 PK11_SETATTRS(attrs, CKA_SUBJECT, issuer->data, issuer->len); attrs++;
michael@0 382 }
michael@0 383
michael@0 384 creater.callback = pk11_RetrieveCrlsCallback;
michael@0 385 creater.callbackArg = (void *) &options;
michael@0 386 creater.findTemplate = theTemplate;
michael@0 387 creater.templateCount = (attrs - theTemplate);
michael@0 388
michael@0 389 return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
michael@0 390 }
michael@0 391
michael@0 392 /*
michael@0 393 * return the crl associated with a derSubjectName
michael@0 394 */
michael@0 395 SECItem *
michael@0 396 PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *crlHandle,
michael@0 397 SECItem *name, int type, char **pUrl)
michael@0 398 {
michael@0 399 NSSCRL **crls, **crlp, *crl = NULL;
michael@0 400 NSSDER subject;
michael@0 401 SECItem *rvItem;
michael@0 402 NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
michael@0 403 char * url = NULL;
michael@0 404
michael@0 405 PORT_SetError(0);
michael@0 406 NSSITEM_FROM_SECITEM(&subject, name);
michael@0 407 if (*slot) {
michael@0 408 nssCryptokiObject **instances;
michael@0 409 nssPKIObjectCollection *collection;
michael@0 410 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
michael@0 411 NSSToken *token = PK11Slot_GetNSSToken(*slot);
michael@0 412 collection = nssCRLCollection_Create(td, NULL);
michael@0 413 if (!collection) {
michael@0 414 goto loser;
michael@0 415 }
michael@0 416 instances = nssToken_FindCRLsBySubject(token, NULL, &subject,
michael@0 417 tokenOnly, 0, NULL);
michael@0 418 nssPKIObjectCollection_AddInstances(collection, instances, 0);
michael@0 419 nss_ZFreeIf(instances);
michael@0 420 crls = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL);
michael@0 421 nssPKIObjectCollection_Destroy(collection);
michael@0 422 } else {
michael@0 423 crls = nssTrustDomain_FindCRLsBySubject(td, &subject);
michael@0 424 }
michael@0 425 if ((!crls) || (*crls == NULL)) {
michael@0 426 if (crls) {
michael@0 427 nssCRLArray_Destroy(crls);
michael@0 428 }
michael@0 429 if (NSS_GetError() == NSS_ERROR_NOT_FOUND) {
michael@0 430 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
michael@0 431 }
michael@0 432 goto loser;
michael@0 433 }
michael@0 434 for (crlp = crls; *crlp; crlp++) {
michael@0 435 if ((!(*crlp)->isKRL && type == SEC_CRL_TYPE) ||
michael@0 436 ((*crlp)->isKRL && type != SEC_CRL_TYPE))
michael@0 437 {
michael@0 438 crl = nssCRL_AddRef(*crlp);
michael@0 439 break;
michael@0 440 }
michael@0 441 }
michael@0 442 nssCRLArray_Destroy(crls);
michael@0 443 if (!crl) {
michael@0 444 /* CRL collection was found, but no interesting CRL's were on it.
michael@0 445 * Not an error */
michael@0 446 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
michael@0 447 goto loser;
michael@0 448 }
michael@0 449 if (crl->url) {
michael@0 450 url = PORT_Strdup(crl->url);
michael@0 451 if (!url) {
michael@0 452 goto loser;
michael@0 453 }
michael@0 454 }
michael@0 455 rvItem = SECITEM_AllocItem(NULL, NULL, crl->encoding.size);
michael@0 456 if (!rvItem) {
michael@0 457 goto loser;
michael@0 458 }
michael@0 459 memcpy(rvItem->data, crl->encoding.data, crl->encoding.size);
michael@0 460 *slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot);
michael@0 461 *crlHandle = crl->object.instances[0]->handle;
michael@0 462 *pUrl = url;
michael@0 463 nssCRL_Destroy(crl);
michael@0 464 return rvItem;
michael@0 465
michael@0 466 loser:
michael@0 467 if (url)
michael@0 468 PORT_Free(url);
michael@0 469 if (crl)
michael@0 470 nssCRL_Destroy(crl);
michael@0 471 if (PORT_GetError() == 0) {
michael@0 472 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
michael@0 473 }
michael@0 474 return NULL;
michael@0 475 }
michael@0 476
michael@0 477 CK_OBJECT_HANDLE
michael@0 478 PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, SECItem *name,
michael@0 479 char *url, int type)
michael@0 480 {
michael@0 481 NSSItem derCRL, derSubject;
michael@0 482 NSSToken *token = PK11Slot_GetNSSToken(slot);
michael@0 483 nssCryptokiObject *object;
michael@0 484 PRBool isKRL = (type == SEC_CRL_TYPE) ? PR_FALSE : PR_TRUE;
michael@0 485 CK_OBJECT_HANDLE rvH;
michael@0 486
michael@0 487 NSSITEM_FROM_SECITEM(&derSubject, name);
michael@0 488 NSSITEM_FROM_SECITEM(&derCRL, crl);
michael@0 489
michael@0 490 object = nssToken_ImportCRL(token, NULL,
michael@0 491 &derSubject, &derCRL, isKRL, url, PR_TRUE);
michael@0 492
michael@0 493 if (object) {
michael@0 494 rvH = object->handle;
michael@0 495 nssCryptokiObject_Destroy(object);
michael@0 496 } else {
michael@0 497 rvH = CK_INVALID_HANDLE;
michael@0 498 PORT_SetError(SEC_ERROR_CRL_IMPORT_FAILED);
michael@0 499 }
michael@0 500 return rvH;
michael@0 501 }
michael@0 502
michael@0 503
michael@0 504 /*
michael@0 505 * delete a crl.
michael@0 506 */
michael@0 507 SECStatus
michael@0 508 SEC_DeletePermCRL(CERTSignedCrl *crl)
michael@0 509 {
michael@0 510 PRStatus status;
michael@0 511 NSSToken *token;
michael@0 512 nssCryptokiObject *object;
michael@0 513 PK11SlotInfo *slot = crl->slot;
michael@0 514
michael@0 515 if (slot == NULL) {
michael@0 516 PORT_Assert(slot);
michael@0 517 /* shouldn't happen */
michael@0 518 PORT_SetError( SEC_ERROR_CRL_INVALID);
michael@0 519 return SECFailure;
michael@0 520 }
michael@0 521 token = PK11Slot_GetNSSToken(slot);
michael@0 522
michael@0 523 object = nss_ZNEW(NULL, nssCryptokiObject);
michael@0 524 if (!object) {
michael@0 525 return SECFailure;
michael@0 526 }
michael@0 527 object->token = nssToken_AddRef(token);
michael@0 528 object->handle = crl->pkcs11ID;
michael@0 529 object->isTokenObject = PR_TRUE;
michael@0 530
michael@0 531 status = nssToken_DeleteStoredObject(object);
michael@0 532
michael@0 533 nssCryptokiObject_Destroy(object);
michael@0 534 return (status == PR_SUCCESS) ? SECSuccess : SECFailure;
michael@0 535 }
michael@0 536
michael@0 537 /*
michael@0 538 * return the certificate associated with a derCert
michael@0 539 */
michael@0 540 SECItem *
michael@0 541 PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr,
michael@0 542 SECItem *name, SECItem **profileTime)
michael@0 543 {
michael@0 544 CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME;
michael@0 545 CK_ATTRIBUTE theTemplate[] = {
michael@0 546 { CKA_SUBJECT, NULL, 0 },
michael@0 547 { CKA_CLASS, NULL, 0 },
michael@0 548 { CKA_NETSCAPE_EMAIL, NULL, 0 },
michael@0 549 };
michael@0 550 CK_ATTRIBUTE smimeData[] = {
michael@0 551 { CKA_SUBJECT, NULL, 0 },
michael@0 552 { CKA_VALUE, NULL, 0 },
michael@0 553 };
michael@0 554 /* if you change the array, change the variable below as well */
michael@0 555 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
michael@0 556 CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
michael@0 557 CK_ATTRIBUTE *attrs = theTemplate;
michael@0 558 CK_RV crv;
michael@0 559 SECItem *emailProfile = NULL;
michael@0 560
michael@0 561 if (!emailAddr || !emailAddr[0]) {
michael@0 562 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 563 return NULL;
michael@0 564 }
michael@0 565
michael@0 566 PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++;
michael@0 567 PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++;
michael@0 568 PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, strlen(emailAddr));
michael@0 569 attrs++;
michael@0 570
michael@0 571 if (*slot) {
michael@0 572 smimeh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize);
michael@0 573 } else {
michael@0 574 PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
michael@0 575 PR_FALSE,PR_TRUE,NULL);
michael@0 576 PK11SlotListElement *le;
michael@0 577
michael@0 578 if (!list) {
michael@0 579 return NULL;
michael@0 580 }
michael@0 581 /* loop through all the slots */
michael@0 582 for (le = list->head; le; le = le->next) {
michael@0 583 smimeh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize);
michael@0 584 if (smimeh != CK_INVALID_HANDLE) {
michael@0 585 *slot = PK11_ReferenceSlot(le->slot);
michael@0 586 break;
michael@0 587 }
michael@0 588 }
michael@0 589 PK11_FreeSlotList(list);
michael@0 590 }
michael@0 591
michael@0 592 if (smimeh == CK_INVALID_HANDLE) {
michael@0 593 PORT_SetError(SEC_ERROR_NO_KRL);
michael@0 594 return NULL;
michael@0 595 }
michael@0 596
michael@0 597 if (profileTime) {
michael@0 598 PK11_SETATTRS(smimeData, CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0);
michael@0 599 }
michael@0 600
michael@0 601 crv = PK11_GetAttributes(NULL,*slot,smimeh,smimeData,2);
michael@0 602 if (crv != CKR_OK) {
michael@0 603 PORT_SetError(PK11_MapError (crv));
michael@0 604 goto loser;
michael@0 605 }
michael@0 606
michael@0 607 if (!profileTime) {
michael@0 608 SECItem profileSubject;
michael@0 609
michael@0 610 profileSubject.data = (unsigned char*) smimeData[0].pValue;
michael@0 611 profileSubject.len = smimeData[0].ulValueLen;
michael@0 612 if (!SECITEM_ItemsAreEqual(&profileSubject,name)) {
michael@0 613 goto loser;
michael@0 614 }
michael@0 615 }
michael@0 616
michael@0 617 emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
michael@0 618 if (emailProfile == NULL) {
michael@0 619 goto loser;
michael@0 620 }
michael@0 621
michael@0 622 emailProfile->data = (unsigned char*) smimeData[1].pValue;
michael@0 623 emailProfile->len = smimeData[1].ulValueLen;
michael@0 624
michael@0 625 if (profileTime) {
michael@0 626 *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
michael@0 627 if (*profileTime) {
michael@0 628 (*profileTime)->data = (unsigned char*) smimeData[0].pValue;
michael@0 629 (*profileTime)->len = smimeData[0].ulValueLen;
michael@0 630 }
michael@0 631 }
michael@0 632
michael@0 633 loser:
michael@0 634 if (emailProfile == NULL) {
michael@0 635 if (smimeData[1].pValue) {
michael@0 636 PORT_Free(smimeData[1].pValue);
michael@0 637 }
michael@0 638 }
michael@0 639 if (profileTime == NULL || *profileTime == NULL) {
michael@0 640 if (smimeData[0].pValue) {
michael@0 641 PORT_Free(smimeData[0].pValue);
michael@0 642 }
michael@0 643 }
michael@0 644 return emailProfile;
michael@0 645 }
michael@0 646
michael@0 647
michael@0 648 SECStatus
michael@0 649 PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj,
michael@0 650 SECItem *emailProfile, SECItem *profileTime)
michael@0 651 {
michael@0 652 CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME;
michael@0 653 CK_BBOOL ck_true = CK_TRUE;
michael@0 654 CK_ATTRIBUTE theTemplate[] = {
michael@0 655 { CKA_CLASS, NULL, 0 },
michael@0 656 { CKA_TOKEN, NULL, 0 },
michael@0 657 { CKA_SUBJECT, NULL, 0 },
michael@0 658 { CKA_NETSCAPE_EMAIL, NULL, 0 },
michael@0 659 { CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0 },
michael@0 660 { CKA_VALUE, NULL, 0 }
michael@0 661 };
michael@0 662 /* if you change the array, change the variable below as well */
michael@0 663 int realSize = 0;
michael@0 664 CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
michael@0 665 CK_ATTRIBUTE *attrs = theTemplate;
michael@0 666 CK_SESSION_HANDLE rwsession;
michael@0 667 PK11SlotInfo *free_slot = NULL;
michael@0 668 CK_RV crv;
michael@0 669 #ifdef DEBUG
michael@0 670 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
michael@0 671 #endif
michael@0 672
michael@0 673 PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++;
michael@0 674 PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true)); attrs++;
michael@0 675 PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len); attrs++;
michael@0 676 PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL,
michael@0 677 emailAddr, PORT_Strlen(emailAddr)+1); attrs++;
michael@0 678 if (profileTime) {
michael@0 679 PK11_SETATTRS(attrs, CKA_NETSCAPE_SMIME_TIMESTAMP, profileTime->data,
michael@0 680 profileTime->len); attrs++;
michael@0 681 PK11_SETATTRS(attrs, CKA_VALUE,emailProfile->data,
michael@0 682 emailProfile->len); attrs++;
michael@0 683 }
michael@0 684 realSize = attrs - theTemplate;
michael@0 685 PORT_Assert (realSize <= tsize);
michael@0 686
michael@0 687 if (slot == NULL) {
michael@0 688 free_slot = slot = PK11_GetInternalKeySlot();
michael@0 689 /* we need to free the key slot in the end!!! */
michael@0 690 }
michael@0 691
michael@0 692 rwsession = PK11_GetRWSession(slot);
michael@0 693 if (rwsession == CK_INVALID_SESSION) {
michael@0 694 PORT_SetError(SEC_ERROR_READ_ONLY);
michael@0 695 if (free_slot) {
michael@0 696 PK11_FreeSlot(free_slot);
michael@0 697 }
michael@0 698 return SECFailure;
michael@0 699 }
michael@0 700
michael@0 701 crv = PK11_GETTAB(slot)->
michael@0 702 C_CreateObject(rwsession,theTemplate,realSize,&smimeh);
michael@0 703 if (crv != CKR_OK) {
michael@0 704 PORT_SetError( PK11_MapError(crv) );
michael@0 705 }
michael@0 706
michael@0 707 PK11_RestoreROSession(slot,rwsession);
michael@0 708
michael@0 709 if (free_slot) {
michael@0 710 PK11_FreeSlot(free_slot);
michael@0 711 }
michael@0 712 return SECSuccess;
michael@0 713 }
michael@0 714
michael@0 715
michael@0 716 CERTSignedCrl * crl_storeCRL (PK11SlotInfo *slot,char *url,
michael@0 717 CERTSignedCrl *newCrl, SECItem *derCrl, int type);
michael@0 718
michael@0 719 /* import the CRL into the token */
michael@0 720
michael@0 721 CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url,
michael@0 722 int type, void *wincx, PRInt32 importOptions, PLArenaPool* arena,
michael@0 723 PRInt32 decodeoptions)
michael@0 724 {
michael@0 725 CERTSignedCrl *newCrl, *crl;
michael@0 726 SECStatus rv;
michael@0 727 CERTCertificate *caCert = NULL;
michael@0 728
michael@0 729 newCrl = crl = NULL;
michael@0 730
michael@0 731 do {
michael@0 732 newCrl = CERT_DecodeDERCrlWithFlags(arena, derCRL, type,
michael@0 733 decodeoptions);
michael@0 734 if (newCrl == NULL) {
michael@0 735 if (type == SEC_CRL_TYPE) {
michael@0 736 /* only promote error when the error code is too generic */
michael@0 737 if (PORT_GetError () == SEC_ERROR_BAD_DER)
michael@0 738 PORT_SetError(SEC_ERROR_CRL_INVALID);
michael@0 739 } else {
michael@0 740 PORT_SetError(SEC_ERROR_KRL_INVALID);
michael@0 741 }
michael@0 742 break;
michael@0 743 }
michael@0 744
michael@0 745 if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){
michael@0 746 CERTCertDBHandle* handle = CERT_GetDefaultCertDB();
michael@0 747 PR_ASSERT(handle != NULL);
michael@0 748 caCert = CERT_FindCertByName (handle,
michael@0 749 &newCrl->crl.derName);
michael@0 750 if (caCert == NULL) {
michael@0 751 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
michael@0 752 break;
michael@0 753 }
michael@0 754
michael@0 755 /* If caCert is a v3 certificate, make sure that it can be used for
michael@0 756 crl signing purpose */
michael@0 757 rv = CERT_CheckCertUsage (caCert, KU_CRL_SIGN);
michael@0 758 if (rv != SECSuccess) {
michael@0 759 break;
michael@0 760 }
michael@0 761
michael@0 762 rv = CERT_VerifySignedData(&newCrl->signatureWrap, caCert,
michael@0 763 PR_Now(), wincx);
michael@0 764 if (rv != SECSuccess) {
michael@0 765 if (type == SEC_CRL_TYPE) {
michael@0 766 PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
michael@0 767 } else {
michael@0 768 PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
michael@0 769 }
michael@0 770 break;
michael@0 771 }
michael@0 772 }
michael@0 773
michael@0 774 crl = crl_storeCRL(slot, url, newCrl, derCRL, type);
michael@0 775
michael@0 776 } while (0);
michael@0 777
michael@0 778 if (crl == NULL) {
michael@0 779 SEC_DestroyCrl (newCrl);
michael@0 780 }
michael@0 781 if (caCert) {
michael@0 782 CERT_DestroyCertificate(caCert);
michael@0 783 }
michael@0 784 return (crl);
michael@0 785 }

mercurial