security/nss/lib/dev/devutil.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 #ifndef DEVM_H
     6 #include "devm.h"
     7 #endif /* DEVM_H */
     9 #ifndef CKHELPER_H
    10 #include "ckhelper.h"
    11 #endif /* CKHELPER_H */
    13 NSS_IMPLEMENT nssCryptokiObject *
    14 nssCryptokiObject_Create (
    15   NSSToken *t, 
    16   nssSession *session,
    17   CK_OBJECT_HANDLE h
    18 )
    19 {
    20     PRStatus status;
    21     NSSSlot *slot;
    22     nssCryptokiObject *object;
    23     CK_BBOOL *isTokenObject;
    24     CK_ATTRIBUTE cert_template[] = {
    25 	{ CKA_TOKEN, NULL, 0 },
    26 	{ CKA_LABEL, NULL, 0 }
    27     };
    28     slot = nssToken_GetSlot(t);
    29     status = nssCKObject_GetAttributes(h, cert_template, 2,
    30                                        NULL, session, slot);
    31     nssSlot_Destroy(slot);
    32     if (status != PR_SUCCESS) {
    33 	/* a failure here indicates a device error */
    34 	return (nssCryptokiObject *)NULL;
    35     }
    36     object = nss_ZNEW(NULL, nssCryptokiObject);
    37     if (!object) {
    38 	return (nssCryptokiObject *)NULL;
    39     }
    40     object->handle = h;
    41     object->token = nssToken_AddRef(t);
    42     isTokenObject = (CK_BBOOL *)cert_template[0].pValue;
    43     object->isTokenObject = *isTokenObject;
    44     nss_ZFreeIf(isTokenObject);
    45     NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label);
    46     return object;
    47 }
    49 NSS_IMPLEMENT void
    50 nssCryptokiObject_Destroy (
    51   nssCryptokiObject *object
    52 )
    53 {
    54     if (object) {
    55 	nssToken_Destroy(object->token);
    56 	nss_ZFreeIf(object->label);
    57 	nss_ZFreeIf(object);
    58     }
    59 }
    61 NSS_IMPLEMENT nssCryptokiObject *
    62 nssCryptokiObject_Clone (
    63   nssCryptokiObject *object
    64 )
    65 {
    66     nssCryptokiObject *rvObject;
    67     rvObject = nss_ZNEW(NULL, nssCryptokiObject);
    68     if (rvObject) {
    69 	rvObject->handle = object->handle;
    70 	rvObject->token = nssToken_AddRef(object->token);
    71 	rvObject->isTokenObject = object->isTokenObject;
    72 	if (object->label) {
    73 	    rvObject->label = nssUTF8_Duplicate(object->label, NULL);
    74 	}
    75     }
    76     return rvObject;
    77 }
    79 NSS_EXTERN PRBool
    80 nssCryptokiObject_Equal (
    81   nssCryptokiObject *o1,
    82   nssCryptokiObject *o2
    83 )
    84 {
    85     return (o1->token == o2->token && o1->handle == o2->handle);
    86 }
    88 NSS_IMPLEMENT PRUint32
    89 nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen)
    90 {
    91     PRInt32 i;
    92     for (i = bufLen - 1; i>=0; ) {
    93 	if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0') break;
    94 	--i;
    95     }
    96     return (PRUint32)(i + 1);
    97 }
    99 /*
   100  * Slot arrays
   101  */
   103 NSS_IMPLEMENT NSSSlot **
   104 nssSlotArray_Clone (
   105   NSSSlot **slots
   106 )
   107 {
   108     NSSSlot **rvSlots = NULL;
   109     NSSSlot **sp = slots;
   110     PRUint32 count = 0;
   111     while (sp && *sp) count++;
   112     if (count > 0) {
   113 	rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1);
   114 	if (rvSlots) {
   115 	    for (sp = slots, count = 0; *sp; sp++) {
   116 		rvSlots[count++] = nssSlot_AddRef(*sp);
   117 	    }
   118 	}
   119     }
   120     return rvSlots;
   121 }
   123 NSS_IMPLEMENT void
   124 nssSlotArray_Destroy (
   125   NSSSlot **slots
   126 )
   127 {
   128     if (slots) {
   129 	NSSSlot **slotp;
   130 	for (slotp = slots; *slotp; slotp++) {
   131 	    nssSlot_Destroy(*slotp);
   132 	}
   133 	nss_ZFreeIf(slots);
   134     }
   135 }
   137 NSS_IMPLEMENT void
   138 NSSSlotArray_Destroy (
   139   NSSSlot **slots
   140 )
   141 {
   142     nssSlotArray_Destroy(slots);
   143 }
   145 NSS_IMPLEMENT void
   146 nssTokenArray_Destroy (
   147   NSSToken **tokens
   148 )
   149 {
   150     if (tokens) {
   151 	NSSToken **tokenp;
   152 	for (tokenp = tokens; *tokenp; tokenp++) {
   153 	    nssToken_Destroy(*tokenp);
   154 	}
   155 	nss_ZFreeIf(tokens);
   156     }
   157 }
   159 NSS_IMPLEMENT void
   160 NSSTokenArray_Destroy (
   161   NSSToken **tokens
   162 )
   163 {
   164     nssTokenArray_Destroy(tokens);
   165 }
   167 NSS_IMPLEMENT void
   168 nssCryptokiObjectArray_Destroy (
   169   nssCryptokiObject **objects
   170 )
   171 {
   172     if (objects) {
   173 	nssCryptokiObject **op;
   174 	for (op = objects; *op; op++) {
   175 	    nssCryptokiObject_Destroy(*op);
   176 	}
   177 	nss_ZFreeIf(objects);
   178     }
   179 }
   181 /* object cache for token */
   183 typedef struct
   184 {
   185   NSSArena *arena;
   186   nssCryptokiObject *object;
   187   CK_ATTRIBUTE_PTR attributes;
   188   CK_ULONG numAttributes;
   189 }
   190 nssCryptokiObjectAndAttributes;
   192 enum {
   193   cachedCerts = 0,
   194   cachedTrust = 1,
   195   cachedCRLs = 2
   196 } cachedObjectType;
   198 struct nssTokenObjectCacheStr
   199 {
   200   NSSToken *token;
   201   PZLock *lock;
   202   PRBool loggedIn;
   203   PRBool doObjectType[3];
   204   PRBool searchedObjectType[3];
   205   nssCryptokiObjectAndAttributes **objects[3];
   206 };
   208 NSS_IMPLEMENT nssTokenObjectCache *
   209 nssTokenObjectCache_Create (
   210   NSSToken *token,
   211   PRBool cacheCerts,
   212   PRBool cacheTrust,
   213   PRBool cacheCRLs
   214 )
   215 {
   216     nssTokenObjectCache *rvCache;
   217     rvCache = nss_ZNEW(NULL, nssTokenObjectCache);
   218     if (!rvCache) {
   219 	goto loser;
   220     }
   221     rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */
   222     if (!rvCache->lock) {
   223 	goto loser;
   224     }
   225     rvCache->doObjectType[cachedCerts] = cacheCerts;
   226     rvCache->doObjectType[cachedTrust] = cacheTrust;
   227     rvCache->doObjectType[cachedCRLs] = cacheCRLs;
   228     rvCache->token = token; /* cache goes away with token */
   229     return rvCache;
   230 loser:
   231     nssTokenObjectCache_Destroy(rvCache);
   232     return (nssTokenObjectCache *)NULL;
   233 }
   235 static void
   236 clear_cache (
   237   nssTokenObjectCache *cache
   238 )
   239 {
   240     nssCryptokiObjectAndAttributes **oa;
   241     PRUint32 objectType;
   242     for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) {
   243 	cache->searchedObjectType[objectType] = PR_FALSE;
   244 	if (!cache->objects[objectType]) {
   245 	    continue;
   246 	}
   247 	for (oa = cache->objects[objectType]; *oa; oa++) {
   248 	    /* prevent the token from being destroyed */
   249 	    (*oa)->object->token = NULL;
   250 	    nssCryptokiObject_Destroy((*oa)->object);
   251 	    nssArena_Destroy((*oa)->arena);
   252 	}
   253 	nss_ZFreeIf(cache->objects[objectType]);
   254 	cache->objects[objectType] = NULL;
   255     }
   256 }
   258 NSS_IMPLEMENT void
   259 nssTokenObjectCache_Clear (
   260   nssTokenObjectCache *cache
   261 )
   262 {
   263     if (cache) {
   264 	PZ_Lock(cache->lock);
   265 	clear_cache(cache);
   266 	PZ_Unlock(cache->lock);
   267     }
   268 }
   270 NSS_IMPLEMENT void
   271 nssTokenObjectCache_Destroy (
   272   nssTokenObjectCache *cache
   273 )
   274 {
   275     if (cache) {
   276 	clear_cache(cache);
   277 	if (cache->lock) {
   278 	    PZ_DestroyLock(cache->lock);
   279 	}
   280 	nss_ZFreeIf(cache);
   281     }
   282 }
   284 NSS_IMPLEMENT PRBool
   285 nssTokenObjectCache_HaveObjectClass (
   286   nssTokenObjectCache *cache,
   287   CK_OBJECT_CLASS objclass
   288 )
   289 {
   290     PRBool haveIt;
   291     PZ_Lock(cache->lock);
   292     switch (objclass) {
   293     case CKO_CERTIFICATE:    haveIt = cache->doObjectType[cachedCerts]; break;
   294     case CKO_NETSCAPE_TRUST: haveIt = cache->doObjectType[cachedTrust]; break;
   295     case CKO_NETSCAPE_CRL:   haveIt = cache->doObjectType[cachedCRLs];  break;
   296     default:                 haveIt = PR_FALSE;
   297     }
   298     PZ_Unlock(cache->lock);
   299     return haveIt;
   300 }
   302 static nssCryptokiObjectAndAttributes **
   303 create_object_array (
   304   nssCryptokiObject **objects,
   305   PRBool *doObjects,
   306   PRUint32 *numObjects,
   307   PRStatus *status
   308 )
   309 {
   310     nssCryptokiObjectAndAttributes **rvOandA = NULL;
   311     *numObjects = 0;
   312     /* There are no objects for this type */
   313     if (!objects || !*objects) {
   314 	*status = PR_SUCCESS;
   315 	return rvOandA;
   316     }
   317     while (*objects++) (*numObjects)++;
   318     if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) {
   319 	/* Hit the maximum allowed, so don't use a cache (there are
   320 	 * too many objects to make caching worthwhile, presumably, if
   321 	 * the token can handle that many objects, it can handle searching.
   322 	 */
   323 	*doObjects = PR_FALSE;
   324 	*status = PR_FAILURE;
   325 	*numObjects = 0;
   326     } else {
   327 	rvOandA = nss_ZNEWARRAY(NULL, 
   328 	                        nssCryptokiObjectAndAttributes *, 
   329 	                        *numObjects + 1);
   330 	*status = rvOandA ? PR_SUCCESS : PR_FAILURE;
   331     }
   332     return rvOandA;
   333 }
   335 static nssCryptokiObjectAndAttributes *
   336 create_object (
   337   nssCryptokiObject *object,
   338   const CK_ATTRIBUTE_TYPE *types,
   339   PRUint32 numTypes,
   340   PRStatus *status
   341 )
   342 {
   343     PRUint32 j;
   344     NSSArena *arena = NULL;
   345     NSSSlot *slot = NULL;
   346     nssSession *session = NULL;
   347     nssCryptokiObjectAndAttributes *rvCachedObject = NULL;
   349     slot = nssToken_GetSlot(object->token);
   350     if (!slot) {
   351         nss_SetError(NSS_ERROR_INVALID_POINTER);
   352         goto loser;
   353     }
   354     session = nssToken_GetDefaultSession(object->token);
   355     if (!session) {
   356         nss_SetError(NSS_ERROR_INVALID_POINTER);
   357         goto loser;
   358     }
   359     arena = nssArena_Create();
   360     if (!arena) {
   361 	goto loser;
   362     }
   363     rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes);
   364     if (!rvCachedObject) {
   365 	goto loser;
   366     }
   367     rvCachedObject->arena = arena;
   368     /* The cache is tied to the token, and therefore the objects
   369      * in it should not hold references to the token.
   370      */
   371     nssToken_Destroy(object->token);
   372     rvCachedObject->object = object;
   373     rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes);
   374     if (!rvCachedObject->attributes) {
   375 	goto loser;
   376     }
   377     for (j=0; j<numTypes; j++) {
   378 	rvCachedObject->attributes[j].type = types[j];
   379     }
   380     *status = nssCKObject_GetAttributes(object->handle,
   381                                         rvCachedObject->attributes,
   382                                         numTypes,
   383                                         arena,
   384                                         session,
   385                                         slot);
   386     if (*status != PR_SUCCESS) {
   387 	goto loser;
   388     }
   389     rvCachedObject->numAttributes = numTypes;
   390     *status = PR_SUCCESS;
   391     nssSlot_Destroy(slot);
   393     return rvCachedObject;
   394 loser:
   395     *status = PR_FAILURE;
   396     if (slot) {
   397 	nssSlot_Destroy(slot);
   398     }
   399     if (arena)
   400 	nssArena_Destroy(arena);
   401     return (nssCryptokiObjectAndAttributes *)NULL;
   402 }
   404 /*
   405  *
   406  * State diagram for cache:
   407  *
   408  *            token !present            token removed
   409  *        +-------------------------+<----------------------+
   410  *        |                         ^                       |
   411  *        v                         |                       |
   412  *  +----------+   slot friendly    |  token present   +----------+ 
   413  *  |   cache  | -----------------> % ---------------> |   cache  |
   414  *  | unloaded |                                       |  loaded  |
   415  *  +----------+                                       +----------+
   416  *    ^   |                                                 ^   |
   417  *    |   |   slot !friendly           slot logged in       |   |
   418  *    |   +-----------------------> % ----------------------+   |
   419  *    |                             |                           |
   420  *    | slot logged out             v  slot !friendly           |
   421  *    +-----------------------------+<--------------------------+
   422  *
   423  */
   425 /* This function must not be called with cache->lock locked. */
   426 static PRBool
   427 token_is_present (
   428   nssTokenObjectCache *cache
   429 )
   430 {
   431     NSSSlot *slot = nssToken_GetSlot(cache->token);
   432     PRBool tokenPresent = nssSlot_IsTokenPresent(slot);
   433     nssSlot_Destroy(slot);
   434     return tokenPresent;
   435 }
   437 static PRBool
   438 search_for_objects (
   439   nssTokenObjectCache *cache
   440 )
   441 {
   442     PRBool doSearch = PR_FALSE;
   443     NSSSlot *slot = nssToken_GetSlot(cache->token);
   444     /* Handle non-friendly slots (slots which require login for objects) */
   445     if (!nssSlot_IsFriendly(slot)) {
   446 	if (nssSlot_IsLoggedIn(slot)) {
   447 	    /* Either no state change, or went from !logged in -> logged in */
   448 	    cache->loggedIn = PR_TRUE;
   449 	    doSearch = PR_TRUE;
   450 	} else {
   451 	    if (cache->loggedIn) {
   452 		/* went from logged in -> !logged in, destroy cached objects */
   453 		clear_cache(cache);
   454 		cache->loggedIn = PR_FALSE;
   455 	    } /* else no state change, still not logged in, so exit */
   456 	}
   457     } else {
   458 	/* slot is friendly, thus always available for search */
   459 	doSearch = PR_TRUE;
   460     }
   461     nssSlot_Destroy(slot);
   462     return doSearch;
   463 }
   465 static nssCryptokiObjectAndAttributes *
   466 create_cert (
   467   nssCryptokiObject *object,
   468   PRStatus *status
   469 )
   470 {
   471     static const CK_ATTRIBUTE_TYPE certAttr[] = {
   472 	CKA_CLASS,
   473 	CKA_TOKEN,
   474 	CKA_LABEL,
   475 	CKA_CERTIFICATE_TYPE,
   476 	CKA_ID,
   477 	CKA_VALUE,
   478 	CKA_ISSUER,
   479 	CKA_SERIAL_NUMBER,
   480 	CKA_SUBJECT,
   481 	CKA_NETSCAPE_EMAIL
   482     };
   483     static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]);
   484     return create_object(object, certAttr, numCertAttr, status);
   485 }
   487 static nssCryptokiObjectAndAttributes *
   488 create_trust (
   489   nssCryptokiObject *object,
   490   PRStatus *status
   491 )
   492 {
   493     static const CK_ATTRIBUTE_TYPE trustAttr[] = {
   494 	CKA_CLASS,
   495 	CKA_TOKEN,
   496 	CKA_LABEL,
   497 	CKA_CERT_SHA1_HASH,
   498 	CKA_CERT_MD5_HASH,
   499 	CKA_ISSUER,
   500 	CKA_SUBJECT,
   501 	CKA_TRUST_SERVER_AUTH,
   502 	CKA_TRUST_CLIENT_AUTH,
   503 	CKA_TRUST_EMAIL_PROTECTION,
   504 	CKA_TRUST_CODE_SIGNING
   505     };
   506     static const PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]);
   507     return create_object(object, trustAttr, numTrustAttr, status);
   508 }
   510 static nssCryptokiObjectAndAttributes *
   511 create_crl (
   512   nssCryptokiObject *object,
   513   PRStatus *status
   514 )
   515 {
   516     static const CK_ATTRIBUTE_TYPE crlAttr[] = {
   517 	CKA_CLASS,
   518 	CKA_TOKEN,
   519 	CKA_LABEL,
   520 	CKA_VALUE,
   521 	CKA_SUBJECT,
   522 	CKA_NETSCAPE_KRL,
   523 	CKA_NETSCAPE_URL
   524     };
   525     static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]);
   526     return create_object(object, crlAttr, numCRLAttr, status);
   527 }
   529 /* Dispatch to the create function for the object type */
   530 static nssCryptokiObjectAndAttributes *
   531 create_object_of_type (
   532   nssCryptokiObject *object,
   533   PRUint32 objectType,
   534   PRStatus *status
   535 )
   536 {
   537     if (objectType == cachedCerts) {
   538 	return create_cert(object, status);
   539     }
   540     if (objectType == cachedTrust) {
   541 	return create_trust(object, status);
   542     }
   543     if (objectType == cachedCRLs) {
   544 	return create_crl(object, status);
   545     }
   546     return (nssCryptokiObjectAndAttributes *)NULL;
   547 }
   549 static PRStatus
   550 get_token_objects_for_cache (
   551   nssTokenObjectCache *cache,
   552   PRUint32 objectType,
   553   CK_OBJECT_CLASS objclass
   554 )
   555 {
   556     PRStatus status;
   557     nssCryptokiObject **objects;
   558     PRBool *doIt = &cache->doObjectType[objectType];
   559     PRUint32 i, numObjects;
   561     if (!search_for_objects(cache) || 
   562          cache->searchedObjectType[objectType] || 
   563         !cache->doObjectType[objectType]) 
   564     {
   565 	/* Either there was a state change that prevents a search
   566 	 * (token logged out), or the search was already done,
   567 	 * or objects of this type are not being cached.
   568 	 */
   569 	return PR_SUCCESS;
   570     }
   571     objects = nssToken_FindObjects(cache->token, NULL, objclass,
   572                                    nssTokenSearchType_TokenForced,
   573                                    MAX_LOCAL_CACHE_OBJECTS, &status);
   574     if (status != PR_SUCCESS) {
   575 	return status;
   576     }
   577     cache->objects[objectType] = create_object_array(objects,
   578                                                      doIt,
   579                                                      &numObjects,
   580                                                      &status);
   581     if (status != PR_SUCCESS) {
   582 	return status;
   583     }
   584     for (i=0; i<numObjects; i++) {
   585 	cache->objects[objectType][i] = create_object_of_type(objects[i],
   586 	                                                      objectType,
   587 	                                                      &status);
   588 	if (status != PR_SUCCESS) {
   589 	    break;
   590 	}
   591     }
   592     if (status == PR_SUCCESS) {
   593 	nss_ZFreeIf(objects);
   594     } else {
   595 	PRUint32 j;
   596 	for (j=0; j<i; j++) {
   597 	    /* sigh */
   598 	    nssToken_AddRef(cache->objects[objectType][j]->object->token);
   599 	    nssArena_Destroy(cache->objects[objectType][j]->arena);
   600 	}
   601 	nss_ZFreeIf(cache->objects[objectType]);
   602 	cache->objects[objectType] = NULL;
   603 	nssCryptokiObjectArray_Destroy(objects);
   604     }
   605     cache->searchedObjectType[objectType] = PR_TRUE;
   606     return status;
   607 }
   609 static CK_ATTRIBUTE_PTR
   610 find_attribute_in_object (
   611   nssCryptokiObjectAndAttributes *obj,
   612   CK_ATTRIBUTE_TYPE attrType
   613 )
   614 {
   615     PRUint32 j;
   616     for (j=0; j<obj->numAttributes; j++) {
   617 	if (attrType == obj->attributes[j].type) {
   618 	    return &obj->attributes[j];
   619 	}
   620     }
   621     return (CK_ATTRIBUTE_PTR)NULL;
   622 }
   624 /* Find all objects in the array that match the supplied template */
   625 static nssCryptokiObject **
   626 find_objects_in_array (
   627   nssCryptokiObjectAndAttributes **objArray,
   628   CK_ATTRIBUTE_PTR ot,
   629   CK_ULONG otlen,
   630   PRUint32 maximumOpt
   631 )
   632 {
   633     PRIntn oi = 0;
   634     PRUint32 i;
   635     NSSArena *arena;
   636     PRUint32 size = 8;
   637     PRUint32 numMatches = 0;
   638     nssCryptokiObject **objects = NULL;
   639     nssCryptokiObjectAndAttributes **matches = NULL;
   640     CK_ATTRIBUTE_PTR attr;
   642     if (!objArray) {
   643 	return (nssCryptokiObject **)NULL;
   644     }
   645     arena = nssArena_Create();
   646     if (!arena) {
   647 	return (nssCryptokiObject **)NULL;
   648     }
   649     matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size);
   650     if (!matches) {
   651 	goto loser;
   652     }
   653     if (maximumOpt == 0) maximumOpt = ~0;
   654     /* loop over the cached objects */
   655     for (; *objArray && numMatches < maximumOpt; objArray++) {
   656 	nssCryptokiObjectAndAttributes *obj = *objArray;
   657 	/* loop over the test template */
   658 	for (i=0; i<otlen; i++) {
   659 	    /* see if the object has the attribute */
   660 	    attr = find_attribute_in_object(obj, ot[i].type);
   661 	    if (!attr) {
   662 		/* nope, match failed */
   663 		break;
   664 	    }
   665 	    /* compare the attribute against the test value */
   666 	    if (ot[i].ulValueLen != attr->ulValueLen ||
   667 	        !nsslibc_memequal(ot[i].pValue, 
   668 	                          attr->pValue,
   669 	                          attr->ulValueLen, NULL))
   670 	    {
   671 		/* nope, match failed */
   672 		break;
   673 	    }
   674 	}
   675 	if (i == otlen) {
   676 	    /* all of the attributes in the test template were found
   677 	     * in the object's template, and they all matched
   678 	     */
   679 	    matches[numMatches++] = obj;
   680 	    if (numMatches == size) {
   681 		size *= 2;
   682 		matches = nss_ZREALLOCARRAY(matches, 
   683 		                            nssCryptokiObjectAndAttributes *, 
   684 		                            size);
   685 		if (!matches) {
   686 		    goto loser;
   687 		}
   688 	    }
   689 	}
   690     }
   691     if (numMatches > 0) {
   692 	objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1);
   693 	if (!objects) {
   694 	    goto loser;
   695 	}
   696 	for (oi=0; oi<(PRIntn)numMatches; oi++) {
   697 	    objects[oi] = nssCryptokiObject_Clone(matches[oi]->object);
   698 	    if (!objects[oi]) {
   699 		goto loser;
   700 	    }
   701 	}
   702     }
   703     nssArena_Destroy(arena);
   704     return objects;
   705 loser:
   706     nssCryptokiObjectArray_Destroy(objects);
   707     nssArena_Destroy(arena);
   708     return (nssCryptokiObject **)NULL;
   709 }
   711 NSS_IMPLEMENT nssCryptokiObject **
   712 nssTokenObjectCache_FindObjectsByTemplate (
   713   nssTokenObjectCache *cache,
   714   CK_OBJECT_CLASS objclass,
   715   CK_ATTRIBUTE_PTR otemplate,
   716   CK_ULONG otlen,
   717   PRUint32 maximumOpt,
   718   PRStatus *statusOpt
   719 )
   720 {
   721     PRStatus status = PR_FAILURE;
   722     nssCryptokiObject **rvObjects = NULL;
   723     PRUint32 objectType;
   724     if (!token_is_present(cache)) {
   725 	status = PR_SUCCESS;
   726 	goto finish;
   727     }
   728     switch (objclass) {
   729     case CKO_CERTIFICATE:    objectType = cachedCerts; break;
   730     case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
   731     case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
   732     default: goto finish;
   733     }
   734     PZ_Lock(cache->lock);
   735     if (cache->doObjectType[objectType]) {
   736 	status = get_token_objects_for_cache(cache, objectType, objclass);
   737 	if (status == PR_SUCCESS) {
   738 	    rvObjects = find_objects_in_array(cache->objects[objectType], 
   739 	                                      otemplate, otlen, maximumOpt);
   740 	}
   741     }
   742     PZ_Unlock(cache->lock);
   743 finish:
   744     if (statusOpt) {
   745 	*statusOpt = status;
   746     }
   747     return rvObjects;
   748 }
   750 static PRBool
   751 cache_available_for_object_type (
   752   nssTokenObjectCache *cache,
   753   PRUint32 objectType
   754 )
   755 {
   756     if (!cache->doObjectType[objectType]) {
   757 	/* not caching this object kind */
   758 	return PR_FALSE;
   759     }
   760     if (!cache->searchedObjectType[objectType]) {
   761 	/* objects are not cached yet */
   762 	return PR_FALSE;
   763     }
   764     if (!search_for_objects(cache)) {
   765 	/* not logged in */
   766 	return PR_FALSE;
   767     }
   768     return PR_TRUE;
   769 }
   771 NSS_IMPLEMENT PRStatus
   772 nssTokenObjectCache_GetObjectAttributes (
   773   nssTokenObjectCache *cache,
   774   NSSArena *arenaOpt,
   775   nssCryptokiObject *object,
   776   CK_OBJECT_CLASS objclass,
   777   CK_ATTRIBUTE_PTR atemplate,
   778   CK_ULONG atlen
   779 )
   780 {
   781     PRUint32 i, j;
   782     NSSArena *arena = NULL;
   783     nssArenaMark *mark = NULL;
   784     nssCryptokiObjectAndAttributes *cachedOA = NULL;
   785     nssCryptokiObjectAndAttributes **oa = NULL;
   786     PRUint32 objectType;
   787     if (!token_is_present(cache)) {
   788 	return PR_FAILURE;
   789     }
   790     PZ_Lock(cache->lock);
   791     switch (objclass) {
   792     case CKO_CERTIFICATE:    objectType = cachedCerts; break;
   793     case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
   794     case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
   795     default: goto loser;
   796     }
   797     if (!cache_available_for_object_type(cache, objectType)) {
   798 	goto loser;
   799     }
   800     oa = cache->objects[objectType];
   801     if (!oa) {
   802 	goto loser;
   803     }
   804     for (; *oa; oa++) {
   805 	if (nssCryptokiObject_Equal((*oa)->object, object)) {
   806 	    cachedOA = *oa;
   807 	    break;
   808 	}
   809     }
   810     if (!cachedOA) {
   811 	goto loser; /* don't have this object */
   812     }
   813     if (arenaOpt) {
   814 	arena = arenaOpt;
   815 	mark = nssArena_Mark(arena);
   816     }
   817     for (i=0; i<atlen; i++) {
   818 	for (j=0; j<cachedOA->numAttributes; j++) {
   819 	    if (atemplate[i].type == cachedOA->attributes[j].type) {
   820 		CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j];
   821 		if (cachedOA->attributes[j].ulValueLen == 0 ||
   822 		    cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) 
   823 		{
   824 		    break; /* invalid attribute */
   825 		}
   826 		if (atemplate[i].ulValueLen > 0) {
   827 		    if (atemplate[i].pValue == NULL ||
   828 		        atemplate[i].ulValueLen < attr->ulValueLen) 
   829 		    {
   830 			goto loser;
   831 		    }
   832 		} else {
   833 		    atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen);
   834 		    if (!atemplate[i].pValue) {
   835 			goto loser;
   836 		    }
   837 		}
   838 		nsslibc_memcpy(atemplate[i].pValue,
   839 		               attr->pValue, attr->ulValueLen);
   840 		atemplate[i].ulValueLen = attr->ulValueLen;
   841 		break;
   842 	    }
   843 	}
   844 	if (j == cachedOA->numAttributes) {
   845 	    atemplate[i].ulValueLen = (CK_ULONG)-1;
   846 	}
   847     }
   848     PZ_Unlock(cache->lock);
   849     if (mark) {
   850 	nssArena_Unmark(arena, mark);
   851     }
   852     return PR_SUCCESS;
   853 loser:
   854     PZ_Unlock(cache->lock);
   855     if (mark) {
   856 	nssArena_Release(arena, mark);
   857     }
   858     return PR_FAILURE;
   859 }
   861 NSS_IMPLEMENT PRStatus
   862 nssTokenObjectCache_ImportObject (
   863   nssTokenObjectCache *cache,
   864   nssCryptokiObject *object,
   865   CK_OBJECT_CLASS objclass,
   866   CK_ATTRIBUTE_PTR ot,
   867   CK_ULONG otlen
   868 )
   869 {
   870     PRStatus status = PR_SUCCESS;
   871     PRUint32 count;
   872     nssCryptokiObjectAndAttributes **oa, ***otype;
   873     PRUint32 objectType;
   874     PRBool haveIt = PR_FALSE;
   876     if (!token_is_present(cache)) {
   877 	return PR_SUCCESS; /* cache not active, ignored */
   878     }
   879     PZ_Lock(cache->lock);
   880     switch (objclass) {
   881     case CKO_CERTIFICATE:    objectType = cachedCerts; break;
   882     case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
   883     case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
   884     default:
   885 	PZ_Unlock(cache->lock);
   886 	return PR_SUCCESS; /* don't need to import it here */
   887     }
   888     if (!cache_available_for_object_type(cache, objectType)) {
   889 	PZ_Unlock(cache->lock);
   890 	return PR_SUCCESS; /* cache not active, ignored */
   891     }
   892     count = 0;
   893     otype = &cache->objects[objectType]; /* index into array of types */
   894     oa = *otype; /* the array of objects for this type */
   895     while (oa && *oa) {
   896 	if (nssCryptokiObject_Equal((*oa)->object, object)) {
   897 	    haveIt = PR_TRUE;
   898 	    break;
   899 	}
   900 	count++;
   901 	oa++;
   902     }
   903     if (haveIt) {
   904 	/* Destroy the old entry */
   905 	(*oa)->object->token = NULL;
   906 	nssCryptokiObject_Destroy((*oa)->object);
   907 	nssArena_Destroy((*oa)->arena);
   908     } else {
   909 	/* Create space for a new entry */
   910 	if (count > 0) {
   911 	    *otype = nss_ZREALLOCARRAY(*otype,
   912 	                               nssCryptokiObjectAndAttributes *, 
   913 	                               count + 2);
   914 	} else {
   915 	    *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2);
   916 	}
   917     }
   918     if (*otype) {
   919 	nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object);
   920 	(*otype)[count] = create_object_of_type(copyObject, objectType,
   921 	                                        &status);
   922     } else {
   923 	status = PR_FAILURE;
   924     }
   925     PZ_Unlock(cache->lock);
   926     return status;
   927 }
   929 NSS_IMPLEMENT void
   930 nssTokenObjectCache_RemoveObject (
   931   nssTokenObjectCache *cache,
   932   nssCryptokiObject *object
   933 )
   934 {
   935     PRUint32 oType;
   936     nssCryptokiObjectAndAttributes **oa, **swp = NULL;
   937     if (!token_is_present(cache)) {
   938 	return;
   939     }
   940     PZ_Lock(cache->lock);
   941     for (oType=0; oType<3; oType++) {
   942 	if (!cache_available_for_object_type(cache, oType) ||
   943 	    !cache->objects[oType])
   944 	{
   945 	    continue;
   946 	}
   947 	for (oa = cache->objects[oType]; *oa; oa++) {
   948 	    if (nssCryptokiObject_Equal((*oa)->object, object)) {
   949 		swp = oa; /* the entry to remove */
   950 		while (oa[1]) oa++; /* go to the tail */
   951 		(*swp)->object->token = NULL;
   952 		nssCryptokiObject_Destroy((*swp)->object);
   953 		nssArena_Destroy((*swp)->arena); /* destroy it */
   954 		*swp = *oa; /* swap the last with the removed */
   955 		*oa = NULL; /* null-terminate the array */
   956 		break;
   957 	    }
   958 	}
   959 	if (swp) {
   960 	    break;
   961 	}
   962     }
   963     if ((oType <3) &&
   964 		cache->objects[oType] && cache->objects[oType][0] == NULL) {
   965 	nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */
   966 	cache->objects[oType] = NULL;
   967     }
   968     PZ_Unlock(cache->lock);
   969 }
   971 /* These two hash algorithms are presently sufficient.
   972 ** They are used for fingerprints of certs which are stored as the 
   973 ** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes.
   974 ** We don't need to add SHAxxx to these now.
   975 */
   976 /* XXX of course this doesn't belong here */
   977 NSS_IMPLEMENT NSSAlgorithmAndParameters *
   978 NSSAlgorithmAndParameters_CreateSHA1Digest (
   979   NSSArena *arenaOpt
   980 )
   981 {
   982     NSSAlgorithmAndParameters *rvAP = NULL;
   983     rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
   984     if (rvAP) {
   985 	rvAP->mechanism.mechanism = CKM_SHA_1;
   986 	rvAP->mechanism.pParameter = NULL;
   987 	rvAP->mechanism.ulParameterLen = 0;
   988     }
   989     return rvAP;
   990 }
   992 NSS_IMPLEMENT NSSAlgorithmAndParameters *
   993 NSSAlgorithmAndParameters_CreateMD5Digest (
   994   NSSArena *arenaOpt
   995 )
   996 {
   997     NSSAlgorithmAndParameters *rvAP = NULL;
   998     rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
   999     if (rvAP) {
  1000 	rvAP->mechanism.mechanism = CKM_MD5;
  1001 	rvAP->mechanism.pParameter = NULL;
  1002 	rvAP->mechanism.ulParameterLen = 0;
  1004     return rvAP;

mercurial