security/nss/lib/dev/devtoken.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "pkcs11.h"
     7 #ifndef DEVM_H
     8 #include "devm.h"
     9 #endif /* DEVM_H */
    11 #ifndef CKHELPER_H
    12 #include "ckhelper.h"
    13 #endif /* CKHELPER_H */
    15 #include "pk11func.h"
    16 #include "dev3hack.h"
    17 #include "secerr.h"
    19 extern const NSSError NSS_ERROR_NOT_FOUND;
    20 extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
    21 extern const NSSError NSS_ERROR_PKCS11;
    23 /* The number of object handles to grab during each call to C_FindObjects */
    24 #define OBJECT_STACK_SIZE 16
    26 NSS_IMPLEMENT PRStatus
    27 nssToken_Destroy (
    28   NSSToken *tok
    29 )
    30 {
    31     if (tok) {
    32 	if (PR_ATOMIC_DECREMENT(&tok->base.refCount) == 0) {
    33 	    PZ_DestroyLock(tok->base.lock);
    34 	    nssTokenObjectCache_Destroy(tok->cache);
    35 	    /* The token holds the first/last reference to the slot.
    36 	     * When the token is actually destroyed, that ref must go too.
    37 	     */
    38 	    (void)nssSlot_Destroy(tok->slot);
    39 	    return nssArena_Destroy(tok->base.arena);
    40 	}
    41     }
    42     return PR_SUCCESS;
    43 }
    45 NSS_IMPLEMENT void
    46 nssToken_Remove (
    47   NSSToken *tok
    48 )
    49 {
    50     nssTokenObjectCache_Clear(tok->cache);
    51 }
    53 NSS_IMPLEMENT void
    54 NSSToken_Destroy (
    55   NSSToken *tok
    56 )
    57 {
    58     (void)nssToken_Destroy(tok);
    59 }
    61 NSS_IMPLEMENT NSSToken *
    62 nssToken_AddRef (
    63   NSSToken *tok
    64 )
    65 {
    66     PR_ATOMIC_INCREMENT(&tok->base.refCount);
    67     return tok;
    68 }
    70 NSS_IMPLEMENT NSSSlot *
    71 nssToken_GetSlot (
    72   NSSToken *tok
    73 )
    74 {
    75     return nssSlot_AddRef(tok->slot);
    76 }
    78 NSS_IMPLEMENT void *
    79 nssToken_GetCryptokiEPV (
    80   NSSToken *token
    81 )
    82 {
    83     return nssSlot_GetCryptokiEPV(token->slot);
    84 }
    86 NSS_IMPLEMENT nssSession *
    87 nssToken_GetDefaultSession (
    88   NSSToken *token
    89 )
    90 {
    91     return token->defaultSession;
    92 }
    94 NSS_IMPLEMENT NSSUTF8 *
    95 nssToken_GetName (
    96   NSSToken *tok
    97 )
    98 {
    99     if (tok == NULL) {
   100 	return "";
   101     }
   102     if (tok->base.name[0] == 0) {
   103 	(void) nssSlot_IsTokenPresent(tok->slot);
   104     } 
   105     return tok->base.name;
   106 }
   108 NSS_IMPLEMENT NSSUTF8 *
   109 NSSToken_GetName (
   110   NSSToken *token
   111 )
   112 {
   113     return nssToken_GetName(token);
   114 }
   116 NSS_IMPLEMENT PRBool
   117 nssToken_IsLoginRequired (
   118   NSSToken *token
   119 )
   120 {
   121     return (token->ckFlags & CKF_LOGIN_REQUIRED);
   122 }
   124 NSS_IMPLEMENT PRBool
   125 nssToken_NeedsPINInitialization (
   126   NSSToken *token
   127 )
   128 {
   129     return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
   130 }
   132 NSS_IMPLEMENT PRStatus
   133 nssToken_DeleteStoredObject (
   134   nssCryptokiObject *instance
   135 )
   136 {
   137     CK_RV ckrv;
   138     PRStatus status;
   139     PRBool createdSession = PR_FALSE;
   140     NSSToken *token = instance->token;
   141     nssSession *session = NULL;
   142     void *epv = nssToken_GetCryptokiEPV(instance->token);
   143     if (token->cache) {
   144 	nssTokenObjectCache_RemoveObject(token->cache, instance);
   145     }
   146     if (instance->isTokenObject) {
   147        if (token->defaultSession && 
   148            nssSession_IsReadWrite(token->defaultSession)) {
   149 	   session = token->defaultSession;
   150        } else {
   151 	   session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
   152 	   createdSession = PR_TRUE;
   153        }
   154     }
   155     if (session == NULL) {
   156 	return PR_FAILURE;
   157     }
   158     nssSession_EnterMonitor(session);
   159     ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
   160     nssSession_ExitMonitor(session);
   161     if (createdSession) {
   162 	nssSession_Destroy(session);
   163     }
   164     status = PR_SUCCESS;
   165     if (ckrv != CKR_OK) {
   166 	status = PR_FAILURE;
   167 	/* use the error stack to pass the PKCS #11 error out  */
   168 	nss_SetError(ckrv);
   169 	nss_SetError(NSS_ERROR_PKCS11);
   170     }
   171     return status;
   172 }
   174 static nssCryptokiObject *
   175 import_object (
   176   NSSToken *tok,
   177   nssSession *sessionOpt,
   178   CK_ATTRIBUTE_PTR objectTemplate,
   179   CK_ULONG otsize
   180 )
   181 {
   182     nssSession *session = NULL;
   183     PRBool createdSession = PR_FALSE;
   184     nssCryptokiObject *object = NULL;
   185     CK_OBJECT_HANDLE handle;
   186     CK_RV ckrv;
   187     void *epv = nssToken_GetCryptokiEPV(tok);
   188     if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
   189 	if (sessionOpt) {
   190 	    if (!nssSession_IsReadWrite(sessionOpt)) {
   191 		nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
   192 		return NULL;
   193 	    }
   194 	    session = sessionOpt;
   195 	} else if (tok->defaultSession && 
   196 	           nssSession_IsReadWrite(tok->defaultSession)) {
   197 	    session = tok->defaultSession;
   198 	} else {
   199 	    session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
   200 	    createdSession = PR_TRUE;
   201 	}
   202     } else {
   203 	session = (sessionOpt) ? sessionOpt : tok->defaultSession;
   204     }
   205     if (session == NULL) {
   206 	nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
   207 	return NULL;
   208     }
   209     nssSession_EnterMonitor(session);
   210     ckrv = CKAPI(epv)->C_CreateObject(session->handle, 
   211                                       objectTemplate, otsize,
   212                                       &handle);
   213     nssSession_ExitMonitor(session);
   214     if (ckrv == CKR_OK) {
   215 	object = nssCryptokiObject_Create(tok, session, handle);
   216     } else {
   217 	nss_SetError(ckrv);
   218 	nss_SetError(NSS_ERROR_PKCS11);
   219     }
   220     if (createdSession) {
   221 	nssSession_Destroy(session);
   222     }
   223     return object;
   224 }
   226 static nssCryptokiObject **
   227 create_objects_from_handles (
   228   NSSToken *tok,
   229   nssSession *session,
   230   CK_OBJECT_HANDLE *handles,
   231   PRUint32 numH
   232 )
   233 {
   234     nssCryptokiObject **objects;
   235     objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
   236     if (objects) {
   237 	PRInt32 i;
   238 	for (i=0; i<(PRInt32)numH; i++) {
   239 	    objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
   240 	    if (!objects[i]) {
   241 		for (--i; i>0; --i) {
   242 		    nssCryptokiObject_Destroy(objects[i]);
   243 		}
   244 		nss_ZFreeIf(objects);
   245 		objects = NULL;
   246 		break;
   247 	    }
   248 	}
   249     }
   250     return objects;
   251 }
   253 static nssCryptokiObject **
   254 find_objects (
   255   NSSToken *tok,
   256   nssSession *sessionOpt,
   257   CK_ATTRIBUTE_PTR obj_template,
   258   CK_ULONG otsize,
   259   PRUint32 maximumOpt,
   260   PRStatus *statusOpt
   261 )
   262 {
   263     CK_RV ckrv = CKR_OK;
   264     CK_ULONG count;
   265     CK_OBJECT_HANDLE *objectHandles = NULL;
   266     CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
   267     PRUint32 arraySize, numHandles;
   268     void *epv = nssToken_GetCryptokiEPV(tok);
   269     nssCryptokiObject **objects;
   270     nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
   272     /* Don't ask the module to use an invalid session handle. */
   273     if (!session || session->handle == CK_INVALID_SESSION) {
   274 	ckrv = CKR_SESSION_HANDLE_INVALID;
   275 	goto loser;                
   276     }
   278     /* the arena is only for the array of object handles */
   279     if (maximumOpt > 0) {
   280 	arraySize = maximumOpt;
   281     } else {
   282 	arraySize = OBJECT_STACK_SIZE;
   283     }
   284     numHandles = 0;
   285     if (arraySize <= OBJECT_STACK_SIZE) {
   286 	objectHandles = staticObjects;
   287     } else {
   288 	objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
   289     }
   290     if (!objectHandles) {
   291 	ckrv = CKR_HOST_MEMORY;
   292 	goto loser;
   293     }
   294     nssSession_EnterMonitor(session); /* ==== session lock === */
   295     /* Initialize the find with the template */
   296     ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
   297                                          obj_template, otsize);
   298     if (ckrv != CKR_OK) {
   299 	nssSession_ExitMonitor(session);
   300 	goto loser;
   301     }
   302     while (PR_TRUE) {
   303 	/* Issue the find for up to arraySize - numHandles objects */
   304 	ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
   305 	                                 objectHandles + numHandles, 
   306 	                                 arraySize - numHandles, 
   307 	                                 &count);
   308 	if (ckrv != CKR_OK) {
   309 	    nssSession_ExitMonitor(session);
   310 	    goto loser;
   311 	}
   312 	/* bump the number of found objects */
   313 	numHandles += count;
   314 	if (maximumOpt > 0 || numHandles < arraySize) {
   315 	    /* When a maximum is provided, the search is done all at once,
   316 	     * so the search is finished.  If the number returned was less 
   317 	     * than the number sought, the search is finished.
   318 	     */
   319 	    break;
   320 	}
   321 	/* the array is filled, double it and continue */
   322 	arraySize *= 2;
   323 	if (objectHandles == staticObjects) {
   324 	    objectHandles = nss_ZNEWARRAY(NULL,CK_OBJECT_HANDLE, arraySize);
   325 	    if (objectHandles) {
   326 		PORT_Memcpy(objectHandles, staticObjects, 
   327 			OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
   328 	    }
   329 	} else {
   330 	    objectHandles = nss_ZREALLOCARRAY(objectHandles, 
   331 	                                  CK_OBJECT_HANDLE, 
   332 	                                  arraySize);
   333 	}
   334 	if (!objectHandles) {
   335 	    nssSession_ExitMonitor(session);
   336 	    ckrv = CKR_HOST_MEMORY;
   337 	    goto loser;
   338 	}
   339     }
   340     ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
   341     nssSession_ExitMonitor(session); /* ==== end session lock === */
   342     if (ckrv != CKR_OK) {
   343 	goto loser;
   344     }
   345     if (numHandles > 0) {
   346 	objects = create_objects_from_handles(tok, session,
   347 	                                      objectHandles, numHandles);
   348     } else {
   349 	nss_SetError(NSS_ERROR_NOT_FOUND);
   350 	objects = NULL;
   351     }
   352     if (objectHandles && objectHandles != staticObjects) {
   353 	nss_ZFreeIf(objectHandles);
   354     }
   355     if (statusOpt) *statusOpt = PR_SUCCESS;
   356     return objects;
   357 loser:
   358     if (objectHandles && objectHandles != staticObjects) {
   359 	nss_ZFreeIf(objectHandles);
   360     }
   361     /*
   362      * These errors should be treated the same as if the objects just weren't
   363      * found..
   364      */
   365     if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
   366 	(ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
   367 	(ckrv == CKR_DATA_INVALID) ||
   368 	(ckrv == CKR_DATA_LEN_RANGE) ||
   369 	(ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
   370 	(ckrv == CKR_TEMPLATE_INCOMPLETE) ||
   371 	(ckrv == CKR_TEMPLATE_INCONSISTENT)) {
   373 	nss_SetError(NSS_ERROR_NOT_FOUND);
   374 	if (statusOpt) *statusOpt = PR_SUCCESS;
   375     } else {
   376 	nss_SetError(ckrv);
   377 	nss_SetError(NSS_ERROR_PKCS11);
   378 	if (statusOpt) *statusOpt = PR_FAILURE;
   379     }
   380     return (nssCryptokiObject **)NULL;
   381 }
   383 static nssCryptokiObject **
   384 find_objects_by_template (
   385   NSSToken *token,
   386   nssSession *sessionOpt,
   387   CK_ATTRIBUTE_PTR obj_template,
   388   CK_ULONG otsize,
   389   PRUint32 maximumOpt,
   390   PRStatus *statusOpt
   391 )
   392 {
   393     CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
   394     nssCryptokiObject **objects = NULL;
   395     PRUint32 i;
   397     if (!token) {
   398     	PORT_SetError(SEC_ERROR_NO_TOKEN);
   399 	if (statusOpt) 
   400 	    *statusOpt = PR_FAILURE;
   401 	return NULL;
   402     }
   403     for (i=0; i<otsize; i++) {
   404 	if (obj_template[i].type == CKA_CLASS) {
   405 	    objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
   406 	    break;
   407 	}
   408     }
   409     PR_ASSERT(i < otsize);
   410     if (i == otsize) {
   411 	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   412 	if (statusOpt) *statusOpt = PR_FAILURE;
   413 	return NULL;
   414     }
   415     /* If these objects are being cached, try looking there first */
   416     if (token->cache && 
   417         nssTokenObjectCache_HaveObjectClass(token->cache, objclass)) 
   418     {
   419 	PRStatus status;
   420 	objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
   421 	                                                    objclass,
   422 	                                                    obj_template,
   423 	                                                    otsize,
   424 	                                                    maximumOpt,
   425 	                                                    &status);
   426 	if (status == PR_SUCCESS) {
   427 	    if (statusOpt) *statusOpt = status;
   428 	    return objects;
   429 	}
   430     }
   431     /* Either they are not cached, or cache failed; look on token. */
   432     objects = find_objects(token, sessionOpt, 
   433                            obj_template, otsize, 
   434                            maximumOpt, statusOpt);
   435     return objects;
   436 }
   438 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
   440 NSS_IMPLEMENT nssCryptokiObject *
   441 nssToken_ImportCertificate (
   442   NSSToken *tok,
   443   nssSession *sessionOpt,
   444   NSSCertificateType certType,
   445   NSSItem *id,
   446   const NSSUTF8 *nickname,
   447   NSSDER *encoding,
   448   NSSDER *issuer,
   449   NSSDER *subject,
   450   NSSDER *serial,
   451   NSSASCII7 *email,
   452   PRBool asTokenObject
   453 )
   454 {
   455     PRStatus status;
   456     CK_CERTIFICATE_TYPE cert_type;
   457     CK_ATTRIBUTE_PTR attr;
   458     CK_ATTRIBUTE cert_tmpl[10];
   459     CK_ULONG ctsize;
   460     nssTokenSearchType searchType;
   461     nssCryptokiObject *rvObject = NULL;
   463     if (!tok) {
   464     	PORT_SetError(SEC_ERROR_NO_TOKEN);
   465 	return NULL;
   466     }
   467     if (certType == NSSCertificateType_PKIX) {
   468 	cert_type = CKC_X_509;
   469     } else {
   470 	return (nssCryptokiObject *)NULL;
   471     }
   472     NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
   473     if (asTokenObject) {
   474 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   475 	searchType = nssTokenSearchType_TokenOnly;
   476     } else {
   477 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   478 	searchType = nssTokenSearchType_SessionOnly;
   479     }
   480     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,            &g_ck_class_cert);
   481     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CERTIFICATE_TYPE,  cert_type);
   482     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,                id);
   483     NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL,             nickname);
   484     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,             encoding);
   485     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,            issuer);
   486     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,           subject);
   487     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,     serial);
   488     if (email) {
   489 	NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL,    email);
   490     }
   491     NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
   492     /* see if the cert is already there */
   493     rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
   494                                                                sessionOpt,
   495                                                                issuer,
   496                                                                serial,
   497                                                                searchType,
   498                                                                NULL);
   499     if (rvObject) {
   500 	NSSItem existingDER;
   501 	NSSSlot *slot = nssToken_GetSlot(tok);
   502 	nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
   503 	if (!session) {
   504 	    nssCryptokiObject_Destroy(rvObject);
   505 	    nssSlot_Destroy(slot);
   506 	    return (nssCryptokiObject *)NULL;
   507 	}
   508 	/* Reject any attempt to import a new cert that has the same
   509 	 * issuer/serial as an existing cert, but does not have the
   510 	 * same encoding
   511 	 */
   512 	NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
   513 	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
   514 	NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
   515 	status = nssCKObject_GetAttributes(rvObject->handle, 
   516 	                                   cert_tmpl, ctsize, NULL,
   517 	                                   session, slot);
   518 	NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
   519 	if (status == PR_SUCCESS) {
   520 	    if (!nssItem_Equal(encoding, &existingDER, NULL)) {
   521 		nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
   522 		status = PR_FAILURE;
   523 	    }
   524 	    nss_ZFreeIf(existingDER.data);
   525 	}
   526 	if (status == PR_FAILURE) {
   527 	    nssCryptokiObject_Destroy(rvObject);
   528 	    nssSession_Destroy(session);
   529 	    nssSlot_Destroy(slot);
   530 	    return (nssCryptokiObject *)NULL;
   531 	}
   532 	/* according to PKCS#11, label, ID, issuer, and serial number 
   533 	 * may change after the object has been created.  For PKIX, the
   534 	 * last two attributes can't change, so for now we'll only worry
   535 	 * about the first two.
   536 	 */
   537 	NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
   538 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,    id);
   539 	NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
   540 	NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
   541 	/* reset the mutable attributes on the token */
   542 	nssCKObject_SetAttributes(rvObject->handle, 
   543 	                          cert_tmpl, ctsize,
   544 	                          session, slot);
   545 	if (!rvObject->label && nickname) {
   546 	    rvObject->label = nssUTF8_Duplicate(nickname, NULL);
   547 	}
   548 	nssSession_Destroy(session);
   549 	nssSlot_Destroy(slot);
   550     } else {
   551 	/* Import the certificate onto the token */
   552 	rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
   553     }
   554     if (rvObject && tok->cache) {
   555 	/* The cache will overwrite the attributes if the object already
   556 	 * exists.
   557 	 */
   558 	nssTokenObjectCache_ImportObject(tok->cache, rvObject,
   559 	                                 CKO_CERTIFICATE,
   560 	                                 cert_tmpl, ctsize);
   561     }
   562     return rvObject;
   563 }
   565 /* traverse all objects of the given class - this should only happen
   566  * if the token has been marked as "traversable"
   567  */
   568 NSS_IMPLEMENT nssCryptokiObject **
   569 nssToken_FindObjects (
   570   NSSToken *token,
   571   nssSession *sessionOpt,
   572   CK_OBJECT_CLASS objclass,
   573   nssTokenSearchType searchType,
   574   PRUint32 maximumOpt,
   575   PRStatus *statusOpt
   576 )
   577 {
   578     CK_ATTRIBUTE_PTR attr;
   579     CK_ATTRIBUTE obj_template[2];
   580     CK_ULONG obj_size;
   581     nssCryptokiObject **objects;
   582     NSS_CK_TEMPLATE_START(obj_template, attr, obj_size);
   583     /* Set the search to token/session only if provided */
   584     if (searchType == nssTokenSearchType_SessionOnly) {
   585 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   586     } else if (searchType == nssTokenSearchType_TokenOnly ||
   587                searchType == nssTokenSearchType_TokenForced) {
   588 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   589     }
   590     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, objclass);
   591     NSS_CK_TEMPLATE_FINISH(obj_template, attr, obj_size);
   593     if (searchType == nssTokenSearchType_TokenForced) {
   594 	objects = find_objects(token, sessionOpt,
   595 	                       obj_template, obj_size,
   596 	                       maximumOpt, statusOpt);
   597     } else {
   598 	objects = find_objects_by_template(token, sessionOpt,
   599 	                                   obj_template, obj_size,
   600 	                                   maximumOpt, statusOpt);
   601     }
   602     return objects;
   603 }
   605 NSS_IMPLEMENT nssCryptokiObject **
   606 nssToken_FindCertificatesBySubject (
   607   NSSToken *token,
   608   nssSession *sessionOpt,
   609   NSSDER *subject,
   610   nssTokenSearchType searchType,
   611   PRUint32 maximumOpt,
   612   PRStatus *statusOpt
   613 )
   614 {
   615     CK_ATTRIBUTE_PTR attr;
   616     CK_ATTRIBUTE subj_template[3];
   617     CK_ULONG stsize;
   618     nssCryptokiObject **objects;
   619     NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
   620     /* Set the search to token/session only if provided */
   621     if (searchType == nssTokenSearchType_SessionOnly) {
   622 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   623     } else if (searchType == nssTokenSearchType_TokenOnly) {
   624 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   625     }
   626     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
   627     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
   628     NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
   629     /* now locate the token certs matching this template */
   630     objects = find_objects_by_template(token, sessionOpt,
   631                                        subj_template, stsize,
   632                                        maximumOpt, statusOpt);
   633     return objects;
   634 }
   636 NSS_IMPLEMENT nssCryptokiObject **
   637 nssToken_FindCertificatesByNickname (
   638   NSSToken *token,
   639   nssSession *sessionOpt,
   640   const NSSUTF8 *name,
   641   nssTokenSearchType searchType,
   642   PRUint32 maximumOpt,
   643   PRStatus *statusOpt
   644 )
   645 {
   646     CK_ATTRIBUTE_PTR attr;
   647     CK_ATTRIBUTE nick_template[3];
   648     CK_ULONG ntsize;
   649     nssCryptokiObject **objects;
   650     NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
   651     NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
   652     /* Set the search to token/session only if provided */
   653     if (searchType == nssTokenSearchType_SessionOnly) {
   654 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   655     } else if (searchType == nssTokenSearchType_TokenOnly) {
   656 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   657     }
   658     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
   659     NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
   660     /* now locate the token certs matching this template */
   661     objects = find_objects_by_template(token, sessionOpt,
   662                                        nick_template, ntsize, 
   663                                        maximumOpt, statusOpt);
   664     if (!objects) {
   665 	/* This is to workaround the fact that PKCS#11 doesn't specify
   666 	 * whether the '\0' should be included.  XXX Is that still true?
   667 	 * im - this is not needed by the current softoken.  However, I'm 
   668 	 * leaving it in until I have surveyed more tokens to see if it needed.
   669 	 * well, its needed by the builtin token...
   670 	 */
   671 	nick_template[0].ulValueLen++;
   672 	objects = find_objects_by_template(token, sessionOpt,
   673 	                                   nick_template, ntsize, 
   674 	                                   maximumOpt, statusOpt);
   675     }
   676     return objects;
   677 }
   679 /* XXX
   680  * This function *does not* use the token object cache, because not even
   681  * the softoken will return a value for CKA_NSS_EMAIL from a call
   682  * to GetAttributes.  The softoken does allow searches with that attribute,
   683  * it just won't return a value for it.
   684  */
   685 NSS_IMPLEMENT nssCryptokiObject **
   686 nssToken_FindCertificatesByEmail (
   687   NSSToken *token,
   688   nssSession *sessionOpt,
   689   NSSASCII7 *email,
   690   nssTokenSearchType searchType,
   691   PRUint32 maximumOpt,
   692   PRStatus *statusOpt
   693 )
   694 {
   695     CK_ATTRIBUTE_PTR attr;
   696     CK_ATTRIBUTE email_template[3];
   697     CK_ULONG etsize;
   698     nssCryptokiObject **objects;
   699     NSS_CK_TEMPLATE_START(email_template, attr, etsize);
   700     NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
   701     /* Set the search to token/session only if provided */
   702     if (searchType == nssTokenSearchType_SessionOnly) {
   703 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   704     } else if (searchType == nssTokenSearchType_TokenOnly) {
   705 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   706     }
   707     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
   708     NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
   709     /* now locate the token certs matching this template */
   710     objects = find_objects(token, sessionOpt,
   711                            email_template, etsize,
   712                            maximumOpt, statusOpt);
   713     if (!objects) {
   714 	/* This is to workaround the fact that PKCS#11 doesn't specify
   715 	 * whether the '\0' should be included.  XXX Is that still true?
   716 	 * im - this is not needed by the current softoken.  However, I'm 
   717 	 * leaving it in until I have surveyed more tokens to see if it needed.
   718 	 * well, its needed by the builtin token...
   719 	 */
   720 	email_template[0].ulValueLen++;
   721 	objects = find_objects(token, sessionOpt,
   722 	                       email_template, etsize,
   723 	                       maximumOpt, statusOpt);
   724     }
   725     return objects;
   726 }
   728 NSS_IMPLEMENT nssCryptokiObject **
   729 nssToken_FindCertificatesByID (
   730   NSSToken *token,
   731   nssSession *sessionOpt,
   732   NSSItem *id,
   733   nssTokenSearchType searchType,
   734   PRUint32 maximumOpt,
   735   PRStatus *statusOpt
   736 )
   737 {
   738     CK_ATTRIBUTE_PTR attr;
   739     CK_ATTRIBUTE id_template[3];
   740     CK_ULONG idtsize;
   741     nssCryptokiObject **objects;
   742     NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
   743     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
   744     /* Set the search to token/session only if provided */
   745     if (searchType == nssTokenSearchType_SessionOnly) {
   746 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   747     } else if (searchType == nssTokenSearchType_TokenOnly) {
   748 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   749     }
   750     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
   751     NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
   752     /* now locate the token certs matching this template */
   753     objects = find_objects_by_template(token, sessionOpt,
   754                                        id_template, idtsize,
   755                                        maximumOpt, statusOpt);
   756     return objects;
   757 }
   759 /*
   760  * decode the serial item and return our result.
   761  * NOTE serialDecode's data is really stored in serial. Don't free it.
   762  */
   763 static PRStatus
   764 nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
   765 {
   766     unsigned char *data = (unsigned char *)serial->data;
   767     int data_left, data_len, index;
   769     if ((serial->size >= 3) && (data[0] == 0x2)) {
   770 	/* remove the der encoding of the serial number before generating the
   771 	 * key.. */
   772 	data_left = serial->size-2;
   773 	data_len = data[1];
   774 	index = 2;
   776 	/* extended length ? (not very likely for a serial number) */
   777 	if (data_len & 0x80) {
   778 	    int len_count = data_len & 0x7f;
   780 	    data_len = 0;
   781 	    data_left -= len_count;
   782 	    if (data_left > 0) {
   783 		while (len_count --) {
   784 		    data_len = (data_len << 8) | data[index++];
   785 		}
   786 	    } 
   787 	}
   788 	/* XXX leaving any leading zeros on the serial number for backwards
   789 	 * compatibility
   790 	 */
   791 	/* not a valid der, must be just an unlucky serial number value */
   792 	if (data_len == data_left) {
   793 	    serialDecode->size = data_len;
   794 	    serialDecode->data = &data[index];
   795 	    return PR_SUCCESS;
   796 	}
   797     }
   798     return PR_FAILURE;
   799 }
   801 NSS_IMPLEMENT nssCryptokiObject *
   802 nssToken_FindCertificateByIssuerAndSerialNumber (
   803   NSSToken *token,
   804   nssSession *sessionOpt,
   805   NSSDER *issuer,
   806   NSSDER *serial,
   807   nssTokenSearchType searchType,
   808   PRStatus *statusOpt
   809 )
   810 {
   811     CK_ATTRIBUTE_PTR attr;
   812     CK_ATTRIBUTE_PTR serialAttr;
   813     CK_ATTRIBUTE cert_template[4];
   814     CK_ULONG ctsize;
   815     nssCryptokiObject **objects;
   816     nssCryptokiObject *rvObject = NULL;
   817     NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
   819     if (!token) {
   820     	PORT_SetError(SEC_ERROR_NO_TOKEN);
   821 	if (statusOpt) 
   822 	    *statusOpt = PR_FAILURE;
   823 	return NULL;
   824     }
   825     /* Set the search to token/session only if provided */
   826     if (searchType == nssTokenSearchType_SessionOnly) {
   827 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   828     } else if ((searchType == nssTokenSearchType_TokenOnly) ||
   829                (searchType == nssTokenSearchType_TokenForced)) {
   830 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   831     }
   832     /* Set the unique id */
   833     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,         &g_ck_class_cert);
   834     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         issuer);
   835     serialAttr = attr;
   836     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,  serial);
   837     NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
   838     /* get the object handle */
   839     if (searchType == nssTokenSearchType_TokenForced) {
   840 	objects = find_objects(token, sessionOpt,
   841 	                       cert_template, ctsize,
   842 	                       1, statusOpt);
   843     } else {
   844 	objects = find_objects_by_template(token, sessionOpt,
   845                                        cert_template, ctsize,
   846                                        1, statusOpt);
   847     }
   848     if (objects) {
   849 	rvObject = objects[0];
   850 	nss_ZFreeIf(objects);
   851     }
   853     /*
   854      * NSS used to incorrectly store serial numbers in their decoded form.
   855      * because of this old tokens have decoded serial numbers.
   856      */
   857     if (!objects) {
   858 	NSSItem serialDecode;
   859 	PRStatus status;
   861 	status = nssToken_decodeSerialItem(serial, &serialDecode);
   862 	if (status != PR_SUCCESS) {
   863 	    return NULL;
   864 	}
   865     	NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr,CKA_SERIAL_NUMBER,&serialDecode);
   866 	if (searchType == nssTokenSearchType_TokenForced) {
   867 	    objects = find_objects(token, sessionOpt,
   868 	                       cert_template, ctsize,
   869 	                       1, statusOpt);
   870 	} else {
   871 	    objects = find_objects_by_template(token, sessionOpt,
   872                                        cert_template, ctsize,
   873                                        1, statusOpt);
   874 	}
   875 	if (objects) {
   876 	    rvObject = objects[0];
   877 	    nss_ZFreeIf(objects);
   878 	}
   879     }
   880     return rvObject;
   881 }
   883 NSS_IMPLEMENT nssCryptokiObject *
   884 nssToken_FindCertificateByEncodedCertificate (
   885   NSSToken *token,
   886   nssSession *sessionOpt,
   887   NSSBER *encodedCertificate,
   888   nssTokenSearchType searchType,
   889   PRStatus *statusOpt
   890 )
   891 {
   892     CK_ATTRIBUTE_PTR attr;
   893     CK_ATTRIBUTE cert_template[3];
   894     CK_ULONG ctsize;
   895     nssCryptokiObject **objects;
   896     nssCryptokiObject *rvObject = NULL;
   897     NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
   898     /* Set the search to token/session only if provided */
   899     if (searchType == nssTokenSearchType_SessionOnly) {
   900 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   901     } else if (searchType == nssTokenSearchType_TokenOnly) {
   902 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   903     }
   904     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
   905     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
   906     NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
   907     /* get the object handle */
   908     objects = find_objects_by_template(token, sessionOpt,
   909                                        cert_template, ctsize,
   910                                        1, statusOpt);
   911     if (objects) {
   912 	rvObject = objects[0];
   913 	nss_ZFreeIf(objects);
   914     }
   915     return rvObject;
   916 }
   918 NSS_IMPLEMENT nssCryptokiObject **
   919 nssToken_FindPrivateKeys (
   920   NSSToken *token,
   921   nssSession *sessionOpt,
   922   nssTokenSearchType searchType,
   923   PRUint32 maximumOpt,
   924   PRStatus *statusOpt
   925 )
   926 {
   927     CK_ATTRIBUTE_PTR attr;
   928     CK_ATTRIBUTE key_template[2];
   929     CK_ULONG ktsize;
   930     nssCryptokiObject **objects;
   932     NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
   933     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
   934     if (searchType == nssTokenSearchType_SessionOnly) {
   935 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
   936     } else if (searchType == nssTokenSearchType_TokenOnly) {
   937 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   938     }
   939     NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
   941     objects = find_objects_by_template(token, sessionOpt,
   942                                        key_template, ktsize, 
   943                                        maximumOpt, statusOpt);
   944     return objects;
   945 }
   947 /* XXX ?there are no session cert objects, so only search token objects */
   948 NSS_IMPLEMENT nssCryptokiObject *
   949 nssToken_FindPrivateKeyByID (
   950   NSSToken *token,
   951   nssSession *sessionOpt,
   952   NSSItem *keyID
   953 )
   954 {
   955     CK_ATTRIBUTE_PTR attr;
   956     CK_ATTRIBUTE key_template[3];
   957     CK_ULONG ktsize;
   958     nssCryptokiObject **objects;
   959     nssCryptokiObject *rvKey = NULL;
   961     NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
   962     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
   963     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   964     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
   965     NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
   967     objects = find_objects_by_template(token, sessionOpt,
   968                                        key_template, ktsize, 
   969                                        1, NULL);
   970     if (objects) {
   971 	rvKey = objects[0];
   972 	nss_ZFreeIf(objects);
   973     }
   974     return rvKey;
   975 }
   977 /* XXX ?there are no session cert objects, so only search token objects */
   978 NSS_IMPLEMENT nssCryptokiObject *
   979 nssToken_FindPublicKeyByID (
   980   NSSToken *token,
   981   nssSession *sessionOpt,
   982   NSSItem *keyID
   983 )
   984 {
   985     CK_ATTRIBUTE_PTR attr;
   986     CK_ATTRIBUTE key_template[3];
   987     CK_ULONG ktsize;
   988     nssCryptokiObject **objects;
   989     nssCryptokiObject *rvKey = NULL;
   991     NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
   992     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
   993     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
   994     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
   995     NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
   997     objects = find_objects_by_template(token, sessionOpt,
   998                                        key_template, ktsize, 
   999                                        1, NULL);
  1000     if (objects) {
  1001 	rvKey = objects[0];
  1002 	nss_ZFreeIf(objects);
  1004     return rvKey;
  1007 static void
  1008 sha1_hash(NSSItem *input, NSSItem *output)
  1010     NSSAlgorithmAndParameters *ap;
  1011     PK11SlotInfo *internal = PK11_GetInternalSlot();
  1012     NSSToken *token = PK11Slot_GetNSSToken(internal);
  1013     ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
  1014     (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
  1015     PK11_FreeSlot(token->pk11slot);
  1016     nss_ZFreeIf(ap);
  1019 static void
  1020 md5_hash(NSSItem *input, NSSItem *output)
  1022     NSSAlgorithmAndParameters *ap;
  1023     PK11SlotInfo *internal = PK11_GetInternalSlot();
  1024     NSSToken *token = PK11Slot_GetNSSToken(internal);
  1025     ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
  1026     (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
  1027     PK11_FreeSlot(token->pk11slot);
  1028     nss_ZFreeIf(ap);
  1031 static CK_TRUST
  1032 get_ck_trust (
  1033   nssTrustLevel nssTrust
  1036     CK_TRUST t;
  1037     switch (nssTrust) {
  1038     case nssTrustLevel_NotTrusted: t = CKT_NSS_NOT_TRUSTED; break;
  1039     case nssTrustLevel_TrustedDelegator: t = CKT_NSS_TRUSTED_DELEGATOR; 
  1040 	break;
  1041     case nssTrustLevel_ValidDelegator: t = CKT_NSS_VALID_DELEGATOR; break;
  1042     case nssTrustLevel_Trusted: t = CKT_NSS_TRUSTED; break;
  1043     case nssTrustLevel_MustVerify: t = CKT_NSS_MUST_VERIFY_TRUST; break;
  1044     case nssTrustLevel_Unknown:
  1045     default: t = CKT_NSS_TRUST_UNKNOWN; break;
  1047     return t;
  1050 NSS_IMPLEMENT nssCryptokiObject *
  1051 nssToken_ImportTrust (
  1052   NSSToken *tok,
  1053   nssSession *sessionOpt,
  1054   NSSDER *certEncoding,
  1055   NSSDER *certIssuer,
  1056   NSSDER *certSerial,
  1057   nssTrustLevel serverAuth,
  1058   nssTrustLevel clientAuth,
  1059   nssTrustLevel codeSigning,
  1060   nssTrustLevel emailProtection,
  1061   PRBool stepUpApproved,
  1062   PRBool asTokenObject
  1065     nssCryptokiObject *object;
  1066     CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
  1067     CK_TRUST ckSA, ckCA, ckCS, ckEP;
  1068     CK_ATTRIBUTE_PTR attr;
  1069     CK_ATTRIBUTE trust_tmpl[11];
  1070     CK_ULONG tsize;
  1071     PRUint8 sha1[20]; /* this is cheating... */
  1072     PRUint8 md5[16];
  1073     NSSItem sha1_result, md5_result;
  1074     sha1_result.data = sha1; sha1_result.size = sizeof sha1;
  1075     md5_result.data = md5; md5_result.size = sizeof md5;
  1076     sha1_hash(certEncoding, &sha1_result);
  1077     md5_hash(certEncoding, &md5_result);
  1078     ckSA = get_ck_trust(serverAuth);
  1079     ckCA = get_ck_trust(clientAuth);
  1080     ckCS = get_ck_trust(codeSigning);
  1081     ckEP = get_ck_trust(emailProtection);
  1082     NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
  1083     if (asTokenObject) {
  1084 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1085     } else {
  1086 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1088     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,           tobjc);
  1089     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,          certIssuer);
  1090     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,   certSerial);
  1091     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
  1092     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH,  &md5_result);
  1093     /* now set the trust values */
  1094     NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH,      ckSA);
  1095     NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH,      ckCA);
  1096     NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING,     ckCS);
  1097     NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
  1098     if (stepUpApproved) {
  1099 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
  1100 	                          &g_ck_true);
  1101     } else {
  1102 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
  1103 	                          &g_ck_false);
  1105     NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
  1106     /* import the trust object onto the token */
  1107     object = import_object(tok, sessionOpt, trust_tmpl, tsize);
  1108     if (object && tok->cache) {
  1109 	nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
  1110 	                                 trust_tmpl, tsize);
  1112     return object;
  1115 NSS_IMPLEMENT nssCryptokiObject *
  1116 nssToken_FindTrustForCertificate (
  1117   NSSToken *token,
  1118   nssSession *sessionOpt,
  1119   NSSDER *certEncoding,
  1120   NSSDER *certIssuer,
  1121   NSSDER *certSerial,
  1122   nssTokenSearchType searchType
  1125     CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
  1126     CK_ATTRIBUTE_PTR attr;
  1127     CK_ATTRIBUTE tobj_template[5];
  1128     CK_ULONG tobj_size;
  1129     nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
  1130     nssCryptokiObject *object = NULL, **objects;
  1132     /* Don't ask the module to use an invalid session handle. */
  1133     if (!session || session->handle == CK_INVALID_SESSION) {
  1134 	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1135 	return object;
  1138     NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
  1139     if (searchType == nssTokenSearchType_TokenOnly) {
  1140 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1142     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,          tobjc);
  1143     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         certIssuer);
  1144     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER , certSerial);
  1145     NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
  1146     objects = find_objects_by_template(token, session,
  1147                                        tobj_template, tobj_size,
  1148                                        1, NULL);
  1149     if (objects) {
  1150 	object = objects[0];
  1151 	nss_ZFreeIf(objects);
  1153     return object;
  1156 NSS_IMPLEMENT nssCryptokiObject *
  1157 nssToken_ImportCRL (
  1158   NSSToken *token,
  1159   nssSession *sessionOpt,
  1160   NSSDER *subject,
  1161   NSSDER *encoding,
  1162   PRBool isKRL,
  1163   NSSUTF8 *url,
  1164   PRBool asTokenObject
  1167     nssCryptokiObject *object;
  1168     CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
  1169     CK_ATTRIBUTE_PTR attr;
  1170     CK_ATTRIBUTE crl_tmpl[6];
  1171     CK_ULONG crlsize;
  1173     NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
  1174     if (asTokenObject) {
  1175 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1176     } else {
  1177 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1179     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,        crlobjc);
  1180     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,      subject);
  1181     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,        encoding);
  1182     NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url);
  1183     if (isKRL) {
  1184 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true);
  1185     } else {
  1186 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false);
  1188     NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
  1190     /* import the crl object onto the token */
  1191     object = import_object(token, sessionOpt, crl_tmpl, crlsize);
  1192     if (object && token->cache) {
  1193 	nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
  1194 	                                 crl_tmpl, crlsize);
  1196     return object;
  1199 NSS_IMPLEMENT nssCryptokiObject **
  1200 nssToken_FindCRLsBySubject (
  1201   NSSToken *token,
  1202   nssSession *sessionOpt,
  1203   NSSDER *subject,
  1204   nssTokenSearchType searchType,
  1205   PRUint32 maximumOpt,
  1206   PRStatus *statusOpt
  1209     CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
  1210     CK_ATTRIBUTE_PTR attr;
  1211     CK_ATTRIBUTE crlobj_template[3];
  1212     CK_ULONG crlobj_size;
  1213     nssCryptokiObject **objects = NULL;
  1214     nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
  1216     /* Don't ask the module to use an invalid session handle. */
  1217     if (!session || session->handle == CK_INVALID_SESSION) {
  1218 	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1219 	return objects;
  1222     NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
  1223     if (searchType == nssTokenSearchType_SessionOnly) {
  1224 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1225     } else if (searchType == nssTokenSearchType_TokenOnly ||
  1226                searchType == nssTokenSearchType_TokenForced) {
  1227 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1229     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
  1230     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
  1231     NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
  1233     objects = find_objects_by_template(token, session,
  1234                                        crlobj_template, crlobj_size,
  1235                                        maximumOpt, statusOpt);
  1236     return objects;
  1239 NSS_IMPLEMENT PRStatus
  1240 nssToken_GetCachedObjectAttributes (
  1241   NSSToken *token,
  1242   NSSArena *arenaOpt,
  1243   nssCryptokiObject *object,
  1244   CK_OBJECT_CLASS objclass,
  1245   CK_ATTRIBUTE_PTR atemplate,
  1246   CK_ULONG atlen
  1249     if (!token->cache) {
  1250 	return PR_FAILURE;
  1252     return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
  1253                                                    object, objclass,
  1254                                                    atemplate, atlen);
  1257 NSS_IMPLEMENT NSSItem *
  1258 nssToken_Digest (
  1259   NSSToken *tok,
  1260   nssSession *sessionOpt,
  1261   NSSAlgorithmAndParameters *ap,
  1262   NSSItem *data,
  1263   NSSItem *rvOpt,
  1264   NSSArena *arenaOpt
  1267     CK_RV ckrv;
  1268     CK_ULONG digestLen;
  1269     CK_BYTE_PTR digest;
  1270     NSSItem *rvItem = NULL;
  1271     void *epv = nssToken_GetCryptokiEPV(tok);
  1272     nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1274     /* Don't ask the module to use an invalid session handle. */
  1275     if (!session || session->handle == CK_INVALID_SESSION) {
  1276 	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1277 	return rvItem;
  1280     nssSession_EnterMonitor(session);
  1281     ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
  1282     if (ckrv != CKR_OK) {
  1283 	nssSession_ExitMonitor(session);
  1284 	return NULL;
  1286 #if 0
  1287     /* XXX the standard says this should work, but it doesn't */
  1288     ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
  1289     if (ckrv != CKR_OK) {
  1290 	nssSession_ExitMonitor(session);
  1291 	return NULL;
  1293 #endif
  1294     digestLen = 0; /* XXX for now */
  1295     digest = NULL;
  1296     if (rvOpt) {
  1297 	if (rvOpt->size > 0 && rvOpt->size < digestLen) {
  1298 	    nssSession_ExitMonitor(session);
  1299 	    /* the error should be bad args */
  1300 	    return NULL;
  1302 	if (rvOpt->data) {
  1303 	    digest = rvOpt->data;
  1305 	digestLen = rvOpt->size;
  1307     if (!digest) {
  1308 	digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
  1309 	if (!digest) {
  1310 	    nssSession_ExitMonitor(session);
  1311 	    return NULL;
  1314     ckrv = CKAPI(epv)->C_Digest(session->handle, 
  1315                                 (CK_BYTE_PTR)data->data, 
  1316                                 (CK_ULONG)data->size,
  1317                                 (CK_BYTE_PTR)digest,
  1318                                 &digestLen);
  1319     nssSession_ExitMonitor(session);
  1320     if (ckrv != CKR_OK) {
  1321 	nss_ZFreeIf(digest);
  1322 	return NULL;
  1324     if (!rvOpt) {
  1325 	rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
  1327     return rvItem;
  1330 NSS_IMPLEMENT PRStatus
  1331 nssToken_BeginDigest (
  1332   NSSToken *tok,
  1333   nssSession *sessionOpt,
  1334   NSSAlgorithmAndParameters *ap
  1337     CK_RV ckrv;
  1338     void *epv = nssToken_GetCryptokiEPV(tok);
  1339     nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1341     /* Don't ask the module to use an invalid session handle. */
  1342     if (!session || session->handle == CK_INVALID_SESSION) {
  1343 	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1344 	return PR_FAILURE;
  1347     nssSession_EnterMonitor(session);
  1348     ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
  1349     nssSession_ExitMonitor(session);
  1350     return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
  1353 NSS_IMPLEMENT PRStatus
  1354 nssToken_ContinueDigest (
  1355   NSSToken *tok,
  1356   nssSession *sessionOpt,
  1357   NSSItem *item
  1360     CK_RV ckrv;
  1361     void *epv = nssToken_GetCryptokiEPV(tok);
  1362     nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1364     /* Don't ask the module to use an invalid session handle. */
  1365     if (!session || session->handle == CK_INVALID_SESSION) {
  1366 	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1367 	return PR_FAILURE;
  1370     nssSession_EnterMonitor(session);
  1371     ckrv = CKAPI(epv)->C_DigestUpdate(session->handle, 
  1372                                       (CK_BYTE_PTR)item->data, 
  1373                                       (CK_ULONG)item->size);
  1374     nssSession_ExitMonitor(session);
  1375     return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
  1378 NSS_IMPLEMENT NSSItem *
  1379 nssToken_FinishDigest (
  1380   NSSToken *tok,
  1381   nssSession *sessionOpt,
  1382   NSSItem *rvOpt,
  1383   NSSArena *arenaOpt
  1386     CK_RV ckrv;
  1387     CK_ULONG digestLen;
  1388     CK_BYTE_PTR digest;
  1389     NSSItem *rvItem = NULL;
  1390     void *epv = nssToken_GetCryptokiEPV(tok);
  1391     nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
  1393     /* Don't ask the module to use an invalid session handle. */
  1394     if (!session || session->handle == CK_INVALID_SESSION) {
  1395 	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1396 	return NULL;
  1399     nssSession_EnterMonitor(session);
  1400     ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
  1401     if (ckrv != CKR_OK || digestLen == 0) {
  1402 	nssSession_ExitMonitor(session);
  1403 	return NULL;
  1405     digest = NULL;
  1406     if (rvOpt) {
  1407 	if (rvOpt->size > 0 && rvOpt->size < digestLen) {
  1408 	    nssSession_ExitMonitor(session);
  1409 	    /* the error should be bad args */
  1410 	    return NULL;
  1412 	if (rvOpt->data) {
  1413 	    digest = rvOpt->data;
  1415 	digestLen = rvOpt->size;
  1417     if (!digest) {
  1418 	digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
  1419 	if (!digest) {
  1420 	    nssSession_ExitMonitor(session);
  1421 	    return NULL;
  1424     ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
  1425     nssSession_ExitMonitor(session);
  1426     if (ckrv != CKR_OK) {
  1427 	nss_ZFreeIf(digest);
  1428 	return NULL;
  1430     if (!rvOpt) {
  1431 	rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
  1433     return rvItem;
  1436 NSS_IMPLEMENT PRBool
  1437 nssToken_IsPresent (
  1438   NSSToken *token
  1441     return nssSlot_IsTokenPresent(token->slot);
  1444 /* Sigh.  The methods to find objects declared above cause problems with
  1445  * the low-level object cache in the softoken -- the objects are found in 
  1446  * toto, then one wave of GetAttributes is done, then another.  Having a 
  1447  * large number of objects causes the cache to be thrashed, as the objects 
  1448  * are gone before there's any chance to ask for their attributes.
  1449  * So, for now, bringing back traversal methods for certs.  This way all of 
  1450  * the cert's attributes can be grabbed immediately after finding it,
  1451  * increasing the likelihood that the cache takes care of it.
  1452  */
  1453 NSS_IMPLEMENT PRStatus
  1454 nssToken_TraverseCertificates (
  1455   NSSToken *token,
  1456   nssSession *sessionOpt,
  1457   nssTokenSearchType searchType,
  1458   PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
  1459   void *arg
  1462     CK_RV ckrv;
  1463     CK_ULONG count;
  1464     CK_OBJECT_HANDLE *objectHandles;
  1465     CK_ATTRIBUTE_PTR attr;
  1466     CK_ATTRIBUTE cert_template[2];
  1467     CK_ULONG ctsize;
  1468     NSSArena *arena;
  1469     PRStatus status;
  1470     PRUint32 arraySize, numHandles;
  1471     nssCryptokiObject **objects;
  1472     void *epv = nssToken_GetCryptokiEPV(token);
  1473     nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
  1475     /* Don't ask the module to use an invalid session handle. */
  1476     if (!session || session->handle == CK_INVALID_SESSION) {
  1477 	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1478 	return PR_FAILURE;
  1481     /* template for all certs */
  1482     NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
  1483     if (searchType == nssTokenSearchType_SessionOnly) {
  1484 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
  1485     } else if (searchType == nssTokenSearchType_TokenOnly ||
  1486                searchType == nssTokenSearchType_TokenForced) {
  1487 	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
  1489     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
  1490     NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
  1492     /* the arena is only for the array of object handles */
  1493     arena = nssArena_Create();
  1494     if (!arena) {
  1495 	return PR_FAILURE;
  1497     arraySize = OBJECT_STACK_SIZE;
  1498     numHandles = 0;
  1499     objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
  1500     if (!objectHandles) {
  1501 	goto loser;
  1503     nssSession_EnterMonitor(session); /* ==== session lock === */
  1504     /* Initialize the find with the template */
  1505     ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
  1506                                          cert_template, ctsize);
  1507     if (ckrv != CKR_OK) {
  1508 	nssSession_ExitMonitor(session);
  1509 	goto loser;
  1511     while (PR_TRUE) {
  1512 	/* Issue the find for up to arraySize - numHandles objects */
  1513 	ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
  1514 	                                 objectHandles + numHandles, 
  1515 	                                 arraySize - numHandles, 
  1516 	                                 &count);
  1517 	if (ckrv != CKR_OK) {
  1518 	    nssSession_ExitMonitor(session);
  1519 	    goto loser;
  1521 	/* bump the number of found objects */
  1522 	numHandles += count;
  1523 	if (numHandles < arraySize) {
  1524 	    break;
  1526 	/* the array is filled, double it and continue */
  1527 	arraySize *= 2;
  1528 	objectHandles = nss_ZREALLOCARRAY(objectHandles, 
  1529 	                                  CK_OBJECT_HANDLE, 
  1530 	                                  arraySize);
  1531 	if (!objectHandles) {
  1532 	    nssSession_ExitMonitor(session);
  1533 	    goto loser;
  1536     ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
  1537     nssSession_ExitMonitor(session); /* ==== end session lock === */
  1538     if (ckrv != CKR_OK) {
  1539 	goto loser;
  1541     if (numHandles > 0) {
  1542 	objects = create_objects_from_handles(token, session,
  1543 	                                      objectHandles, numHandles);
  1544 	if (objects) {
  1545 	    nssCryptokiObject **op;
  1546 	    for (op = objects; *op; op++) {
  1547 		status = (*callback)(*op, arg);
  1549 	    nss_ZFreeIf(objects);
  1552     nssArena_Destroy(arena);
  1553     return PR_SUCCESS;
  1554 loser:
  1555     nssArena_Destroy(arena);
  1556     return PR_FAILURE;
  1559 NSS_IMPLEMENT PRBool
  1560 nssToken_IsPrivateKeyAvailable (
  1561   NSSToken *token,
  1562   NSSCertificate *c,
  1563   nssCryptokiObject *instance
  1566     CK_OBJECT_CLASS theClass;
  1568     if (token == NULL) return PR_FALSE;
  1569     if (c == NULL) return PR_FALSE;
  1571     theClass = CKO_PRIVATE_KEY;
  1572     if (!nssSlot_IsLoggedIn(token->slot)) {
  1573 	theClass = CKO_PUBLIC_KEY;
  1575     if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) 
  1576 						!= CK_INVALID_HANDLE) {
  1577 	return PR_TRUE;
  1579     return PR_FALSE;

mercurial