~ubuntu-branches/ubuntu/trusty/xulrunner/trusty

« back to all changes in this revision

Viewing changes to security/nss-fips/lib/dev/devtoken.c

  • Committer: Bazaar Package Importer
  • Author(s): Devid Antonio Filoni
  • Date: 2008-08-25 13:04:18 UTC
  • mfrom: (1.1.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20080825130418-ck1i2ms384tzb9m0
Tags: 1.8.1.16+nobinonly-0ubuntu1
* New upstream release (taken from upstream CVS), LP: #254618.
* Fix MFSA 2008-35, MFSA 2008-34, MFSA 2008-33, MFSA 2008-32, MFSA 2008-31,
  MFSA 2008-30, MFSA 2008-29, MFSA 2008-28, MFSA 2008-27, MFSA 2008-25,
  MFSA 2008-24, MFSA 2008-23, MFSA 2008-22, MFSA 2008-21, MFSA 2008-26 also
  known as CVE-2008-2933, CVE-2008-2785, CVE-2008-2811, CVE-2008-2810,
  CVE-2008-2809, CVE-2008-2808, CVE-2008-2807, CVE-2008-2806, CVE-2008-2805,
  CVE-2008-2803, CVE-2008-2802, CVE-2008-2801, CVE-2008-2800, CVE-2008-2798.
* Drop 89_bz419350_attachment_306066 patch, merged upstream.
* Bump Standards-Version to 3.8.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ***** BEGIN LICENSE BLOCK *****
 
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
3
 *
 
4
 * The contents of this file are subject to the Mozilla Public License Version
 
5
 * 1.1 (the "License"); you may not use this file except in compliance with
 
6
 * the License. You may obtain a copy of the License at
 
7
 * http://www.mozilla.org/MPL/
 
8
 *
 
9
 * Software distributed under the License is distributed on an "AS IS" basis,
 
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
11
 * for the specific language governing rights and limitations under the
 
12
 * License.
 
13
 *
 
14
 * The Original Code is the Netscape security libraries.
 
15
 *
 
16
 * The Initial Developer of the Original Code is
 
17
 * Netscape Communications Corporation.
 
18
 * Portions created by the Initial Developer are Copyright (C) 1994-2000
 
19
 * the Initial Developer. All Rights Reserved.
 
20
 *
 
21
 * Contributor(s):
 
22
 *
 
23
 * Alternatively, the contents of this file may be used under the terms of
 
24
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
25
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
26
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
27
 * of those above. If you wish to allow use of your version of this file only
 
28
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
29
 * use your version of this file under the terms of the MPL, indicate your
 
30
 * decision by deleting the provisions above and replace them with the notice
 
31
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
32
 * the provisions above, a recipient may use your version of this file under
 
33
 * the terms of any one of the MPL, the GPL or the LGPL.
 
34
 *
 
35
 * ***** END LICENSE BLOCK ***** */
 
36
 
 
37
#ifdef DEBUG
 
38
static const char CVS_ID[] = "@(#) $RCSfile: devtoken.c,v $ $Revision: 1.39 $ $Date: 2005/01/20 02:25:47 $";
 
39
#endif /* DEBUG */
 
40
 
 
41
#ifndef NSSCKEPV_H
 
42
#include "nssckepv.h"
 
43
#endif /* NSSCKEPV_H */
 
44
 
 
45
#ifndef DEVM_H
 
46
#include "devm.h"
 
47
#endif /* DEVM_H */
 
48
 
 
49
#ifndef CKHELPER_H
 
50
#include "ckhelper.h"
 
51
#endif /* CKHELPER_H */
 
52
 
 
53
#ifdef NSS_3_4_CODE
 
54
#include "pk11func.h"
 
55
#include "dev3hack.h"
 
56
#include "secerr.h"
 
57
#endif
 
58
 
 
59
extern const NSSError NSS_ERROR_NOT_FOUND;
 
60
 
 
61
/* The number of object handles to grab during each call to C_FindObjects */
 
62
#define OBJECT_STACK_SIZE 16
 
63
 
 
64
#ifdef PURE_STAN_BUILD
 
65
struct NSSTokenStr
 
66
{
 
67
  struct nssDeviceBaseStr base;
 
68
  NSSSlot *slot;  /* Peer */
 
69
  CK_FLAGS ckFlags; /* from CK_TOKEN_INFO.flags */
 
70
  nssSession *defaultSession;
 
71
  nssTokenObjectCache *cache;
 
72
};
 
73
 
 
74
NSS_IMPLEMENT NSSToken *
 
75
nssToken_Create (
 
76
  CK_SLOT_ID slotID,
 
77
  NSSSlot *peer
 
78
)
 
79
{
 
80
    NSSArena *arena;
 
81
    NSSToken *rvToken;
 
82
    nssSession *session = NULL;
 
83
    NSSUTF8 *tokenName = NULL;
 
84
    PRUint32 length;
 
85
    PRBool readWrite;
 
86
    CK_TOKEN_INFO tokenInfo;
 
87
    CK_RV ckrv;
 
88
    void *epv = nssSlot_GetCryptokiEPV(peer);
 
89
    arena = NSSArena_Create();
 
90
    if(!arena) {
 
91
        return (NSSToken *)NULL;
 
92
    }
 
93
    rvToken = nss_ZNEW(arena, NSSToken);
 
94
    if (!rvToken) {
 
95
        goto loser;
 
96
    }
 
97
    /* Get token information */
 
98
    ckrv = CKAPI(epv)->C_GetTokenInfo(slotID, &tokenInfo);
 
99
    if (ckrv != CKR_OK) {
 
100
        /* set an error here, eh? */
 
101
        goto loser;
 
102
    }
 
103
    /* Grab the slot description from the PKCS#11 fixed-length buffer */
 
104
    length = nssPKCS11String_Length(tokenInfo.label, sizeof(tokenInfo.label));
 
105
    if (length > 0) {
 
106
        tokenName = nssUTF8_Create(arena, nssStringType_UTF8String, 
 
107
                                   (void *)tokenInfo.label, length);
 
108
        if (!tokenName) {
 
109
            goto loser;
 
110
        }
 
111
    }
 
112
    /* Open a default session handle for the token. */
 
113
    if (tokenInfo.ulMaxSessionCount == 1) {
 
114
        /* if the token can only handle one session, it must be RW. */
 
115
        readWrite = PR_TRUE;
 
116
    } else {
 
117
        readWrite = PR_FALSE;
 
118
    }
 
119
    session = nssSlot_CreateSession(peer, arena, readWrite);
 
120
    if (session == NULL) {
 
121
        goto loser;
 
122
    }
 
123
    /* TODO: seed the RNG here */
 
124
    rvToken->base.arena = arena;
 
125
    rvToken->base.refCount = 1;
 
126
    rvToken->base.name = tokenName;
 
127
    rvToken->base.lock = PZ_NewLock(nssNSSILockOther); /* XXX */
 
128
    if (!rvToken->base.lock) {
 
129
        goto loser;
 
130
    }
 
131
    rvToken->slot = peer; /* slot owns ref to token */
 
132
    rvToken->ckFlags = tokenInfo.flags;
 
133
    rvToken->defaultSession = session;
 
134
    if (nssSlot_IsHardware(peer)) {
 
135
        rvToken->cache = nssTokenObjectCache_Create(rvToken, 
 
136
                                                    PR_TRUE, PR_TRUE, PR_TRUE);
 
137
        if (!rvToken->cache) {
 
138
            nssSlot_Destroy(peer);
 
139
            goto loser;
 
140
        }
 
141
    }
 
142
    return rvToken;
 
143
loser:
 
144
    if (session) {
 
145
        nssSession_Destroy(session);
 
146
    }
 
147
    nssArena_Destroy(arena);
 
148
    return (NSSToken *)NULL;
 
149
}
 
150
#endif /* PURE_STAN_BUILD */
 
151
 
 
152
NSS_IMPLEMENT PRStatus
 
153
nssToken_Destroy (
 
154
  NSSToken *tok
 
155
)
 
156
{
 
157
    if (tok) {
 
158
        if (PR_AtomicDecrement(&tok->base.refCount) == 0) {
 
159
            PZ_DestroyLock(tok->base.lock);
 
160
            nssTokenObjectCache_Destroy(tok->cache);
 
161
            return nssArena_Destroy(tok->base.arena);
 
162
        }
 
163
    }
 
164
    return PR_SUCCESS;
 
165
}
 
166
 
 
167
NSS_IMPLEMENT void
 
168
nssToken_Remove (
 
169
  NSSToken *tok
 
170
)
 
171
{
 
172
    nssTokenObjectCache_Clear(tok->cache);
 
173
}
 
174
 
 
175
NSS_IMPLEMENT void
 
176
NSSToken_Destroy (
 
177
  NSSToken *tok
 
178
)
 
179
{
 
180
    (void)nssToken_Destroy(tok);
 
181
}
 
182
 
 
183
NSS_IMPLEMENT NSSToken *
 
184
nssToken_AddRef (
 
185
  NSSToken *tok
 
186
)
 
187
{
 
188
    PR_AtomicIncrement(&tok->base.refCount);
 
189
    return tok;
 
190
}
 
191
 
 
192
NSS_IMPLEMENT NSSSlot *
 
193
nssToken_GetSlot (
 
194
  NSSToken *tok
 
195
)
 
196
{
 
197
    return nssSlot_AddRef(tok->slot);
 
198
}
 
199
 
 
200
#ifdef PURE_STAN_BUILD
 
201
NSS_IMPLEMENT NSSModule *
 
202
nssToken_GetModule (
 
203
  NSSToken *token
 
204
)
 
205
{
 
206
    return nssSlot_GetModule(token->slot);
 
207
}
 
208
#endif
 
209
 
 
210
NSS_IMPLEMENT void *
 
211
nssToken_GetCryptokiEPV (
 
212
  NSSToken *token
 
213
)
 
214
{
 
215
    return nssSlot_GetCryptokiEPV(token->slot);
 
216
}
 
217
 
 
218
NSS_IMPLEMENT nssSession *
 
219
nssToken_GetDefaultSession (
 
220
  NSSToken *token
 
221
)
 
222
{
 
223
    return token->defaultSession;
 
224
}
 
225
 
 
226
NSS_IMPLEMENT NSSUTF8 *
 
227
nssToken_GetName (
 
228
  NSSToken *tok
 
229
)
 
230
{
 
231
    if (tok == NULL) {
 
232
        return "";
 
233
    }
 
234
    if (tok->base.name[0] == 0) {
 
235
        (void) nssSlot_IsTokenPresent(tok->slot);
 
236
    } 
 
237
    return tok->base.name;
 
238
}
 
239
 
 
240
NSS_IMPLEMENT NSSUTF8 *
 
241
NSSToken_GetName (
 
242
  NSSToken *token
 
243
)
 
244
{
 
245
    return nssToken_GetName(token);
 
246
}
 
247
 
 
248
NSS_IMPLEMENT PRBool
 
249
nssToken_IsLoginRequired (
 
250
  NSSToken *token
 
251
)
 
252
{
 
253
    return (token->ckFlags & CKF_LOGIN_REQUIRED);
 
254
}
 
255
 
 
256
NSS_IMPLEMENT PRBool
 
257
nssToken_NeedsPINInitialization (
 
258
  NSSToken *token
 
259
)
 
260
{
 
261
    return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
 
262
}
 
263
 
 
264
NSS_IMPLEMENT PRStatus
 
265
nssToken_DeleteStoredObject (
 
266
  nssCryptokiObject *instance
 
267
)
 
268
{
 
269
    CK_RV ckrv;
 
270
    PRStatus status;
 
271
    PRBool createdSession = PR_FALSE;
 
272
    NSSToken *token = instance->token;
 
273
    nssSession *session = NULL;
 
274
    void *epv = nssToken_GetCryptokiEPV(instance->token);
 
275
    if (token->cache) {
 
276
        nssTokenObjectCache_RemoveObject(token->cache, instance);
 
277
    }
 
278
    if (instance->isTokenObject) {
 
279
       if (nssSession_IsReadWrite(token->defaultSession)) {
 
280
           session = token->defaultSession;
 
281
       } else {
 
282
           session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
 
283
           createdSession = PR_TRUE;
 
284
       }
 
285
    }
 
286
    if (session == NULL) {
 
287
        return PR_FAILURE;
 
288
    }
 
289
    nssSession_EnterMonitor(session);
 
290
    ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
 
291
    nssSession_ExitMonitor(session);
 
292
    if (createdSession) {
 
293
        nssSession_Destroy(session);
 
294
    }
 
295
    status = (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
 
296
    return status;
 
297
}
 
298
 
 
299
static nssCryptokiObject *
 
300
import_object (
 
301
  NSSToken *tok,
 
302
  nssSession *sessionOpt,
 
303
  CK_ATTRIBUTE_PTR objectTemplate,
 
304
  CK_ULONG otsize
 
305
)
 
306
{
 
307
    nssSession *session = NULL;
 
308
    PRBool createdSession = PR_FALSE;
 
309
    nssCryptokiObject *object = NULL;
 
310
    CK_OBJECT_HANDLE handle;
 
311
    CK_RV ckrv;
 
312
    void *epv = nssToken_GetCryptokiEPV(tok);
 
313
    if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
 
314
        if (sessionOpt) {
 
315
            if (!nssSession_IsReadWrite(sessionOpt)) {
 
316
                return CK_INVALID_HANDLE;
 
317
            } else {
 
318
                session = sessionOpt;
 
319
            }
 
320
        } else if (nssSession_IsReadWrite(tok->defaultSession)) {
 
321
            session = tok->defaultSession;
 
322
        } else {
 
323
            session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
 
324
            createdSession = PR_TRUE;
 
325
        }
 
326
    } else {
 
327
        session = (sessionOpt) ? sessionOpt : tok->defaultSession;
 
328
    }
 
329
    if (session == NULL) {
 
330
        return CK_INVALID_HANDLE;
 
331
    }
 
332
    nssSession_EnterMonitor(session);
 
333
    ckrv = CKAPI(epv)->C_CreateObject(session->handle, 
 
334
                                      objectTemplate, otsize,
 
335
                                      &handle);
 
336
    nssSession_ExitMonitor(session);
 
337
    if (ckrv == CKR_OK) {
 
338
        object = nssCryptokiObject_Create(tok, session, handle);
 
339
    }
 
340
    if (createdSession) {
 
341
        nssSession_Destroy(session);
 
342
    }
 
343
    return object;
 
344
}
 
345
 
 
346
static nssCryptokiObject **
 
347
create_objects_from_handles (
 
348
  NSSToken *tok,
 
349
  nssSession *session,
 
350
  CK_OBJECT_HANDLE *handles,
 
351
  PRUint32 numH
 
352
)
 
353
{
 
354
    nssCryptokiObject **objects;
 
355
    objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
 
356
    if (objects) {
 
357
        PRInt32 i;
 
358
        for (i=0; i<(PRInt32)numH; i++) {
 
359
            objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
 
360
            if (!objects[i]) {
 
361
                for (--i; i>0; --i) {
 
362
                    nssCryptokiObject_Destroy(objects[i]);
 
363
                }
 
364
                return (nssCryptokiObject **)NULL;
 
365
            }
 
366
        }
 
367
    }
 
368
    return objects;
 
369
}
 
370
 
 
371
static nssCryptokiObject **
 
372
find_objects (
 
373
  NSSToken *tok,
 
374
  nssSession *sessionOpt,
 
375
  CK_ATTRIBUTE_PTR obj_template,
 
376
  CK_ULONG otsize,
 
377
  PRUint32 maximumOpt,
 
378
  PRStatus *statusOpt
 
379
)
 
380
{
 
381
    CK_RV ckrv = CKR_OK;
 
382
    CK_ULONG count;
 
383
    CK_OBJECT_HANDLE *objectHandles;
 
384
    CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
 
385
    PRUint32 arraySize, numHandles;
 
386
    void *epv = nssToken_GetCryptokiEPV(tok);
 
387
    nssCryptokiObject **objects;
 
388
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
 
389
 
 
390
    /* the arena is only for the array of object handles */
 
391
    if (maximumOpt > 0) {
 
392
        arraySize = maximumOpt;
 
393
    } else {
 
394
        arraySize = OBJECT_STACK_SIZE;
 
395
    }
 
396
    numHandles = 0;
 
397
    if (arraySize <= OBJECT_STACK_SIZE) {
 
398
        objectHandles = staticObjects;
 
399
    } else {
 
400
        objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
 
401
    }
 
402
    if (!objectHandles) {
 
403
        ckrv = CKR_HOST_MEMORY;
 
404
        goto loser;
 
405
    }
 
406
    nssSession_EnterMonitor(session); /* ==== session lock === */
 
407
    /* Initialize the find with the template */
 
408
    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
 
409
                                         obj_template, otsize);
 
410
    if (ckrv != CKR_OK) {
 
411
        nssSession_ExitMonitor(session);
 
412
        goto loser;
 
413
    }
 
414
    while (PR_TRUE) {
 
415
        /* Issue the find for up to arraySize - numHandles objects */
 
416
        ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
 
417
                                         objectHandles + numHandles, 
 
418
                                         arraySize - numHandles, 
 
419
                                         &count);
 
420
        if (ckrv != CKR_OK) {
 
421
            nssSession_ExitMonitor(session);
 
422
            goto loser;
 
423
        }
 
424
        /* bump the number of found objects */
 
425
        numHandles += count;
 
426
        if (maximumOpt > 0 || numHandles < arraySize) {
 
427
            /* When a maximum is provided, the search is done all at once,
 
428
             * so the search is finished.  If the number returned was less 
 
429
             * than the number sought, the search is finished.
 
430
             */
 
431
            break;
 
432
        }
 
433
        /* the array is filled, double it and continue */
 
434
        arraySize *= 2;
 
435
        if (objectHandles == staticObjects) {
 
436
            objectHandles = nss_ZNEWARRAY(NULL,CK_OBJECT_HANDLE, arraySize);
 
437
            if (objectHandles) {
 
438
                PORT_Memcpy(objectHandles, staticObjects, 
 
439
                        OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
 
440
            }
 
441
        } else {
 
442
            objectHandles = nss_ZREALLOCARRAY(objectHandles, 
 
443
                                          CK_OBJECT_HANDLE, 
 
444
                                          arraySize);
 
445
        }
 
446
        if (!objectHandles) {
 
447
            nssSession_ExitMonitor(session);
 
448
            ckrv = CKR_HOST_MEMORY;
 
449
            goto loser;
 
450
        }
 
451
    }
 
452
    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
 
453
    nssSession_ExitMonitor(session); /* ==== end session lock === */
 
454
    if (ckrv != CKR_OK) {
 
455
        goto loser;
 
456
    }
 
457
    if (numHandles > 0) {
 
458
        objects = create_objects_from_handles(tok, session,
 
459
                                              objectHandles, numHandles);
 
460
    } else {
 
461
        nss_SetError(NSS_ERROR_NOT_FOUND);
 
462
        objects = NULL;
 
463
    }
 
464
    if (objectHandles && objectHandles != staticObjects) {
 
465
        nss_ZFreeIf(objectHandles);
 
466
    }
 
467
    if (statusOpt) *statusOpt = PR_SUCCESS;
 
468
    return objects;
 
469
loser:
 
470
    if (objectHandles && objectHandles != staticObjects) {
 
471
        nss_ZFreeIf(objectHandles);
 
472
    }
 
473
    /*
 
474
     * These errors should be treated the same as if the objects just weren't
 
475
     * found..
 
476
     */
 
477
    if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
 
478
        (ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
 
479
        (ckrv == CKR_DATA_INVALID) ||
 
480
        (ckrv == CKR_DATA_LEN_RANGE) ||
 
481
        (ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
 
482
        (ckrv == CKR_TEMPLATE_INCOMPLETE) ||
 
483
        (ckrv == CKR_TEMPLATE_INCONSISTENT)) {
 
484
 
 
485
        nss_SetError(NSS_ERROR_NOT_FOUND);
 
486
        if (statusOpt) *statusOpt = PR_SUCCESS;
 
487
    } else {
 
488
        if (statusOpt) *statusOpt = PR_FAILURE;
 
489
    }
 
490
    return (nssCryptokiObject **)NULL;
 
491
}
 
492
 
 
493
static nssCryptokiObject **
 
494
find_objects_by_template (
 
495
  NSSToken *token,
 
496
  nssSession *sessionOpt,
 
497
  CK_ATTRIBUTE_PTR obj_template,
 
498
  CK_ULONG otsize,
 
499
  PRUint32 maximumOpt,
 
500
  PRStatus *statusOpt
 
501
)
 
502
{
 
503
    CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
 
504
    nssCryptokiObject **objects = NULL;
 
505
    PRUint32 i;
 
506
    for (i=0; i<otsize; i++) {
 
507
        if (obj_template[i].type == CKA_CLASS) {
 
508
            objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
 
509
            break;
 
510
        }
 
511
    }
 
512
    PR_ASSERT(i < otsize);
 
513
    if (i == otsize) {
 
514
#ifdef NSS_3_4_CODE
 
515
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 
516
#endif
 
517
        if (statusOpt) *statusOpt = PR_FAILURE;
 
518
        return NULL;
 
519
    }
 
520
    /* If these objects are being cached, try looking there first */
 
521
    if (token->cache && 
 
522
        nssTokenObjectCache_HaveObjectClass(token->cache, objclass)) 
 
523
    {
 
524
        PRStatus status;
 
525
        objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
 
526
                                                            objclass,
 
527
                                                            obj_template,
 
528
                                                            otsize,
 
529
                                                            maximumOpt,
 
530
                                                            &status);
 
531
        if (status == PR_SUCCESS) {
 
532
            if (statusOpt) *statusOpt = status;
 
533
            return objects;
 
534
        }
 
535
    }
 
536
    /* Either they are not cached, or cache failed; look on token. */
 
537
    objects = find_objects(token, sessionOpt, 
 
538
                           obj_template, otsize, 
 
539
                           maximumOpt, statusOpt);
 
540
    return objects;
 
541
}
 
542
 
 
543
extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
 
544
 
 
545
NSS_IMPLEMENT nssCryptokiObject *
 
546
nssToken_ImportCertificate (
 
547
  NSSToken *tok,
 
548
  nssSession *sessionOpt,
 
549
  NSSCertificateType certType,
 
550
  NSSItem *id,
 
551
  NSSUTF8 *nickname,
 
552
  NSSDER *encoding,
 
553
  NSSDER *issuer,
 
554
  NSSDER *subject,
 
555
  NSSDER *serial,
 
556
  NSSASCII7 *email,
 
557
  PRBool asTokenObject
 
558
)
 
559
{
 
560
    PRStatus status;
 
561
    CK_CERTIFICATE_TYPE cert_type;
 
562
    CK_ATTRIBUTE_PTR attr;
 
563
    CK_ATTRIBUTE cert_tmpl[10];
 
564
    CK_ULONG ctsize;
 
565
    nssTokenSearchType searchType;
 
566
    nssCryptokiObject *rvObject = NULL;
 
567
 
 
568
    if (certType == NSSCertificateType_PKIX) {
 
569
        cert_type = CKC_X_509;
 
570
    } else {
 
571
        return (nssCryptokiObject *)NULL;
 
572
    }
 
573
    NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
 
574
    if (asTokenObject) {
 
575
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
576
        searchType = nssTokenSearchType_TokenOnly;
 
577
    } else {
 
578
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
579
        searchType = nssTokenSearchType_SessionOnly;
 
580
    }
 
581
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,            &g_ck_class_cert);
 
582
    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CERTIFICATE_TYPE,  cert_type);
 
583
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,                id);
 
584
    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL,             nickname);
 
585
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,             encoding);
 
586
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,            issuer);
 
587
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,           subject);
 
588
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,     serial);
 
589
    if (email) {
 
590
        NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_EMAIL,    email);
 
591
    }
 
592
    NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
 
593
    /* see if the cert is already there */
 
594
    rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
 
595
                                                               sessionOpt,
 
596
                                                               issuer,
 
597
                                                               serial,
 
598
                                                               searchType,
 
599
                                                               NULL);
 
600
    if (rvObject) {
 
601
        NSSItem existingDER;
 
602
        NSSSlot *slot = nssToken_GetSlot(tok);
 
603
        nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
 
604
        if (!session) {
 
605
            nssCryptokiObject_Destroy(rvObject);
 
606
            nssSlot_Destroy(slot);
 
607
            return (nssCryptokiObject *)NULL;
 
608
        }
 
609
        /* Reject any attempt to import a new cert that has the same
 
610
         * issuer/serial as an existing cert, but does not have the
 
611
         * same encoding
 
612
         */
 
613
        NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
 
614
        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
 
615
        NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
 
616
        status = nssCKObject_GetAttributes(rvObject->handle, 
 
617
                                           cert_tmpl, ctsize, NULL,
 
618
                                           session, slot);
 
619
        NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
 
620
        if (status == PR_SUCCESS) {
 
621
            if (!nssItem_Equal(encoding, &existingDER, NULL)) {
 
622
                nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
 
623
                status = PR_FAILURE;
 
624
            }
 
625
            nss_ZFreeIf(existingDER.data);
 
626
        }
 
627
        if (status == PR_FAILURE) {
 
628
            nssCryptokiObject_Destroy(rvObject);
 
629
            nssSession_Destroy(session);
 
630
            nssSlot_Destroy(slot);
 
631
            return (nssCryptokiObject *)NULL;
 
632
        }
 
633
        /* according to PKCS#11, label, ID, issuer, and serial number 
 
634
         * may change after the object has been created.  For PKIX, the
 
635
         * last two attributes can't change, so for now we'll only worry
 
636
         * about the first two.
 
637
         */
 
638
        NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
 
639
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,    id);
 
640
        NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
 
641
        NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
 
642
        /* reset the mutable attributes on the token */
 
643
        nssCKObject_SetAttributes(rvObject->handle, 
 
644
                                  cert_tmpl, ctsize,
 
645
                                  session, slot);
 
646
        if (!rvObject->label && nickname) {
 
647
            rvObject->label = nssUTF8_Duplicate(nickname, NULL);
 
648
        }
 
649
        nssSession_Destroy(session);
 
650
        nssSlot_Destroy(slot);
 
651
    } else {
 
652
        /* Import the certificate onto the token */
 
653
        rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
 
654
    }
 
655
    if (rvObject && tok->cache) {
 
656
        /* The cache will overwrite the attributes if the object already
 
657
         * exists.
 
658
         */
 
659
        nssTokenObjectCache_ImportObject(tok->cache, rvObject,
 
660
                                         CKO_CERTIFICATE,
 
661
                                         cert_tmpl, ctsize);
 
662
    }
 
663
    return rvObject;
 
664
}
 
665
 
 
666
/* traverse all certificates - this should only happen if the token
 
667
 * has been marked as "traversable"
 
668
 */
 
669
NSS_IMPLEMENT nssCryptokiObject **
 
670
nssToken_FindCertificates (
 
671
  NSSToken *token,
 
672
  nssSession *sessionOpt,
 
673
  nssTokenSearchType searchType,
 
674
  PRUint32 maximumOpt,
 
675
  PRStatus *statusOpt
 
676
)
 
677
{
 
678
    CK_ATTRIBUTE_PTR attr;
 
679
    CK_ATTRIBUTE cert_template[2];
 
680
    CK_ULONG ctsize;
 
681
    nssCryptokiObject **objects;
 
682
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
 
683
    /* Set the search to token/session only if provided */
 
684
    if (searchType == nssTokenSearchType_SessionOnly) {
 
685
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
686
    } else if (searchType == nssTokenSearchType_TokenOnly ||
 
687
               searchType == nssTokenSearchType_TokenForced) {
 
688
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
689
    }
 
690
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 
691
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
 
692
 
 
693
    if (searchType == nssTokenSearchType_TokenForced) {
 
694
        objects = find_objects(token, sessionOpt,
 
695
                               cert_template, ctsize,
 
696
                               maximumOpt, statusOpt);
 
697
    } else {
 
698
        objects = find_objects_by_template(token, sessionOpt,
 
699
                                           cert_template, ctsize,
 
700
                                           maximumOpt, statusOpt);
 
701
    }
 
702
    return objects;
 
703
}
 
704
 
 
705
NSS_IMPLEMENT nssCryptokiObject **
 
706
nssToken_FindCertificatesBySubject (
 
707
  NSSToken *token,
 
708
  nssSession *sessionOpt,
 
709
  NSSDER *subject,
 
710
  nssTokenSearchType searchType,
 
711
  PRUint32 maximumOpt,
 
712
  PRStatus *statusOpt
 
713
)
 
714
{
 
715
    CK_ATTRIBUTE_PTR attr;
 
716
    CK_ATTRIBUTE subj_template[3];
 
717
    CK_ULONG stsize;
 
718
    nssCryptokiObject **objects;
 
719
    NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
 
720
    /* Set the search to token/session only if provided */
 
721
    if (searchType == nssTokenSearchType_SessionOnly) {
 
722
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
723
    } else if (searchType == nssTokenSearchType_TokenOnly) {
 
724
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
725
    }
 
726
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 
727
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
 
728
    NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
 
729
    /* now locate the token certs matching this template */
 
730
    objects = find_objects_by_template(token, sessionOpt,
 
731
                                       subj_template, stsize,
 
732
                                       maximumOpt, statusOpt);
 
733
    return objects;
 
734
}
 
735
 
 
736
NSS_IMPLEMENT nssCryptokiObject **
 
737
nssToken_FindCertificatesByNickname (
 
738
  NSSToken *token,
 
739
  nssSession *sessionOpt,
 
740
  NSSUTF8 *name,
 
741
  nssTokenSearchType searchType,
 
742
  PRUint32 maximumOpt,
 
743
  PRStatus *statusOpt
 
744
)
 
745
{
 
746
    CK_ATTRIBUTE_PTR attr;
 
747
    CK_ATTRIBUTE nick_template[3];
 
748
    CK_ULONG ntsize;
 
749
    nssCryptokiObject **objects;
 
750
    NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
 
751
    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
 
752
    /* Set the search to token/session only if provided */
 
753
    if (searchType == nssTokenSearchType_SessionOnly) {
 
754
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
755
    } else if (searchType == nssTokenSearchType_TokenOnly) {
 
756
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
757
    }
 
758
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 
759
    NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
 
760
    /* now locate the token certs matching this template */
 
761
    objects = find_objects_by_template(token, sessionOpt,
 
762
                                       nick_template, ntsize, 
 
763
                                       maximumOpt, statusOpt);
 
764
    if (!objects) {
 
765
        /* This is to workaround the fact that PKCS#11 doesn't specify
 
766
         * whether the '\0' should be included.  XXX Is that still true?
 
767
         * im - this is not needed by the current softoken.  However, I'm 
 
768
         * leaving it in until I have surveyed more tokens to see if it needed.
 
769
         * well, its needed by the builtin token...
 
770
         */
 
771
        nick_template[0].ulValueLen++;
 
772
        objects = find_objects_by_template(token, sessionOpt,
 
773
                                           nick_template, ntsize, 
 
774
                                           maximumOpt, statusOpt);
 
775
    }
 
776
    return objects;
 
777
}
 
778
 
 
779
/* XXX
 
780
 * This function *does not* use the token object cache, because not even
 
781
 * the softoken will return a value for CKA_NETSCAPE_EMAIL from a call
 
782
 * to GetAttributes.  The softoken does allow searches with that attribute,
 
783
 * it just won't return a value for it.
 
784
 */
 
785
NSS_IMPLEMENT nssCryptokiObject **
 
786
nssToken_FindCertificatesByEmail (
 
787
  NSSToken *token,
 
788
  nssSession *sessionOpt,
 
789
  NSSASCII7 *email,
 
790
  nssTokenSearchType searchType,
 
791
  PRUint32 maximumOpt,
 
792
  PRStatus *statusOpt
 
793
)
 
794
{
 
795
    CK_ATTRIBUTE_PTR attr;
 
796
    CK_ATTRIBUTE email_template[3];
 
797
    CK_ULONG etsize;
 
798
    nssCryptokiObject **objects;
 
799
    NSS_CK_TEMPLATE_START(email_template, attr, etsize);
 
800
    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_EMAIL, email);
 
801
    /* Set the search to token/session only if provided */
 
802
    if (searchType == nssTokenSearchType_SessionOnly) {
 
803
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
804
    } else if (searchType == nssTokenSearchType_TokenOnly) {
 
805
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
806
    }
 
807
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 
808
    NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
 
809
    /* now locate the token certs matching this template */
 
810
    objects = find_objects(token, sessionOpt,
 
811
                           email_template, etsize,
 
812
                           maximumOpt, statusOpt);
 
813
    if (!objects) {
 
814
        /* This is to workaround the fact that PKCS#11 doesn't specify
 
815
         * whether the '\0' should be included.  XXX Is that still true?
 
816
         * im - this is not needed by the current softoken.  However, I'm 
 
817
         * leaving it in until I have surveyed more tokens to see if it needed.
 
818
         * well, its needed by the builtin token...
 
819
         */
 
820
        email_template[0].ulValueLen++;
 
821
        objects = find_objects(token, sessionOpt,
 
822
                               email_template, etsize,
 
823
                               maximumOpt, statusOpt);
 
824
    }
 
825
    return objects;
 
826
}
 
827
 
 
828
NSS_IMPLEMENT nssCryptokiObject **
 
829
nssToken_FindCertificatesByID (
 
830
  NSSToken *token,
 
831
  nssSession *sessionOpt,
 
832
  NSSItem *id,
 
833
  nssTokenSearchType searchType,
 
834
  PRUint32 maximumOpt,
 
835
  PRStatus *statusOpt
 
836
)
 
837
{
 
838
    CK_ATTRIBUTE_PTR attr;
 
839
    CK_ATTRIBUTE id_template[3];
 
840
    CK_ULONG idtsize;
 
841
    nssCryptokiObject **objects;
 
842
    NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
 
843
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
 
844
    /* Set the search to token/session only if provided */
 
845
    if (searchType == nssTokenSearchType_SessionOnly) {
 
846
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
847
    } else if (searchType == nssTokenSearchType_TokenOnly) {
 
848
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
849
    }
 
850
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 
851
    NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
 
852
    /* now locate the token certs matching this template */
 
853
    objects = find_objects_by_template(token, sessionOpt,
 
854
                                       id_template, idtsize,
 
855
                                       maximumOpt, statusOpt);
 
856
    return objects;
 
857
}
 
858
 
 
859
/*
 
860
 * decode the serial item and return our result.
 
861
 * NOTE serialDecode's data is really stored in serial. Don't free it.
 
862
 */
 
863
static PRStatus
 
864
nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
 
865
{
 
866
    unsigned char *data = (unsigned char *)serial->data;
 
867
    int data_left, data_len, index;
 
868
 
 
869
    if ((serial->size >= 3) && (data[0] == 0x2)) {
 
870
        /* remove the der encoding of the serial number before generating the
 
871
         * key.. */
 
872
        data_left = serial->size-2;
 
873
        data_len = data[1];
 
874
        index = 2;
 
875
 
 
876
        /* extended length ? (not very likely for a serial number) */
 
877
        if (data_len & 0x80) {
 
878
            int len_count = data_len & 0x7f;
 
879
 
 
880
            data_len = 0;
 
881
            data_left -= len_count;
 
882
            if (data_left > 0) {
 
883
                while (len_count --) {
 
884
                    data_len = (data_len << 8) | data[index++];
 
885
                }
 
886
            } 
 
887
        }
 
888
        /* XXX leaving any leading zeros on the serial number for backwards
 
889
         * compatibility
 
890
         */
 
891
        /* not a valid der, must be just an unlucky serial number value */
 
892
        if (data_len == data_left) {
 
893
            serialDecode->size = data_len;
 
894
            serialDecode->data = &data[index];
 
895
            return PR_SUCCESS;
 
896
        }
 
897
    }
 
898
    return PR_FAILURE;
 
899
}
 
900
 
 
901
NSS_IMPLEMENT nssCryptokiObject *
 
902
nssToken_FindCertificateByIssuerAndSerialNumber (
 
903
  NSSToken *token,
 
904
  nssSession *sessionOpt,
 
905
  NSSDER *issuer,
 
906
  NSSDER *serial,
 
907
  nssTokenSearchType searchType,
 
908
  PRStatus *statusOpt
 
909
)
 
910
{
 
911
    CK_ATTRIBUTE_PTR attr;
 
912
    CK_ATTRIBUTE_PTR serialAttr;
 
913
    CK_ATTRIBUTE cert_template[4];
 
914
    CK_ULONG ctsize;
 
915
    nssCryptokiObject **objects;
 
916
    nssCryptokiObject *rvObject = NULL;
 
917
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
 
918
    /* Set the search to token/session only if provided */
 
919
    if (searchType == nssTokenSearchType_SessionOnly) {
 
920
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
921
    } else if ((searchType == nssTokenSearchType_TokenOnly) ||
 
922
               (searchType == nssTokenSearchType_TokenForced)) {
 
923
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
924
    }
 
925
    /* Set the unique id */
 
926
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,         &g_ck_class_cert);
 
927
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         issuer);
 
928
    serialAttr = attr;
 
929
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,  serial);
 
930
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
 
931
    /* get the object handle */
 
932
    if (searchType == nssTokenSearchType_TokenForced) {
 
933
        objects = find_objects(token, sessionOpt,
 
934
                               cert_template, ctsize,
 
935
                               1, statusOpt);
 
936
    } else {
 
937
        objects = find_objects_by_template(token, sessionOpt,
 
938
                                       cert_template, ctsize,
 
939
                                       1, statusOpt);
 
940
    }
 
941
    if (objects) {
 
942
        rvObject = objects[0];
 
943
        nss_ZFreeIf(objects);
 
944
    }
 
945
 
 
946
    /*
 
947
     * NSS used to incorrectly store serial numbers in their decoded form.
 
948
     * because of this old tokens have decoded serial numbers.
 
949
     */
 
950
    if (!objects) {
 
951
        NSSItem serialDecode;
 
952
        PRStatus status;
 
953
 
 
954
        status = nssToken_decodeSerialItem(serial, &serialDecode);
 
955
        if (status != PR_SUCCESS) {
 
956
            return NULL;
 
957
        }
 
958
        NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr,CKA_SERIAL_NUMBER,&serialDecode);
 
959
        if (searchType == nssTokenSearchType_TokenForced) {
 
960
            objects = find_objects(token, sessionOpt,
 
961
                               cert_template, ctsize,
 
962
                               1, statusOpt);
 
963
        } else {
 
964
            objects = find_objects_by_template(token, sessionOpt,
 
965
                                       cert_template, ctsize,
 
966
                                       1, statusOpt);
 
967
        }
 
968
        if (objects) {
 
969
            rvObject = objects[0];
 
970
            nss_ZFreeIf(objects);
 
971
        }
 
972
    }
 
973
    return rvObject;
 
974
}
 
975
 
 
976
NSS_IMPLEMENT nssCryptokiObject *
 
977
nssToken_FindCertificateByEncodedCertificate (
 
978
  NSSToken *token,
 
979
  nssSession *sessionOpt,
 
980
  NSSBER *encodedCertificate,
 
981
  nssTokenSearchType searchType,
 
982
  PRStatus *statusOpt
 
983
)
 
984
{
 
985
    CK_ATTRIBUTE_PTR attr;
 
986
    CK_ATTRIBUTE cert_template[3];
 
987
    CK_ULONG ctsize;
 
988
    nssCryptokiObject **objects;
 
989
    nssCryptokiObject *rvObject = NULL;
 
990
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
 
991
    /* Set the search to token/session only if provided */
 
992
    if (searchType == nssTokenSearchType_SessionOnly) {
 
993
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
994
    } else if (searchType == nssTokenSearchType_TokenOnly) {
 
995
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
996
    }
 
997
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 
998
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
 
999
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
 
1000
    /* get the object handle */
 
1001
    objects = find_objects_by_template(token, sessionOpt,
 
1002
                                       cert_template, ctsize,
 
1003
                                       1, statusOpt);
 
1004
    if (objects) {
 
1005
        rvObject = objects[0];
 
1006
        nss_ZFreeIf(objects);
 
1007
    }
 
1008
    return rvObject;
 
1009
}
 
1010
 
 
1011
NSS_IMPLEMENT nssCryptokiObject **
 
1012
nssToken_FindPrivateKeys (
 
1013
  NSSToken *token,
 
1014
  nssSession *sessionOpt,
 
1015
  nssTokenSearchType searchType,
 
1016
  PRUint32 maximumOpt,
 
1017
  PRStatus *statusOpt
 
1018
)
 
1019
{
 
1020
    CK_ATTRIBUTE_PTR attr;
 
1021
    CK_ATTRIBUTE key_template[2];
 
1022
    CK_ULONG ktsize;
 
1023
    nssCryptokiObject **objects;
 
1024
 
 
1025
    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
 
1026
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
 
1027
    if (searchType == nssTokenSearchType_SessionOnly) {
 
1028
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
1029
    } else if (searchType == nssTokenSearchType_TokenOnly) {
 
1030
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
1031
    }
 
1032
    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
 
1033
 
 
1034
    objects = find_objects_by_template(token, sessionOpt,
 
1035
                                       key_template, ktsize, 
 
1036
                                       maximumOpt, statusOpt);
 
1037
    return objects;
 
1038
}
 
1039
 
 
1040
/* XXX ?there are no session cert objects, so only search token objects */
 
1041
NSS_IMPLEMENT nssCryptokiObject *
 
1042
nssToken_FindPrivateKeyByID (
 
1043
  NSSToken *token,
 
1044
  nssSession *sessionOpt,
 
1045
  NSSItem *keyID
 
1046
)
 
1047
{
 
1048
    CK_ATTRIBUTE_PTR attr;
 
1049
    CK_ATTRIBUTE key_template[3];
 
1050
    CK_ULONG ktsize;
 
1051
    nssCryptokiObject **objects;
 
1052
    nssCryptokiObject *rvKey = NULL;
 
1053
 
 
1054
    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
 
1055
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
 
1056
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
1057
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
 
1058
    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
 
1059
 
 
1060
    objects = find_objects_by_template(token, sessionOpt,
 
1061
                                       key_template, ktsize, 
 
1062
                                       1, NULL);
 
1063
    if (objects) {
 
1064
        rvKey = objects[0];
 
1065
        nss_ZFreeIf(objects);
 
1066
    }
 
1067
    return rvKey;
 
1068
}
 
1069
 
 
1070
/* XXX ?there are no session cert objects, so only search token objects */
 
1071
NSS_IMPLEMENT nssCryptokiObject *
 
1072
nssToken_FindPublicKeyByID (
 
1073
  NSSToken *token,
 
1074
  nssSession *sessionOpt,
 
1075
  NSSItem *keyID
 
1076
)
 
1077
{
 
1078
    CK_ATTRIBUTE_PTR attr;
 
1079
    CK_ATTRIBUTE key_template[3];
 
1080
    CK_ULONG ktsize;
 
1081
    nssCryptokiObject **objects;
 
1082
    nssCryptokiObject *rvKey = NULL;
 
1083
 
 
1084
    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
 
1085
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
 
1086
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
1087
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
 
1088
    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
 
1089
 
 
1090
    objects = find_objects_by_template(token, sessionOpt,
 
1091
                                       key_template, ktsize, 
 
1092
                                       1, NULL);
 
1093
    if (objects) {
 
1094
        rvKey = objects[0];
 
1095
        nss_ZFreeIf(objects);
 
1096
    }
 
1097
    return rvKey;
 
1098
}
 
1099
 
 
1100
static void
 
1101
sha1_hash(NSSItem *input, NSSItem *output)
 
1102
{
 
1103
    NSSAlgorithmAndParameters *ap;
 
1104
#ifdef NSS_3_4_CODE
 
1105
    PK11SlotInfo *internal = PK11_GetInternalSlot();
 
1106
    NSSToken *token = PK11Slot_GetNSSToken(internal);
 
1107
#else
 
1108
    NSSToken *token = nss_GetDefaultCryptoToken();
 
1109
#endif
 
1110
    ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
 
1111
    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
 
1112
#ifdef NSS_3_4_CODE
 
1113
    PK11_FreeSlot(token->pk11slot);
 
1114
#endif
 
1115
    nss_ZFreeIf(ap);
 
1116
}
 
1117
 
 
1118
static void
 
1119
md5_hash(NSSItem *input, NSSItem *output)
 
1120
{
 
1121
    NSSAlgorithmAndParameters *ap;
 
1122
#ifdef NSS_3_4_CODE
 
1123
    PK11SlotInfo *internal = PK11_GetInternalSlot();
 
1124
    NSSToken *token = PK11Slot_GetNSSToken(internal);
 
1125
#else
 
1126
    NSSToken *token = nss_GetDefaultCryptoToken();
 
1127
#endif
 
1128
    ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
 
1129
    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
 
1130
#ifdef NSS_3_4_CODE
 
1131
    PK11_FreeSlot(token->pk11slot);
 
1132
#endif
 
1133
    nss_ZFreeIf(ap);
 
1134
}
 
1135
 
 
1136
static CK_TRUST
 
1137
get_ck_trust (
 
1138
  nssTrustLevel nssTrust
 
1139
)
 
1140
{
 
1141
    CK_TRUST t;
 
1142
    switch (nssTrust) {
 
1143
    case nssTrustLevel_NotTrusted: t = CKT_NETSCAPE_UNTRUSTED; break;
 
1144
    case nssTrustLevel_TrustedDelegator: t = CKT_NETSCAPE_TRUSTED_DELEGATOR; 
 
1145
        break;
 
1146
    case nssTrustLevel_ValidDelegator: t = CKT_NETSCAPE_VALID_DELEGATOR; break;
 
1147
    case nssTrustLevel_Trusted: t = CKT_NETSCAPE_TRUSTED; break;
 
1148
    case nssTrustLevel_Valid: t = CKT_NETSCAPE_VALID; break;
 
1149
    case nssTrustLevel_Unknown:
 
1150
    default: t = CKT_NETSCAPE_TRUST_UNKNOWN; break;
 
1151
    }
 
1152
    return t;
 
1153
}
 
1154
 
 
1155
NSS_IMPLEMENT nssCryptokiObject *
 
1156
nssToken_ImportTrust (
 
1157
  NSSToken *tok,
 
1158
  nssSession *sessionOpt,
 
1159
  NSSDER *certEncoding,
 
1160
  NSSDER *certIssuer,
 
1161
  NSSDER *certSerial,
 
1162
  nssTrustLevel serverAuth,
 
1163
  nssTrustLevel clientAuth,
 
1164
  nssTrustLevel codeSigning,
 
1165
  nssTrustLevel emailProtection,
 
1166
  PRBool stepUpApproved,
 
1167
  PRBool asTokenObject
 
1168
)
 
1169
{
 
1170
    nssCryptokiObject *object;
 
1171
    CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
 
1172
    CK_TRUST ckSA, ckCA, ckCS, ckEP;
 
1173
    CK_ATTRIBUTE_PTR attr;
 
1174
    CK_ATTRIBUTE trust_tmpl[11];
 
1175
    CK_ULONG tsize;
 
1176
    PRUint8 sha1[20]; /* this is cheating... */
 
1177
    PRUint8 md5[16];
 
1178
    NSSItem sha1_result, md5_result;
 
1179
    sha1_result.data = sha1; sha1_result.size = sizeof sha1;
 
1180
    md5_result.data = md5; md5_result.size = sizeof md5;
 
1181
    sha1_hash(certEncoding, &sha1_result);
 
1182
    md5_hash(certEncoding, &md5_result);
 
1183
    ckSA = get_ck_trust(serverAuth);
 
1184
    ckCA = get_ck_trust(clientAuth);
 
1185
    ckCS = get_ck_trust(codeSigning);
 
1186
    ckEP = get_ck_trust(emailProtection);
 
1187
    NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
 
1188
    if (asTokenObject) {
 
1189
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
1190
    } else {
 
1191
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
1192
    }
 
1193
    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,           tobjc);
 
1194
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,          certIssuer);
 
1195
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,   certSerial);
 
1196
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
 
1197
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH,  &md5_result);
 
1198
    /* now set the trust values */
 
1199
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH,      ckSA);
 
1200
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH,      ckCA);
 
1201
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING,     ckCS);
 
1202
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
 
1203
    if (stepUpApproved) {
 
1204
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
 
1205
                                  &g_ck_true);
 
1206
    } else {
 
1207
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
 
1208
                                  &g_ck_false);
 
1209
    }
 
1210
    NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
 
1211
    /* import the trust object onto the token */
 
1212
    object = import_object(tok, sessionOpt, trust_tmpl, tsize);
 
1213
    if (object && tok->cache) {
 
1214
        nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
 
1215
                                         trust_tmpl, tsize);
 
1216
    }
 
1217
    return object;
 
1218
}
 
1219
 
 
1220
NSS_IMPLEMENT nssCryptokiObject **
 
1221
nssToken_FindTrustObjects (
 
1222
  NSSToken *token,
 
1223
  nssSession *sessionOpt,
 
1224
  nssTokenSearchType searchType,
 
1225
  PRUint32 maximumOpt,
 
1226
  PRStatus *statusOpt
 
1227
)
 
1228
{
 
1229
    CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
 
1230
    CK_ATTRIBUTE_PTR attr;
 
1231
    CK_ATTRIBUTE tobj_template[2];
 
1232
    CK_ULONG tobj_size;
 
1233
    nssCryptokiObject **objects;
 
1234
    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
 
1235
 
 
1236
    NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
 
1237
    if (searchType == nssTokenSearchType_SessionOnly) {
 
1238
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
1239
    } else if (searchType == nssTokenSearchType_TokenOnly ||
 
1240
               searchType == nssTokenSearchType_TokenForced) {
 
1241
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
1242
    }
 
1243
    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc);
 
1244
    NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
 
1245
 
 
1246
    if (searchType == nssTokenSearchType_TokenForced) {
 
1247
        objects = find_objects(token, session,
 
1248
                               tobj_template, tobj_size,
 
1249
                               maximumOpt, statusOpt);
 
1250
    } else {
 
1251
        objects = find_objects_by_template(token, session,
 
1252
                                           tobj_template, tobj_size,
 
1253
                                           maximumOpt, statusOpt);
 
1254
    }
 
1255
    return objects;
 
1256
}
 
1257
 
 
1258
NSS_IMPLEMENT nssCryptokiObject *
 
1259
nssToken_FindTrustForCertificate (
 
1260
  NSSToken *token,
 
1261
  nssSession *sessionOpt,
 
1262
  NSSDER *certEncoding,
 
1263
  NSSDER *certIssuer,
 
1264
  NSSDER *certSerial,
 
1265
  nssTokenSearchType searchType
 
1266
)
 
1267
{
 
1268
    CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
 
1269
    CK_ATTRIBUTE_PTR attr;
 
1270
    CK_ATTRIBUTE tobj_template[5];
 
1271
    CK_ULONG tobj_size;
 
1272
    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
 
1273
    nssCryptokiObject *object, **objects;
 
1274
 
 
1275
    NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
 
1276
    if (searchType == nssTokenSearchType_SessionOnly) {
 
1277
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
1278
    } else if (searchType == nssTokenSearchType_TokenOnly) {
 
1279
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
1280
    }
 
1281
    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,          tobjc);
 
1282
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         certIssuer);
 
1283
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER , certSerial);
 
1284
    NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
 
1285
    object = NULL;
 
1286
    objects = find_objects_by_template(token, session,
 
1287
                                       tobj_template, tobj_size,
 
1288
                                       1, NULL);
 
1289
    if (objects) {
 
1290
        object = objects[0];
 
1291
        nss_ZFreeIf(objects);
 
1292
    }
 
1293
    return object;
 
1294
}
 
1295
 
 
1296
NSS_IMPLEMENT nssCryptokiObject *
 
1297
nssToken_ImportCRL (
 
1298
  NSSToken *token,
 
1299
  nssSession *sessionOpt,
 
1300
  NSSDER *subject,
 
1301
  NSSDER *encoding,
 
1302
  PRBool isKRL,
 
1303
  NSSUTF8 *url,
 
1304
  PRBool asTokenObject
 
1305
)
 
1306
{
 
1307
    nssCryptokiObject *object;
 
1308
    CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
 
1309
    CK_ATTRIBUTE_PTR attr;
 
1310
    CK_ATTRIBUTE crl_tmpl[6];
 
1311
    CK_ULONG crlsize;
 
1312
 
 
1313
    NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
 
1314
    if (asTokenObject) {
 
1315
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
1316
    } else {
 
1317
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
1318
    }
 
1319
    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,        crlobjc);
 
1320
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,      subject);
 
1321
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,        encoding);
 
1322
    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_URL, url);
 
1323
    if (isKRL) {
 
1324
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NETSCAPE_KRL, &g_ck_true);
 
1325
    } else {
 
1326
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NETSCAPE_KRL, &g_ck_false);
 
1327
    }
 
1328
    NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
 
1329
 
 
1330
    /* import the crl object onto the token */
 
1331
    object = import_object(token, sessionOpt, crl_tmpl, crlsize);
 
1332
    if (object && token->cache) {
 
1333
        nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
 
1334
                                         crl_tmpl, crlsize);
 
1335
    }
 
1336
    return object;
 
1337
}
 
1338
 
 
1339
NSS_IMPLEMENT nssCryptokiObject **
 
1340
nssToken_FindCRLs (
 
1341
  NSSToken *token,
 
1342
  nssSession *sessionOpt,
 
1343
  nssTokenSearchType searchType,
 
1344
  PRUint32 maximumOpt,
 
1345
  PRStatus *statusOpt
 
1346
)
 
1347
{
 
1348
    CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
 
1349
    CK_ATTRIBUTE_PTR attr;
 
1350
    CK_ATTRIBUTE crlobj_template[2];
 
1351
    CK_ULONG crlobj_size;
 
1352
    nssCryptokiObject **objects;
 
1353
    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
 
1354
 
 
1355
    NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
 
1356
    if (searchType == nssTokenSearchType_SessionOnly) {
 
1357
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
1358
    } else if (searchType == nssTokenSearchType_TokenOnly ||
 
1359
               searchType == nssTokenSearchType_TokenForced) {
 
1360
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
1361
    }
 
1362
    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
 
1363
    NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
 
1364
 
 
1365
    if (searchType == nssTokenSearchType_TokenForced) {
 
1366
        objects = find_objects(token, session,
 
1367
                               crlobj_template, crlobj_size,
 
1368
                               maximumOpt, statusOpt);
 
1369
    } else {
 
1370
        objects = find_objects_by_template(token, session,
 
1371
                                           crlobj_template, crlobj_size,
 
1372
                                           maximumOpt, statusOpt);
 
1373
    }
 
1374
    return objects;
 
1375
}
 
1376
 
 
1377
NSS_IMPLEMENT nssCryptokiObject **
 
1378
nssToken_FindCRLsBySubject (
 
1379
  NSSToken *token,
 
1380
  nssSession *sessionOpt,
 
1381
  NSSDER *subject,
 
1382
  nssTokenSearchType searchType,
 
1383
  PRUint32 maximumOpt,
 
1384
  PRStatus *statusOpt
 
1385
)
 
1386
{
 
1387
    CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
 
1388
    CK_ATTRIBUTE_PTR attr;
 
1389
    CK_ATTRIBUTE crlobj_template[3];
 
1390
    CK_ULONG crlobj_size;
 
1391
    nssCryptokiObject **objects;
 
1392
    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
 
1393
 
 
1394
    NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
 
1395
    if (searchType == nssTokenSearchType_SessionOnly) {
 
1396
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
1397
    } else if (searchType == nssTokenSearchType_TokenOnly ||
 
1398
               searchType == nssTokenSearchType_TokenForced) {
 
1399
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
1400
    }
 
1401
    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
 
1402
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
 
1403
    NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
 
1404
 
 
1405
    objects = find_objects_by_template(token, session,
 
1406
                                       crlobj_template, crlobj_size,
 
1407
                                       maximumOpt, statusOpt);
 
1408
    return objects;
 
1409
}
 
1410
 
 
1411
NSS_IMPLEMENT PRStatus
 
1412
nssToken_GetCachedObjectAttributes (
 
1413
  NSSToken *token,
 
1414
  NSSArena *arenaOpt,
 
1415
  nssCryptokiObject *object,
 
1416
  CK_OBJECT_CLASS objclass,
 
1417
  CK_ATTRIBUTE_PTR atemplate,
 
1418
  CK_ULONG atlen
 
1419
)
 
1420
{
 
1421
    if (!token->cache) {
 
1422
        return PR_FAILURE;
 
1423
    }
 
1424
    return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
 
1425
                                                   object, objclass,
 
1426
                                                   atemplate, atlen);
 
1427
}
 
1428
 
 
1429
NSS_IMPLEMENT NSSItem *
 
1430
nssToken_Digest (
 
1431
  NSSToken *tok,
 
1432
  nssSession *sessionOpt,
 
1433
  NSSAlgorithmAndParameters *ap,
 
1434
  NSSItem *data,
 
1435
  NSSItem *rvOpt,
 
1436
  NSSArena *arenaOpt
 
1437
)
 
1438
{
 
1439
    CK_RV ckrv;
 
1440
    CK_ULONG digestLen;
 
1441
    CK_BYTE_PTR digest;
 
1442
    NSSItem *rvItem = NULL;
 
1443
    void *epv = nssToken_GetCryptokiEPV(tok);
 
1444
    nssSession *session;
 
1445
    session = (sessionOpt) ? sessionOpt : tok->defaultSession;
 
1446
    nssSession_EnterMonitor(session);
 
1447
    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
 
1448
    if (ckrv != CKR_OK) {
 
1449
        nssSession_ExitMonitor(session);
 
1450
        return NULL;
 
1451
    }
 
1452
#if 0
 
1453
    /* XXX the standard says this should work, but it doesn't */
 
1454
    ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
 
1455
    if (ckrv != CKR_OK) {
 
1456
        nssSession_ExitMonitor(session);
 
1457
        return NULL;
 
1458
    }
 
1459
#endif
 
1460
    digestLen = 0; /* XXX for now */
 
1461
    digest = NULL;
 
1462
    if (rvOpt) {
 
1463
        if (rvOpt->size > 0 && rvOpt->size < digestLen) {
 
1464
            nssSession_ExitMonitor(session);
 
1465
            /* the error should be bad args */
 
1466
            return NULL;
 
1467
        }
 
1468
        if (rvOpt->data) {
 
1469
            digest = rvOpt->data;
 
1470
        }
 
1471
        digestLen = rvOpt->size;
 
1472
    }
 
1473
    if (!digest) {
 
1474
        digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
 
1475
        if (!digest) {
 
1476
            nssSession_ExitMonitor(session);
 
1477
            return NULL;
 
1478
        }
 
1479
    }
 
1480
    ckrv = CKAPI(epv)->C_Digest(session->handle, 
 
1481
                                (CK_BYTE_PTR)data->data, 
 
1482
                                (CK_ULONG)data->size,
 
1483
                                (CK_BYTE_PTR)digest,
 
1484
                                &digestLen);
 
1485
    nssSession_ExitMonitor(session);
 
1486
    if (ckrv != CKR_OK) {
 
1487
        nss_ZFreeIf(digest);
 
1488
        return NULL;
 
1489
    }
 
1490
    if (!rvOpt) {
 
1491
        rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
 
1492
    }
 
1493
    return rvItem;
 
1494
}
 
1495
 
 
1496
NSS_IMPLEMENT PRStatus
 
1497
nssToken_BeginDigest (
 
1498
  NSSToken *tok,
 
1499
  nssSession *sessionOpt,
 
1500
  NSSAlgorithmAndParameters *ap
 
1501
)
 
1502
{
 
1503
    CK_RV ckrv;
 
1504
    nssSession *session;
 
1505
    void *epv = nssToken_GetCryptokiEPV(tok);
 
1506
    session = (sessionOpt) ? sessionOpt : tok->defaultSession;
 
1507
    nssSession_EnterMonitor(session);
 
1508
    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
 
1509
    nssSession_ExitMonitor(session);
 
1510
    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
 
1511
}
 
1512
 
 
1513
NSS_IMPLEMENT PRStatus
 
1514
nssToken_ContinueDigest (
 
1515
  NSSToken *tok,
 
1516
  nssSession *sessionOpt,
 
1517
  NSSItem *item
 
1518
)
 
1519
{
 
1520
    CK_RV ckrv;
 
1521
    nssSession *session;
 
1522
    void *epv = nssToken_GetCryptokiEPV(tok);
 
1523
    session = (sessionOpt) ? sessionOpt : tok->defaultSession;
 
1524
    nssSession_EnterMonitor(session);
 
1525
    ckrv = CKAPI(epv)->C_DigestUpdate(session->handle, 
 
1526
                                      (CK_BYTE_PTR)item->data, 
 
1527
                                      (CK_ULONG)item->size);
 
1528
    nssSession_ExitMonitor(session);
 
1529
    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
 
1530
}
 
1531
 
 
1532
NSS_IMPLEMENT NSSItem *
 
1533
nssToken_FinishDigest (
 
1534
  NSSToken *tok,
 
1535
  nssSession *sessionOpt,
 
1536
  NSSItem *rvOpt,
 
1537
  NSSArena *arenaOpt
 
1538
)
 
1539
{
 
1540
    CK_RV ckrv;
 
1541
    CK_ULONG digestLen;
 
1542
    CK_BYTE_PTR digest;
 
1543
    NSSItem *rvItem = NULL;
 
1544
    void *epv = nssToken_GetCryptokiEPV(tok);
 
1545
    nssSession *session;
 
1546
    session = (sessionOpt) ? sessionOpt : tok->defaultSession;
 
1547
    nssSession_EnterMonitor(session);
 
1548
    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
 
1549
    if (ckrv != CKR_OK || digestLen == 0) {
 
1550
        nssSession_ExitMonitor(session);
 
1551
        return NULL;
 
1552
    }
 
1553
    digest = NULL;
 
1554
    if (rvOpt) {
 
1555
        if (rvOpt->size > 0 && rvOpt->size < digestLen) {
 
1556
            nssSession_ExitMonitor(session);
 
1557
            /* the error should be bad args */
 
1558
            return NULL;
 
1559
        }
 
1560
        if (rvOpt->data) {
 
1561
            digest = rvOpt->data;
 
1562
        }
 
1563
        digestLen = rvOpt->size;
 
1564
    }
 
1565
    if (!digest) {
 
1566
        digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
 
1567
        if (!digest) {
 
1568
            nssSession_ExitMonitor(session);
 
1569
            return NULL;
 
1570
        }
 
1571
    }
 
1572
    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
 
1573
    nssSession_ExitMonitor(session);
 
1574
    if (ckrv != CKR_OK) {
 
1575
        nss_ZFreeIf(digest);
 
1576
        return NULL;
 
1577
    }
 
1578
    if (!rvOpt) {
 
1579
        rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
 
1580
    }
 
1581
    return rvItem;
 
1582
}
 
1583
 
 
1584
NSS_IMPLEMENT PRBool
 
1585
nssToken_IsPresent (
 
1586
  NSSToken *token
 
1587
)
 
1588
{
 
1589
    return nssSlot_IsTokenPresent(token->slot);
 
1590
}
 
1591
 
 
1592
/* Sigh.  The methods to find objects declared above cause problems with
 
1593
 * the low-level object cache in the softoken -- the objects are found in 
 
1594
 * toto, then one wave of GetAttributes is done, then another.  Having a 
 
1595
 * large number of objects causes the cache to be thrashed, as the objects 
 
1596
 * are gone before there's any chance to ask for their attributes.
 
1597
 * So, for now, bringing back traversal methods for certs.  This way all of 
 
1598
 * the cert's attributes can be grabbed immediately after finding it,
 
1599
 * increasing the likelihood that the cache takes care of it.
 
1600
 */
 
1601
NSS_IMPLEMENT PRStatus
 
1602
nssToken_TraverseCertificates (
 
1603
  NSSToken *token,
 
1604
  nssSession *sessionOpt,
 
1605
  nssTokenSearchType searchType,
 
1606
  PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
 
1607
  void *arg
 
1608
)
 
1609
{
 
1610
    CK_RV ckrv;
 
1611
    CK_ULONG count;
 
1612
    CK_OBJECT_HANDLE *objectHandles;
 
1613
    CK_ATTRIBUTE_PTR attr;
 
1614
    CK_ATTRIBUTE cert_template[2];
 
1615
    CK_ULONG ctsize;
 
1616
    NSSArena *arena;
 
1617
    PRStatus status;
 
1618
    PRUint32 arraySize, numHandles;
 
1619
    nssCryptokiObject **objects;
 
1620
    void *epv = nssToken_GetCryptokiEPV(token);
 
1621
    nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
 
1622
 
 
1623
    /* template for all certs */
 
1624
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
 
1625
    if (searchType == nssTokenSearchType_SessionOnly) {
 
1626
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
 
1627
    } else if (searchType == nssTokenSearchType_TokenOnly ||
 
1628
               searchType == nssTokenSearchType_TokenForced) {
 
1629
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
 
1630
    }
 
1631
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
 
1632
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
 
1633
 
 
1634
    /* the arena is only for the array of object handles */
 
1635
    arena = nssArena_Create();
 
1636
    if (!arena) {
 
1637
        return PR_FAILURE;
 
1638
    }
 
1639
    arraySize = OBJECT_STACK_SIZE;
 
1640
    numHandles = 0;
 
1641
    objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
 
1642
    if (!objectHandles) {
 
1643
        goto loser;
 
1644
    }
 
1645
    nssSession_EnterMonitor(session); /* ==== session lock === */
 
1646
    /* Initialize the find with the template */
 
1647
    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
 
1648
                                         cert_template, ctsize);
 
1649
    if (ckrv != CKR_OK) {
 
1650
        nssSession_ExitMonitor(session);
 
1651
        goto loser;
 
1652
    }
 
1653
    while (PR_TRUE) {
 
1654
        /* Issue the find for up to arraySize - numHandles objects */
 
1655
        ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
 
1656
                                         objectHandles + numHandles, 
 
1657
                                         arraySize - numHandles, 
 
1658
                                         &count);
 
1659
        if (ckrv != CKR_OK) {
 
1660
            nssSession_ExitMonitor(session);
 
1661
            goto loser;
 
1662
        }
 
1663
        /* bump the number of found objects */
 
1664
        numHandles += count;
 
1665
        if (numHandles < arraySize) {
 
1666
            break;
 
1667
        }
 
1668
        /* the array is filled, double it and continue */
 
1669
        arraySize *= 2;
 
1670
        objectHandles = nss_ZREALLOCARRAY(objectHandles, 
 
1671
                                          CK_OBJECT_HANDLE, 
 
1672
                                          arraySize);
 
1673
        if (!objectHandles) {
 
1674
            nssSession_ExitMonitor(session);
 
1675
            goto loser;
 
1676
        }
 
1677
    }
 
1678
    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
 
1679
    nssSession_ExitMonitor(session); /* ==== end session lock === */
 
1680
    if (ckrv != CKR_OK) {
 
1681
        goto loser;
 
1682
    }
 
1683
    if (numHandles > 0) {
 
1684
        objects = create_objects_from_handles(token, session,
 
1685
                                              objectHandles, numHandles);
 
1686
        if (objects) {
 
1687
            nssCryptokiObject **op;
 
1688
            for (op = objects; *op; op++) {
 
1689
                status = (*callback)(*op, arg);
 
1690
            }
 
1691
            nss_ZFreeIf(objects);
 
1692
        }
 
1693
    }
 
1694
    nssArena_Destroy(arena);
 
1695
    return PR_SUCCESS;
 
1696
loser:
 
1697
    nssArena_Destroy(arena);
 
1698
    return PR_FAILURE;
 
1699
}
 
1700
 
 
1701
NSS_IMPLEMENT PRBool
 
1702
nssToken_IsPrivateKeyAvailable (
 
1703
  NSSToken *token,
 
1704
  NSSCertificate *c,
 
1705
  nssCryptokiObject *instance
 
1706
)
 
1707
{
 
1708
    CK_OBJECT_CLASS theClass;
 
1709
 
 
1710
    if (token == NULL) return PR_FALSE;
 
1711
    if (c == NULL) return PR_FALSE;
 
1712
 
 
1713
    theClass = CKO_PRIVATE_KEY;
 
1714
    if (!nssSlot_IsLoggedIn(token->slot)) {
 
1715
        theClass = CKO_PUBLIC_KEY;
 
1716
    }
 
1717
    if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) 
 
1718
                                                != CK_INVALID_HANDLE) {
 
1719
        return PR_TRUE;
 
1720
    }
 
1721
    return PR_FALSE;
 
1722
}