Coverage Report

Created: 2025-06-24 06:49

/src/nss/lib/pk11wrap/pk11nobj.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 Netscape specific PKCS #11 objects (CRLs, Trust objects,
6
 * etc).
7
 */
8
9
#include <stddef.h>
10
11
#include "secport.h"
12
#include "seccomon.h"
13
#include "secmod.h"
14
#include "secmodi.h"
15
#include "secmodti.h"
16
#include "pkcs11.h"
17
#include "pk11func.h"
18
#include "cert.h"
19
#include "certi.h"
20
#include "secitem.h"
21
#include "sechash.h"
22
#include "secoid.h"
23
24
#include "certdb.h"
25
#include "secerr.h"
26
27
#include "pki3hack.h"
28
#include "dev3hack.h"
29
30
#include "devm.h"
31
#include "pki.h"
32
#include "pkim.h"
33
34
extern const NSSError NSS_ERROR_NOT_FOUND;
35
36
CK_TRUST
37
pk11_GetTrustField(PK11SlotInfo *slot, PLArenaPool *arena,
38
                   CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type)
39
0
{
40
0
    CK_TRUST rv = 0;
41
0
    SECItem item;
42
43
0
    item.data = NULL;
44
0
    item.len = 0;
45
46
0
    if (SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item)) {
47
0
        PORT_Assert(item.len == sizeof(CK_TRUST));
48
0
        PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST));
49
        /* Damn, is there an endian problem here? */
50
0
        return rv;
51
0
    }
52
53
0
    return 0;
54
0
}
55
56
PRBool
57
pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust)
58
0
{
59
0
    PLArenaPool *arena;
60
61
0
    CK_ATTRIBUTE tobjTemplate[] = {
62
0
        { CKA_CLASS, NULL, 0 },
63
0
        { CKA_CERT_SHA1_HASH, NULL, 0 },
64
0
    };
65
66
0
    CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
67
0
    CK_OBJECT_HANDLE tobjID;
68
0
    unsigned char sha1_hash[SHA1_LENGTH];
69
70
0
    CK_TRUST serverAuth, codeSigning, emailProtection, clientAuth;
71
72
0
    PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len);
73
74
0
    PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc));
75
0
    PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash,
76
0
                  SHA1_LENGTH);
77
78
0
    tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate,
79
0
                                       sizeof(tobjTemplate) / sizeof(tobjTemplate[0]));
80
0
    if (CK_INVALID_HANDLE == tobjID) {
81
0
        return PR_FALSE;
82
0
    }
83
84
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
85
0
    if (NULL == arena)
86
0
        return PR_FALSE;
87
88
    /* Unfortunately, it seems that PK11_GetAttributes doesn't deal
89
     * well with nonexistent attributes.  I guess we have to check
90
     * the trust info fields one at a time.
91
     */
92
93
    /* We could verify CKA_CERT_HASH here */
94
95
    /* We could verify CKA_EXPIRES here */
96
97
    /* "Purpose" trust information */
98
0
    serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH);
99
0
    clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH);
100
0
    codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING);
101
0
    emailProtection = pk11_GetTrustField(slot, arena, tobjID,
102
0
                                         CKA_TRUST_EMAIL_PROTECTION);
103
    /* Here's where the fun logic happens.  We have to map back from the
104
     * key usage, extended key usage, purpose, and possibly other trust values
105
     * into the old trust-flags bits.  */
106
107
    /* First implementation: keep it simple for testing.  We can study what other
108
     * mappings would be appropriate and add them later.. fgmr 20000724 */
109
110
0
    if (serverAuth == CKT_NSS_TRUSTED) {
111
0
        trust->sslFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
112
0
    }
113
114
0
    if (serverAuth == CKT_NSS_TRUSTED_DELEGATOR) {
115
0
        trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA |
116
0
                           CERTDB_NS_TRUSTED_CA;
117
0
    }
118
0
    if (clientAuth == CKT_NSS_TRUSTED_DELEGATOR) {
119
0
        trust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA;
120
0
    }
121
122
0
    if (emailProtection == CKT_NSS_TRUSTED) {
123
0
        trust->emailFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
124
0
    }
125
126
0
    if (emailProtection == CKT_NSS_TRUSTED_DELEGATOR) {
127
0
        trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
128
0
    }
129
130
0
    if (codeSigning == CKT_NSS_TRUSTED) {
131
0
        trust->objectSigningFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
132
0
    }
133
134
0
    if (codeSigning == CKT_NSS_TRUSTED_DELEGATOR) {
135
0
        trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
136
0
    }
137
138
    /* There's certainly a lot more logic that can go here.. */
139
140
0
    PORT_FreeArena(arena, PR_FALSE);
141
142
0
    return PR_TRUE;
143
0
}
144
145
static SECStatus
146
pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg)
147
0
{
148
0
    SECItem derCrl;
149
0
    CERTCrlHeadNode *head = (CERTCrlHeadNode *)arg;
150
0
    CERTCrlNode *new_node = NULL;
151
0
    CK_ATTRIBUTE fetchCrl[3] = {
152
0
        { CKA_VALUE, NULL, 0 },
153
0
        { CKA_NSS_KRL, NULL, 0 },
154
0
        { CKA_NSS_URL, NULL, 0 },
155
0
    };
156
0
    const int fetchCrlSize = sizeof(fetchCrl) / sizeof(fetchCrl[2]);
157
0
    CK_RV crv;
158
0
    SECStatus rv = SECFailure;
159
160
0
    crv = PK11_GetAttributes(head->arena, slot, crlID, fetchCrl, fetchCrlSize);
161
0
    if (CKR_OK != crv) {
162
0
        PORT_SetError(PK11_MapError(crv));
163
0
        goto loser;
164
0
    }
165
166
0
    if (!fetchCrl[1].pValue) {
167
0
        PORT_SetError(SEC_ERROR_CRL_INVALID);
168
0
        goto loser;
169
0
    }
170
171
0
    new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode));
172
0
    if (new_node == NULL) {
173
0
        goto loser;
174
0
    }
175
176
0
    if (*((CK_BBOOL *)fetchCrl[1].pValue))
177
0
        new_node->type = SEC_KRL_TYPE;
178
0
    else
179
0
        new_node->type = SEC_CRL_TYPE;
180
181
0
    derCrl.type = siBuffer;
182
0
    derCrl.data = (unsigned char *)fetchCrl[0].pValue;
183
0
    derCrl.len = fetchCrl[0].ulValueLen;
184
0
    new_node->crl = CERT_DecodeDERCrl(head->arena, &derCrl, new_node->type);
185
0
    if (new_node->crl == NULL) {
186
0
        goto loser;
187
0
    }
188
189
0
    if (fetchCrl[2].pValue) {
190
0
        int nnlen = fetchCrl[2].ulValueLen;
191
0
        new_node->crl->url = (char *)PORT_ArenaAlloc(head->arena, nnlen + 1);
192
0
        if (!new_node->crl->url) {
193
0
            goto loser;
194
0
        }
195
0
        PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
196
0
        new_node->crl->url[nnlen] = 0;
197
0
    } else {
198
0
        new_node->crl->url = NULL;
199
0
    }
200
201
0
    new_node->next = NULL;
202
0
    if (head->last) {
203
0
        head->last->next = new_node;
204
0
        head->last = new_node;
205
0
    } else {
206
0
        head->first = head->last = new_node;
207
0
    }
208
0
    rv = SECSuccess;
209
210
0
loser:
211
0
    return (rv);
212
0
}
213
214
/*
215
 * Return a list of all the CRLs .
216
 * CRLs are allocated in the list's arena.
217
 */
218
SECStatus
219
PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx)
220
0
{
221
0
    pk11TraverseSlot creater;
222
0
    CK_ATTRIBUTE theTemplate[2];
223
0
    CK_ATTRIBUTE *attrs;
224
0
    CK_OBJECT_CLASS certClass = CKO_NSS_CRL;
225
0
    CK_BBOOL isKrl = CK_FALSE;
226
227
0
    attrs = theTemplate;
228
0
    PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
229
0
    attrs++;
230
0
    if (type != -1) {
231
0
        isKrl = (CK_BBOOL)(type == SEC_KRL_TYPE);
232
0
        PK11_SETATTRS(attrs, CKA_NSS_KRL, &isKrl, sizeof(isKrl));
233
0
        attrs++;
234
0
    }
235
236
0
    creater.callback = pk11_CollectCrls;
237
0
    creater.callbackArg = (void *)nodes;
238
0
    creater.findTemplate = theTemplate;
239
0
    creater.templateCount = (attrs - theTemplate);
240
241
0
    return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
242
0
}
243
244
struct crlOptionsStr {
245
    CERTCrlHeadNode *head;
246
    PRInt32 decodeOptions;
247
};
248
249
typedef struct crlOptionsStr crlOptions;
250
251
static SECStatus
252
pk11_RetrieveCrlsCallback(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID,
253
                          void *arg)
254
0
{
255
0
    SECItem *derCrl = NULL;
256
0
    crlOptions *options = (crlOptions *)arg;
257
0
    CERTCrlHeadNode *head = options->head;
258
0
    CERTCrlNode *new_node = NULL;
259
0
    CK_ATTRIBUTE fetchCrl[3] = {
260
0
        { CKA_VALUE, NULL, 0 },
261
0
        { CKA_NSS_KRL, NULL, 0 },
262
0
        { CKA_NSS_URL, NULL, 0 },
263
0
    };
264
0
    const int fetchCrlSize = sizeof(fetchCrl) / sizeof(fetchCrl[2]);
265
0
    CK_RV crv;
266
0
    SECStatus rv = SECFailure;
267
0
    PRBool adopted = PR_FALSE; /* whether the CRL adopted the DER memory
268
                                  successfully */
269
0
    int i;
270
271
0
    crv = PK11_GetAttributes(NULL, slot, crlID, fetchCrl, fetchCrlSize);
272
0
    if (CKR_OK != crv) {
273
0
        PORT_SetError(PK11_MapError(crv));
274
0
        goto loser;
275
0
    }
276
277
0
    if (!fetchCrl[1].pValue) {
278
        /* reject KRLs */
279
0
        PORT_SetError(SEC_ERROR_CRL_INVALID);
280
0
        goto loser;
281
0
    }
282
283
0
    new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena,
284
0
                                              sizeof(CERTCrlNode));
285
0
    if (new_node == NULL) {
286
0
        goto loser;
287
0
    }
288
289
0
    new_node->type = SEC_CRL_TYPE;
290
291
0
    derCrl = SECITEM_AllocItem(NULL, NULL, 0);
292
0
    if (!derCrl) {
293
0
        goto loser;
294
0
    }
295
0
    derCrl->type = siBuffer;
296
0
    derCrl->data = (unsigned char *)fetchCrl[0].pValue;
297
0
    derCrl->len = fetchCrl[0].ulValueLen;
298
0
    new_node->crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, new_node->type,
299
0
                                               options->decodeOptions);
300
0
    if (new_node->crl == NULL) {
301
0
        goto loser;
302
0
    }
303
0
    adopted = PR_TRUE; /* now that the CRL has adopted the DER memory,
304
                          we won't need to free it upon exit */
305
306
0
    if (fetchCrl[2].pValue && fetchCrl[2].ulValueLen) {
307
        /* copy the URL if there is one */
308
0
        int nnlen = fetchCrl[2].ulValueLen;
309
0
        new_node->crl->url = (char *)PORT_ArenaAlloc(new_node->crl->arena,
310
0
                                                     nnlen + 1);
311
0
        if (!new_node->crl->url) {
312
0
            goto loser;
313
0
        }
314
0
        PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
315
0
        new_node->crl->url[nnlen] = 0;
316
0
    } else {
317
0
        new_node->crl->url = NULL;
318
0
    }
319
320
0
    new_node->next = NULL;
321
0
    if (head->last) {
322
0
        head->last->next = new_node;
323
0
        head->last = new_node;
324
0
    } else {
325
0
        head->first = head->last = new_node;
326
0
    }
327
0
    rv = SECSuccess;
328
0
    new_node->crl->slot = PK11_ReferenceSlot(slot);
329
0
    new_node->crl->pkcs11ID = crlID;
330
331
0
loser:
332
    /* free attributes that weren't adopted by the CRL */
333
0
    for (i = 1; i < fetchCrlSize; i++) {
334
0
        if (fetchCrl[i].pValue) {
335
0
            PORT_Free(fetchCrl[i].pValue);
336
0
        }
337
0
    }
338
    /* free the DER if the CRL object didn't adopt it */
339
0
    if (fetchCrl[0].pValue && PR_FALSE == adopted) {
340
0
        PORT_Free(fetchCrl[0].pValue);
341
0
    }
342
0
    if (derCrl && !adopted) {
343
        /* clear the data fields, which we already took care of above */
344
0
        derCrl->data = NULL;
345
0
        derCrl->len = 0;
346
        /* free the memory for the SECItem structure itself */
347
0
        SECITEM_FreeItem(derCrl, PR_TRUE);
348
0
    }
349
0
    return (rv);
350
0
}
351
352
/*
353
 * Return a list of CRLs matching specified issuer and type
354
 * CRLs are not allocated in the list's arena, but rather in their own,
355
 * arena, so that they can be used individually in the CRL cache .
356
 * CRLs are always partially decoded for efficiency.
357
 */
358
SECStatus
359
pk11_RetrieveCrls(CERTCrlHeadNode *nodes, SECItem *issuer,
360
                  void *wincx)
361
9
{
362
9
    pk11TraverseSlot creater;
363
9
    CK_ATTRIBUTE theTemplate[2];
364
9
    CK_ATTRIBUTE *attrs;
365
9
    CK_OBJECT_CLASS crlClass = CKO_NSS_CRL;
366
9
    crlOptions options;
367
368
9
    attrs = theTemplate;
369
9
    PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass));
370
9
    attrs++;
371
372
9
    options.head = nodes;
373
374
    /* - do a partial decoding - we don't need to decode the entries while fetching
375
       - don't copy the DER for optimal performance - CRL can be very large
376
       - have the CRL objects adopt the DER, so SEC_DestroyCrl will free it
377
       - keep bad CRL objects. The CRL cache is interested in them, for
378
         security purposes. Bad CRL objects are a sign of something amiss.
379
     */
380
381
9
    options.decodeOptions = CRL_DECODE_SKIP_ENTRIES | CRL_DECODE_DONT_COPY_DER |
382
9
                            CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_KEEP_BAD_CRL;
383
9
    if (issuer) {
384
9
        PK11_SETATTRS(attrs, CKA_SUBJECT, issuer->data, issuer->len);
385
9
        attrs++;
386
9
    }
387
388
9
    creater.callback = pk11_RetrieveCrlsCallback;
389
9
    creater.callbackArg = (void *)&options;
390
9
    creater.findTemplate = theTemplate;
391
9
    creater.templateCount = (attrs - theTemplate);
392
393
9
    return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
394
9
}
395
396
/*
397
 * return the crl associated with a derSubjectName
398
 */
399
SECItem *
400
PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *crlHandle,
401
                   SECItem *name, int type, char **pUrl)
402
0
{
403
0
    NSSCRL **crls, **crlp, *crl = NULL;
404
0
    NSSDER subject;
405
0
    SECItem *rvItem;
406
0
    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
407
0
    char *url = NULL;
408
409
0
    PORT_SetError(0);
410
0
    NSSITEM_FROM_SECITEM(&subject, name);
411
0
    if (*slot) {
412
0
        nssCryptokiObject **instances;
413
0
        nssPKIObjectCollection *collection;
414
0
        nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
415
0
        NSSToken *token = PK11Slot_GetNSSToken(*slot);
416
0
        if (!token) {
417
0
            goto loser;
418
0
        }
419
0
        collection = nssCRLCollection_Create(td, NULL);
420
0
        if (!collection) {
421
0
            (void)nssToken_Destroy(token);
422
0
            goto loser;
423
0
        }
424
0
        instances = nssToken_FindCRLsBySubject(token, NULL, &subject,
425
0
                                               tokenOnly, 0, NULL);
426
0
        (void)nssToken_Destroy(token);
427
0
        nssPKIObjectCollection_AddInstances(collection, instances, 0);
428
0
        nss_ZFreeIf(instances);
429
0
        crls = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL);
430
0
        nssPKIObjectCollection_Destroy(collection);
431
0
    } else {
432
0
        crls = nssTrustDomain_FindCRLsBySubject(td, &subject);
433
0
    }
434
0
    if ((!crls) || (*crls == NULL)) {
435
0
        if (crls) {
436
0
            nssCRLArray_Destroy(crls);
437
0
        }
438
0
        if (NSS_GetError() == NSS_ERROR_NOT_FOUND) {
439
0
            PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
440
0
        }
441
0
        goto loser;
442
0
    }
443
0
    for (crlp = crls; *crlp; crlp++) {
444
0
        if ((!(*crlp)->isKRL && type == SEC_CRL_TYPE) ||
445
0
            ((*crlp)->isKRL && type != SEC_CRL_TYPE)) {
446
0
            crl = nssCRL_AddRef(*crlp);
447
0
            break;
448
0
        }
449
0
    }
450
0
    nssCRLArray_Destroy(crls);
451
0
    if (!crl) {
452
        /* CRL collection was found, but no interesting CRL's were on it.
453
         * Not an error */
454
0
        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
455
0
        goto loser;
456
0
    }
457
0
    if (crl->url) {
458
0
        url = PORT_Strdup(crl->url);
459
0
        if (!url) {
460
0
            goto loser;
461
0
        }
462
0
    }
463
0
    rvItem = SECITEM_AllocItem(NULL, NULL, crl->encoding.size);
464
0
    if (!rvItem) {
465
0
        goto loser;
466
0
    }
467
0
    memcpy(rvItem->data, crl->encoding.data, crl->encoding.size);
468
0
    *slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot);
469
0
    *crlHandle = crl->object.instances[0]->handle;
470
0
    *pUrl = url;
471
0
    nssCRL_Destroy(crl);
472
0
    return rvItem;
473
474
0
loser:
475
0
    if (url)
476
0
        PORT_Free(url);
477
0
    if (crl)
478
0
        nssCRL_Destroy(crl);
479
0
    if (PORT_GetError() == 0) {
480
0
        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
481
0
    }
482
0
    return NULL;
483
0
}
484
485
CK_OBJECT_HANDLE
486
PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, SECItem *name,
487
            char *url, int type)
488
0
{
489
0
    NSSItem derCRL, derSubject;
490
0
    NSSToken *token;
491
0
    nssCryptokiObject *object;
492
0
    PRBool isKRL = (type == SEC_CRL_TYPE) ? PR_FALSE : PR_TRUE;
493
0
    CK_OBJECT_HANDLE rvH;
494
495
0
    NSSITEM_FROM_SECITEM(&derSubject, name);
496
0
    NSSITEM_FROM_SECITEM(&derCRL, crl);
497
0
    token = PK11Slot_GetNSSToken(slot);
498
0
    if (!token) {
499
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
500
0
        return CK_INVALID_HANDLE;
501
0
    }
502
0
    object = nssToken_ImportCRL(token, NULL,
503
0
                                &derSubject, &derCRL, isKRL, url, PR_TRUE);
504
0
    (void)nssToken_Destroy(token);
505
506
0
    if (object) {
507
0
        rvH = object->handle;
508
0
        nssCryptokiObject_Destroy(object);
509
0
    } else {
510
0
        rvH = CK_INVALID_HANDLE;
511
0
        PORT_SetError(SEC_ERROR_CRL_IMPORT_FAILED);
512
0
    }
513
0
    return rvH;
514
0
}
515
516
/*
517
 * delete a crl.
518
 */
519
SECStatus
520
SEC_DeletePermCRL(CERTSignedCrl *crl)
521
0
{
522
0
    PRStatus status;
523
0
    nssCryptokiObject *object;
524
0
    NSSToken *token;
525
0
    PK11SlotInfo *slot = crl->slot;
526
527
0
    if (slot == NULL) {
528
0
        PORT_Assert(slot);
529
        /* shouldn't happen */
530
0
        PORT_SetError(SEC_ERROR_CRL_INVALID);
531
0
        return SECFailure;
532
0
    }
533
534
0
    token = PK11Slot_GetNSSToken(slot);
535
0
    if (!token) {
536
0
        return SECFailure;
537
0
    }
538
0
    object = nss_ZNEW(NULL, nssCryptokiObject);
539
0
    if (!object) {
540
0
        (void)nssToken_Destroy(token);
541
0
        return SECFailure;
542
0
    }
543
0
    object->token = token; /* object takes ownership */
544
0
    object->handle = crl->pkcs11ID;
545
0
    object->isTokenObject = PR_TRUE;
546
547
0
    status = nssToken_DeleteStoredObject(object);
548
549
0
    nssCryptokiObject_Destroy(object);
550
0
    return (status == PR_SUCCESS) ? SECSuccess : SECFailure;
551
0
}
552
553
/* search with email with and without NULL
554
 * The sql database accepts the email with a NULL as it's written,
555
 * the dbm database strips the NULL on write so won't match if
556
 * it's there on find */
557
static CK_OBJECT_HANDLE
558
pk11_FindSMimeObjectByTemplate(PK11SlotInfo *slot,
559
                               CK_ATTRIBUTE *theTemplate, size_t tsize)
560
0
{
561
0
    CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
562
0
    CK_ATTRIBUTE *last;
563
564
0
    PORT_Assert(tsize != 0);
565
566
0
    smimeh = pk11_FindObjectByTemplate(slot, theTemplate, (int)tsize);
567
0
    if (smimeh != CK_INVALID_HANDLE) {
568
0
        return smimeh;
569
0
    }
570
0
    last = &theTemplate[tsize - 1];
571
0
    if ((last->type == CKA_NSS_EMAIL) && (last->ulValueLen != 0)) {
572
0
        CK_ULONG save_len = last->ulValueLen;
573
0
        last->ulValueLen--;
574
0
        smimeh = pk11_FindObjectByTemplate(slot, theTemplate, (int)tsize);
575
0
        last->ulValueLen = save_len; /* restore the original */
576
0
        return smimeh;
577
0
    }
578
0
    return CK_INVALID_HANDLE;
579
0
}
580
581
/*
582
 * return the certificate associated with a derCert
583
 */
584
SECItem *
585
PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr,
586
                      SECItem *name, SECItem **profileTime)
587
0
{
588
0
    CK_OBJECT_CLASS smimeClass = CKO_NSS_SMIME;
589
0
    CK_ATTRIBUTE theTemplate[] = {
590
0
        { CKA_CLASS, NULL, 0 },
591
0
        { CKA_SUBJECT, NULL, 0 },
592
0
        { CKA_NSS_EMAIL, NULL, 0 },
593
0
    };
594
0
    CK_ATTRIBUTE smimeData[] = {
595
0
        { CKA_SUBJECT, NULL, 0 },
596
0
        { CKA_VALUE, NULL, 0 },
597
0
    };
598
    /* if you change the array, change the variable below as well */
599
0
    const size_t tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
600
0
    CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
601
0
    CK_ATTRIBUTE *attrs = theTemplate;
602
0
    CK_RV crv;
603
0
    SECItem *emailProfile = NULL;
604
605
0
    if (!emailAddr || !emailAddr[0]) {
606
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
607
0
        return NULL;
608
0
    }
609
610
0
    PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass));
611
0
    attrs++;
612
0
    PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len);
613
0
    attrs++;
614
0
    PK11_SETATTRS(attrs, CKA_NSS_EMAIL, emailAddr, strlen(emailAddr) + 1);
615
0
    attrs++;
616
617
0
    if (*slot) {
618
0
        smimeh = pk11_FindSMimeObjectByTemplate(*slot, theTemplate, tsize);
619
0
    } else {
620
0
        PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
621
0
                                               PR_FALSE, PR_TRUE, NULL);
622
0
        PK11SlotListElement *le;
623
624
0
        if (!list) {
625
0
            return NULL;
626
0
        }
627
        /* loop through all the slots */
628
0
        for (le = list->head; le; le = le->next) {
629
0
            smimeh = pk11_FindSMimeObjectByTemplate(le->slot, theTemplate, tsize);
630
0
            if (smimeh != CK_INVALID_HANDLE) {
631
0
                *slot = PK11_ReferenceSlot(le->slot);
632
0
                break;
633
0
            }
634
0
        }
635
0
        PK11_FreeSlotList(list);
636
0
    }
637
638
0
    if (smimeh == CK_INVALID_HANDLE) {
639
0
        PORT_SetError(SEC_ERROR_NO_KRL);
640
0
        return NULL;
641
0
    }
642
643
0
    if (profileTime) {
644
0
        PK11_SETATTRS(smimeData, CKA_NSS_SMIME_TIMESTAMP, NULL, 0);
645
0
    }
646
647
0
    crv = PK11_GetAttributes(NULL, *slot, smimeh, smimeData, 2);
648
0
    if (crv != CKR_OK) {
649
0
        PORT_SetError(PK11_MapError(crv));
650
0
        goto loser;
651
0
    }
652
653
0
    if (!profileTime) {
654
0
        SECItem profileSubject;
655
656
0
        profileSubject.data = (unsigned char *)smimeData[0].pValue;
657
0
        profileSubject.len = smimeData[0].ulValueLen;
658
0
        if (!SECITEM_ItemsAreEqual(&profileSubject, name)) {
659
0
            goto loser;
660
0
        }
661
0
    }
662
663
0
    emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
664
0
    if (emailProfile == NULL) {
665
0
        goto loser;
666
0
    }
667
668
0
    emailProfile->data = (unsigned char *)smimeData[1].pValue;
669
0
    emailProfile->len = smimeData[1].ulValueLen;
670
671
0
    if (profileTime) {
672
0
        *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
673
0
        if (*profileTime) {
674
0
            (*profileTime)->data = (unsigned char *)smimeData[0].pValue;
675
0
            (*profileTime)->len = smimeData[0].ulValueLen;
676
0
        }
677
0
    }
678
679
0
loser:
680
0
    if (emailProfile == NULL) {
681
0
        if (smimeData[1].pValue) {
682
0
            PORT_Free(smimeData[1].pValue);
683
0
        }
684
0
    }
685
0
    if (profileTime == NULL || *profileTime == NULL) {
686
0
        if (smimeData[0].pValue) {
687
0
            PORT_Free(smimeData[0].pValue);
688
0
        }
689
0
    }
690
0
    return emailProfile;
691
0
}
692
693
SECStatus
694
PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj,
695
                      SECItem *emailProfile, SECItem *profileTime)
696
0
{
697
0
    CK_OBJECT_CLASS smimeClass = CKO_NSS_SMIME;
698
0
    CK_BBOOL ck_true = CK_TRUE;
699
0
    CK_ATTRIBUTE theTemplate[] = {
700
0
        { CKA_CLASS, NULL, 0 },
701
0
        { CKA_TOKEN, NULL, 0 },
702
0
        { CKA_SUBJECT, NULL, 0 },
703
0
        { CKA_NSS_EMAIL, NULL, 0 },
704
0
        { CKA_NSS_SMIME_TIMESTAMP, NULL, 0 },
705
0
        { CKA_VALUE, NULL, 0 }
706
0
    };
707
    /* if you change the array, change the variable below as well */
708
0
    int realSize = 0;
709
0
    CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
710
0
    CK_ATTRIBUTE *attrs = theTemplate;
711
0
    CK_SESSION_HANDLE rwsession;
712
0
    PK11SlotInfo *free_slot = NULL;
713
0
    CK_RV crv;
714
0
#ifdef DEBUG
715
0
    int tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
716
0
#endif
717
718
0
    PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass));
719
0
    attrs++;
720
0
    PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true));
721
0
    attrs++;
722
0
    PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len);
723
0
    attrs++;
724
0
    PK11_SETATTRS(attrs, CKA_NSS_EMAIL,
725
0
                  emailAddr, PORT_Strlen(emailAddr) + 1);
726
0
    attrs++;
727
0
    if (profileTime) {
728
0
        PK11_SETATTRS(attrs, CKA_NSS_SMIME_TIMESTAMP, profileTime->data,
729
0
                      profileTime->len);
730
0
        attrs++;
731
0
        PK11_SETATTRS(attrs, CKA_VALUE, emailProfile->data,
732
0
                      emailProfile->len);
733
0
        attrs++;
734
0
    }
735
0
    realSize = attrs - theTemplate;
736
0
    PORT_Assert(realSize <= tsize);
737
738
0
    if (slot == NULL) {
739
0
        free_slot = slot = PK11_GetInternalKeySlot();
740
        /* we need to free the key slot in the end!!! */
741
0
    }
742
743
0
    rwsession = PK11_GetRWSession(slot);
744
0
    if (rwsession == CK_INVALID_HANDLE) {
745
0
        PORT_SetError(SEC_ERROR_READ_ONLY);
746
0
        if (free_slot) {
747
0
            PK11_FreeSlot(free_slot);
748
0
        }
749
0
        return SECFailure;
750
0
    }
751
752
0
    crv = PK11_GETTAB(slot)->C_CreateObject(rwsession, theTemplate, realSize, &smimeh);
753
0
    if (crv != CKR_OK) {
754
0
        PORT_SetError(PK11_MapError(crv));
755
0
    }
756
757
0
    PK11_RestoreROSession(slot, rwsession);
758
759
0
    if (free_slot) {
760
0
        PK11_FreeSlot(free_slot);
761
0
    }
762
0
    return SECSuccess;
763
0
}
764
765
CERTSignedCrl *crl_storeCRL(PK11SlotInfo *slot, char *url,
766
                            CERTSignedCrl *newCrl, SECItem *derCrl, int type);
767
768
/* import the CRL into the token */
769
770
CERTSignedCrl *
771
PK11_ImportCRL(PK11SlotInfo *slot, SECItem *derCRL, char *url,
772
               int type, void *wincx, PRInt32 importOptions, PLArenaPool *arena,
773
               PRInt32 decodeoptions)
774
0
{
775
0
    CERTSignedCrl *newCrl, *crl;
776
0
    SECStatus rv;
777
0
    CERTCertificate *caCert = NULL;
778
779
0
    newCrl = crl = NULL;
780
781
0
    do {
782
0
        newCrl = CERT_DecodeDERCrlWithFlags(arena, derCRL, type,
783
0
                                            decodeoptions);
784
0
        if (newCrl == NULL) {
785
0
            if (type == SEC_CRL_TYPE) {
786
                /* only promote error when the error code is too generic */
787
0
                if (PORT_GetError() == SEC_ERROR_BAD_DER)
788
0
                    PORT_SetError(SEC_ERROR_CRL_INVALID);
789
0
            } else {
790
0
                PORT_SetError(SEC_ERROR_KRL_INVALID);
791
0
            }
792
0
            break;
793
0
        }
794
795
0
        if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)) {
796
0
            CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
797
0
            PR_ASSERT(handle != NULL);
798
0
            caCert = CERT_FindCertByName(handle,
799
0
                                         &newCrl->crl.derName);
800
0
            if (caCert == NULL) {
801
0
                PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
802
0
                break;
803
0
            }
804
805
            /* If caCert is a v3 certificate, make sure that it can be used for
806
               crl signing purpose */
807
0
            rv = CERT_CheckCertUsage(caCert, KU_CRL_SIGN);
808
0
            if (rv != SECSuccess) {
809
0
                break;
810
0
            }
811
812
0
            rv = CERT_VerifySignedData(&newCrl->signatureWrap, caCert,
813
0
                                       PR_Now(), wincx);
814
0
            if (rv != SECSuccess) {
815
0
                if (type == SEC_CRL_TYPE) {
816
0
                    PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
817
0
                } else {
818
0
                    PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
819
0
                }
820
0
                break;
821
0
            }
822
0
        }
823
824
0
        crl = crl_storeCRL(slot, url, newCrl, derCRL, type);
825
826
0
    } while (0);
827
828
0
    if (crl == NULL) {
829
0
        SEC_DestroyCrl(newCrl);
830
0
    }
831
0
    if (caCert) {
832
0
        CERT_DestroyCertificate(caCert);
833
0
    }
834
0
    return (crl);
835
0
}