Coverage Report

Created: 2026-02-05 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/pk11wrap/pk11obj.c
Line
Count
Source
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/. */
4
/*
5
 * This file manages object type indepentent functions.
6
 */
7
#include <limits.h>
8
#include <stddef.h>
9
10
#include "seccomon.h"
11
#include "secder.h"
12
#include "secmod.h"
13
#include "secmodi.h"
14
#include "secmodti.h"
15
#include "pkcs11.h"
16
#include "pkcs11t.h"
17
#include "pk11func.h"
18
#include "keyhi.h"
19
#include "keyi.h"
20
#include "secitem.h"
21
#include "secerr.h"
22
#include "sslerr.h"
23
24
264
#define PK11_SEARCH_CHUNKSIZE 10
25
26
/*
27
 * Build a block big enough to hold the data
28
 */
29
SECItem *
30
PK11_BlockData(SECItem *data, unsigned long size)
31
0
{
32
0
    SECItem *newData;
33
34
0
    if (size == 0u)
35
0
        return NULL;
36
37
0
    newData = (SECItem *)PORT_Alloc(sizeof(SECItem));
38
0
    if (newData == NULL)
39
0
        return NULL;
40
41
0
    newData->len = (data->len + (size - 1)) / size;
42
0
    newData->len *= size;
43
44
0
    newData->data = (unsigned char *)PORT_ZAlloc(newData->len);
45
0
    if (newData->data == NULL) {
46
0
        PORT_Free(newData);
47
0
        return NULL;
48
0
    }
49
0
    PORT_Memset(newData->data, newData->len - data->len, newData->len);
50
0
    PORT_Memcpy(newData->data, data->data, data->len);
51
0
    return newData;
52
0
}
53
54
SECStatus
55
PK11_DestroyObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE object)
56
257k
{
57
257k
    CK_RV crv;
58
59
257k
    PK11_EnterSlotMonitor(slot);
60
257k
    crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session, object);
61
257k
    PK11_ExitSlotMonitor(slot);
62
257k
    if (crv != CKR_OK) {
63
0
        return SECFailure;
64
0
    }
65
257k
    return SECSuccess;
66
257k
}
67
68
SECStatus
69
PK11_DestroyTokenObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE object)
70
0
{
71
0
    CK_RV crv;
72
0
    SECStatus rv = SECSuccess;
73
0
    CK_SESSION_HANDLE rwsession;
74
75
0
    rwsession = PK11_GetRWSession(slot);
76
0
    if (rwsession == CK_INVALID_HANDLE) {
77
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
78
0
        return SECFailure;
79
0
    }
80
81
0
    crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession, object);
82
0
    if (crv != CKR_OK) {
83
0
        rv = SECFailure;
84
0
        PORT_SetError(PK11_MapError(crv));
85
0
    }
86
0
    PK11_RestoreROSession(slot, rwsession);
87
0
    return rv;
88
0
}
89
90
/*
91
 * Read in a single attribute into a SECItem. Allocate space for it with
92
 * PORT_Alloc unless an arena is supplied. In the latter case use the arena
93
 * to allocate the space.
94
 *
95
 * PK11_ReadAttribute sets the 'data' and 'len' fields of the SECItem but
96
 * does not modify its 'type' field.
97
 */
98
SECStatus
99
PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
100
                   CK_ATTRIBUTE_TYPE type, PLArenaPool *arena, SECItem *result)
101
366k
{
102
366k
    CK_ATTRIBUTE attr = { 0, NULL, 0 };
103
366k
    CK_RV crv;
104
105
366k
    attr.type = type;
106
107
366k
    PK11_EnterSlotMonitor(slot);
108
366k
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1);
109
366k
    if (crv != CKR_OK) {
110
46
        PK11_ExitSlotMonitor(slot);
111
46
        PORT_SetError(PK11_MapError(crv));
112
46
        return SECFailure;
113
46
    }
114
366k
    if (arena) {
115
248
        attr.pValue = PORT_ArenaAlloc(arena, attr.ulValueLen);
116
366k
    } else {
117
366k
        attr.pValue = PORT_Alloc(attr.ulValueLen);
118
366k
    }
119
366k
    if (attr.pValue == NULL) {
120
0
        PK11_ExitSlotMonitor(slot);
121
0
        return SECFailure;
122
0
    }
123
366k
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1);
124
366k
    PK11_ExitSlotMonitor(slot);
125
366k
    if (crv != CKR_OK) {
126
0
        PORT_SetError(PK11_MapError(crv));
127
0
        if (!arena)
128
0
            PORT_Free(attr.pValue);
129
0
        return SECFailure;
130
0
    }
131
132
366k
    result->data = (unsigned char *)attr.pValue;
133
366k
    result->len = attr.ulValueLen;
134
135
366k
    return SECSuccess;
136
366k
}
137
138
/*
139
 * Read in a single attribute into a Ulong.
140
 */
141
CK_ULONG
142
PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
143
                        CK_ATTRIBUTE_TYPE type)
144
106k
{
145
106k
    CK_ATTRIBUTE attr;
146
106k
    CK_ULONG value = CK_UNAVAILABLE_INFORMATION;
147
106k
    CK_RV crv;
148
149
106k
    PK11_SETATTRS(&attr, type, &value, sizeof(value));
150
151
106k
    PK11_EnterSlotMonitor(slot);
152
106k
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id, &attr, 1);
153
106k
    PK11_ExitSlotMonitor(slot);
154
106k
    if (crv != CKR_OK) {
155
0
        PORT_SetError(PK11_MapError(crv));
156
0
    }
157
106k
    return value;
158
106k
}
159
160
/*
161
 * check to see if a bool has been set.
162
 */
163
CK_BBOOL
164
pk11_HasAttributeSet_Lock(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
165
                          CK_ATTRIBUTE_TYPE type, PRBool haslock)
166
363k
{
167
363k
    CK_BBOOL ckvalue = CK_FALSE;
168
363k
    CK_ATTRIBUTE theTemplate;
169
363k
    CK_RV crv;
170
171
    /* Prepare to retrieve the attribute. */
172
363k
    PK11_SETATTRS(&theTemplate, type, &ckvalue, sizeof(CK_BBOOL));
173
174
    /* Retrieve attribute value. */
175
363k
    if (!haslock)
176
363k
        PK11_EnterSlotMonitor(slot);
177
363k
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, id,
178
363k
                                                 &theTemplate, 1);
179
363k
    if (!haslock)
180
363k
        PK11_ExitSlotMonitor(slot);
181
363k
    if (crv != CKR_OK) {
182
8
        PORT_SetError(PK11_MapError(crv));
183
8
        return CK_FALSE;
184
8
    }
185
186
363k
    return ckvalue;
187
363k
}
188
189
CK_BBOOL
190
PK11_HasAttributeSet(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
191
                     CK_ATTRIBUTE_TYPE type, PRBool haslock)
192
363k
{
193
363k
    PR_ASSERT(haslock == PR_FALSE);
194
363k
    return pk11_HasAttributeSet_Lock(slot, id, type, PR_FALSE);
195
363k
}
196
197
/*
198
 * returns a full list of attributes. Allocate space for them. If an arena is
199
 * provided, allocate space out of the arena.
200
 */
201
CK_RV
202
PK11_GetAttributes(PLArenaPool *arena, PK11SlotInfo *slot,
203
                   CK_OBJECT_HANDLE obj, CK_ATTRIBUTE *attr, int count)
204
132k
{
205
132k
    int i;
206
    /* make pedantic happy... note that it's only used arena != NULL */
207
132k
    void *mark = NULL;
208
132k
    CK_RV crv;
209
132k
    if (slot->session == CK_INVALID_HANDLE)
210
0
        return CKR_SESSION_HANDLE_INVALID;
211
212
    /*
213
     * first get all the lengths of the parameters.
214
     */
215
132k
    PK11_EnterSlotMonitor(slot);
216
132k
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, obj, attr, count);
217
132k
    if (crv != CKR_OK) {
218
114
        PK11_ExitSlotMonitor(slot);
219
114
        return crv;
220
114
    }
221
222
132k
    if (arena) {
223
106k
        mark = PORT_ArenaMark(arena);
224
106k
        if (mark == NULL)
225
0
            return CKR_HOST_MEMORY;
226
106k
    }
227
228
    /*
229
     * now allocate space to store the results.
230
     */
231
592k
    for (i = 0; i < count; i++) {
232
460k
        if (attr[i].ulValueLen == 0)
233
261
            continue;
234
459k
        if (arena) {
235
434k
            attr[i].pValue = PORT_ArenaAlloc(arena, attr[i].ulValueLen);
236
434k
            if (attr[i].pValue == NULL) {
237
                /* arena failures, just release the mark */
238
0
                PORT_ArenaRelease(arena, mark);
239
0
                PK11_ExitSlotMonitor(slot);
240
0
                return CKR_HOST_MEMORY;
241
0
            }
242
434k
        } else {
243
25.8k
            attr[i].pValue = PORT_Alloc(attr[i].ulValueLen);
244
25.8k
            if (attr[i].pValue == NULL) {
245
                /* Separate malloc failures, loop to release what we have
246
                 * so far */
247
0
                int j;
248
0
                for (j = 0; j < i; j++) {
249
0
                    PORT_Free(attr[j].pValue);
250
                    /* don't give the caller pointers to freed memory */
251
0
                    attr[j].pValue = NULL;
252
0
                }
253
0
                PK11_ExitSlotMonitor(slot);
254
0
                return CKR_HOST_MEMORY;
255
0
            }
256
25.8k
        }
257
459k
    }
258
259
    /*
260
     * finally get the results.
261
     */
262
132k
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, obj, attr, count);
263
132k
    PK11_ExitSlotMonitor(slot);
264
132k
    if (crv != CKR_OK) {
265
0
        if (arena) {
266
0
            PORT_ArenaRelease(arena, mark);
267
0
        } else {
268
0
            for (i = 0; i < count; i++) {
269
0
                PORT_Free(attr[i].pValue);
270
                /* don't give the caller pointers to freed memory */
271
0
                attr[i].pValue = NULL;
272
0
            }
273
0
        }
274
132k
    } else if (arena && mark) {
275
106k
        PORT_ArenaUnmark(arena, mark);
276
106k
    }
277
132k
    return crv;
278
132k
}
279
280
PRBool
281
PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle)
282
150k
{
283
150k
    return (PRBool)PK11_HasAttributeSet(slot, handle, CKA_TOKEN, PR_FALSE);
284
150k
}
285
286
char *
287
PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
288
114
{
289
114
    char *nickname = NULL;
290
114
    SECItem result;
291
114
    SECStatus rv;
292
293
114
    rv = PK11_ReadAttribute(slot, id, CKA_LABEL, NULL, &result);
294
114
    if (rv != SECSuccess) {
295
0
        return NULL;
296
0
    }
297
298
114
    nickname = PORT_ZAlloc(result.len + 1);
299
114
    if (nickname == NULL) {
300
0
        PORT_Free(result.data);
301
0
        return NULL;
302
0
    }
303
114
    PORT_Memcpy(nickname, result.data, result.len);
304
114
    PORT_Free(result.data);
305
114
    return nickname;
306
114
}
307
308
SECStatus
309
PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
310
                       const char *nickname)
311
0
{
312
0
    int len = PORT_Strlen(nickname);
313
0
    CK_ATTRIBUTE setTemplate;
314
0
    CK_RV crv;
315
0
    CK_SESSION_HANDLE rwsession;
316
317
0
    if (len < 0) {
318
0
        return SECFailure;
319
0
    }
320
321
0
    PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *)nickname, len);
322
0
    rwsession = PK11_GetRWSession(slot);
323
0
    if (rwsession == CK_INVALID_HANDLE) {
324
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
325
0
        return SECFailure;
326
0
    }
327
0
    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id,
328
0
                                                 &setTemplate, 1);
329
0
    PK11_RestoreROSession(slot, rwsession);
330
0
    if (crv != CKR_OK) {
331
0
        PORT_SetError(PK11_MapError(crv));
332
0
        return SECFailure;
333
0
    }
334
0
    return SECSuccess;
335
0
}
336
337
/*
338
 * strip leading zero's from key material
339
 */
340
void
341
pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib)
342
116k
{
343
116k
    char *ptr = (char *)attrib->pValue;
344
116k
    unsigned long len = attrib->ulValueLen;
345
346
116k
    while ((len > 1) && (*ptr == 0)) {
347
0
        len--;
348
0
        ptr++;
349
0
    }
350
116k
    attrib->pValue = ptr;
351
116k
    attrib->ulValueLen = len;
352
116k
}
353
354
/*
355
 * get a new session on a slot. If we run out of session, use the slot's
356
 * 'exclusive' session. In this case owner becomes false.
357
 */
358
CK_SESSION_HANDLE
359
pk11_GetNewSession(PK11SlotInfo *slot, PRBool *owner)
360
1.92M
{
361
1.92M
    CK_SESSION_HANDLE session;
362
1.92M
    *owner = PR_TRUE;
363
1.92M
    if (!slot->isThreadSafe)
364
0
        PK11_EnterSlotMonitor(slot);
365
1.92M
    if (PK11_GETTAB(slot)->C_OpenSession(slot->slotID, CKF_SERIAL_SESSION,
366
1.92M
                                         slot, pk11_notify, &session) != CKR_OK) {
367
0
        *owner = PR_FALSE;
368
0
        session = slot->session;
369
0
    }
370
1.92M
    if (!slot->isThreadSafe)
371
0
        PK11_ExitSlotMonitor(slot);
372
373
1.92M
    return session;
374
1.92M
}
375
376
void
377
pk11_CloseSession(PK11SlotInfo *slot, CK_SESSION_HANDLE session, PRBool owner)
378
1.92M
{
379
1.92M
    if (!owner)
380
40
        return;
381
1.92M
    if (!slot->isThreadSafe)
382
0
        PK11_EnterSlotMonitor(slot);
383
1.92M
    (void)PK11_GETTAB(slot)->C_CloseSession(session);
384
1.92M
    if (!slot->isThreadSafe)
385
0
        PK11_ExitSlotMonitor(slot);
386
1.92M
}
387
388
SECStatus
389
PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
390
                     const CK_ATTRIBUTE *theTemplate, int count,
391
                     PRBool token, CK_OBJECT_HANDLE *objectID)
392
90.0k
{
393
90.0k
    CK_SESSION_HANDLE rwsession;
394
90.0k
    CK_RV crv;
395
90.0k
    SECStatus rv = SECSuccess;
396
397
90.0k
    rwsession = session;
398
90.0k
    if (token) {
399
0
        rwsession = PK11_GetRWSession(slot);
400
90.0k
    } else if (rwsession == CK_INVALID_HANDLE) {
401
47.8k
        rwsession = slot->session;
402
47.8k
        if (rwsession != CK_INVALID_HANDLE)
403
47.8k
            PK11_EnterSlotMonitor(slot);
404
47.8k
    }
405
90.0k
    if (rwsession == CK_INVALID_HANDLE) {
406
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
407
0
        return SECFailure;
408
0
    }
409
90.0k
    crv = PK11_GETTAB(slot)->C_CreateObject(rwsession,
410
90.0k
                                            /* cast away const :-( */ (CK_ATTRIBUTE_PTR)theTemplate,
411
90.0k
                                            count, objectID);
412
90.0k
    if (crv != CKR_OK) {
413
5.12k
        PORT_SetError(PK11_MapError(crv));
414
5.12k
        rv = SECFailure;
415
5.12k
    }
416
90.0k
    if (token) {
417
0
        PK11_RestoreROSession(slot, rwsession);
418
90.0k
    } else if (session == CK_INVALID_HANDLE) {
419
47.8k
        PK11_ExitSlotMonitor(slot);
420
47.8k
    }
421
422
90.0k
    return rv;
423
90.0k
}
424
425
/* This function may add a maximum of 9 attributes. */
426
unsigned int
427
pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue)
428
858k
{
429
430
858k
    const static CK_ATTRIBUTE_TYPE attrTypes[12] = {
431
858k
        CKA_ENCRYPT, CKA_DECRYPT, 0 /* DIGEST */, CKA_SIGN,
432
858k
        CKA_SIGN_RECOVER, CKA_VERIFY, CKA_VERIFY_RECOVER, 0 /* GEN */,
433
858k
        0 /* GEN PAIR */, CKA_WRAP, CKA_UNWRAP, CKA_DERIVE
434
858k
    };
435
436
858k
    const CK_ATTRIBUTE_TYPE *pType = attrTypes;
437
858k
    CK_ATTRIBUTE *attr = attrs;
438
858k
    CK_FLAGS test = CKF_ENCRYPT;
439
440
858k
    PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS));
441
858k
    flags &= CKF_KEY_OPERATION_FLAGS;
442
443
5.83M
    for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) {
444
4.97M
        if (test & flags) {
445
1.73M
            flags ^= test;
446
1.73M
            PR_ASSERT(*pType);
447
1.73M
            PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue);
448
1.73M
            ++attr;
449
1.73M
        }
450
4.97M
    }
451
858k
    return (attr - attrs);
452
858k
}
453
454
/*
455
 * Check for conflicting flags, for example, if both PK11_ATTR_PRIVATE
456
 * and PK11_ATTR_PUBLIC are set.
457
 */
458
PRBool
459
pk11_BadAttrFlags(PK11AttrFlags attrFlags)
460
530k
{
461
530k
    PK11AttrFlags trueFlags = attrFlags & 0x55555555;
462
530k
    PK11AttrFlags falseFlags = (attrFlags >> 1) & 0x55555555;
463
530k
    return ((trueFlags & falseFlags) != 0);
464
530k
}
465
466
/*
467
 * This function may add a maximum of 5 attributes.
468
 * The caller must make sure the attribute flags don't have conflicts.
469
 */
470
unsigned int
471
pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, CK_ATTRIBUTE *attrs,
472
                           CK_BBOOL *ckTrue, CK_BBOOL *ckFalse)
473
319k
{
474
319k
    const static CK_ATTRIBUTE_TYPE attrTypes[5] = {
475
319k
        CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_SENSITIVE,
476
319k
        CKA_EXTRACTABLE
477
319k
    };
478
479
319k
    const CK_ATTRIBUTE_TYPE *pType = attrTypes;
480
319k
    CK_ATTRIBUTE *attr = attrs;
481
319k
    PK11AttrFlags test = PK11_ATTR_TOKEN;
482
483
319k
    PR_ASSERT(!pk11_BadAttrFlags(attrFlags));
484
485
    /* we test two related bitflags in each iteration */
486
862k
    for (; attrFlags && test <= PK11_ATTR_EXTRACTABLE; test <<= 2, ++pType) {
487
543k
        if (test & attrFlags) {
488
8.24k
            attrFlags ^= test;
489
8.24k
            PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue);
490
8.24k
            ++attr;
491
534k
        } else if ((test << 1) & attrFlags) {
492
425k
            attrFlags ^= (test << 1);
493
425k
            PK11_SETATTRS(attr, *pType, ckFalse, sizeof *ckFalse);
494
425k
            ++attr;
495
425k
        }
496
543k
    }
497
319k
    return (attr - attrs);
498
319k
}
499
500
/*
501
 * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually
502
 * set up a signature to get the signaure length.
503
 */
504
static int
505
pk11_backupGetSignLength(SECKEYPrivateKey *key)
506
0
{
507
0
    PK11SlotInfo *slot = key->pkcs11Slot;
508
0
    CK_MECHANISM mech = { 0, NULL, 0 };
509
0
    PRBool owner = PR_TRUE;
510
0
    CK_SESSION_HANDLE session;
511
0
    CK_ULONG len;
512
0
    CK_RV crv;
513
0
    unsigned char h_data[20] = { 0 };
514
0
    unsigned char buf[20]; /* obviously to small */
515
0
    CK_ULONG smallLen = sizeof(buf);
516
517
0
    mech.mechanism = PK11_MapSignKeyType(key->keyType);
518
519
0
    session = pk11_GetNewSession(slot, &owner);
520
0
    if (!owner || !(slot->isThreadSafe))
521
0
        PK11_EnterSlotMonitor(slot);
522
0
    crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, key->pkcs11ID);
523
0
    if (crv != CKR_OK) {
524
0
        if (!owner || !(slot->isThreadSafe))
525
0
            PK11_ExitSlotMonitor(slot);
526
0
        pk11_CloseSession(slot, session, owner);
527
0
        PORT_SetError(PK11_MapError(crv));
528
0
        return -1;
529
0
    }
530
0
    len = 0;
531
0
    crv = PK11_GETTAB(slot)->C_Sign(session, h_data, sizeof(h_data),
532
0
                                    NULL, &len);
533
    /* now call C_Sign with too small a buffer to clear the session state */
534
0
    (void)PK11_GETTAB(slot)->C_Sign(session, h_data, sizeof(h_data), buf, &smallLen);
535
536
0
    if (!owner || !(slot->isThreadSafe))
537
0
        PK11_ExitSlotMonitor(slot);
538
0
    pk11_CloseSession(slot, session, owner);
539
0
    if (crv != CKR_OK) {
540
0
        PORT_SetError(PK11_MapError(crv));
541
0
        return -1;
542
0
    }
543
0
    return len;
544
0
}
545
546
/*
547
 * get the length of a signature object based on the key
548
 */
549
int
550
PK11_SignatureLen(SECKEYPrivateKey *key)
551
33.1k
{
552
33.1k
    int val;
553
33.1k
    SECItem attributeItem = { siBuffer, NULL, 0 };
554
33.1k
    SECStatus rv;
555
33.1k
    int length;
556
33.1k
    SECOidTag paramSet;
557
558
33.1k
    switch (key->keyType) {
559
23.8k
        case rsaKey:
560
23.8k
        case rsaPssKey:
561
23.8k
            val = PK11_GetPrivateModulusLen(key);
562
23.8k
            if (val == -1) {
563
0
                return pk11_backupGetSignLength(key);
564
0
            }
565
23.8k
            return (unsigned long)val;
566
567
0
        case fortezzaKey:
568
0
            return 40;
569
570
0
        case dsaKey:
571
0
            rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_SUBPRIME,
572
0
                                    NULL, &attributeItem);
573
0
            if (rv == SECSuccess) {
574
0
                length = attributeItem.len;
575
0
                if ((length > 0) && attributeItem.data[0] == 0) {
576
0
                    length--;
577
0
                }
578
0
                PORT_Free(attributeItem.data);
579
0
                return length * 2;
580
0
            }
581
0
            return pk11_backupGetSignLength(key);
582
9.24k
        case ecKey:
583
9.27k
        case edKey:
584
9.27k
            rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, CKA_EC_PARAMS,
585
9.27k
                                    NULL, &attributeItem);
586
9.27k
            if (rv == SECSuccess) {
587
9.27k
                length = SECKEY_ECParamsToBasePointOrderLen(&attributeItem);
588
9.27k
                PORT_Free(attributeItem.data);
589
9.27k
                if (length != 0) {
590
9.27k
                    length = ((length + 7) / 8) * 2;
591
9.27k
                    return length;
592
9.27k
                }
593
9.27k
            }
594
0
            return pk11_backupGetSignLength(key);
595
0
        case mldsaKey:
596
0
            paramSet = seckey_GetParameterSet(key);
597
0
            if (paramSet == SEC_OID_UNKNOWN) {
598
0
                break;
599
0
            }
600
601
0
            return SECKEY_MLDSAOidParamsToLen(paramSet, SECKEYSignatureType);
602
11
        default:
603
11
            break;
604
33.1k
    }
605
11
    PORT_SetError(SEC_ERROR_INVALID_KEY);
606
11
    return 0;
607
33.1k
}
608
609
/*
610
 * copy a key (or any other object) on a token
611
 */
612
CK_OBJECT_HANDLE
613
PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject)
614
8
{
615
8
    CK_OBJECT_HANDLE destObject;
616
8
    CK_RV crv;
617
618
8
    PK11_EnterSlotMonitor(slot);
619
8
    crv = PK11_GETTAB(slot)->C_CopyObject(slot->session, srcObject, NULL, 0,
620
8
                                          &destObject);
621
8
    PK11_ExitSlotMonitor(slot);
622
8
    if (crv == CKR_OK)
623
8
        return destObject;
624
0
    PORT_SetError(PK11_MapError(crv));
625
0
    return CK_INVALID_HANDLE;
626
8
}
627
628
PRBool
629
pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs,
630
                        CK_ATTRIBUTE_TYPE target)
631
3.58M
{
632
9.16M
    for (; numAttrs > 0; ++attr, --numAttrs) {
633
5.57M
        if (attr->type == target)
634
0
            return PR_TRUE;
635
5.57M
    }
636
3.58M
    return PR_FALSE;
637
3.58M
}
638
639
/*
640
 * Recover the Signed data. We need this because our old verify can't
641
 * figure out which hash algorithm to use until we decryptted this.
642
 */
643
SECStatus
644
PK11_VerifyRecover(SECKEYPublicKey *key, const SECItem *sig,
645
                   SECItem *dsig, void *wincx)
646
17.7k
{
647
17.7k
    PK11SlotInfo *slot = key->pkcs11Slot;
648
17.7k
    CK_OBJECT_HANDLE id = key->pkcs11ID;
649
17.7k
    CK_MECHANISM mech = { 0, NULL, 0 };
650
17.7k
    PRBool owner = PR_TRUE;
651
17.7k
    CK_SESSION_HANDLE session;
652
17.7k
    CK_ULONG len;
653
17.7k
    CK_RV crv;
654
655
17.7k
    mech.mechanism = PK11_MapSignKeyType(key->keyType);
656
657
17.7k
    if (slot == NULL) {
658
20
        slot = PK11_GetBestSlotWithAttributes(mech.mechanism,
659
20
                                              CKF_VERIFY_RECOVER, 0, wincx);
660
20
        if (slot == NULL) {
661
0
            PORT_SetError(SEC_ERROR_NO_MODULE);
662
0
            return SECFailure;
663
0
        }
664
20
        id = PK11_ImportPublicKey(slot, key, PR_FALSE);
665
17.6k
    } else {
666
17.6k
        PK11_ReferenceSlot(slot);
667
17.6k
    }
668
669
17.7k
    if (id == CK_INVALID_HANDLE) {
670
14
        PK11_FreeSlot(slot);
671
14
        PORT_SetError(SEC_ERROR_BAD_KEY);
672
14
        return SECFailure;
673
14
    }
674
675
17.6k
    session = pk11_GetNewSession(slot, &owner);
676
17.6k
    if (!owner || !(slot->isThreadSafe))
677
0
        PK11_EnterSlotMonitor(slot);
678
17.6k
    crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session, &mech, id);
679
17.6k
    if (crv != CKR_OK) {
680
0
        if (!owner || !(slot->isThreadSafe))
681
0
            PK11_ExitSlotMonitor(slot);
682
0
        pk11_CloseSession(slot, session, owner);
683
0
        PORT_SetError(PK11_MapError(crv));
684
0
        PK11_FreeSlot(slot);
685
0
        return SECFailure;
686
0
    }
687
17.6k
    len = dsig->len;
688
17.6k
    crv = PK11_GETTAB(slot)->C_VerifyRecover(session, sig->data,
689
17.6k
                                             sig->len, dsig->data, &len);
690
17.6k
    if (!owner || !(slot->isThreadSafe))
691
0
        PK11_ExitSlotMonitor(slot);
692
17.6k
    pk11_CloseSession(slot, session, owner);
693
17.6k
    dsig->len = len;
694
17.6k
    if (crv != CKR_OK) {
695
17.5k
        PORT_SetError(PK11_MapError(crv));
696
17.5k
        PK11_FreeSlot(slot);
697
17.5k
        return SECFailure;
698
17.5k
    }
699
118
    PK11_FreeSlot(slot);
700
118
    return SECSuccess;
701
17.6k
}
702
703
/*
704
 * verify a signature from its hash.
705
 */
706
SECStatus
707
PK11_Verify(SECKEYPublicKey *key, const SECItem *sig, const SECItem *hash,
708
            void *wincx)
709
463
{
710
463
    CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType);
711
463
    return PK11_VerifyWithMechanism(key, mech, NULL, sig, hash, wincx);
712
463
}
713
714
/*
715
 * Verify a signature from its hash using the given algorithm.
716
 */
717
SECStatus
718
PK11_VerifyWithMechanism(SECKEYPublicKey *key, CK_MECHANISM_TYPE mechanism,
719
                         const SECItem *param, const SECItem *sig,
720
                         const SECItem *hash, void *wincx)
721
11.2k
{
722
11.2k
    PK11SlotInfo *slot = key->pkcs11Slot;
723
11.2k
    CK_OBJECT_HANDLE id = key->pkcs11ID;
724
11.2k
    CK_MECHANISM mech = { 0, NULL, 0 };
725
11.2k
    PRBool owner = PR_TRUE;
726
11.2k
    CK_SESSION_HANDLE session;
727
11.2k
    CK_RV crv;
728
729
11.2k
    mech.mechanism = mechanism;
730
11.2k
    if (param) {
731
5.87k
        mech.pParameter = param->data;
732
5.87k
        mech.ulParameterLen = param->len;
733
5.87k
    }
734
735
11.2k
    if (slot == NULL) {
736
7.62k
        unsigned int length = 0;
737
7.62k
        if ((mech.mechanism == CKM_DSA) &&
738
            /* 129 is 1024 bits translated to bytes and
739
             * padded with an optional '0' to maintain a
740
             * positive sign */
741
3.60k
            (key->u.dsa.params.prime.len > 129)) {
742
            /* we need to get a slot that not only can do DSA, but can do DSA2
743
             * key lengths */
744
3.60k
            length = key->u.dsa.params.prime.len;
745
3.60k
            if (key->u.dsa.params.prime.data[0] == 0) {
746
0
                length--;
747
0
            }
748
            /* convert keysize to bits for slot lookup */
749
3.60k
            length *= 8;
750
3.60k
        }
751
7.62k
        slot = PK11_GetBestSlotWithAttributes(mech.mechanism,
752
7.62k
                                              CKF_VERIFY, length, wincx);
753
7.62k
        if (slot == NULL) {
754
2
            PORT_SetError(SEC_ERROR_NO_MODULE);
755
2
            return SECFailure;
756
2
        }
757
7.61k
        id = PK11_ImportPublicKey(slot, key, PR_FALSE);
758
759
7.61k
    } else {
760
3.65k
        PK11_ReferenceSlot(slot);
761
3.65k
    }
762
763
11.2k
    if (id == CK_INVALID_HANDLE) {
764
191
        PK11_FreeSlot(slot);
765
191
        PORT_SetError(SEC_ERROR_BAD_KEY);
766
191
        return SECFailure;
767
191
    }
768
769
11.0k
    session = pk11_GetNewSession(slot, &owner);
770
11.0k
    if (!owner || !(slot->isThreadSafe))
771
0
        PK11_EnterSlotMonitor(slot);
772
11.0k
    if (PK11_CheckPKCS11Version(slot, 3, 2, PR_TRUE) >= 0) {
773
11.0k
        crv = PK11_GETTAB(slot)->C_VerifySignatureInit(session, &mech, id,
774
11.0k
                                                       sig->data, sig->len);
775
11.0k
        if (crv != CKR_OK) {
776
3
            if (!owner || !(slot->isThreadSafe))
777
0
                PK11_ExitSlotMonitor(slot);
778
3
            pk11_CloseSession(slot, session, owner);
779
3
            PK11_FreeSlot(slot);
780
3
            PORT_SetError(PK11_MapError(crv));
781
3
            return SECFailure;
782
3
        }
783
11.0k
        crv = PK11_GETTAB(slot)->C_VerifySignature(session, hash->data,
784
11.0k
                                                   hash->len);
785
11.0k
    } else {
786
0
        crv = PK11_GETTAB(slot)->C_VerifyInit(session, &mech, id);
787
0
        if (crv != CKR_OK) {
788
0
            if (!owner || !(slot->isThreadSafe))
789
0
                PK11_ExitSlotMonitor(slot);
790
0
            pk11_CloseSession(slot, session, owner);
791
0
            PK11_FreeSlot(slot);
792
0
            PORT_SetError(PK11_MapError(crv));
793
0
            return SECFailure;
794
0
        }
795
0
        crv = PK11_GETTAB(slot)->C_Verify(session, hash->data,
796
0
                                          hash->len, sig->data, sig->len);
797
0
    }
798
11.0k
    if (!owner || !(slot->isThreadSafe))
799
0
        PK11_ExitSlotMonitor(slot);
800
801
11.0k
    pk11_CloseSession(slot, session, owner);
802
11.0k
    PK11_FreeSlot(slot);
803
11.0k
    if (crv != CKR_OK) {
804
10.3k
        PORT_SetError(PK11_MapError(crv));
805
10.3k
        return SECFailure;
806
10.3k
    }
807
753
    return SECSuccess;
808
11.0k
}
809
810
/*
811
 * sign a hash. The algorithm is determined by the key.
812
 */
813
SECStatus
814
PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, const SECItem *hash)
815
26.4k
{
816
26.4k
    CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType);
817
26.4k
    return PK11_SignWithMechanism(key, mech, NULL, sig, hash);
818
26.4k
}
819
820
/*
821
 * Sign a hash using the given algorithm.
822
 */
823
SECStatus
824
PK11_SignWithMechanism(SECKEYPrivateKey *key, CK_MECHANISM_TYPE mechanism,
825
                       const SECItem *param, SECItem *sig, const SECItem *hash)
826
30.2k
{
827
30.2k
    PK11SlotInfo *slot = key->pkcs11Slot;
828
30.2k
    CK_MECHANISM mech = { 0, NULL, 0 };
829
30.2k
    PRBool owner = PR_TRUE;
830
30.2k
    CK_SESSION_HANDLE session;
831
30.2k
    PRBool haslock = PR_FALSE;
832
30.2k
    CK_ULONG len;
833
30.2k
    CK_RV crv;
834
835
30.2k
    mech.mechanism = mechanism;
836
30.2k
    if (param) {
837
839
        mech.pParameter = param->data;
838
839
        mech.ulParameterLen = param->len;
839
839
    }
840
841
30.2k
    if (SECKEY_HAS_ATTRIBUTE_SET(key, CKA_PRIVATE)) {
842
0
        PK11_HandlePasswordCheck(slot, key->wincx);
843
0
    }
844
845
30.2k
    session = pk11_GetNewSession(slot, &owner);
846
30.2k
    haslock = (!owner || !(slot->isThreadSafe));
847
30.2k
    if (haslock)
848
0
        PK11_EnterSlotMonitor(slot);
849
30.2k
    crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, key->pkcs11ID);
850
30.2k
    if (crv != CKR_OK) {
851
0
        if (haslock)
852
0
            PK11_ExitSlotMonitor(slot);
853
0
        pk11_CloseSession(slot, session, owner);
854
0
        PORT_SetError(PK11_MapError(crv));
855
0
        return SECFailure;
856
0
    }
857
858
    /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then
859
     * do C_Login with CKU_CONTEXT_SPECIFIC
860
     * between C_SignInit and C_Sign */
861
30.2k
    if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) {
862
0
        PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE);
863
0
    }
864
865
30.2k
    len = sig->len;
866
30.2k
    crv = PK11_GETTAB(slot)->C_Sign(session, hash->data,
867
30.2k
                                    hash->len, sig->data, &len);
868
30.2k
    if (haslock)
869
0
        PK11_ExitSlotMonitor(slot);
870
30.2k
    pk11_CloseSession(slot, session, owner);
871
30.2k
    sig->len = len;
872
30.2k
    if (crv != CKR_OK) {
873
0
        PORT_SetError(PK11_MapError(crv));
874
0
        return SECFailure;
875
0
    }
876
30.2k
    return SECSuccess;
877
30.2k
}
878
879
/*
880
 * sign data with a MAC key.
881
 */
882
SECStatus
883
PK11_SignWithSymKey(PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism,
884
                    SECItem *param, SECItem *sig, const SECItem *data)
885
22.9k
{
886
22.9k
    PK11SlotInfo *slot = symKey->slot;
887
22.9k
    CK_MECHANISM mech = { 0, NULL, 0 };
888
22.9k
    PRBool owner = PR_TRUE;
889
22.9k
    CK_SESSION_HANDLE session;
890
22.9k
    PRBool haslock = PR_FALSE;
891
22.9k
    CK_ULONG len;
892
22.9k
    CK_RV crv;
893
894
22.9k
    mech.mechanism = mechanism;
895
22.9k
    if (param) {
896
22.8k
        mech.pParameter = param->data;
897
22.8k
        mech.ulParameterLen = param->len;
898
22.8k
    }
899
900
22.9k
    session = pk11_GetNewSession(slot, &owner);
901
22.9k
    haslock = (!owner || !(slot->isThreadSafe));
902
22.9k
    if (haslock)
903
0
        PK11_EnterSlotMonitor(slot);
904
22.9k
    crv = PK11_GETTAB(slot)->C_SignInit(session, &mech, symKey->objectID);
905
22.9k
    if (crv != CKR_OK) {
906
0
        if (haslock)
907
0
            PK11_ExitSlotMonitor(slot);
908
0
        pk11_CloseSession(slot, session, owner);
909
0
        PORT_SetError(PK11_MapError(crv));
910
0
        return SECFailure;
911
0
    }
912
913
22.9k
    len = sig->len;
914
22.9k
    crv = PK11_GETTAB(slot)->C_Sign(session, data->data,
915
22.9k
                                    data->len, sig->data, &len);
916
22.9k
    if (haslock)
917
0
        PK11_ExitSlotMonitor(slot);
918
22.9k
    pk11_CloseSession(slot, session, owner);
919
22.9k
    sig->len = len;
920
22.9k
    if (crv != CKR_OK) {
921
0
        PORT_SetError(PK11_MapError(crv));
922
0
        return SECFailure;
923
0
    }
924
22.9k
    return SECSuccess;
925
22.9k
}
926
927
SECStatus
928
PK11_Decrypt(PK11SymKey *symKey,
929
             CK_MECHANISM_TYPE mechanism, SECItem *param,
930
             unsigned char *out, unsigned int *outLen,
931
             unsigned int maxLen,
932
             const unsigned char *enc, unsigned encLen)
933
1.60k
{
934
1.60k
    PK11SlotInfo *slot = symKey->slot;
935
1.60k
    CK_MECHANISM mech = { 0, NULL, 0 };
936
1.60k
    CK_ULONG len = maxLen;
937
1.60k
    PRBool owner = PR_TRUE;
938
1.60k
    CK_SESSION_HANDLE session;
939
1.60k
    PRBool haslock = PR_FALSE;
940
1.60k
    CK_RV crv;
941
942
1.60k
    mech.mechanism = mechanism;
943
1.60k
    if (param) {
944
1.60k
        mech.pParameter = param->data;
945
1.60k
        mech.ulParameterLen = param->len;
946
1.60k
    }
947
948
1.60k
    session = pk11_GetNewSession(slot, &owner);
949
1.60k
    haslock = (!owner || !slot->isThreadSafe);
950
1.60k
    if (haslock)
951
0
        PK11_EnterSlotMonitor(slot);
952
1.60k
    crv = PK11_GETTAB(slot)->C_DecryptInit(session, &mech, symKey->objectID);
953
1.60k
    if (crv != CKR_OK) {
954
136
        if (haslock)
955
0
            PK11_ExitSlotMonitor(slot);
956
136
        pk11_CloseSession(slot, session, owner);
957
136
        PORT_SetError(PK11_MapError(crv));
958
136
        return SECFailure;
959
136
    }
960
961
1.47k
    crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen,
962
1.47k
                                       out, &len);
963
1.47k
    if (haslock)
964
0
        PK11_ExitSlotMonitor(slot);
965
1.47k
    pk11_CloseSession(slot, session, owner);
966
1.47k
    if (crv != CKR_OK) {
967
251
        PORT_SetError(PK11_MapError(crv));
968
251
        return SECFailure;
969
251
    }
970
1.22k
    *outLen = len;
971
1.22k
    return SECSuccess;
972
1.47k
}
973
974
SECStatus
975
PK11_Encrypt(PK11SymKey *symKey,
976
             CK_MECHANISM_TYPE mechanism, SECItem *param,
977
             unsigned char *out, unsigned int *outLen,
978
             unsigned int maxLen,
979
             const unsigned char *data, unsigned int dataLen)
980
35.6k
{
981
35.6k
    PK11SlotInfo *slot = symKey->slot;
982
35.6k
    CK_MECHANISM mech = { 0, NULL, 0 };
983
35.6k
    CK_ULONG len = maxLen;
984
35.6k
    PRBool owner = PR_TRUE;
985
35.6k
    CK_SESSION_HANDLE session;
986
35.6k
    PRBool haslock = PR_FALSE;
987
35.6k
    CK_RV crv;
988
989
35.6k
    mech.mechanism = mechanism;
990
35.6k
    if (param) {
991
15.0k
        mech.pParameter = param->data;
992
15.0k
        mech.ulParameterLen = param->len;
993
15.0k
    }
994
995
35.6k
    session = pk11_GetNewSession(slot, &owner);
996
35.6k
    haslock = (!owner || !slot->isThreadSafe);
997
35.6k
    if (haslock)
998
0
        PK11_EnterSlotMonitor(slot);
999
35.6k
    crv = PK11_GETTAB(slot)->C_EncryptInit(session, &mech, symKey->objectID);
1000
35.6k
    if (crv != CKR_OK) {
1001
646
        if (haslock)
1002
0
            PK11_ExitSlotMonitor(slot);
1003
646
        pk11_CloseSession(slot, session, owner);
1004
646
        PORT_SetError(PK11_MapError(crv));
1005
646
        return SECFailure;
1006
646
    }
1007
34.9k
    crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data,
1008
34.9k
                                       dataLen, out, &len);
1009
34.9k
    if (haslock)
1010
0
        PK11_ExitSlotMonitor(slot);
1011
34.9k
    pk11_CloseSession(slot, session, owner);
1012
34.9k
    if (crv != CKR_OK) {
1013
216
        PORT_SetError(PK11_MapError(crv));
1014
216
        return SECFailure;
1015
216
    }
1016
34.7k
    *outLen = len;
1017
34.7k
    return SECSuccess;
1018
34.9k
}
1019
1020
static SECStatus
1021
pk11_PrivDecryptRaw(SECKEYPrivateKey *key,
1022
                    unsigned char *data, unsigned *outLen, unsigned int maxLen,
1023
                    const unsigned char *enc, unsigned encLen,
1024
                    CK_MECHANISM_PTR mech)
1025
0
{
1026
0
    PK11SlotInfo *slot = key->pkcs11Slot;
1027
0
    CK_ULONG out = maxLen;
1028
0
    PRBool owner = PR_TRUE;
1029
0
    CK_SESSION_HANDLE session;
1030
0
    PRBool haslock = PR_FALSE;
1031
0
    CK_RV crv;
1032
1033
0
    if (key->keyType != rsaKey) {
1034
0
        PORT_SetError(SEC_ERROR_INVALID_KEY);
1035
0
        return SECFailure;
1036
0
    }
1037
1038
    /* Why do we do a PK11_handle check here? for simple
1039
     * decryption? .. because the user may have asked for 'ask always'
1040
     * and this is a private key operation. In practice, thought, it's mute
1041
     * since only servers wind up using this function */
1042
0
    if (SECKEY_HAS_ATTRIBUTE_SET(key, CKA_PRIVATE)) {
1043
0
        PK11_HandlePasswordCheck(slot, key->wincx);
1044
0
    }
1045
0
    session = pk11_GetNewSession(slot, &owner);
1046
0
    haslock = (!owner || !(slot->isThreadSafe));
1047
0
    if (haslock)
1048
0
        PK11_EnterSlotMonitor(slot);
1049
0
    crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, key->pkcs11ID);
1050
0
    if (crv != CKR_OK) {
1051
0
        if (haslock)
1052
0
            PK11_ExitSlotMonitor(slot);
1053
0
        pk11_CloseSession(slot, session, owner);
1054
0
        PORT_SetError(PK11_MapError(crv));
1055
0
        return SECFailure;
1056
0
    }
1057
1058
    /* PKCS11 2.20 says if CKA_ALWAYS_AUTHENTICATE then
1059
     * do C_Login with CKU_CONTEXT_SPECIFIC
1060
     * between C_DecryptInit and C_Decrypt
1061
     * ... But see note above about servers */
1062
0
    if (SECKEY_HAS_ATTRIBUTE_SET_LOCK(key, CKA_ALWAYS_AUTHENTICATE, haslock)) {
1063
0
        PK11_DoPassword(slot, session, PR_FALSE, key->wincx, haslock, PR_TRUE);
1064
0
    }
1065
1066
0
    crv = PK11_GETTAB(slot)->C_Decrypt(session, (unsigned char *)enc, encLen,
1067
0
                                       data, &out);
1068
0
    if (haslock)
1069
0
        PK11_ExitSlotMonitor(slot);
1070
0
    pk11_CloseSession(slot, session, owner);
1071
0
    *outLen = out;
1072
0
    if (crv != CKR_OK) {
1073
0
        PORT_SetError(PK11_MapError(crv));
1074
0
        return SECFailure;
1075
0
    }
1076
0
    return SECSuccess;
1077
0
}
1078
1079
SECStatus
1080
PK11_PubDecryptRaw(SECKEYPrivateKey *key,
1081
                   unsigned char *data, unsigned *outLen, unsigned int maxLen,
1082
                   const unsigned char *enc, unsigned encLen)
1083
0
{
1084
0
    CK_MECHANISM mech = { CKM_RSA_X_509, NULL, 0 };
1085
0
    return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
1086
0
}
1087
1088
SECStatus
1089
PK11_PrivDecryptPKCS1(SECKEYPrivateKey *key,
1090
                      unsigned char *data, unsigned *outLen, unsigned int maxLen,
1091
                      const unsigned char *enc, unsigned encLen)
1092
0
{
1093
0
    CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 };
1094
0
    return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
1095
0
}
1096
1097
static SECStatus
1098
pk11_PubEncryptRaw(SECKEYPublicKey *key,
1099
                   unsigned char *out, unsigned int *outLen,
1100
                   unsigned int maxLen,
1101
                   const unsigned char *data, unsigned dataLen,
1102
                   CK_MECHANISM_PTR mech, void *wincx)
1103
0
{
1104
0
    PK11SlotInfo *slot;
1105
0
    CK_OBJECT_HANDLE id;
1106
0
    CK_ULONG len = maxLen;
1107
0
    PRBool owner = PR_TRUE;
1108
0
    CK_SESSION_HANDLE session;
1109
0
    CK_RV crv;
1110
1111
0
    slot = PK11_GetBestSlotWithAttributes(mech->mechanism, CKF_ENCRYPT, 0, wincx);
1112
0
    if (slot == NULL) {
1113
0
        PORT_SetError(SEC_ERROR_NO_MODULE);
1114
0
        return SECFailure;
1115
0
    }
1116
1117
0
    id = PK11_ImportPublicKey(slot, key, PR_FALSE);
1118
1119
0
    if (id == CK_INVALID_HANDLE) {
1120
0
        PK11_FreeSlot(slot);
1121
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
1122
0
        return SECFailure;
1123
0
    }
1124
1125
0
    session = pk11_GetNewSession(slot, &owner);
1126
0
    if (!owner || !(slot->isThreadSafe))
1127
0
        PK11_EnterSlotMonitor(slot);
1128
0
    crv = PK11_GETTAB(slot)->C_EncryptInit(session, mech, id);
1129
0
    if (crv != CKR_OK) {
1130
0
        if (!owner || !(slot->isThreadSafe))
1131
0
            PK11_ExitSlotMonitor(slot);
1132
0
        pk11_CloseSession(slot, session, owner);
1133
0
        PK11_FreeSlot(slot);
1134
0
        PORT_SetError(PK11_MapError(crv));
1135
0
        return SECFailure;
1136
0
    }
1137
0
    crv = PK11_GETTAB(slot)->C_Encrypt(session, (unsigned char *)data, dataLen,
1138
0
                                       out, &len);
1139
0
    if (!owner || !(slot->isThreadSafe))
1140
0
        PK11_ExitSlotMonitor(slot);
1141
0
    pk11_CloseSession(slot, session, owner);
1142
0
    PK11_FreeSlot(slot);
1143
0
    *outLen = len;
1144
0
    if (crv != CKR_OK) {
1145
0
        PORT_SetError(PK11_MapError(crv));
1146
0
        return SECFailure;
1147
0
    }
1148
0
    return SECSuccess;
1149
0
}
1150
1151
SECStatus
1152
PK11_PubEncryptRaw(SECKEYPublicKey *key,
1153
                   unsigned char *enc,
1154
                   const unsigned char *data, unsigned dataLen,
1155
                   void *wincx)
1156
0
{
1157
0
    CK_MECHANISM mech = { CKM_RSA_X_509, NULL, 0 };
1158
0
    unsigned int outLen;
1159
0
    if (!key || key->keyType != rsaKey) {
1160
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
1161
0
        return SECFailure;
1162
0
    }
1163
0
    outLen = SECKEY_PublicKeyStrength(key);
1164
0
    return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech,
1165
0
                              wincx);
1166
0
}
1167
1168
SECStatus
1169
PK11_PubEncryptPKCS1(SECKEYPublicKey *key,
1170
                     unsigned char *enc,
1171
                     const unsigned char *data, unsigned dataLen,
1172
                     void *wincx)
1173
0
{
1174
0
    CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 };
1175
0
    unsigned int outLen;
1176
0
    if (!key || key->keyType != rsaKey) {
1177
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
1178
0
        return SECFailure;
1179
0
    }
1180
0
    outLen = SECKEY_PublicKeyStrength(key);
1181
0
    return pk11_PubEncryptRaw(key, enc, &outLen, outLen, data, dataLen, &mech,
1182
0
                              wincx);
1183
0
}
1184
1185
SECStatus
1186
PK11_PrivDecrypt(SECKEYPrivateKey *key,
1187
                 CK_MECHANISM_TYPE mechanism, SECItem *param,
1188
                 unsigned char *out, unsigned int *outLen,
1189
                 unsigned int maxLen,
1190
                 const unsigned char *enc, unsigned encLen)
1191
0
{
1192
0
    CK_MECHANISM mech = { mechanism, NULL, 0 };
1193
0
    if (param) {
1194
0
        mech.pParameter = param->data;
1195
0
        mech.ulParameterLen = param->len;
1196
0
    }
1197
0
    return pk11_PrivDecryptRaw(key, out, outLen, maxLen, enc, encLen, &mech);
1198
0
}
1199
1200
SECStatus
1201
PK11_PubEncrypt(SECKEYPublicKey *key,
1202
                CK_MECHANISM_TYPE mechanism, SECItem *param,
1203
                unsigned char *out, unsigned int *outLen,
1204
                unsigned int maxLen,
1205
                const unsigned char *data, unsigned dataLen,
1206
                void *wincx)
1207
0
{
1208
0
    CK_MECHANISM mech = { mechanism, NULL, 0 };
1209
0
    if (param) {
1210
0
        mech.pParameter = param->data;
1211
0
        mech.ulParameterLen = param->len;
1212
0
    }
1213
0
    return pk11_PubEncryptRaw(key, out, outLen, maxLen, data, dataLen, &mech,
1214
0
                              wincx);
1215
0
}
1216
1217
SECKEYPrivateKey *
1218
PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
1219
                   CK_MECHANISM_TYPE wrapType, SECItem *param,
1220
                   SECItem *wrappedKey, SECItem *label,
1221
                   const SECItem *idValue, PRBool perm, PRBool sensitive,
1222
                   CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage,
1223
                   int usageCount, void *wincx)
1224
0
{
1225
0
    CK_BBOOL cktrue = CK_TRUE;
1226
0
    CK_BBOOL ckfalse = CK_FALSE;
1227
0
    CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
1228
0
    CK_ATTRIBUTE keyTemplate[15];
1229
0
    int templateCount = 0;
1230
0
    CK_OBJECT_HANDLE privKeyID;
1231
0
    CK_MECHANISM mechanism;
1232
0
    CK_ATTRIBUTE *attrs = keyTemplate;
1233
0
    SECItem *param_free = NULL, *ck_id = NULL;
1234
0
    CK_RV crv;
1235
0
    CK_SESSION_HANDLE rwsession;
1236
0
    PK11SymKey *newKey = NULL;
1237
0
    int i;
1238
1239
0
    if (!slot || !wrappedKey || !idValue) {
1240
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1241
0
        return NULL;
1242
0
    }
1243
1244
0
    ck_id = PK11_MakeIDFromPubKey(idValue);
1245
0
    if (!ck_id) {
1246
0
        return NULL;
1247
0
    }
1248
1249
0
    PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse,
1250
0
                  sizeof(cktrue));
1251
0
    attrs++;
1252
0
    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
1253
0
    attrs++;
1254
0
    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
1255
0
    attrs++;
1256
0
    PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse,
1257
0
                  sizeof(cktrue));
1258
0
    attrs++;
1259
0
    PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse,
1260
0
                  sizeof(cktrue));
1261
0
    attrs++;
1262
0
    if (label && label->data) {
1263
0
        PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len);
1264
0
        attrs++;
1265
0
    }
1266
0
    PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
1267
0
    attrs++;
1268
0
    for (i = 0; i < usageCount; i++) {
1269
0
        PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue));
1270
0
        attrs++;
1271
0
    }
1272
1273
0
    if (PK11_IsInternal(slot)) {
1274
0
        PK11_SETATTRS(attrs, CKA_NSS_DB, idValue->data,
1275
0
                      idValue->len);
1276
0
        attrs++;
1277
0
    }
1278
1279
0
    templateCount = attrs - keyTemplate;
1280
0
    PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE)));
1281
1282
0
    mechanism.mechanism = wrapType;
1283
0
    if (!param)
1284
0
        param = param_free = PK11_ParamFromIV(wrapType, NULL);
1285
0
    if (param) {
1286
0
        mechanism.pParameter = param->data;
1287
0
        mechanism.ulParameterLen = param->len;
1288
0
    } else {
1289
0
        mechanism.pParameter = NULL;
1290
0
        mechanism.ulParameterLen = 0;
1291
0
    }
1292
1293
0
    if (wrappingKey->slot != slot) {
1294
0
        newKey = pk11_CopyToSlot(slot, wrapType, CKA_UNWRAP, wrappingKey);
1295
0
    } else {
1296
0
        newKey = PK11_ReferenceSymKey(wrappingKey);
1297
0
    }
1298
1299
0
    if (newKey) {
1300
0
        if (perm) {
1301
            /* Get RW Session will either lock the monitor if necessary,
1302
             *  or return a thread safe session handle, or fail. */
1303
0
            rwsession = PK11_GetRWSession(slot);
1304
0
        } else {
1305
0
            rwsession = slot->session;
1306
0
            if (rwsession != CK_INVALID_HANDLE)
1307
0
                PK11_EnterSlotMonitor(slot);
1308
0
        }
1309
        /* This is a lot a work to deal with fussy PKCS #11 modules
1310
         * that can't bother to return BAD_DATA when presented with an
1311
         * invalid session! */
1312
0
        if (rwsession == CK_INVALID_HANDLE) {
1313
0
            PORT_SetError(SEC_ERROR_BAD_DATA);
1314
0
            goto loser;
1315
0
        }
1316
0
        crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism,
1317
0
                                             newKey->objectID,
1318
0
                                             wrappedKey->data,
1319
0
                                             wrappedKey->len, keyTemplate,
1320
0
                                             templateCount, &privKeyID);
1321
1322
0
        if (perm) {
1323
0
            PK11_RestoreROSession(slot, rwsession);
1324
0
        } else {
1325
0
            PK11_ExitSlotMonitor(slot);
1326
0
        }
1327
0
        PK11_FreeSymKey(newKey);
1328
0
        newKey = NULL;
1329
0
    } else {
1330
0
        crv = CKR_FUNCTION_NOT_SUPPORTED;
1331
0
    }
1332
1333
0
    SECITEM_FreeItem(ck_id, PR_TRUE);
1334
0
    ck_id = NULL;
1335
1336
0
    if (crv != CKR_OK) {
1337
        /* we couldn't unwrap the key, use the internal module to do the
1338
         * unwrap, then load the new key into the token */
1339
0
        PK11SlotInfo *int_slot = PK11_GetInternalSlot();
1340
1341
0
        if (int_slot && (slot != int_slot)) {
1342
0
            SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot,
1343
0
                                                           wrappingKey, wrapType, param, wrappedKey, label,
1344
0
                                                           idValue, PR_FALSE, PR_FALSE,
1345
0
                                                           keyType, usage, usageCount, wincx);
1346
0
            if (privKey) {
1347
0
                SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(slot, privKey,
1348
0
                                                                NULL, perm, sensitive);
1349
0
                SECKEY_DestroyPrivateKey(privKey);
1350
0
                PK11_FreeSlot(int_slot);
1351
0
                SECITEM_FreeItem(param_free, PR_TRUE);
1352
0
                return newPrivKey;
1353
0
            }
1354
0
        }
1355
0
        if (int_slot)
1356
0
            PK11_FreeSlot(int_slot);
1357
0
        PORT_SetError(PK11_MapError(crv));
1358
0
        SECITEM_FreeItem(param_free, PR_TRUE);
1359
0
        return NULL;
1360
0
    }
1361
0
    SECITEM_FreeItem(param_free, PR_TRUE);
1362
0
    return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx);
1363
1364
0
loser:
1365
0
    PK11_FreeSymKey(newKey);
1366
0
    SECITEM_FreeItem(ck_id, PR_TRUE);
1367
0
    SECITEM_FreeItem(param_free, PR_TRUE);
1368
0
    return NULL;
1369
0
}
1370
1371
/*
1372
 * PK11_UnwrapPrivKeyByKeyType is like PK11_UnwrapPrivKey but uses the
1373
 * keyType and the keyUsage to determine what usage attributes to set.
1374
 */
1375
#define _MAX_USAGE 6
1376
SECKEYPrivateKey *
1377
PK11_UnwrapPrivKeyByKeyType(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
1378
                            CK_MECHANISM_TYPE wrapType, SECItem *param,
1379
                            SECItem *wrappedKey, SECItem *label,
1380
                            const SECItem *idValue, PRBool perm, PRBool sensitive,
1381
                            KeyType keyType, unsigned int keyUsage, void *wincx)
1382
0
{
1383
0
    CK_KEY_TYPE pk11KeyType = pk11_getPKCS11KeyTypeFromKeyType(keyType);
1384
0
    CK_ATTRIBUTE_TYPE usage[_MAX_USAGE];
1385
0
    int usageCount = 0;
1386
0
    PRBool needKeyUsage = PR_FALSE;
1387
1388
    /* RSA and ecKeys can be used in more than one usage, use the
1389
     * key usage to determine which usage to actual set */
1390
0
    if ((keyType == rsaKey) || (keyType == ecKey)) {
1391
0
        needKeyUsage = PR_TRUE;
1392
0
    }
1393
1394
    /* use the pk11_mapXXXXKeyType functions to determine what kind
1395
     * of attributes to set on the key. Using these functions reduces
1396
     * the number of places we need to update to add new key types */
1397
0
    if ((pk11_mapWrapKeyType(keyType) != CKM_INVALID_MECHANISM) &&
1398
0
        (!needKeyUsage || keyUsage & KU_KEY_ENCIPHERMENT)) {
1399
0
        usage[usageCount++] = CKA_UNWRAP;
1400
0
        usage[usageCount++] = CKA_DECRYPT;
1401
0
    }
1402
0
    if ((pk11_mapKemKeyType(keyType) != CKM_INVALID_MECHANISM) &&
1403
0
        (!needKeyUsage || keyUsage & KU_KEY_AGREEMENT)) {
1404
0
        usage[usageCount++] = CKA_DECAPSULATE;
1405
0
    }
1406
0
    if ((PK11_MapSignKeyType(keyType) != CKM_INVALID_MECHANISM) &&
1407
0
        (!needKeyUsage || keyUsage & KU_DIGITAL_SIGNATURE)) {
1408
0
        usage[usageCount++] = CKA_SIGN;
1409
0
        if (keyType == rsaKey) {
1410
0
            usage[usageCount++] = CKA_SIGN_RECOVER;
1411
0
        }
1412
0
    }
1413
0
    if ((pk11_mapDeriveKeyType(keyType) != CKM_INVALID_MECHANISM) &&
1414
0
        (!needKeyUsage || keyUsage & KU_KEY_AGREEMENT)) {
1415
0
        usage[usageCount++] = CKA_DERIVE;
1416
0
    }
1417
1418
0
    PORT_Assert(usageCount <= _MAX_USAGE);
1419
1420
0
    if (usageCount == 0) {
1421
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1422
0
    }
1423
0
    return PK11_UnwrapPrivKey(slot, wrappingKey, wrapType, param, wrappedKey,
1424
0
                              label, idValue, perm, sensitive, pk11KeyType,
1425
0
                              usage, usageCount, wincx);
1426
0
}
1427
1428
/*
1429
 * Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey
1430
 * The strategy is to get both keys to reside in the same slot,
1431
 * one that can perform the desired crypto mechanism and then
1432
 * call C_WrapKey after all the setup has taken place.
1433
 */
1434
SECStatus
1435
PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
1436
                 SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType,
1437
                 SECItem *param, SECItem *wrappedKey, void *wincx)
1438
0
{
1439
0
    PK11SlotInfo *privSlot = privKey->pkcs11Slot; /* The slot where
1440
                                                   * the private key
1441
                                                   * we are going to
1442
                                                   * wrap lives.
1443
                                                   */
1444
0
    PK11SymKey *newSymKey = NULL;
1445
0
    SECKEYPrivateKey *newPrivKey = NULL;
1446
0
    SECItem *param_free = NULL;
1447
0
    CK_ULONG len = wrappedKey->len;
1448
0
    CK_MECHANISM mech;
1449
0
    CK_RV crv;
1450
1451
0
    if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) {
1452
        /* Figure out a slot that does the mechanism and try to import
1453
         * the private key onto that slot.
1454
         */
1455
0
        PK11SlotInfo *int_slot = PK11_GetInternalSlot();
1456
1457
0
        privSlot = int_slot; /* The private key has a new home */
1458
0
        newPrivKey = PK11_LoadPrivKey(privSlot, privKey, NULL, PR_FALSE, PR_FALSE);
1459
        /* newPrivKey has allocated its own reference to the slot, so it's
1460
         * safe until we destroy newPrivkey.
1461
         */
1462
0
        PK11_FreeSlot(int_slot);
1463
0
        if (newPrivKey == NULL) {
1464
0
            return SECFailure;
1465
0
        }
1466
0
        privKey = newPrivKey;
1467
0
    }
1468
1469
0
    if (privSlot != wrappingKey->slot) {
1470
0
        newSymKey = pk11_CopyToSlot(privSlot, wrapType, CKA_WRAP,
1471
0
                                    wrappingKey);
1472
0
        wrappingKey = newSymKey;
1473
0
    }
1474
1475
0
    if (wrappingKey == NULL) {
1476
0
        if (newPrivKey) {
1477
0
            SECKEY_DestroyPrivateKey(newPrivKey);
1478
0
        }
1479
0
        return SECFailure;
1480
0
    }
1481
0
    mech.mechanism = wrapType;
1482
0
    if (!param) {
1483
0
        param = param_free = PK11_ParamFromIV(wrapType, NULL);
1484
0
    }
1485
0
    if (param) {
1486
0
        mech.pParameter = param->data;
1487
0
        mech.ulParameterLen = param->len;
1488
0
    } else {
1489
0
        mech.pParameter = NULL;
1490
0
        mech.ulParameterLen = 0;
1491
0
    }
1492
1493
0
    PK11_EnterSlotMonitor(privSlot);
1494
0
    crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech,
1495
0
                                           wrappingKey->objectID,
1496
0
                                           privKey->pkcs11ID,
1497
0
                                           wrappedKey->data, &len);
1498
0
    PK11_ExitSlotMonitor(privSlot);
1499
1500
0
    if (newSymKey) {
1501
0
        PK11_FreeSymKey(newSymKey);
1502
0
    }
1503
0
    if (newPrivKey) {
1504
0
        SECKEY_DestroyPrivateKey(newPrivKey);
1505
0
    }
1506
0
    if (param_free) {
1507
0
        SECITEM_FreeItem(param_free, PR_TRUE);
1508
0
    }
1509
1510
0
    if (crv != CKR_OK) {
1511
0
        PORT_SetError(PK11_MapError(crv));
1512
0
        return SECFailure;
1513
0
    }
1514
1515
0
    wrappedKey->len = len;
1516
0
    return SECSuccess;
1517
0
}
1518
1519
#if 0
1520
/*
1521
 * Sample code relating to linked list returned by PK11_FindGenericObjects
1522
 */
1523
1524
/*
1525
 * You can walk the list with the following code:
1526
 */
1527
    firstObj = PK11_FindGenericObjects(slot, objClass);
1528
    for (thisObj=firstObj;
1529
         thisObj;
1530
         thisObj=PK11_GetNextGenericObject(thisObj)) {
1531
        /* operate on thisObj */
1532
    }
1533
/*
1534
 * If you want a particular object from the list...
1535
 */
1536
    firstObj = PK11_FindGenericObjects(slot, objClass);
1537
    for (thisObj=firstObj;
1538
         thisObj;
1539
         thisObj=PK11_GetNextGenericObject(thisObj)) {
1540
      if (isMyObj(thisObj)) {
1541
       if ( thisObj == firstObj) {
1542
                /* NOTE: firstObj could be NULL at this point */
1543
      firstObj = PK11_GetNextGenericObject(thsObj);
1544
       }
1545
       PK11_UnlinkGenericObject(thisObj);
1546
            myObj = thisObj;
1547
            break;
1548
        }
1549
    }
1550
1551
    PK11_DestroyGenericObjects(firstObj);
1552
1553
      /* use myObj */
1554
1555
    PK11_DestroyGenericObject(myObj);
1556
#endif /* sample code */
1557
1558
/*
1559
 * return a linked, non-circular list of generic objects.
1560
 * If you are only interested
1561
 * in one object, just use the first object in the list. To find the
1562
 * rest of the list use PK11_GetNextGenericObject() to return the next object.
1563
 */
1564
PK11GenericObject *
1565
PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass)
1566
0
{
1567
0
    CK_ATTRIBUTE template[1];
1568
0
    CK_ATTRIBUTE *attrs = template;
1569
0
    CK_OBJECT_HANDLE *objectIDs = NULL;
1570
0
    PK11GenericObject *lastObj = NULL, *obj;
1571
0
    PK11GenericObject *firstObj = NULL;
1572
0
    int i, count = 0;
1573
1574
0
    PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass));
1575
0
    attrs++;
1576
1577
0
    objectIDs = pk11_FindObjectsByTemplate(slot, template, 1, &count);
1578
0
    if (objectIDs == NULL) {
1579
0
        return NULL;
1580
0
    }
1581
1582
    /* where we connect our object once we've created it.. */
1583
0
    for (i = 0; i < count; i++) {
1584
0
        obj = PORT_New(PK11GenericObject);
1585
0
        if (!obj) {
1586
0
            if (firstObj) {
1587
0
                PK11_DestroyGenericObjects(firstObj);
1588
0
            }
1589
0
            PORT_Free(objectIDs);
1590
0
            return NULL;
1591
0
        }
1592
        /* initialize it */
1593
0
        obj->slot = PK11_ReferenceSlot(slot);
1594
0
        obj->objectID = objectIDs[i];
1595
0
        obj->owner = PR_FALSE;
1596
0
        obj->next = NULL;
1597
0
        obj->prev = NULL;
1598
1599
        /* link it in */
1600
0
        if (firstObj == NULL) {
1601
0
            firstObj = obj;
1602
0
        } else {
1603
0
            PK11_LinkGenericObject(lastObj, obj);
1604
0
        }
1605
0
        lastObj = obj;
1606
0
    }
1607
0
    PORT_Free(objectIDs);
1608
0
    return firstObj;
1609
0
}
1610
1611
/*
1612
 * get the Next Object in the list.
1613
 */
1614
PK11GenericObject *
1615
PK11_GetNextGenericObject(PK11GenericObject *object)
1616
0
{
1617
0
    return object->next;
1618
0
}
1619
1620
PK11GenericObject *
1621
PK11_GetPrevGenericObject(PK11GenericObject *object)
1622
0
{
1623
0
    return object->prev;
1624
0
}
1625
1626
/*
1627
 * Link a single object into a new list.
1628
 * if the object is already in another list, remove it first.
1629
 */
1630
SECStatus
1631
PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object)
1632
0
{
1633
0
    PK11_UnlinkGenericObject(object);
1634
0
    object->prev = list;
1635
0
    object->next = list->next;
1636
0
    list->next = object;
1637
0
    if (object->next != NULL) {
1638
0
        object->next->prev = object;
1639
0
    }
1640
0
    return SECSuccess;
1641
0
}
1642
1643
/*
1644
 * remove an object from the list. If the object isn't already in
1645
 * a list unlink becomes a noop.
1646
 */
1647
SECStatus
1648
PK11_UnlinkGenericObject(PK11GenericObject *object)
1649
21.3k
{
1650
21.3k
    if (object->prev != NULL) {
1651
0
        object->prev->next = object->next;
1652
0
    }
1653
21.3k
    if (object->next != NULL) {
1654
0
        object->next->prev = object->prev;
1655
0
    }
1656
1657
21.3k
    object->next = NULL;
1658
21.3k
    object->prev = NULL;
1659
21.3k
    return SECSuccess;
1660
21.3k
}
1661
1662
/*
1663
 * This function removes a single object from the list and destroys it.
1664
 * For an already unlinked object there is no difference between
1665
 * PK11_DestroyGenericObject and PK11_DestroyGenericObjects
1666
 */
1667
SECStatus
1668
PK11_DestroyGenericObject(PK11GenericObject *object)
1669
21.3k
{
1670
21.3k
    if (object == NULL) {
1671
0
        return SECSuccess;
1672
0
    }
1673
1674
21.3k
    PK11_UnlinkGenericObject(object);
1675
21.3k
    if (object->slot) {
1676
21.3k
        if (object->owner) {
1677
0
            PK11_DestroyObject(object->slot, object->objectID);
1678
0
        }
1679
21.3k
        PK11_FreeSlot(object->slot);
1680
21.3k
    }
1681
21.3k
    PORT_Free(object);
1682
21.3k
    return SECSuccess;
1683
21.3k
}
1684
1685
/*
1686
 * walk down a link list of generic objects destroying them.
1687
 * This will destroy all objects in a list that the object is linked into.
1688
 * (the list is traversed in both directions).
1689
 */
1690
SECStatus
1691
PK11_DestroyGenericObjects(PK11GenericObject *objects)
1692
0
{
1693
0
    PK11GenericObject *nextObject;
1694
0
    PK11GenericObject *prevObject;
1695
1696
0
    if (objects == NULL) {
1697
0
        return SECSuccess;
1698
0
    }
1699
1700
0
    nextObject = objects->next;
1701
0
    prevObject = objects->prev;
1702
1703
    /* delete all the objects after it in the list */
1704
0
    for (; objects; objects = nextObject) {
1705
0
        nextObject = objects->next;
1706
0
        PK11_DestroyGenericObject(objects);
1707
0
    }
1708
    /* delete all the objects before it in the list */
1709
0
    for (objects = prevObject; objects; objects = prevObject) {
1710
0
        prevObject = objects->prev;
1711
0
        PK11_DestroyGenericObject(objects);
1712
0
    }
1713
0
    return SECSuccess;
1714
0
}
1715
1716
/*
1717
 * Hand Create a new object and return the Generic object for our new object.
1718
 */
1719
PK11GenericObject *
1720
pk11_CreateGenericObjectHelper(PK11SlotInfo *slot,
1721
                               const CK_ATTRIBUTE *pTemplate,
1722
                               int count, PRBool token, PRBool owner)
1723
21.3k
{
1724
21.3k
    CK_OBJECT_HANDLE objectID;
1725
21.3k
    PK11GenericObject *obj;
1726
21.3k
    CK_RV crv;
1727
1728
21.3k
    PK11_EnterSlotMonitor(slot);
1729
21.3k
    crv = PK11_CreateNewObject(slot, slot->session, pTemplate, count,
1730
21.3k
                               token, &objectID);
1731
21.3k
    PK11_ExitSlotMonitor(slot);
1732
21.3k
    if (crv != CKR_OK) {
1733
0
        PORT_SetError(PK11_MapError(crv));
1734
0
        return NULL;
1735
0
    }
1736
1737
21.3k
    obj = PORT_New(PK11GenericObject);
1738
21.3k
    if (!obj) {
1739
        /* error set by PORT_New */
1740
0
        return NULL;
1741
0
    }
1742
1743
    /* initialize it */
1744
21.3k
    obj->slot = PK11_ReferenceSlot(slot);
1745
21.3k
    obj->objectID = objectID;
1746
21.3k
    obj->owner = owner;
1747
21.3k
    obj->next = NULL;
1748
21.3k
    obj->prev = NULL;
1749
21.3k
    return obj;
1750
21.3k
}
1751
1752
/* This is the classic interface. Applications would call this function to
1753
 * create new object that would not be destroyed later. This lead to resource
1754
 * leaks (and thus memory leaks in the PKCS #11 module).  To solve this we have
1755
 * a new interface that automatically marks objects created on the fly to be
1756
 * destroyed later.
1757
 * The old interface is preserved because applications like Mozilla purposefully
1758
 * leak the reference to be found later with PK11_FindGenericObjects. New
1759
 * applications should use the new interface PK11_CreateManagedGenericObject */
1760
PK11GenericObject *
1761
PK11_CreateGenericObject(PK11SlotInfo *slot, const CK_ATTRIBUTE *pTemplate,
1762
                         int count, PRBool token)
1763
21.3k
{
1764
21.3k
    return pk11_CreateGenericObjectHelper(slot, pTemplate, count, token,
1765
21.3k
                                          PR_FALSE);
1766
21.3k
}
1767
1768
/* Use this interface. It will automatically destroy any temporary objects
1769
 * (token = PR_FALSE) when the PK11GenericObject is freed. Permanent objects still
1770
 * need to be destroyed by hand with PK11_DestroyTokenObject.
1771
 */
1772
PK11GenericObject *
1773
PK11_CreateManagedGenericObject(PK11SlotInfo *slot,
1774
                                const CK_ATTRIBUTE *pTemplate, int count, PRBool token)
1775
0
{
1776
0
    return pk11_CreateGenericObjectHelper(slot, pTemplate, count, token,
1777
0
                                          !token);
1778
0
}
1779
1780
CK_OBJECT_HANDLE
1781
PK11_GetObjectHandle(PK11ObjectType objType, void *objSpec,
1782
                     PK11SlotInfo **slotp)
1783
21.3k
{
1784
21.3k
    CK_OBJECT_HANDLE handle = CK_INVALID_HANDLE;
1785
21.3k
    PK11SlotInfo *slot = NULL;
1786
1787
21.3k
    switch (objType) {
1788
21.3k
        case PK11_TypeGeneric:
1789
21.3k
            slot = ((PK11GenericObject *)objSpec)->slot;
1790
21.3k
            handle = ((PK11GenericObject *)objSpec)->objectID;
1791
21.3k
            break;
1792
0
        case PK11_TypePrivKey:
1793
0
            slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot;
1794
0
            handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID;
1795
0
            break;
1796
0
        case PK11_TypePubKey:
1797
0
            slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot;
1798
0
            handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID;
1799
0
            break;
1800
0
        case PK11_TypeSymKey:
1801
0
            slot = ((PK11SymKey *)objSpec)->slot;
1802
0
            handle = ((PK11SymKey *)objSpec)->objectID;
1803
0
            break;
1804
0
        case PK11_TypeCert:
1805
0
            handle = PK11_FindObjectForCert((CERTCertificate *)objSpec, NULL,
1806
0
                                            &slot);
1807
0
            break;
1808
0
        default:
1809
0
            PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
1810
0
            break;
1811
21.3k
    }
1812
21.3k
    if (slotp) {
1813
0
        *slotp = slot;
1814
0
    }
1815
    /* paranoia. If the object doesn't have a slot, then it's handle isn't
1816
     * valid either */
1817
21.3k
    if (slot == NULL) {
1818
0
        handle = CK_INVALID_HANDLE;
1819
0
    }
1820
21.3k
    return handle;
1821
21.3k
}
1822
1823
/*
1824
 * Change an attribute on a raw object
1825
 */
1826
SECStatus
1827
PK11_WriteRawAttribute(PK11ObjectType objType, void *objSpec,
1828
                       CK_ATTRIBUTE_TYPE attrType, SECItem *item)
1829
0
{
1830
0
    PK11SlotInfo *slot = NULL;
1831
0
    CK_OBJECT_HANDLE handle = 0;
1832
0
    CK_ATTRIBUTE setTemplate;
1833
0
    CK_RV crv;
1834
0
    CK_SESSION_HANDLE rwsession;
1835
1836
0
    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
1837
0
    if (handle == CK_INVALID_HANDLE) {
1838
0
        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
1839
0
        return SECFailure;
1840
0
    }
1841
1842
0
    PK11_SETATTRS(&setTemplate, attrType, (CK_CHAR *)item->data, item->len);
1843
0
    rwsession = PK11_GetRWSession(slot);
1844
0
    if (rwsession == CK_INVALID_HANDLE) {
1845
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
1846
0
        return SECFailure;
1847
0
    }
1848
0
    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, handle,
1849
0
                                                 &setTemplate, 1);
1850
0
    PK11_RestoreROSession(slot, rwsession);
1851
0
    if (crv != CKR_OK) {
1852
0
        PORT_SetError(PK11_MapError(crv));
1853
0
        return SECFailure;
1854
0
    }
1855
0
    return SECSuccess;
1856
0
}
1857
1858
SECStatus
1859
PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec,
1860
                      CK_ATTRIBUTE_TYPE attrType, SECItem *item)
1861
0
{
1862
0
    PK11SlotInfo *slot = NULL;
1863
0
    CK_OBJECT_HANDLE handle = 0;
1864
1865
0
    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
1866
0
    if (handle == CK_INVALID_HANDLE) {
1867
0
        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
1868
0
        return SECFailure;
1869
0
    }
1870
1871
0
    return PK11_ReadAttribute(slot, handle, attrType, NULL, item);
1872
0
}
1873
1874
SECStatus
1875
PK11_ReadRawAttributes(PLArenaPool *arena, PK11ObjectType objType, void *objSpec,
1876
                       CK_ATTRIBUTE *pTemplate, unsigned int count)
1877
0
{
1878
0
    PK11SlotInfo *slot = NULL;
1879
0
    CK_OBJECT_HANDLE handle = 0;
1880
1881
0
    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
1882
0
    if (handle == CK_INVALID_HANDLE) {
1883
0
        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
1884
0
        return SECFailure;
1885
0
    }
1886
0
    CK_RV crv = PK11_GetAttributes(arena, slot, handle, pTemplate, count);
1887
0
    if (crv != CKR_OK) {
1888
0
        PORT_SetError(PK11_MapError(crv));
1889
0
        return SECFailure;
1890
0
    }
1891
0
    return SECSuccess;
1892
0
}
1893
1894
SECStatus
1895
PK11_ReadDistrustAfterAttribute(PK11SlotInfo *slot,
1896
                                CK_OBJECT_HANDLE object,
1897
                                CK_ATTRIBUTE_TYPE type,
1898
                                /* out */ PRBool *distrusted,
1899
                                /* out */ PRTime *time)
1900
0
{
1901
0
    if (!slot || !distrusted || !time) {
1902
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1903
0
        return SECFailure;
1904
0
    }
1905
1906
0
    if (type != CKA_NSS_SERVER_DISTRUST_AFTER && type != CKA_NSS_EMAIL_DISTRUST_AFTER) {
1907
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1908
0
        return SECFailure;
1909
0
    }
1910
1911
    // The CKA_NSS_SERVER_DISTRUST_AFTER and CKA_NSS_EMAIL_DISTRUST_AFTER
1912
    // attributes have either a 13 byte UTCTime value or a 1 byte value
1913
    // (equal to 0) indicating that no distrust after date is set.
1914
0
    unsigned char buf[13] = { 0 };
1915
0
    CK_ATTRIBUTE attr = { .type = type, .pValue = buf, .ulValueLen = sizeof buf };
1916
0
    CK_RV crv;
1917
1918
0
    PK11_EnterSlotMonitor(slot);
1919
0
    crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session, object, &attr, 1);
1920
0
    PK11_ExitSlotMonitor(slot);
1921
0
    if (crv != CKR_OK) {
1922
0
        PORT_SetError(PK11_MapError(crv));
1923
0
        return SECFailure;
1924
0
    }
1925
1926
0
    if (attr.ulValueLen == 1 && buf[0] == 0) {
1927
        // The distrust after date is not set.
1928
0
        *distrusted = PR_FALSE;
1929
0
        return SECSuccess;
1930
0
    }
1931
1932
0
    if (attr.ulValueLen != sizeof buf) {
1933
        // Ensure the date is encoded in the expected 13 byte format.
1934
0
        PORT_SetError(SEC_ERROR_INVALID_TIME);
1935
0
        return SECFailure;
1936
0
    }
1937
1938
0
    *distrusted = PR_TRUE;
1939
0
    SECItem item = { siUTCTime, buf, sizeof buf };
1940
0
    return DER_UTCTimeToTime(time, &item);
1941
0
}
1942
1943
/*
1944
 * return the object handle that matches the template
1945
 */
1946
CK_OBJECT_HANDLE
1947
pk11_FindObjectByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *theTemplate, size_t tsize)
1948
86
{
1949
86
    CK_OBJECT_HANDLE object;
1950
86
    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
1951
86
    CK_ULONG objectCount;
1952
1953
    /*
1954
     * issue the find
1955
     */
1956
86
    PK11_EnterSlotMonitor(slot);
1957
86
    if (slot->session != CK_INVALID_HANDLE) {
1958
86
        crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
1959
86
                                                   theTemplate, tsize);
1960
86
    }
1961
86
    if (crv != CKR_OK) {
1962
0
        PK11_ExitSlotMonitor(slot);
1963
0
        PORT_SetError(PK11_MapError(crv));
1964
0
        return CK_INVALID_HANDLE;
1965
0
    }
1966
1967
86
    crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, &object, 1, &objectCount);
1968
86
    PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
1969
86
    PK11_ExitSlotMonitor(slot);
1970
86
    if ((crv != CKR_OK) || (objectCount < 1)) {
1971
        /* shouldn't use SSL_ERROR... here */
1972
86
        PORT_SetError(crv != CKR_OK ? PK11_MapError(crv) : SSL_ERROR_NO_CERTIFICATE);
1973
86
        return CK_INVALID_HANDLE;
1974
86
    }
1975
1976
    /* blow up if the PKCS #11 module returns us and invalid object handle */
1977
0
    PORT_Assert(object != CK_INVALID_HANDLE);
1978
0
    return object;
1979
86
}
1980
1981
/*
1982
 * return all the object handles that matches the template
1983
 */
1984
CK_OBJECT_HANDLE *
1985
pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,
1986
                           size_t templCount, int *object_count)
1987
88
{
1988
88
    CK_OBJECT_HANDLE *objID = NULL;
1989
88
    CK_ULONG returned_count = 0;
1990
88
    PRBool owner = PR_TRUE;
1991
88
    CK_SESSION_HANDLE session;
1992
88
    PRBool haslock = PR_FALSE;
1993
88
    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
1994
1995
88
    session = pk11_GetNewSession(slot, &owner);
1996
88
    haslock = (!owner || !(slot->isThreadSafe));
1997
88
    if (haslock) {
1998
0
        PK11_EnterSlotMonitor(slot);
1999
0
    }
2000
88
    if (session != CK_INVALID_HANDLE) {
2001
88
        crv = PK11_GETTAB(slot)->C_FindObjectsInit(session,
2002
88
                                                   findTemplate, templCount);
2003
88
    }
2004
88
    if (crv != CKR_OK) {
2005
0
        if (haslock)
2006
0
            PK11_ExitSlotMonitor(slot);
2007
0
        pk11_CloseSession(slot, session, owner);
2008
0
        PORT_SetError(PK11_MapError(crv));
2009
0
        *object_count = -1;
2010
0
        return NULL;
2011
0
    }
2012
2013
    /*
2014
     * collect all the Matching Objects
2015
     */
2016
88
    do {
2017
88
        CK_OBJECT_HANDLE *oldObjID = objID;
2018
2019
88
        if (objID == NULL) {
2020
88
            objID = (CK_OBJECT_HANDLE *)PORT_Alloc(sizeof(CK_OBJECT_HANDLE) *
2021
88
                                                   (*object_count + PK11_SEARCH_CHUNKSIZE));
2022
88
        } else {
2023
0
            objID = (CK_OBJECT_HANDLE *)PORT_Realloc(objID,
2024
0
                                                     sizeof(CK_OBJECT_HANDLE) * (*object_count + PK11_SEARCH_CHUNKSIZE));
2025
0
        }
2026
2027
88
        if (objID == NULL) {
2028
0
            if (oldObjID)
2029
0
                PORT_Free(oldObjID);
2030
0
            break;
2031
0
        }
2032
88
        crv = PK11_GETTAB(slot)->C_FindObjects(session,
2033
88
                                               &objID[*object_count], PK11_SEARCH_CHUNKSIZE, &returned_count);
2034
88
        if (crv != CKR_OK) {
2035
0
            PORT_SetError(PK11_MapError(crv));
2036
0
            PORT_Free(objID);
2037
0
            objID = NULL;
2038
0
            break;
2039
0
        }
2040
88
        *object_count += returned_count;
2041
88
    } while (returned_count == PK11_SEARCH_CHUNKSIZE);
2042
2043
88
    PK11_GETTAB(slot)->C_FindObjectsFinal(session);
2044
88
    if (haslock) {
2045
0
        PK11_ExitSlotMonitor(slot);
2046
0
    }
2047
88
    pk11_CloseSession(slot, session, owner);
2048
2049
88
    if (objID && (*object_count == 0)) {
2050
88
        PORT_Free(objID);
2051
88
        return NULL;
2052
88
    }
2053
0
    if (objID == NULL)
2054
0
        *object_count = -1;
2055
0
    return objID;
2056
88
}
2057
2058
SECStatus
2059
PK11_FindRawCertsWithSubject(PK11SlotInfo *slot, SECItem *derSubject,
2060
                             CERTCertificateList **results)
2061
0
{
2062
0
    if (!slot || !derSubject || !results) {
2063
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2064
0
        return SECFailure;
2065
0
    }
2066
0
    *results = NULL;
2067
2068
    // derSubject->data may be null. If so, derSubject->len must be 0.
2069
0
    if (!derSubject->data && derSubject->len != 0) {
2070
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2071
0
        return SECFailure;
2072
0
    }
2073
2074
0
    CK_CERTIFICATE_TYPE ckc_x_509 = CKC_X_509;
2075
0
    CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE;
2076
0
    CK_ATTRIBUTE subjectTemplate[] = {
2077
0
        { CKA_CERTIFICATE_TYPE, &ckc_x_509, sizeof(ckc_x_509) },
2078
0
        { CKA_CLASS, &cko_certificate, sizeof(cko_certificate) },
2079
0
        { CKA_SUBJECT, derSubject->data, derSubject->len },
2080
0
    };
2081
0
    const size_t templateCount = sizeof(subjectTemplate) / sizeof(subjectTemplate[0]);
2082
0
    int handleCount = 0;
2083
0
    CK_OBJECT_HANDLE *handles =
2084
0
        pk11_FindObjectsByTemplate(slot, subjectTemplate, templateCount,
2085
0
                                   &handleCount);
2086
0
    if (!handles) {
2087
        // pk11_FindObjectsByTemplate indicates there was an error by setting
2088
        // handleCount to -1 (and it has set an error with PORT_SetError).
2089
0
        if (handleCount == -1) {
2090
0
            return SECFailure;
2091
0
        }
2092
0
        return SECSuccess;
2093
0
    }
2094
0
    PORT_Assert(handleCount > 0);
2095
0
    if (handleCount <= 0) {
2096
0
        PORT_Free(handles);
2097
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2098
0
        return SECFailure;
2099
0
    }
2100
0
    if (handleCount > INT_MAX / sizeof(SECItem)) {
2101
0
        PORT_Free(handles);
2102
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2103
0
        return SECFailure;
2104
0
    }
2105
0
    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2106
0
    if (!arena) {
2107
0
        PORT_Free(handles);
2108
0
        return SECFailure;
2109
0
    }
2110
0
    CERTCertificateList *rawCertificates =
2111
0
        PORT_ArenaNew(arena, CERTCertificateList);
2112
0
    if (!rawCertificates) {
2113
0
        PORT_Free(handles);
2114
0
        PORT_FreeArena(arena, PR_FALSE);
2115
0
        return SECFailure;
2116
0
    }
2117
0
    rawCertificates->arena = arena;
2118
0
    rawCertificates->certs = PORT_ArenaNewArray(arena, SECItem, handleCount);
2119
0
    if (!rawCertificates->certs) {
2120
0
        PORT_Free(handles);
2121
0
        PORT_FreeArena(arena, PR_FALSE);
2122
0
        return SECFailure;
2123
0
    }
2124
0
    rawCertificates->len = handleCount;
2125
0
    int handleIndex;
2126
0
    for (handleIndex = 0; handleIndex < handleCount; handleIndex++) {
2127
0
        SECStatus rv =
2128
0
            PK11_ReadAttribute(slot, handles[handleIndex], CKA_VALUE, arena,
2129
0
                               &rawCertificates->certs[handleIndex]);
2130
0
        if (rv != SECSuccess) {
2131
0
            PORT_Free(handles);
2132
0
            PORT_FreeArena(arena, PR_FALSE);
2133
0
            return SECFailure;
2134
0
        }
2135
0
        if (!rawCertificates->certs[handleIndex].data) {
2136
0
            PORT_Free(handles);
2137
0
            PORT_FreeArena(arena, PR_FALSE);
2138
0
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2139
0
            return SECFailure;
2140
0
        }
2141
0
    }
2142
0
    PORT_Free(handles);
2143
0
    *results = rawCertificates;
2144
0
    return SECSuccess;
2145
0
}
2146
2147
/*
2148
 * given a PKCS #11 object, match it's peer based on the KeyID. searchID
2149
 * is typically a privateKey or a certificate while the peer is the opposite
2150
 */
2151
CK_OBJECT_HANDLE
2152
PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID,
2153
               CK_OBJECT_CLASS matchclass)
2154
315
{
2155
315
    CK_ATTRIBUTE theTemplate[] = {
2156
315
        { CKA_ID, NULL, 0 },
2157
315
        { CKA_CLASS, NULL, 0 }
2158
315
    };
2159
    /* if you change the array, change the variable below as well */
2160
315
    CK_ATTRIBUTE *keyclass = &theTemplate[1];
2161
315
    const size_t tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
2162
    /* if you change the array, change the variable below as well */
2163
315
    CK_OBJECT_HANDLE peerID;
2164
315
    PORTCheapArenaPool tmpArena;
2165
315
    CK_RV crv;
2166
2167
    /* now we need to create space for the public key */
2168
315
    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
2169
2170
315
    crv = PK11_GetAttributes(&tmpArena.arena, slot, searchID, theTemplate, tsize);
2171
315
    if (crv != CKR_OK) {
2172
0
        PORT_DestroyCheapArena(&tmpArena);
2173
0
        PORT_SetError(PK11_MapError(crv));
2174
0
        return CK_INVALID_HANDLE;
2175
0
    }
2176
2177
315
    if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) {
2178
261
        PORT_DestroyCheapArena(&tmpArena);
2179
261
        if (matchclass == CKO_CERTIFICATE) {
2180
174
            PORT_SetError(SEC_ERROR_BAD_KEY);
2181
174
        } else {
2182
87
            PORT_SetError(SEC_ERROR_NO_KEY);
2183
87
        }
2184
261
        return CK_INVALID_HANDLE;
2185
261
    }
2186
2187
    /*
2188
     * issue the find
2189
     */
2190
54
    *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass;
2191
2192
54
    peerID = pk11_FindObjectByTemplate(slot, theTemplate, tsize);
2193
54
    PORT_DestroyCheapArena(&tmpArena);
2194
2195
54
    return peerID;
2196
315
}
2197
2198
/*
2199
 * count the number of objects that match the template.
2200
 */
2201
int
2202
PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,
2203
                      int templCount)
2204
0
{
2205
0
    CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE];
2206
0
    int object_count = 0;
2207
0
    CK_ULONG returned_count = 0;
2208
0
    CK_RV crv = CKR_SESSION_HANDLE_INVALID;
2209
2210
0
    PK11_EnterSlotMonitor(slot);
2211
0
    if (slot->session != CK_INVALID_HANDLE) {
2212
0
        crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
2213
0
                                                   findTemplate, templCount);
2214
0
    }
2215
0
    if (crv != CKR_OK) {
2216
0
        PK11_ExitSlotMonitor(slot);
2217
0
        PORT_SetError(PK11_MapError(crv));
2218
0
        return object_count;
2219
0
    }
2220
2221
    /*
2222
     * collect all the Matching Objects
2223
     */
2224
0
    do {
2225
0
        crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, objID,
2226
0
                                               PK11_SEARCH_CHUNKSIZE,
2227
0
                                               &returned_count);
2228
0
        if (crv != CKR_OK) {
2229
0
            PORT_SetError(PK11_MapError(crv));
2230
0
            break;
2231
0
        }
2232
0
        object_count += returned_count;
2233
0
    } while (returned_count == PK11_SEARCH_CHUNKSIZE);
2234
2235
0
    PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
2236
0
    PK11_ExitSlotMonitor(slot);
2237
0
    return object_count;
2238
0
}
2239
2240
/*
2241
 * Traverse all the objects in a given slot.
2242
 */
2243
SECStatus
2244
PK11_TraverseSlot(PK11SlotInfo *slot, void *arg)
2245
24
{
2246
24
    int i;
2247
24
    CK_OBJECT_HANDLE *objID = NULL;
2248
24
    int object_count = 0;
2249
24
    pk11TraverseSlot *slotcb = (pk11TraverseSlot *)arg;
2250
2251
24
    objID = pk11_FindObjectsByTemplate(slot, slotcb->findTemplate,
2252
24
                                       slotcb->templateCount, &object_count);
2253
2254
    /*Actually this isn't a failure... there just were no objs to be found*/
2255
24
    if (object_count == 0) {
2256
24
        return SECSuccess;
2257
24
    }
2258
2259
0
    if (objID == NULL) {
2260
0
        return SECFailure;
2261
0
    }
2262
2263
0
    for (i = 0; i < object_count; i++) {
2264
0
        (*slotcb->callback)(slot, objID[i], slotcb->callbackArg);
2265
0
    }
2266
0
    PORT_Free(objID);
2267
0
    return SECSuccess;
2268
0
}
2269
2270
/*
2271
 * Traverse all the objects in all slots.
2272
 */
2273
SECStatus
2274
pk11_TraverseAllSlots(SECStatus (*callback)(PK11SlotInfo *, void *),
2275
                      void *arg, PRBool forceLogin, void *wincx)
2276
17
{
2277
17
    PK11SlotList *list;
2278
17
    PK11SlotListElement *le;
2279
17
    SECStatus rv;
2280
2281
    /* get them all! */
2282
17
    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, wincx);
2283
17
    if (list == NULL)
2284
0
        return SECFailure;
2285
2286
    /* look at each slot and authenticate as necessary */
2287
51
    for (le = list->head; le; le = le->next) {
2288
34
        if (forceLogin) {
2289
10
            rv = pk11_AuthenticateUnfriendly(le->slot, PR_FALSE, wincx);
2290
10
            if (rv != SECSuccess) {
2291
0
                continue;
2292
0
            }
2293
10
        }
2294
34
        if (callback) {
2295
24
            (*callback)(le->slot, arg);
2296
24
        }
2297
34
    }
2298
2299
17
    PK11_FreeSlotList(list);
2300
2301
17
    return SECSuccess;
2302
17
}
2303
2304
CK_OBJECT_HANDLE *
2305
PK11_FindObjectsFromNickname(char *nickname, PK11SlotInfo **slotptr,
2306
                             CK_OBJECT_CLASS objclass, int *returnCount, void *wincx)
2307
0
{
2308
0
    char *tokenName;
2309
0
    char *delimit;
2310
0
    PK11SlotInfo *slot;
2311
0
    CK_OBJECT_HANDLE *objID;
2312
0
    CK_ATTRIBUTE findTemplate[] = {
2313
0
        { CKA_LABEL, NULL, 0 },
2314
0
        { CKA_CLASS, NULL, 0 },
2315
0
    };
2316
0
    const size_t findCount = sizeof(findTemplate) / sizeof(findTemplate[0]);
2317
0
    SECStatus rv;
2318
0
    PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass));
2319
2320
0
    *slotptr = slot = NULL;
2321
0
    *returnCount = 0;
2322
    /* first find the slot associated with this nickname */
2323
0
    if ((delimit = PORT_Strchr(nickname, ':')) != NULL) {
2324
0
        int len = delimit - nickname;
2325
0
        tokenName = (char *)PORT_Alloc(len + 1);
2326
0
        if (!tokenName) {
2327
0
            return CK_INVALID_HANDLE;
2328
0
        }
2329
0
        PORT_Memcpy(tokenName, nickname, len);
2330
0
        tokenName[len] = 0;
2331
2332
0
        slot = *slotptr = PK11_FindSlotByName(tokenName);
2333
0
        PORT_Free(tokenName);
2334
        /* if we couldn't find a slot, assume the nickname is an internal cert
2335
         * with no proceding slot name */
2336
0
        if (slot == NULL) {
2337
0
            slot = *slotptr = PK11_GetInternalKeySlot();
2338
0
        } else {
2339
0
            nickname = delimit + 1;
2340
0
        }
2341
0
    } else {
2342
0
        *slotptr = slot = PK11_GetInternalKeySlot();
2343
0
    }
2344
0
    if (slot == NULL) {
2345
0
        return CK_INVALID_HANDLE;
2346
0
    }
2347
2348
0
    rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
2349
0
    if (rv != SECSuccess) {
2350
0
        PK11_FreeSlot(slot);
2351
0
        *slotptr = NULL;
2352
0
        return CK_INVALID_HANDLE;
2353
0
    }
2354
2355
0
    findTemplate[0].pValue = nickname;
2356
0
    findTemplate[0].ulValueLen = PORT_Strlen(nickname);
2357
0
    objID = pk11_FindObjectsByTemplate(slot, findTemplate, findCount, returnCount);
2358
0
    if (objID == NULL) {
2359
        /* PKCS #11 isn't clear on whether or not the NULL is
2360
         * stored in the template.... try the find again with the
2361
         * full null terminated string. */
2362
0
        findTemplate[0].ulValueLen += 1;
2363
0
        objID = pk11_FindObjectsByTemplate(slot, findTemplate, findCount,
2364
0
                                           returnCount);
2365
0
        if (objID == NULL) {
2366
            /* Well that's the best we can do. It's just not here */
2367
            /* what about faked nicknames? */
2368
0
            PK11_FreeSlot(slot);
2369
0
            *slotptr = NULL;
2370
0
            *returnCount = 0;
2371
0
        }
2372
0
    }
2373
2374
0
    return objID;
2375
0
}
2376
2377
SECItem *
2378
pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle)
2379
0
{
2380
0
    CK_ATTRIBUTE theTemplate[] = {
2381
0
        { CKA_ID, NULL, 0 },
2382
0
    };
2383
0
    int tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
2384
0
    CK_RV crv;
2385
0
    SECItem *item;
2386
2387
0
    item = SECITEM_AllocItem(NULL, NULL, 0);
2388
2389
0
    if (item == NULL) {
2390
0
        return NULL;
2391
0
    }
2392
2393
0
    crv = PK11_GetAttributes(NULL, slot, handle, theTemplate, tsize);
2394
0
    if (crv != CKR_OK) {
2395
0
        SECITEM_FreeItem(item, PR_TRUE);
2396
0
        PORT_SetError(PK11_MapError(crv));
2397
0
        return NULL;
2398
0
    }
2399
2400
0
    item->data = (unsigned char *)theTemplate[0].pValue;
2401
0
    item->len = theTemplate[0].ulValueLen;
2402
2403
0
    return item;
2404
0
}
2405
2406
PRBool
2407
PK11_ObjectGetFIPSStatus(PK11ObjectType objType, void *objSpec)
2408
0
{
2409
0
    PK11SlotInfo *slot = NULL;
2410
0
    CK_OBJECT_HANDLE handle = 0;
2411
2412
0
    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
2413
0
    if (handle == CK_INVALID_HANDLE) {
2414
0
        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
2415
0
        return PR_FALSE;
2416
0
    }
2417
0
    return pk11slot_GetFIPSStatus(slot, slot->session, handle,
2418
0
                                  CKT_NSS_OBJECT_CHECK);
2419
0
}