Coverage Report

Created: 2018-09-25 14:53

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