Coverage Report

Created: 2025-12-20 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/pki/certificate.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#ifndef NSSPKI_H
6
#include "nsspki.h"
7
#endif /* NSSPKI_H */
8
9
#ifndef PKIT_H
10
#include "pkit.h"
11
#endif /* PKIT_H */
12
13
#ifndef PKIM_H
14
#include "pkim.h"
15
#endif /* PKIM_H */
16
17
#ifndef DEV_H
18
#include "dev.h"
19
#endif /* DEV_H */
20
21
#include "pkistore.h"
22
23
#include "pki3hack.h"
24
#include "pk11func.h"
25
#include "hasht.h"
26
27
#ifndef BASE_H
28
#include "base.h"
29
#endif /* BASE_H */
30
31
extern const NSSError NSS_ERROR_NOT_FOUND;
32
33
/* Creates a certificate from a base object */
34
NSS_IMPLEMENT NSSCertificate *
35
nssCertificate_Create(
36
    nssPKIObject *object)
37
0
{
38
0
    PRStatus status;
39
0
    NSSCertificate *rvCert;
40
0
    nssArenaMark *mark;
41
0
    NSSArena *arena = object->arena;
42
0
    PR_ASSERT(object->instances != NULL && object->numInstances > 0);
43
0
    PR_ASSERT(object->lockType == nssPKIMonitor);
44
0
    mark = nssArena_Mark(arena);
45
0
    rvCert = nss_ZNEW(arena, NSSCertificate);
46
0
    if (!rvCert) {
47
0
        return (NSSCertificate *)NULL;
48
0
    }
49
0
    rvCert->object = *object;
50
    /* XXX should choose instance based on some criteria */
51
0
    status = nssCryptokiCertificate_GetAttributes(object->instances[0],
52
0
                                                  NULL, /* XXX sessionOpt */
53
0
                                                  arena,
54
0
                                                  &rvCert->type,
55
0
                                                  &rvCert->id,
56
0
                                                  &rvCert->encoding,
57
0
                                                  &rvCert->issuer,
58
0
                                                  &rvCert->serial,
59
0
                                                  &rvCert->subject);
60
0
    if (status != PR_SUCCESS ||
61
0
        !rvCert->encoding.data ||
62
0
        !rvCert->encoding.size ||
63
0
        !rvCert->issuer.data ||
64
0
        !rvCert->issuer.size ||
65
0
        !rvCert->serial.data ||
66
0
        !rvCert->serial.size) {
67
0
        if (mark)
68
0
            nssArena_Release(arena, mark);
69
0
        return (NSSCertificate *)NULL;
70
0
    }
71
0
    if (mark)
72
0
        nssArena_Unmark(arena, mark);
73
0
    return rvCert;
74
0
}
75
76
NSS_IMPLEMENT NSSCertificate *
77
nssCertificate_AddRef(
78
    NSSCertificate *c)
79
445k
{
80
445k
    if (c) {
81
445k
        nssPKIObject_AddRef(&c->object);
82
445k
    }
83
445k
    return c;
84
445k
}
85
86
NSS_IMPLEMENT PRStatus
87
nssCertificate_Destroy(
88
    NSSCertificate *c)
89
554k
{
90
554k
    nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
91
554k
    nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
92
93
554k
    if (c) {
94
554k
        PRUint32 i;
95
554k
        nssDecodedCert *dc = c->decoding;
96
554k
        NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
97
554k
        NSSCryptoContext *cc = c->object.cryptoContext;
98
99
554k
        PR_ASSERT(c->object.refCount > 0);
100
101
        /* --- LOCK storage --- */
102
554k
        if (cc) {
103
554k
            nssCertificateStore_Lock(cc->certStore, &lockTrace);
104
554k
        } else {
105
0
            nssTrustDomain_LockCertCache(td);
106
0
        }
107
554k
        if (PR_ATOMIC_DECREMENT(&c->object.refCount) == 0) {
108
            /* --- remove cert and UNLOCK storage --- */
109
91.6k
            if (cc) {
110
91.6k
                nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
111
91.6k
                nssCertificateStore_Unlock(cc->certStore, &lockTrace,
112
91.6k
                                           &unlockTrace);
113
91.6k
            } else {
114
0
                nssTrustDomain_RemoveCertFromCacheLOCKED(td, c);
115
0
                nssTrustDomain_UnlockCertCache(td);
116
0
            }
117
            /* free cert data */
118
91.6k
            for (i = 0; i < c->object.numInstances; i++) {
119
0
                nssCryptokiObject_Destroy(c->object.instances[i]);
120
0
            }
121
91.6k
            nssPKIObject_DestroyLock(&c->object);
122
91.6k
            nssArena_Destroy(c->object.arena);
123
91.6k
            nssDecodedCert_Destroy(dc);
124
462k
        } else {
125
            /* --- UNLOCK storage --- */
126
462k
            if (cc) {
127
462k
                nssCertificateStore_Unlock(cc->certStore,
128
462k
                                           &lockTrace,
129
462k
                                           &unlockTrace);
130
462k
            } else {
131
0
                nssTrustDomain_UnlockCertCache(td);
132
0
            }
133
462k
        }
134
554k
    }
135
554k
    return PR_SUCCESS;
136
554k
}
137
138
NSS_IMPLEMENT PRStatus
139
NSSCertificate_Destroy(NSSCertificate *c)
140
553k
{
141
553k
    return nssCertificate_Destroy(c);
142
553k
}
143
144
NSS_IMPLEMENT NSSDER *
145
nssCertificate_GetEncoding(NSSCertificate *c)
146
8.46k
{
147
8.46k
    if (c->encoding.size > 0 && c->encoding.data) {
148
8.46k
        return &c->encoding;
149
8.46k
    } else {
150
0
        return (NSSDER *)NULL;
151
0
    }
152
8.46k
}
153
154
NSS_IMPLEMENT NSSDER *
155
nssCertificate_GetIssuer(NSSCertificate *c)
156
0
{
157
0
    if (c->issuer.size > 0 && c->issuer.data) {
158
0
        return &c->issuer;
159
0
    } else {
160
0
        return (NSSDER *)NULL;
161
0
    }
162
0
}
163
164
NSS_IMPLEMENT NSSDER *
165
nssCertificate_GetSerialNumber(NSSCertificate *c)
166
0
{
167
0
    if (c->serial.size > 0 && c->serial.data) {
168
0
        return &c->serial;
169
0
    } else {
170
0
        return (NSSDER *)NULL;
171
0
    }
172
0
}
173
174
NSS_IMPLEMENT NSSDER *
175
nssCertificate_GetSubject(NSSCertificate *c)
176
0
{
177
0
    if (c->subject.size > 0 && c->subject.data) {
178
0
        return &c->subject;
179
0
    } else {
180
0
        return (NSSDER *)NULL;
181
0
    }
182
0
}
183
184
/* Returns a copy, Caller must free using nss_ZFreeIf */
185
NSS_IMPLEMENT NSSUTF8 *
186
nssCertificate_GetNickname(
187
    NSSCertificate *c,
188
    NSSToken *tokenOpt)
189
0
{
190
0
    return nssPKIObject_GetNicknameForToken(&c->object, tokenOpt);
191
0
}
192
193
NSS_IMPLEMENT NSSASCII7 *
194
nssCertificate_GetEmailAddress(NSSCertificate *c)
195
0
{
196
0
    return c->email;
197
0
}
198
199
NSS_IMPLEMENT PRStatus
200
NSSCertificate_DeleteStoredObject(
201
    NSSCertificate *c,
202
    NSSCallback *uhh)
203
0
{
204
0
    return nssPKIObject_DeleteStoredObject(&c->object, uhh, PR_TRUE);
205
0
}
206
207
NSS_IMPLEMENT PRStatus
208
NSSCertificate_Validate(
209
    NSSCertificate *c,
210
    NSSTime *timeOpt, /* NULL for "now" */
211
    NSSUsage *usage,
212
    NSSPolicies *policiesOpt /* NULL for none */
213
)
214
0
{
215
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
216
0
    return PR_FAILURE;
217
0
}
218
219
NSS_IMPLEMENT void ** /* void *[] */
220
NSSCertificate_ValidateCompletely(
221
    NSSCertificate *c,
222
    NSSTime *timeOpt, /* NULL for "now" */
223
    NSSUsage *usage,
224
    NSSPolicies *policiesOpt, /* NULL for none */
225
    void **rvOpt,             /* NULL for allocate */
226
    PRUint32 rvLimit,         /* zero for no limit */
227
    NSSArena *arenaOpt        /* NULL for heap */
228
)
229
0
{
230
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
231
0
    return NULL;
232
0
}
233
234
NSS_IMPLEMENT PRStatus
235
NSSCertificate_ValidateAndDiscoverUsagesAndPolicies(
236
    NSSCertificate *c,
237
    NSSTime **notBeforeOutOpt,
238
    NSSTime **notAfterOutOpt,
239
    void *allowedUsages,
240
    void *disallowedUsages,
241
    void *allowedPolicies,
242
    void *disallowedPolicies,
243
    /* more args.. work on this fgmr */
244
    NSSArena *arenaOpt)
245
0
{
246
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
247
0
    return PR_FAILURE;
248
0
}
249
250
NSS_IMPLEMENT NSSDER *
251
NSSCertificate_Encode(
252
    NSSCertificate *c,
253
    NSSDER *rvOpt,
254
    NSSArena *arenaOpt)
255
0
{
256
    /* Item, DER, BER are all typedefs now... */
257
0
    return nssItem_Duplicate((NSSItem *)&c->encoding, arenaOpt, rvOpt);
258
0
}
259
260
NSS_IMPLEMENT nssDecodedCert *
261
nssCertificate_GetDecoding(
262
    NSSCertificate *c)
263
10.8k
{
264
10.8k
    nssDecodedCert *deco = NULL;
265
10.8k
    if (c->type == NSSCertificateType_PKIX) {
266
0
        (void)STAN_GetCERTCertificate(c);
267
0
    }
268
10.8k
    nssPKIObject_Lock(&c->object);
269
10.8k
    if (!c->decoding) {
270
0
        deco = nssDecodedCert_Create(NULL, &c->encoding, c->type);
271
0
        PORT_Assert(!c->decoding);
272
0
        c->decoding = deco;
273
10.8k
    } else {
274
10.8k
        deco = c->decoding;
275
10.8k
    }
276
10.8k
    nssPKIObject_Unlock(&c->object);
277
10.8k
    return deco;
278
10.8k
}
279
280
static NSSCertificate **
281
filter_subject_certs_for_id(
282
    NSSCertificate **subjectCerts,
283
    void *id)
284
1.39k
{
285
1.39k
    NSSCertificate **si;
286
1.39k
    nssDecodedCert *dcp;
287
1.39k
    int nextOpenSlot = 0;
288
1.39k
    int i;
289
1.39k
    nssCertIDMatch matchLevel = nssCertIDMatch_Unknown;
290
1.39k
    nssCertIDMatch match;
291
292
    /* walk the subject certs */
293
2.78k
    for (si = subjectCerts; *si; si++) {
294
1.39k
        dcp = nssCertificate_GetDecoding(*si);
295
1.39k
        if (!dcp) {
296
0
            NSSCertificate_Destroy(*si);
297
0
            continue;
298
0
        }
299
1.39k
        match = dcp->matchIdentifier(dcp, id);
300
1.39k
        switch (match) {
301
123
            case nssCertIDMatch_Yes:
302
123
                if (matchLevel == nssCertIDMatch_Unknown) {
303
                    /* we have non-definitive matches, forget them */
304
123
                    for (i = 0; i < nextOpenSlot; i++) {
305
0
                        NSSCertificate_Destroy(subjectCerts[i]);
306
0
                        subjectCerts[i] = NULL;
307
0
                    }
308
123
                    nextOpenSlot = 0;
309
                    /* only keep definitive matches from now on */
310
123
                    matchLevel = nssCertIDMatch_Yes;
311
123
                }
312
                /* keep the cert */
313
123
                subjectCerts[nextOpenSlot++] = *si;
314
123
                break;
315
1.23k
            case nssCertIDMatch_Unknown:
316
1.23k
                if (matchLevel == nssCertIDMatch_Unknown) {
317
                    /* only have non-definitive matches so far, keep it */
318
1.23k
                    subjectCerts[nextOpenSlot++] = *si;
319
1.23k
                    break;
320
1.23k
                }
321
            /* else fall through, we have a definitive match already */
322
29
            case nssCertIDMatch_No:
323
29
            default:
324
29
                NSSCertificate_Destroy(*si);
325
29
                *si = NULL;
326
1.39k
        }
327
1.39k
    }
328
1.39k
    subjectCerts[nextOpenSlot] = NULL;
329
1.39k
    return subjectCerts;
330
1.39k
}
331
332
static NSSCertificate **
333
filter_certs_for_valid_issuers(NSSCertificate **certs)
334
1.39k
{
335
1.39k
    NSSCertificate **cp;
336
1.39k
    nssDecodedCert *dcp;
337
1.39k
    int nextOpenSlot = 0;
338
339
2.75k
    for (cp = certs; *cp; cp++) {
340
1.36k
        dcp = nssCertificate_GetDecoding(*cp);
341
1.36k
        if (dcp && dcp->isValidIssuer(dcp)) {
342
1.21k
            certs[nextOpenSlot++] = *cp;
343
1.21k
        } else {
344
147
            NSSCertificate_Destroy(*cp);
345
147
        }
346
1.36k
    }
347
1.39k
    certs[nextOpenSlot] = NULL;
348
1.39k
    return certs;
349
1.39k
}
350
351
static NSSCertificate *
352
find_cert_issuer(
353
    NSSCertificate *c,
354
    NSSTime *timeOpt,
355
    NSSUsage *usage,
356
    NSSPolicies *policiesOpt,
357
    NSSTrustDomain *td,
358
    NSSCryptoContext *cc)
359
3.49k
{
360
3.49k
    NSSArena *arena;
361
3.49k
    NSSCertificate **certs = NULL;
362
3.49k
    NSSCertificate **ccIssuers = NULL;
363
3.49k
    NSSCertificate **tdIssuers = NULL;
364
3.49k
    NSSCertificate *issuer = NULL;
365
366
3.49k
    if (!cc)
367
0
        cc = c->object.cryptoContext;
368
3.49k
    if (!td)
369
0
        td = NSSCertificate_GetTrustDomain(c);
370
3.49k
    arena = nssArena_Create();
371
3.49k
    if (!arena) {
372
0
        return (NSSCertificate *)NULL;
373
0
    }
374
3.49k
    if (cc) {
375
3.49k
        ccIssuers = nssCryptoContext_FindCertificatesBySubject(cc,
376
3.49k
                                                               &c->issuer,
377
3.49k
                                                               NULL,
378
3.49k
                                                               0,
379
3.49k
                                                               arena);
380
3.49k
    }
381
3.49k
    if (td)
382
3.49k
        tdIssuers = nssTrustDomain_FindCertificatesBySubject(td,
383
3.49k
                                                             &c->issuer,
384
3.49k
                                                             NULL,
385
3.49k
                                                             0,
386
3.49k
                                                             arena);
387
3.49k
    certs = nssCertificateArray_Join(ccIssuers, tdIssuers);
388
3.49k
    if (certs) {
389
1.39k
        nssDecodedCert *dc = NULL;
390
1.39k
        void *issuerID = NULL;
391
1.39k
        dc = nssCertificate_GetDecoding(c);
392
1.39k
        if (dc) {
393
1.39k
            issuerID = dc->getIssuerIdentifier(dc);
394
1.39k
        }
395
        /* XXX review based on CERT_FindCertIssuer
396
         * this function is not using the authCertIssuer field as a fallback
397
         * if authority key id does not exist
398
         */
399
1.39k
        if (issuerID) {
400
1.39k
            certs = filter_subject_certs_for_id(certs, issuerID);
401
1.39k
        }
402
1.39k
        certs = filter_certs_for_valid_issuers(certs);
403
1.39k
        issuer = nssCertificateArray_FindBestCertificate(certs,
404
1.39k
                                                         timeOpt,
405
1.39k
                                                         usage,
406
1.39k
                                                         policiesOpt);
407
1.39k
        nssCertificateArray_Destroy(certs);
408
1.39k
    }
409
3.49k
    nssArena_Destroy(arena);
410
3.49k
    return issuer;
411
3.49k
}
412
413
/* This function returns the built chain, as far as it gets,
414
** even if/when it fails to find an issuer, and returns PR_FAILURE
415
*/
416
NSS_IMPLEMENT NSSCertificate **
417
nssCertificate_BuildChain(
418
    NSSCertificate *c,
419
    NSSTime *timeOpt,
420
    NSSUsage *usage,
421
    NSSPolicies *policiesOpt,
422
    NSSCertificate **rvOpt,
423
    PRUint32 rvLimit,
424
    NSSArena *arenaOpt,
425
    PRStatus *statusOpt,
426
    NSSTrustDomain *td,
427
    NSSCryptoContext *cc)
428
7.25k
{
429
7.25k
    NSSCertificate **rvChain = NULL;
430
7.25k
    NSSUsage issuerUsage = *usage;
431
7.25k
    nssPKIObjectCollection *collection = NULL;
432
7.25k
    PRUint32 rvCount = 0;
433
7.25k
    PRStatus st;
434
7.25k
    PRStatus ret = PR_SUCCESS;
435
436
7.25k
    if (!c || !cc ||
437
7.25k
        (!td && (td = NSSCertificate_GetTrustDomain(c)) == NULL)) {
438
0
        goto loser;
439
0
    }
440
    /* bump the usage up to CA level */
441
7.25k
    issuerUsage.nss3lookingForCA = PR_TRUE;
442
7.25k
    collection = nssCertificateCollection_Create(td, NULL);
443
7.25k
    if (!collection)
444
0
        goto loser;
445
7.25k
    st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
446
7.25k
    if (st != PR_SUCCESS)
447
0
        goto loser;
448
8.46k
    for (rvCount = 1; (!rvLimit || rvCount < rvLimit); ++rvCount) {
449
7.25k
        CERTCertificate *cCert = STAN_GetCERTCertificate(c);
450
7.25k
        if (cCert->isRoot) {
451
            /* not including the issuer of the self-signed cert, which is,
452
             * of course, itself
453
             */
454
3.76k
            break;
455
3.76k
        }
456
3.49k
        c = find_cert_issuer(c, timeOpt, &issuerUsage, policiesOpt, td, cc);
457
3.49k
        if (!c) {
458
2.27k
            ret = PR_FAILURE;
459
2.27k
            break;
460
2.27k
        }
461
1.21k
        st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
462
1.21k
        nssCertificate_Destroy(c); /* collection has it */
463
1.21k
        if (st != PR_SUCCESS)
464
0
            goto loser;
465
1.21k
    }
466
7.25k
    rvChain = nssPKIObjectCollection_GetCertificates(collection,
467
7.25k
                                                     rvOpt,
468
7.25k
                                                     rvLimit,
469
7.25k
                                                     arenaOpt);
470
7.25k
    if (rvChain) {
471
7.25k
        nssPKIObjectCollection_Destroy(collection);
472
7.25k
        if (statusOpt)
473
7.24k
            *statusOpt = ret;
474
7.25k
        if (ret != PR_SUCCESS)
475
2.27k
            nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
476
7.25k
        return rvChain;
477
7.25k
    }
478
479
0
loser:
480
0
    if (collection)
481
0
        nssPKIObjectCollection_Destroy(collection);
482
0
    if (statusOpt)
483
0
        *statusOpt = PR_FAILURE;
484
0
    nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
485
0
    return rvChain;
486
7.25k
}
487
488
NSS_IMPLEMENT NSSCertificate **
489
NSSCertificate_BuildChain(
490
    NSSCertificate *c,
491
    NSSTime *timeOpt,
492
    NSSUsage *usage,
493
    NSSPolicies *policiesOpt,
494
    NSSCertificate **rvOpt,
495
    PRUint32 rvLimit, /* zero for no limit */
496
    NSSArena *arenaOpt,
497
    PRStatus *statusOpt,
498
    NSSTrustDomain *td,
499
    NSSCryptoContext *cc)
500
7.25k
{
501
7.25k
    return nssCertificate_BuildChain(c, timeOpt, usage, policiesOpt,
502
7.25k
                                     rvOpt, rvLimit, arenaOpt, statusOpt,
503
7.25k
                                     td, cc);
504
7.25k
}
505
506
NSS_IMPLEMENT NSSCryptoContext *
507
nssCertificate_GetCryptoContext(NSSCertificate *c)
508
0
{
509
0
    return c->object.cryptoContext;
510
0
}
511
512
NSS_IMPLEMENT NSSTrustDomain *
513
nssCertificate_GetTrustDomain(NSSCertificate *c)
514
0
{
515
0
    return c->object.trustDomain;
516
0
}
517
518
NSS_IMPLEMENT NSSTrustDomain *
519
NSSCertificate_GetTrustDomain(NSSCertificate *c)
520
0
{
521
0
    return nssCertificate_GetTrustDomain(c);
522
0
}
523
524
NSS_IMPLEMENT NSSToken *
525
NSSCertificate_GetToken(
526
    NSSCertificate *c,
527
    PRStatus *statusOpt)
528
0
{
529
0
    return (NSSToken *)NULL;
530
0
}
531
532
NSS_IMPLEMENT NSSSlot *
533
NSSCertificate_GetSlot(
534
    NSSCertificate *c,
535
    PRStatus *statusOpt)
536
0
{
537
0
    return (NSSSlot *)NULL;
538
0
}
539
540
NSS_IMPLEMENT NSSModule *
541
NSSCertificate_GetModule(
542
    NSSCertificate *c,
543
    PRStatus *statusOpt)
544
0
{
545
0
    return (NSSModule *)NULL;
546
0
}
547
548
NSS_IMPLEMENT NSSItem *
549
NSSCertificate_Encrypt(
550
    NSSCertificate *c,
551
    NSSAlgorithmAndParameters *apOpt,
552
    NSSItem *data,
553
    NSSTime *timeOpt,
554
    NSSUsage *usage,
555
    NSSPolicies *policiesOpt,
556
    NSSCallback *uhh,
557
    NSSItem *rvOpt,
558
    NSSArena *arenaOpt)
559
0
{
560
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
561
0
    return NULL;
562
0
}
563
564
NSS_IMPLEMENT PRStatus
565
NSSCertificate_Verify(
566
    NSSCertificate *c,
567
    NSSAlgorithmAndParameters *apOpt,
568
    NSSItem *data,
569
    NSSItem *signature,
570
    NSSTime *timeOpt,
571
    NSSUsage *usage,
572
    NSSPolicies *policiesOpt,
573
    NSSCallback *uhh)
574
0
{
575
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
576
0
    return PR_FAILURE;
577
0
}
578
579
NSS_IMPLEMENT NSSItem *
580
NSSCertificate_VerifyRecover(
581
    NSSCertificate *c,
582
    NSSAlgorithmAndParameters *apOpt,
583
    NSSItem *signature,
584
    NSSTime *timeOpt,
585
    NSSUsage *usage,
586
    NSSPolicies *policiesOpt,
587
    NSSCallback *uhh,
588
    NSSItem *rvOpt,
589
    NSSArena *arenaOpt)
590
0
{
591
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
592
0
    return NULL;
593
0
}
594
595
NSS_IMPLEMENT NSSItem *
596
NSSCertificate_WrapSymmetricKey(
597
    NSSCertificate *c,
598
    NSSAlgorithmAndParameters *apOpt,
599
    NSSSymmetricKey *keyToWrap,
600
    NSSTime *timeOpt,
601
    NSSUsage *usage,
602
    NSSPolicies *policiesOpt,
603
    NSSCallback *uhh,
604
    NSSItem *rvOpt,
605
    NSSArena *arenaOpt)
606
0
{
607
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
608
0
    return NULL;
609
0
}
610
611
NSS_IMPLEMENT NSSCryptoContext *
612
NSSCertificate_CreateCryptoContext(
613
    NSSCertificate *c,
614
    NSSAlgorithmAndParameters *apOpt,
615
    NSSTime *timeOpt,
616
    NSSUsage *usage,
617
    NSSPolicies *policiesOpt,
618
    NSSCallback *uhh)
619
0
{
620
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
621
0
    return NULL;
622
0
}
623
624
NSS_IMPLEMENT NSSPublicKey *
625
NSSCertificate_GetPublicKey(
626
    NSSCertificate *c)
627
0
{
628
#if 0
629
    CK_ATTRIBUTE pubktemplate[] = {
630
    { CKA_CLASS,   NULL, 0 },
631
    { CKA_ID,      NULL, 0 },
632
    { CKA_SUBJECT, NULL, 0 }
633
    };
634
    PRStatus nssrv;
635
    CK_ULONG count = sizeof(pubktemplate) / sizeof(pubktemplate[0]);
636
    NSS_CK_SET_ATTRIBUTE_ITEM(pubktemplate, 0, &g_ck_class_pubkey);
637
    if (c->id.size > 0) {
638
    /* CKA_ID */
639
    NSS_CK_ITEM_TO_ATTRIBUTE(&c->id, &pubktemplate[1]);
640
    } else {
641
    /* failure, yes? */
642
    return (NSSPublicKey *)NULL;
643
    }
644
    if (c->subject.size > 0) {
645
    /* CKA_SUBJECT */
646
    NSS_CK_ITEM_TO_ATTRIBUTE(&c->subject, &pubktemplate[2]);
647
    } else {
648
    /* failure, yes? */
649
    return (NSSPublicKey *)NULL;
650
    }
651
    /* Try the cert's token first */
652
    if (c->token) {
653
    nssrv = nssToken_FindObjectByTemplate(c->token, pubktemplate, count);
654
    }
655
#endif
656
    /* Try all other key tokens */
657
0
    return (NSSPublicKey *)NULL;
658
0
}
659
660
NSS_IMPLEMENT NSSPrivateKey *
661
NSSCertificate_FindPrivateKey(
662
    NSSCertificate *c,
663
    NSSCallback *uhh)
664
0
{
665
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
666
0
    return NULL;
667
0
}
668
669
NSS_IMPLEMENT PRBool
670
NSSCertificate_IsPrivateKeyAvailable(
671
    NSSCertificate *c,
672
    NSSCallback *uhh,
673
    PRStatus *statusOpt)
674
0
{
675
0
    PRBool isUser = PR_FALSE;
676
0
    nssCryptokiObject **ip;
677
0
    nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
678
0
    if (!instances) {
679
0
        return PR_FALSE;
680
0
    }
681
0
    for (ip = instances; *ip; ip++) {
682
0
        nssCryptokiObject *instance = *ip;
683
0
        if (nssToken_IsPrivateKeyAvailable(instance->token, c, instance)) {
684
0
            isUser = PR_TRUE;
685
0
        }
686
0
    }
687
0
    nssCryptokiObjectArray_Destroy(instances);
688
0
    return isUser;
689
0
}
690
691
/* sort the subject cert list from newest to oldest */
692
PRIntn
693
nssCertificate_SubjectListSort(
694
    void *v1,
695
    void *v2)
696
2.77k
{
697
2.77k
    NSSCertificate *c1 = (NSSCertificate *)v1;
698
2.77k
    NSSCertificate *c2 = (NSSCertificate *)v2;
699
2.77k
    nssDecodedCert *dc1 = nssCertificate_GetDecoding(c1);
700
2.77k
    nssDecodedCert *dc2 = nssCertificate_GetDecoding(c2);
701
2.77k
    if (!dc1) {
702
0
        return dc2 ? 1 : 0;
703
2.77k
    } else if (!dc2) {
704
0
        return -1;
705
2.77k
    } else {
706
2.77k
        return dc1->isNewerThan(dc1, dc2) ? -1 : 1;
707
2.77k
    }
708
2.77k
}
709
710
NSS_IMPLEMENT PRBool
711
NSSUserCertificate_IsStillPresent(
712
    NSSUserCertificate *uc,
713
    PRStatus *statusOpt)
714
0
{
715
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
716
0
    return PR_FALSE;
717
0
}
718
719
NSS_IMPLEMENT NSSItem *
720
NSSUserCertificate_Decrypt(
721
    NSSUserCertificate *uc,
722
    NSSAlgorithmAndParameters *apOpt,
723
    NSSItem *data,
724
    NSSTime *timeOpt,
725
    NSSUsage *usage,
726
    NSSPolicies *policiesOpt,
727
    NSSCallback *uhh,
728
    NSSItem *rvOpt,
729
    NSSArena *arenaOpt)
730
0
{
731
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
732
0
    return NULL;
733
0
}
734
735
NSS_IMPLEMENT NSSItem *
736
NSSUserCertificate_Sign(
737
    NSSUserCertificate *uc,
738
    NSSAlgorithmAndParameters *apOpt,
739
    NSSItem *data,
740
    NSSTime *timeOpt,
741
    NSSUsage *usage,
742
    NSSPolicies *policiesOpt,
743
    NSSCallback *uhh,
744
    NSSItem *rvOpt,
745
    NSSArena *arenaOpt)
746
0
{
747
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
748
0
    return NULL;
749
0
}
750
751
NSS_IMPLEMENT NSSItem *
752
NSSUserCertificate_SignRecover(
753
    NSSUserCertificate *uc,
754
    NSSAlgorithmAndParameters *apOpt,
755
    NSSItem *data,
756
    NSSTime *timeOpt,
757
    NSSUsage *usage,
758
    NSSPolicies *policiesOpt,
759
    NSSCallback *uhh,
760
    NSSItem *rvOpt,
761
    NSSArena *arenaOpt)
762
0
{
763
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
764
0
    return NULL;
765
0
}
766
767
NSS_IMPLEMENT NSSSymmetricKey *
768
NSSUserCertificate_UnwrapSymmetricKey(
769
    NSSUserCertificate *uc,
770
    NSSAlgorithmAndParameters *apOpt,
771
    NSSItem *wrappedKey,
772
    NSSTime *timeOpt,
773
    NSSUsage *usage,
774
    NSSPolicies *policiesOpt,
775
    NSSCallback *uhh,
776
    NSSItem *rvOpt,
777
    NSSArena *arenaOpt)
778
0
{
779
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
780
0
    return NULL;
781
0
}
782
783
NSS_IMPLEMENT NSSSymmetricKey *
784
NSSUserCertificate_DeriveSymmetricKey(
785
    NSSUserCertificate *uc, /* provides private key */
786
    NSSCertificate *c,      /* provides public key */
787
    NSSAlgorithmAndParameters *apOpt,
788
    NSSOID *target,
789
    PRUint32 keySizeOpt, /* zero for best allowed */
790
    NSSOperations operations,
791
    NSSCallback *uhh)
792
0
{
793
0
    nss_SetError(NSS_ERROR_NOT_FOUND);
794
0
    return NULL;
795
0
}
796
797
NSS_IMPLEMENT nssSMIMEProfile *
798
nssSMIMEProfile_Create(
799
    NSSCertificate *cert,
800
    NSSItem *profileTime,
801
    NSSItem *profileData)
802
0
{
803
0
    NSSArena *arena;
804
0
    nssSMIMEProfile *rvProfile;
805
0
    nssPKIObject *object;
806
0
    NSSTrustDomain *td = nssCertificate_GetTrustDomain(cert);
807
0
    NSSCryptoContext *cc = nssCertificate_GetCryptoContext(cert);
808
0
    arena = nssArena_Create();
809
0
    if (!arena) {
810
0
        return NULL;
811
0
    }
812
0
    object = nssPKIObject_Create(arena, NULL, td, cc, nssPKILock);
813
0
    if (!object) {
814
0
        goto loser;
815
0
    }
816
0
    rvProfile = nss_ZNEW(arena, nssSMIMEProfile);
817
0
    if (!rvProfile) {
818
0
        goto loser;
819
0
    }
820
0
    rvProfile->object = *object;
821
0
    rvProfile->certificate = cert;
822
0
    rvProfile->email = nssUTF8_Duplicate(cert->email, arena);
823
0
    rvProfile->subject = nssItem_Duplicate(&cert->subject, arena, NULL);
824
0
    if (profileTime) {
825
0
        rvProfile->profileTime = nssItem_Duplicate(profileTime, arena, NULL);
826
0
    }
827
0
    if (profileData) {
828
0
        rvProfile->profileData = nssItem_Duplicate(profileData, arena, NULL);
829
0
    }
830
0
    return rvProfile;
831
0
loser:
832
0
    if (object)
833
0
        nssPKIObject_Destroy(object);
834
0
    else if (arena)
835
0
        nssArena_Destroy(arena);
836
0
    return (nssSMIMEProfile *)NULL;
837
0
}
838
839
/* execute a callback function on all members of a cert list */
840
NSS_EXTERN PRStatus
841
nssCertificateList_DoCallback(
842
    nssList *certList,
843
    PRStatus (*callback)(NSSCertificate *c, void *arg),
844
    void *arg)
845
1.39k
{
846
1.39k
    nssListIterator *certs;
847
1.39k
    NSSCertificate *cert;
848
1.39k
    certs = nssList_CreateIterator(certList);
849
1.39k
    if (!certs) {
850
0
        return PR_FAILURE;
851
0
    }
852
1.39k
    for (cert = (NSSCertificate *)nssListIterator_Start(certs);
853
2.78k
         cert != (NSSCertificate *)NULL;
854
1.39k
         cert = (NSSCertificate *)nssListIterator_Next(certs)) {
855
1.39k
        (void)(*callback)(cert, arg);
856
1.39k
    }
857
1.39k
    nssListIterator_Finish(certs);
858
1.39k
    nssListIterator_Destroy(certs);
859
1.39k
    return PR_SUCCESS;
860
1.39k
}
861
862
static PRStatus
863
add_ref_callback(NSSCertificate *c, void *a)
864
1.39k
{
865
1.39k
    nssCertificate_AddRef(c);
866
1.39k
    return PR_SUCCESS;
867
1.39k
}
868
869
NSS_IMPLEMENT void
870
nssCertificateList_AddReferences(
871
    nssList *certList)
872
1.39k
{
873
1.39k
    (void)nssCertificateList_DoCallback(certList, add_ref_callback, NULL);
874
1.39k
}
875
876
/*
877
 * Is this trust record safe to apply to all certs of the same issuer/SN
878
 * independent of the cert matching the hash. This is only true is the trust
879
 * is unknown or distrusted. In general this feature is only useful to
880
 * explicitly distrusting certs. It is not safe to use to trust certs, so
881
 * only allow unknown and untrusted trust types.
882
 */
883
PRBool
884
nssTrust_IsSafeToIgnoreCertHash(nssTrustLevel serverAuth,
885
                                nssTrustLevel clientAuth, nssTrustLevel codeSigning,
886
                                nssTrustLevel email, PRBool stepup)
887
0
{
888
    /* step up is a trust type, if it's on, we must have a hash for the cert */
889
0
    if (stepup) {
890
0
        return PR_FALSE;
891
0
    }
892
0
    if ((serverAuth != nssTrustLevel_Unknown) &&
893
0
        (serverAuth != nssTrustLevel_NotTrusted)) {
894
0
        return PR_FALSE;
895
0
    }
896
0
    if ((clientAuth != nssTrustLevel_Unknown) &&
897
0
        (clientAuth != nssTrustLevel_NotTrusted)) {
898
0
        return PR_FALSE;
899
0
    }
900
0
    if ((codeSigning != nssTrustLevel_Unknown) &&
901
0
        (codeSigning != nssTrustLevel_NotTrusted)) {
902
0
        return PR_FALSE;
903
0
    }
904
0
    if ((email != nssTrustLevel_Unknown) &&
905
0
        (email != nssTrustLevel_NotTrusted)) {
906
0
        return PR_FALSE;
907
0
    }
908
    /* record only has Unknown and Untrusted entries, ok to accept without a
909
     * hash */
910
0
    return PR_TRUE;
911
0
}
912
913
/* verify that hash and mechanism matches certifcate. This function
914
 * uses hashCache and hashCacheMech from the caller to allow us to
915
 * use previous calculated hash values if they are the same */
916
static PRBool
917
nssTrust_isValidHash(const NSSItem *hash, CK_MECHANISM_TYPE hashMech,
918
                     NSSItem *cert, NSSItem *hashCache,
919
                     CK_MECHANISM_TYPE *hashCacheMech)
920
0
{
921
0
    if ((hashMech == CKM_INVALID_MECHANISM) || (hash->size == 0)) {
922
0
        return PR_FALSE;
923
0
    }
924
0
    if (*hashCacheMech != hashMech) {
925
        /* the cache doesn't have the correct mech, get a
926
         * new hash for the cert */
927
0
        hashCache->size = HASH_LENGTH_MAX;
928
0
        PRStatus ret = NSSAlgorithm_DigestBuf(hashMech, cert, hashCache);
929
0
        if (ret != PR_SUCCESS) {
930
0
            *hashCacheMech = CKM_INVALID_MECHANISM;
931
0
            return PR_FALSE;
932
0
        }
933
0
        *hashCacheMech = hashMech;
934
0
    }
935
0
    return ((hash->size == hashCache->size) && (PORT_Memcmp(hash->data,
936
0
                                                            hashCache->data,
937
0
                                                            hash->size) == 0));
938
0
}
939
940
NSS_IMPLEMENT NSSTrust *
941
nssTrust_Create(
942
    nssPKIObject *object,
943
    NSSItem *certData)
944
0
{
945
0
    PRStatus status;
946
0
    PRUint32 i;
947
0
    PRUint32 lastTrustOrder, myTrustOrder;
948
0
    unsigned char hashCacheBuf[HASH_LENGTH_MAX];
949
0
    unsigned char hashAttrBuf[HASH_LENGTH_MAX];
950
0
    NSSItem hashAttr = { hashAttrBuf, sizeof(hashAttrBuf) };
951
0
    NSSItem hashCache = { hashCacheBuf, sizeof(hashCacheBuf) };
952
0
    NSSTrust *rvt;
953
0
    CK_MECHANISM_TYPE hashMech = CKM_INVALID_MECHANISM;
954
0
    CK_MECHANISM_TYPE hashCacheMech = CKM_INVALID_MECHANISM;
955
0
    nssCryptokiObject *instance;
956
0
    nssTrustLevel serverAuth, clientAuth, codeSigning, emailProtection;
957
0
    PRBool stepUp;
958
959
0
    lastTrustOrder = 1 << 16; /* just make it big */
960
0
    PR_ASSERT(object->instances != NULL && object->numInstances > 0);
961
0
    rvt = nss_ZNEW(object->arena, NSSTrust);
962
0
    if (!rvt) {
963
0
        return (NSSTrust *)NULL;
964
0
    }
965
0
    rvt->object = *object;
966
967
    /* trust has to peek into the base object members */
968
0
    nssPKIObject_Lock(object);
969
0
    for (i = 0; i < object->numInstances; i++) {
970
0
        hashAttr.size = sizeof(hashAttrBuf); /* reset to allocated size */
971
0
        instance = object->instances[i];
972
0
        myTrustOrder = nssToken_GetTrustOrder(instance->token);
973
0
        status = nssCryptokiTrust_GetAttributes(instance, NULL,
974
0
                                                &hashAttr,
975
0
                                                &hashMech,
976
0
                                                &serverAuth,
977
0
                                                &clientAuth,
978
0
                                                &codeSigning,
979
0
                                                &emailProtection,
980
0
                                                &stepUp);
981
0
        if (status != PR_SUCCESS) {
982
0
            nssPKIObject_Unlock(object);
983
0
            return (NSSTrust *)NULL;
984
0
        }
985
        /* if no hash is specified, then trust applies to all certs with
986
         * this issuer/SN. NOTE: This is only true for entries that
987
         * have distrust and unknown record */
988
0
        if (!(
989
                /* we continue if there is no hash, and the trust type is
990
                 * safe to accept without a hash ... or ... */
991
0
                (((hashAttr.size == 0) || (hashMech == CKM_INVALID_MECHANISM)) &&
992
0
                 nssTrust_IsSafeToIgnoreCertHash(serverAuth, clientAuth,
993
0
                                                 codeSigning, emailProtection,
994
0
                                                 stepUp)) ||
995
                /* we have a hash of the correct size, and it matches */
996
0
                nssTrust_isValidHash(&hashAttr, hashMech, certData,
997
0
                                     &hashCache, &hashCacheMech))) {
998
999
0
            nssPKIObject_Unlock(object);
1000
0
            return (NSSTrust *)NULL;
1001
0
        }
1002
0
        if (rvt->serverAuth == nssTrustLevel_Unknown ||
1003
0
            myTrustOrder < lastTrustOrder) {
1004
0
            rvt->serverAuth = serverAuth;
1005
0
        }
1006
0
        if (rvt->clientAuth == nssTrustLevel_Unknown ||
1007
0
            myTrustOrder < lastTrustOrder) {
1008
0
            rvt->clientAuth = clientAuth;
1009
0
        }
1010
0
        if (rvt->emailProtection == nssTrustLevel_Unknown ||
1011
0
            myTrustOrder < lastTrustOrder) {
1012
0
            rvt->emailProtection = emailProtection;
1013
0
        }
1014
0
        if (rvt->codeSigning == nssTrustLevel_Unknown ||
1015
0
            myTrustOrder < lastTrustOrder) {
1016
0
            rvt->codeSigning = codeSigning;
1017
0
        }
1018
0
        rvt->stepUpApproved = stepUp;
1019
0
        lastTrustOrder = myTrustOrder;
1020
0
    }
1021
0
    nssPKIObject_Unlock(object);
1022
0
    return rvt;
1023
0
}
1024
1025
NSS_IMPLEMENT NSSTrust *
1026
nssTrust_AddRef(NSSTrust *trust)
1027
0
{
1028
0
    if (trust) {
1029
0
        nssPKIObject_AddRef(&trust->object);
1030
0
    }
1031
0
    return trust;
1032
0
}
1033
1034
NSS_IMPLEMENT PRStatus
1035
nssTrust_Destroy(NSSTrust *trust)
1036
0
{
1037
0
    if (trust) {
1038
0
        (void)nssPKIObject_Destroy(&trust->object);
1039
0
    }
1040
0
    return PR_SUCCESS;
1041
0
}
1042
1043
NSS_IMPLEMENT nssSMIMEProfile *
1044
nssSMIMEProfile_AddRef(nssSMIMEProfile *profile)
1045
0
{
1046
0
    if (profile) {
1047
0
        nssPKIObject_AddRef(&profile->object);
1048
0
    }
1049
0
    return profile;
1050
0
}
1051
1052
NSS_IMPLEMENT PRStatus
1053
nssSMIMEProfile_Destroy(nssSMIMEProfile *profile)
1054
0
{
1055
0
    if (profile) {
1056
0
        (void)nssPKIObject_Destroy(&profile->object);
1057
0
    }
1058
0
    return PR_SUCCESS;
1059
0
}
1060
1061
NSS_IMPLEMENT NSSCRL *
1062
nssCRL_Create(nssPKIObject *object)
1063
0
{
1064
0
    PRStatus status;
1065
0
    NSSCRL *rvCRL;
1066
0
    NSSArena *arena = object->arena;
1067
0
    PR_ASSERT(object->instances != NULL && object->numInstances > 0);
1068
0
    rvCRL = nss_ZNEW(arena, NSSCRL);
1069
0
    if (!rvCRL) {
1070
0
        return (NSSCRL *)NULL;
1071
0
    }
1072
0
    rvCRL->object = *object;
1073
    /* XXX should choose instance based on some criteria */
1074
0
    status = nssCryptokiCRL_GetAttributes(object->instances[0],
1075
0
                                          NULL, /* XXX sessionOpt */
1076
0
                                          arena,
1077
0
                                          &rvCRL->encoding,
1078
0
                                          NULL, /* subject */
1079
0
                                          NULL, /* class */
1080
0
                                          &rvCRL->url,
1081
0
                                          &rvCRL->isKRL);
1082
0
    if (status != PR_SUCCESS) {
1083
0
        if (!arena) {
1084
0
            nssPKIObject_Destroy((nssPKIObject *)rvCRL);
1085
0
        }
1086
0
        return (NSSCRL *)NULL;
1087
0
    }
1088
0
    return rvCRL;
1089
0
}
1090
1091
NSS_IMPLEMENT NSSCRL *
1092
nssCRL_AddRef(NSSCRL *crl)
1093
0
{
1094
0
    if (crl) {
1095
0
        nssPKIObject_AddRef(&crl->object);
1096
0
    }
1097
0
    return crl;
1098
0
}
1099
1100
NSS_IMPLEMENT PRStatus
1101
nssCRL_Destroy(NSSCRL *crl)
1102
0
{
1103
0
    if (crl) {
1104
0
        (void)nssPKIObject_Destroy(&crl->object);
1105
0
    }
1106
0
    return PR_SUCCESS;
1107
0
}
1108
1109
NSS_IMPLEMENT PRStatus
1110
nssCRL_DeleteStoredObject(
1111
    NSSCRL *crl,
1112
    NSSCallback *uhh)
1113
0
{
1114
0
    return nssPKIObject_DeleteStoredObject(&crl->object, uhh, PR_TRUE);
1115
0
}
1116
1117
NSS_IMPLEMENT NSSDER *
1118
nssCRL_GetEncoding(NSSCRL *crl)
1119
0
{
1120
0
    if (crl && crl->encoding.data != NULL && crl->encoding.size > 0) {
1121
0
        return &crl->encoding;
1122
0
    } else {
1123
        return (NSSDER *)NULL;
1124
0
    }
1125
0
}