Coverage Report

Created: 2025-07-01 06:25

/src/nss/lib/certdb/certdb.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
/*
6
 * Certificate handling code
7
 */
8
9
#include "nssilock.h"
10
#include "prmon.h"
11
#include "prtime.h"
12
#include "cert.h"
13
#include "certi.h"
14
#include "secder.h"
15
#include "secoid.h"
16
#include "secasn1.h"
17
#include "genname.h"
18
#include "keyhi.h"
19
#include "secitem.h"
20
#include "certdb.h"
21
#include "prprf.h"
22
#include "sechash.h"
23
#include "prlong.h"
24
#include "certxutl.h"
25
#include "portreg.h"
26
#include "secerr.h"
27
#include "sslerr.h"
28
#include "pk11func.h"
29
#include "xconst.h" /* for  CERT_DecodeAltNameExtension */
30
31
#include "pki.h"
32
#include "pki3hack.h"
33
34
SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
35
SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
36
SEC_ASN1_MKSUB(SEC_BitStringTemplate)
37
SEC_ASN1_MKSUB(SEC_IntegerTemplate)
38
SEC_ASN1_MKSUB(SEC_SkipTemplate)
39
40
/*
41
 * Certificate database handling code
42
 */
43
44
const SEC_ASN1Template CERT_CertExtensionTemplate[] = {
45
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertExtension) },
46
    { SEC_ASN1_OBJECT_ID, offsetof(CERTCertExtension, id) },
47
    { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
48
      offsetof(CERTCertExtension, critical) },
49
    { SEC_ASN1_OCTET_STRING, offsetof(CERTCertExtension, value) },
50
    { 0 }
51
};
52
53
const SEC_ASN1Template CERT_SequenceOfCertExtensionTemplate[] = {
54
    { SEC_ASN1_SEQUENCE_OF, 0, CERT_CertExtensionTemplate }
55
};
56
57
const SEC_ASN1Template CERT_TimeChoiceTemplate[] = {
58
    { SEC_ASN1_CHOICE, offsetof(SECItem, type), 0, sizeof(SECItem) },
59
    { SEC_ASN1_UTC_TIME, 0, 0, siUTCTime },
60
    { SEC_ASN1_GENERALIZED_TIME, 0, 0, siGeneralizedTime },
61
    { 0 }
62
};
63
64
const SEC_ASN1Template CERT_ValidityTemplate[] = {
65
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTValidity) },
66
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTValidity, notBefore),
67
      SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 },
68
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTValidity, notAfter),
69
      SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 },
70
    { 0 }
71
};
72
73
const SEC_ASN1Template CERT_CertificateTemplate[] = {
74
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificate) },
75
    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
76
          SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, /* XXX DER_DEFAULT */
77
      offsetof(CERTCertificate, version),
78
      SEC_ASN1_SUB(SEC_IntegerTemplate) },
79
    { SEC_ASN1_INTEGER, offsetof(CERTCertificate, serialNumber) },
80
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCertificate, signature),
81
      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
82
    { SEC_ASN1_SAVE, offsetof(CERTCertificate, derIssuer) },
83
    { SEC_ASN1_INLINE, offsetof(CERTCertificate, issuer), CERT_NameTemplate },
84
    { SEC_ASN1_INLINE, offsetof(CERTCertificate, validity),
85
      CERT_ValidityTemplate },
86
    { SEC_ASN1_SAVE, offsetof(CERTCertificate, derSubject) },
87
    { SEC_ASN1_INLINE, offsetof(CERTCertificate, subject), CERT_NameTemplate },
88
    { SEC_ASN1_SAVE, offsetof(CERTCertificate, derPublicKey) },
89
    { SEC_ASN1_INLINE, offsetof(CERTCertificate, subjectPublicKeyInfo),
90
      CERT_SubjectPublicKeyInfoTemplate },
91
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
92
      offsetof(CERTCertificate, issuerID),
93
      SEC_ASN1_SUB(SEC_BitStringTemplate) },
94
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
95
      offsetof(CERTCertificate, subjectID),
96
      SEC_ASN1_SUB(SEC_BitStringTemplate) },
97
    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
98
          SEC_ASN1_CONTEXT_SPECIFIC | 3,
99
      offsetof(CERTCertificate, extensions),
100
      CERT_SequenceOfCertExtensionTemplate },
101
    { 0 }
102
};
103
104
const SEC_ASN1Template SEC_SignedCertificateTemplate[] = {
105
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificate) },
106
    { SEC_ASN1_SAVE, offsetof(CERTCertificate, signatureWrap.data) },
107
    { SEC_ASN1_INLINE, 0, CERT_CertificateTemplate },
108
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
109
      offsetof(CERTCertificate, signatureWrap.signatureAlgorithm),
110
      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
111
    { SEC_ASN1_BIT_STRING, offsetof(CERTCertificate, signatureWrap.signature) },
112
    { 0 }
113
};
114
115
/*
116
 * Find the subjectName in a DER encoded certificate
117
 */
118
const SEC_ASN1Template SEC_CertSubjectTemplate[] = {
119
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
120
    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
121
          SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
122
      0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
123
    { SEC_ASN1_SKIP },                     /* serial number */
124
    { SEC_ASN1_SKIP },                     /* signature algorithm */
125
    { SEC_ASN1_SKIP },                     /* issuer */
126
    { SEC_ASN1_SKIP },                     /* validity */
127
    { SEC_ASN1_ANY, 0, NULL },             /* subject */
128
    { SEC_ASN1_SKIP_REST },
129
    { 0 }
130
};
131
132
/*
133
 * Find the issuerName in a DER encoded certificate
134
 */
135
const SEC_ASN1Template SEC_CertIssuerTemplate[] = {
136
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
137
    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
138
          SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
139
      0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
140
    { SEC_ASN1_SKIP },                     /* serial number */
141
    { SEC_ASN1_SKIP },                     /* signature algorithm */
142
    { SEC_ASN1_ANY, 0, NULL },             /* issuer */
143
    { SEC_ASN1_SKIP_REST },
144
    { 0 }
145
};
146
/*
147
 * Find the subjectName in a DER encoded certificate
148
 */
149
const SEC_ASN1Template SEC_CertSerialNumberTemplate[] = {
150
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
151
    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
152
          SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
153
      0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
154
    { SEC_ASN1_ANY, 0, NULL },             /* serial number */
155
    { SEC_ASN1_SKIP_REST },
156
    { 0 }
157
};
158
159
/*
160
 * Find the issuer and serialNumber in a DER encoded certificate.
161
 * This data is used as the database lookup key since its the unique
162
 * identifier of a certificate.
163
 */
164
const SEC_ASN1Template CERT_CertKeyTemplate[] = {
165
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertKey) },
166
    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
167
          SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
168
      0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
169
    { SEC_ASN1_INTEGER, offsetof(CERTCertKey, serialNumber) },
170
    { SEC_ASN1_SKIP }, /* signature algorithm */
171
    { SEC_ASN1_ANY, offsetof(CERTCertKey, derIssuer) },
172
    { SEC_ASN1_SKIP_REST },
173
    { 0 }
174
};
175
176
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_TimeChoiceTemplate)
177
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateTemplate)
178
SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SignedCertificateTemplate)
179
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SequenceOfCertExtensionTemplate)
180
181
SECStatus
182
CERT_KeyFromIssuerAndSN(PLArenaPool *arena, SECItem *issuer, SECItem *sn,
183
                        SECItem *key)
184
0
{
185
0
    key->len = sn->len + issuer->len;
186
187
0
    if ((sn->data == NULL) || (issuer->data == NULL)) {
188
0
        goto loser;
189
0
    }
190
191
0
    key->data = (unsigned char *)PORT_ArenaAlloc(arena, key->len);
192
0
    if (!key->data) {
193
0
        goto loser;
194
0
    }
195
196
    /* copy the serialNumber */
197
0
    PORT_Memcpy(key->data, sn->data, sn->len);
198
199
    /* copy the issuer */
200
0
    PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
201
202
0
    return (SECSuccess);
203
204
0
loser:
205
0
    return (SECFailure);
206
0
}
207
208
/*
209
 * Extract the subject name from a DER certificate
210
 */
211
SECStatus
212
CERT_NameFromDERCert(SECItem *derCert, SECItem *derName)
213
0
{
214
0
    int rv;
215
0
    PLArenaPool *arena;
216
0
    CERTSignedData sd;
217
0
    void *tmpptr;
218
219
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
220
221
0
    if (!arena) {
222
0
        return (SECFailure);
223
0
    }
224
225
0
    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
226
0
    rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
227
228
0
    if (rv) {
229
0
        goto loser;
230
0
    }
231
232
0
    PORT_Memset(derName, 0, sizeof(SECItem));
233
0
    rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSubjectTemplate,
234
0
                                &sd.data);
235
236
0
    if (rv) {
237
0
        goto loser;
238
0
    }
239
240
0
    tmpptr = derName->data;
241
0
    derName->data = (unsigned char *)PORT_Alloc(derName->len);
242
0
    if (derName->data == NULL) {
243
0
        goto loser;
244
0
    }
245
246
0
    PORT_Memcpy(derName->data, tmpptr, derName->len);
247
248
0
    PORT_FreeArena(arena, PR_FALSE);
249
0
    return (SECSuccess);
250
251
0
loser:
252
0
    PORT_FreeArena(arena, PR_FALSE);
253
0
    return (SECFailure);
254
0
}
255
256
SECStatus
257
CERT_IssuerNameFromDERCert(SECItem *derCert, SECItem *derName)
258
0
{
259
0
    int rv;
260
0
    PORTCheapArenaPool tmpArena;
261
0
    CERTSignedData sd;
262
0
    void *tmpptr;
263
264
0
    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
265
266
0
    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
267
0
    rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &sd, CERT_SignedDataTemplate,
268
0
                                derCert);
269
0
    if (rv) {
270
0
        goto loser;
271
0
    }
272
273
0
    PORT_Memset(derName, 0, sizeof(SECItem));
274
0
    rv = SEC_QuickDERDecodeItem(&tmpArena.arena, derName,
275
0
                                SEC_CertIssuerTemplate, &sd.data);
276
0
    if (rv) {
277
0
        goto loser;
278
0
    }
279
280
0
    tmpptr = derName->data;
281
0
    derName->data = (unsigned char *)PORT_Alloc(derName->len);
282
0
    if (derName->data == NULL) {
283
0
        goto loser;
284
0
    }
285
286
0
    PORT_Memcpy(derName->data, tmpptr, derName->len);
287
288
0
    PORT_DestroyCheapArena(&tmpArena);
289
0
    return (SECSuccess);
290
291
0
loser:
292
0
    PORT_DestroyCheapArena(&tmpArena);
293
0
    return (SECFailure);
294
0
}
295
296
SECStatus
297
CERT_SerialNumberFromDERCert(SECItem *derCert, SECItem *derName)
298
0
{
299
0
    int rv;
300
0
    PORTCheapArenaPool tmpArena;
301
0
    CERTSignedData sd;
302
0
    void *tmpptr;
303
304
0
    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
305
306
0
    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
307
0
    rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &sd, CERT_SignedDataTemplate,
308
0
                                derCert);
309
0
    if (rv) {
310
0
        goto loser;
311
0
    }
312
313
0
    PORT_Memset(derName, 0, sizeof(SECItem));
314
0
    rv = SEC_QuickDERDecodeItem(&tmpArena.arena, derName,
315
0
                                SEC_CertSerialNumberTemplate, &sd.data);
316
0
    if (rv) {
317
0
        goto loser;
318
0
    }
319
320
0
    tmpptr = derName->data;
321
0
    derName->data = (unsigned char *)PORT_Alloc(derName->len);
322
0
    if (derName->data == NULL) {
323
0
        goto loser;
324
0
    }
325
326
0
    PORT_Memcpy(derName->data, tmpptr, derName->len);
327
328
0
    PORT_DestroyCheapArena(&tmpArena);
329
0
    return (SECSuccess);
330
331
0
loser:
332
0
    PORT_DestroyCheapArena(&tmpArena);
333
0
    return (SECFailure);
334
0
}
335
336
/*
337
 * Generate a database key, based on serial number and issuer, from a
338
 * DER certificate.
339
 */
340
SECStatus
341
CERT_KeyFromDERCert(PLArenaPool *reqArena, SECItem *derCert, SECItem *key)
342
0
{
343
0
    int rv;
344
0
    CERTSignedData sd;
345
0
    CERTCertKey certkey;
346
347
0
    if (!reqArena) {
348
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
349
0
        return SECFailure;
350
0
    }
351
352
0
    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
353
0
    rv =
354
0
        SEC_QuickDERDecodeItem(reqArena, &sd, CERT_SignedDataTemplate, derCert);
355
356
0
    if (rv) {
357
0
        goto loser;
358
0
    }
359
360
0
    PORT_Memset(&certkey, 0, sizeof(CERTCertKey));
361
0
    rv = SEC_QuickDERDecodeItem(reqArena, &certkey, CERT_CertKeyTemplate,
362
0
                                &sd.data);
363
364
0
    if (rv) {
365
0
        goto loser;
366
0
    }
367
368
0
    return (CERT_KeyFromIssuerAndSN(reqArena, &certkey.derIssuer,
369
0
                                    &certkey.serialNumber, key));
370
0
loser:
371
0
    return (SECFailure);
372
0
}
373
374
/*
375
 * fill in keyUsage field of the cert based on the cert extension
376
 * if the extension is not critical, then we allow all uses
377
 */
378
static SECStatus
379
GetKeyUsage(CERTCertificate *cert)
380
0
{
381
0
    SECStatus rv;
382
0
    SECItem tmpitem;
383
384
0
    rv = CERT_FindKeyUsageExtension(cert, &tmpitem);
385
0
    if (rv == SECSuccess) {
386
        /* remember the actual value of the extension */
387
0
        cert->rawKeyUsage = tmpitem.len ? tmpitem.data[0] : 0;
388
0
        cert->keyUsagePresent = PR_TRUE;
389
0
        cert->keyUsage = cert->rawKeyUsage;
390
391
0
        PORT_Free(tmpitem.data);
392
0
        tmpitem.data = NULL;
393
0
    } else {
394
        /* if the extension is not present, then we allow all uses */
395
0
        cert->keyUsage = KU_ALL;
396
0
        cert->rawKeyUsage = KU_ALL;
397
0
        cert->keyUsagePresent = PR_FALSE;
398
0
    }
399
400
0
    if (CERT_GovtApprovedBitSet(cert)) {
401
0
        cert->keyUsage |= KU_NS_GOVT_APPROVED;
402
0
        cert->rawKeyUsage |= KU_NS_GOVT_APPROVED;
403
0
    }
404
405
0
    return (SECSuccess);
406
0
}
407
408
static SECStatus
409
findOIDinOIDSeqByTagNum(CERTOidSequence *seq, SECOidTag tagnum)
410
0
{
411
0
    SECItem **oids;
412
0
    SECItem *oid;
413
0
    SECStatus rv = SECFailure;
414
415
0
    if (seq != NULL) {
416
0
        oids = seq->oids;
417
0
        while (oids != NULL && *oids != NULL) {
418
0
            oid = *oids;
419
0
            if (SECOID_FindOIDTag(oid) == tagnum) {
420
0
                rv = SECSuccess;
421
0
                break;
422
0
            }
423
0
            oids++;
424
0
        }
425
0
    }
426
0
    return rv;
427
0
}
428
429
/*
430
 * fill in nsCertType field of the cert based on the cert extension
431
 */
432
SECStatus
433
cert_GetCertType(CERTCertificate *cert)
434
0
{
435
0
    PRUint32 nsCertType;
436
437
0
    if (cert->nsCertType) {
438
        /* once set, no need to recalculate */
439
0
        return SECSuccess;
440
0
    }
441
0
    nsCertType = cert_ComputeCertType(cert);
442
443
    /* Assert that it is safe to cast &cert->nsCertType to "PRInt32 *" */
444
0
    PORT_Assert(sizeof(cert->nsCertType) == sizeof(PRInt32));
445
0
    PR_ATOMIC_SET((PRInt32 *)&cert->nsCertType, nsCertType);
446
0
    return SECSuccess;
447
0
}
448
449
PRBool
450
cert_IsIPsecOID(CERTOidSequence *extKeyUsage)
451
0
{
452
0
    if (findOIDinOIDSeqByTagNum(
453
0
            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_IKE) == SECSuccess) {
454
0
        return PR_TRUE;
455
0
    }
456
0
    if (findOIDinOIDSeqByTagNum(
457
0
            extKeyUsage, SEC_OID_IPSEC_IKE_END) == SECSuccess) {
458
0
        return PR_TRUE;
459
0
    }
460
0
    if (findOIDinOIDSeqByTagNum(
461
0
            extKeyUsage, SEC_OID_IPSEC_IKE_INTERMEDIATE) == SECSuccess) {
462
0
        return PR_TRUE;
463
0
    }
464
    /* these are now deprecated, but may show up. Treat them the same as IKE */
465
0
    if (findOIDinOIDSeqByTagNum(
466
0
            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_END) == SECSuccess) {
467
0
        return PR_TRUE;
468
0
    }
469
0
    if (findOIDinOIDSeqByTagNum(
470
0
            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL) == SECSuccess) {
471
0
        return PR_TRUE;
472
0
    }
473
0
    if (findOIDinOIDSeqByTagNum(
474
0
            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_USER) == SECSuccess) {
475
0
        return PR_TRUE;
476
0
    }
477
    /* this one should probably be in cert_ComputeCertType and set all usages? */
478
0
    if (findOIDinOIDSeqByTagNum(
479
0
            extKeyUsage, SEC_OID_X509_ANY_EXT_KEY_USAGE) == SECSuccess) {
480
0
        return PR_TRUE;
481
0
    }
482
0
    return PR_FALSE;
483
0
}
484
485
PRUint32
486
cert_ComputeCertType(CERTCertificate *cert)
487
0
{
488
0
    SECStatus rv;
489
0
    SECItem tmpitem;
490
0
    SECItem encodedExtKeyUsage;
491
0
    CERTOidSequence *extKeyUsage = NULL;
492
0
    CERTBasicConstraints basicConstraint;
493
0
    PRUint32 nsCertType = 0;
494
0
    PRBool isCA = PR_FALSE;
495
496
0
    tmpitem.data = NULL;
497
0
    CERT_FindNSCertTypeExtension(cert, &tmpitem);
498
0
    encodedExtKeyUsage.data = NULL;
499
0
    rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE,
500
0
                                &encodedExtKeyUsage);
501
0
    if (rv == SECSuccess) {
502
0
        extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage);
503
0
    }
504
0
    rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
505
0
    if (rv == SECSuccess) {
506
0
        isCA = basicConstraint.isCA;
507
0
    }
508
0
    if (tmpitem.data != NULL || extKeyUsage != NULL) {
509
0
        if (tmpitem.data == NULL || tmpitem.len == 0) {
510
0
            nsCertType = 0;
511
0
        } else {
512
0
            nsCertType = tmpitem.data[0];
513
0
        }
514
515
        /* free tmpitem data pointer to avoid memory leak */
516
0
        PORT_Free(tmpitem.data);
517
0
        tmpitem.data = NULL;
518
519
        /*
520
         * for this release, we will allow SSL certs with an email address
521
         * to be used for email
522
         */
523
0
        if ((nsCertType & NS_CERT_TYPE_SSL_CLIENT) && cert->emailAddr &&
524
0
            cert->emailAddr[0]) {
525
0
            nsCertType |= NS_CERT_TYPE_EMAIL;
526
0
        }
527
        /*
528
         * for this release, we will allow SSL intermediate CAs to be
529
         * email intermediate CAs too.
530
         */
531
0
        if (nsCertType & NS_CERT_TYPE_SSL_CA) {
532
0
            nsCertType |= NS_CERT_TYPE_EMAIL_CA;
533
0
        }
534
        /*
535
         * allow a cert with the extended key usage of EMail Protect
536
         * to be used for email or as an email CA, if basic constraints
537
         * indicates that it is a CA.
538
         */
539
0
        if (findOIDinOIDSeqByTagNum(extKeyUsage,
540
0
                                    SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT) ==
541
0
            SECSuccess) {
542
0
            nsCertType |= isCA ? NS_CERT_TYPE_EMAIL_CA : NS_CERT_TYPE_EMAIL;
543
0
        }
544
0
        if (findOIDinOIDSeqByTagNum(
545
0
                extKeyUsage, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH) == SECSuccess) {
546
0
            nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_SERVER;
547
0
        }
548
        /*
549
         * Treat certs with step-up OID as also having SSL server type.
550
         * COMODO needs this behaviour until June 2020.  See Bug 737802.
551
         */
552
0
        if (findOIDinOIDSeqByTagNum(extKeyUsage,
553
0
                                    SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) ==
554
0
            SECSuccess) {
555
0
            nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_SERVER;
556
0
        }
557
0
        if (findOIDinOIDSeqByTagNum(
558
0
                extKeyUsage, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH) == SECSuccess) {
559
0
            nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_CLIENT;
560
0
        }
561
0
        if (cert_IsIPsecOID(extKeyUsage)) {
562
0
            nsCertType |= isCA ? NS_CERT_TYPE_IPSEC_CA : NS_CERT_TYPE_IPSEC;
563
0
        }
564
0
        if (findOIDinOIDSeqByTagNum(
565
0
                extKeyUsage, SEC_OID_EXT_KEY_USAGE_CODE_SIGN) == SECSuccess) {
566
0
            nsCertType |= isCA ? NS_CERT_TYPE_OBJECT_SIGNING_CA : NS_CERT_TYPE_OBJECT_SIGNING;
567
0
        }
568
0
        if (findOIDinOIDSeqByTagNum(
569
0
                extKeyUsage, SEC_OID_EXT_KEY_USAGE_TIME_STAMP) == SECSuccess) {
570
0
            nsCertType |= EXT_KEY_USAGE_TIME_STAMP;
571
0
        }
572
0
        if (findOIDinOIDSeqByTagNum(extKeyUsage, SEC_OID_OCSP_RESPONDER) ==
573
0
            SECSuccess) {
574
0
            nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
575
0
        }
576
0
    } else {
577
        /* If no NS Cert Type extension and no EKU extension, then */
578
0
        nsCertType = 0;
579
0
        if (CERT_IsCACert(cert, &nsCertType))
580
0
            nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
581
        /* if the basic constraint extension says the cert is a CA, then
582
           allow SSL CA and EMAIL CA and Status Responder */
583
0
        if (isCA) {
584
0
            nsCertType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
585
0
                           EXT_KEY_USAGE_STATUS_RESPONDER);
586
0
        }
587
        /* allow any ssl or email (no ca or object signing. */
588
0
        nsCertType |= NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER |
589
0
                      NS_CERT_TYPE_EMAIL;
590
0
    }
591
592
    /* IPSEC is allowed to use SSL client and server certs as well as email certs */
593
0
    if (nsCertType & (NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_EMAIL)) {
594
0
        nsCertType |= NS_CERT_TYPE_IPSEC;
595
0
    }
596
0
    if (nsCertType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA)) {
597
0
        nsCertType |= NS_CERT_TYPE_IPSEC_CA;
598
0
    }
599
600
0
    if (encodedExtKeyUsage.data != NULL) {
601
0
        PORT_Free(encodedExtKeyUsage.data);
602
0
    }
603
0
    if (extKeyUsage != NULL) {
604
0
        CERT_DestroyOidSequence(extKeyUsage);
605
0
    }
606
0
    return nsCertType;
607
0
}
608
609
/*
610
 * cert_GetKeyID() - extract or generate the subjectKeyID from a certificate
611
 */
612
SECStatus
613
cert_GetKeyID(CERTCertificate *cert)
614
0
{
615
0
    SECItem tmpitem;
616
0
    SECStatus rv;
617
618
0
    cert->subjectKeyID.len = 0;
619
620
    /* see of the cert has a key identifier extension */
621
0
    rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
622
0
    if (rv == SECSuccess) {
623
0
        cert->subjectKeyID.data =
624
0
            (unsigned char *)PORT_ArenaAlloc(cert->arena, tmpitem.len);
625
0
        if (cert->subjectKeyID.data != NULL) {
626
0
            PORT_Memcpy(cert->subjectKeyID.data, tmpitem.data, tmpitem.len);
627
0
            cert->subjectKeyID.len = tmpitem.len;
628
0
            cert->keyIDGenerated = PR_FALSE;
629
0
        }
630
631
0
        PORT_Free(tmpitem.data);
632
0
    }
633
634
    /* if the cert doesn't have a key identifier extension, then generate one*/
635
0
    if (cert->subjectKeyID.len == 0) {
636
        /*
637
         * pkix says that if the subjectKeyID is not present, then we should
638
         * use the SHA-1 hash of the DER-encoded publicKeyInfo from the cert
639
         */
640
0
        cert->subjectKeyID.data =
641
0
            (unsigned char *)PORT_ArenaAlloc(cert->arena, SHA1_LENGTH);
642
0
        if (cert->subjectKeyID.data != NULL) {
643
0
            rv = PK11_HashBuf(SEC_OID_SHA1, cert->subjectKeyID.data,
644
0
                              cert->derPublicKey.data, cert->derPublicKey.len);
645
0
            if (rv == SECSuccess) {
646
0
                cert->subjectKeyID.len = SHA1_LENGTH;
647
0
            }
648
0
        }
649
0
    }
650
651
0
    if (cert->subjectKeyID.len == 0) {
652
0
        return (SECFailure);
653
0
    }
654
0
    return (SECSuccess);
655
0
}
656
657
static PRBool
658
cert_IsRootCert(CERTCertificate *cert)
659
0
{
660
0
    SECStatus rv;
661
0
    SECItem tmpitem;
662
663
    /* cache the authKeyID extension, if present */
664
0
    cert->authKeyID = CERT_FindAuthKeyIDExten(cert->arena, cert);
665
666
    /* it MUST be self-issued to be a root */
667
0
    if (cert->derIssuer.len == 0 ||
668
0
        !SECITEM_ItemsAreEqual(&cert->derIssuer, &cert->derSubject)) {
669
0
        return PR_FALSE;
670
0
    }
671
672
    /* check the authKeyID extension */
673
0
    if (cert->authKeyID) {
674
        /* authority key identifier is present */
675
0
        if (cert->authKeyID->keyID.len > 0) {
676
            /* the keyIdentifier field is set, look for subjectKeyID */
677
0
            rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
678
0
            if (rv == SECSuccess) {
679
0
                PRBool match;
680
                /* also present, they MUST match for it to be a root */
681
0
                match =
682
0
                    SECITEM_ItemsAreEqual(&cert->authKeyID->keyID, &tmpitem);
683
0
                PORT_Free(tmpitem.data);
684
0
                if (!match)
685
0
                    return PR_FALSE; /* else fall through */
686
0
            } else {
687
                /* the subject key ID is required when AKI is present */
688
0
                return PR_FALSE;
689
0
            }
690
0
        }
691
0
        if (cert->authKeyID->authCertIssuer) {
692
0
            SECItem *caName;
693
0
            caName = (SECItem *)CERT_GetGeneralNameByType(
694
0
                cert->authKeyID->authCertIssuer, certDirectoryName, PR_TRUE);
695
0
            if (caName) {
696
0
                if (!SECITEM_ItemsAreEqual(&cert->derIssuer, caName)) {
697
0
                    return PR_FALSE;
698
0
                } /* else fall through */
699
0
            }     /* else ??? could not get general name as directory name? */
700
0
        }
701
0
        if (cert->authKeyID->authCertSerialNumber.len > 0) {
702
0
            if (!SECITEM_ItemsAreEqual(
703
0
                    &cert->serialNumber,
704
0
                    &cert->authKeyID->authCertSerialNumber)) {
705
0
                return PR_FALSE;
706
0
            } /* else fall through */
707
0
        }
708
        /* all of the AKI fields that were present passed the test */
709
0
        return PR_TRUE;
710
0
    }
711
    /* else the AKI was not present, so this is a root */
712
0
    return PR_TRUE;
713
0
}
714
715
/*
716
 * take a DER certificate and decode it into a certificate structure
717
 */
718
CERTCertificate *
719
CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
720
                          char *nickname)
721
0
{
722
0
    CERTCertificate *cert;
723
0
    PLArenaPool *arena;
724
0
    void *data;
725
0
    int rv;
726
0
    int len;
727
0
    char *tmpname;
728
729
    /* make a new arena */
730
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
731
732
0
    if (!arena) {
733
0
        return 0;
734
0
    }
735
736
    /* allocate the certificate structure */
737
0
    cert = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
738
739
0
    if (!cert) {
740
0
        goto loser;
741
0
    }
742
743
0
    cert->arena = arena;
744
745
0
    if (copyDER) {
746
        /* copy the DER data for the cert into this arena */
747
0
        data = (void *)PORT_ArenaAlloc(arena, derSignedCert->len);
748
0
        if (!data) {
749
0
            goto loser;
750
0
        }
751
0
        cert->derCert.data = (unsigned char *)data;
752
0
        cert->derCert.len = derSignedCert->len;
753
0
        PORT_Memcpy(data, derSignedCert->data, derSignedCert->len);
754
0
    } else {
755
        /* point to passed in DER data */
756
0
        cert->derCert = *derSignedCert;
757
0
    }
758
759
    /* decode the certificate info */
760
0
    rv = SEC_QuickDERDecodeItem(arena, cert, SEC_SignedCertificateTemplate,
761
0
                                &cert->derCert);
762
763
0
    if (rv) {
764
0
        goto loser;
765
0
    }
766
767
0
    if (cert_HasUnknownCriticalExten(cert->extensions) == PR_TRUE) {
768
0
        cert->options.bits.hasUnsupportedCriticalExt = PR_TRUE;
769
0
    }
770
771
    /* generate and save the database key for the cert */
772
0
    rv = CERT_KeyFromIssuerAndSN(arena, &cert->derIssuer, &cert->serialNumber,
773
0
                                 &cert->certKey);
774
0
    if (rv) {
775
0
        goto loser;
776
0
    }
777
778
    /* set the nickname */
779
0
    if (nickname == NULL) {
780
0
        cert->nickname = NULL;
781
0
    } else {
782
        /* copy and install the nickname */
783
0
        len = PORT_Strlen(nickname) + 1;
784
0
        cert->nickname = (char *)PORT_ArenaAlloc(arena, len);
785
0
        if (cert->nickname == NULL) {
786
0
            goto loser;
787
0
        }
788
789
0
        PORT_Memcpy(cert->nickname, nickname, len);
790
0
    }
791
792
    /* set the email address */
793
0
    cert->emailAddr = cert_GetCertificateEmailAddresses(cert);
794
795
    /* initialize the subjectKeyID */
796
0
    rv = cert_GetKeyID(cert);
797
0
    if (rv != SECSuccess) {
798
0
        goto loser;
799
0
    }
800
801
    /* initialize keyUsage */
802
0
    rv = GetKeyUsage(cert);
803
0
    if (rv != SECSuccess) {
804
0
        goto loser;
805
0
    }
806
807
    /* determine if this is a root cert */
808
0
    cert->isRoot = cert_IsRootCert(cert);
809
810
    /* initialize the certType */
811
0
    rv = cert_GetCertType(cert);
812
0
    if (rv != SECSuccess) {
813
0
        goto loser;
814
0
    }
815
816
0
    tmpname = CERT_NameToAscii(&cert->subject);
817
0
    if (tmpname != NULL) {
818
0
        cert->subjectName = PORT_ArenaStrdup(cert->arena, tmpname);
819
0
        PORT_Free(tmpname);
820
0
    }
821
822
0
    tmpname = CERT_NameToAscii(&cert->issuer);
823
0
    if (tmpname != NULL) {
824
0
        cert->issuerName = PORT_ArenaStrdup(cert->arena, tmpname);
825
0
        PORT_Free(tmpname);
826
0
    }
827
828
0
    cert->referenceCount = 1;
829
0
    cert->slot = NULL;
830
0
    cert->pkcs11ID = CK_INVALID_HANDLE;
831
0
    cert->dbnickname = NULL;
832
833
0
    return (cert);
834
835
0
loser:
836
837
0
    if (arena) {
838
0
        PORT_FreeArena(arena, PR_FALSE);
839
0
    }
840
841
0
    return (0);
842
0
}
843
844
CERTCertificate *
845
__CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
846
                            char *nickname)
847
0
{
848
0
    return CERT_DecodeDERCertificate(derSignedCert, copyDER, nickname);
849
0
}
850
851
CERTValidity *
852
CERT_CreateValidity(PRTime notBefore, PRTime notAfter)
853
0
{
854
0
    CERTValidity *v;
855
0
    int rv;
856
0
    PLArenaPool *arena;
857
858
0
    if (notBefore > notAfter) {
859
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
860
0
        return NULL;
861
0
    }
862
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
863
864
0
    if (!arena) {
865
0
        return (0);
866
0
    }
867
868
0
    v = (CERTValidity *)PORT_ArenaZAlloc(arena, sizeof(CERTValidity));
869
0
    if (v) {
870
0
        v->arena = arena;
871
0
        rv = DER_EncodeTimeChoice(arena, &v->notBefore, notBefore);
872
0
        if (rv)
873
0
            goto loser;
874
0
        rv = DER_EncodeTimeChoice(arena, &v->notAfter, notAfter);
875
0
        if (rv)
876
0
            goto loser;
877
0
    }
878
0
    return v;
879
880
0
loser:
881
0
    CERT_DestroyValidity(v);
882
0
    return 0;
883
0
}
884
885
SECStatus
886
CERT_CopyValidity(PLArenaPool *arena, CERTValidity *to, CERTValidity *from)
887
0
{
888
0
    SECStatus rv;
889
890
0
    CERT_DestroyValidity(to);
891
0
    to->arena = arena;
892
893
0
    rv = SECITEM_CopyItem(arena, &to->notBefore, &from->notBefore);
894
0
    if (rv)
895
0
        return rv;
896
0
    rv = SECITEM_CopyItem(arena, &to->notAfter, &from->notAfter);
897
0
    return rv;
898
0
}
899
900
void
901
CERT_DestroyValidity(CERTValidity *v)
902
0
{
903
0
    if (v && v->arena) {
904
0
        PORT_FreeArena(v->arena, PR_FALSE);
905
0
    }
906
0
    return;
907
0
}
908
909
/*
910
** Amount of time that a certifiate is allowed good before it is actually
911
** good. This is used for pending certificates, ones that are about to be
912
** valid. The slop is designed to allow for some variance in the clocks
913
** of the machine checking the certificate.
914
*/
915
#define PENDING_SLOP (24L * 60L * 60L)     /* seconds per day */
916
static PRInt32 pendingSlop = PENDING_SLOP; /* seconds */
917
918
PRInt32
919
CERT_GetSlopTime(void)
920
0
{
921
0
    return pendingSlop; /* seconds */
922
0
}
923
924
SECStatus
925
CERT_SetSlopTime(PRInt32 slop) /* seconds */
926
0
{
927
0
    if (slop < 0)
928
0
        return SECFailure;
929
0
    pendingSlop = slop;
930
0
    return SECSuccess;
931
0
}
932
933
SECStatus
934
CERT_GetCertTimes(const CERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
935
0
{
936
0
    SECStatus rv;
937
938
0
    if (!c || !notBefore || !notAfter) {
939
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
940
0
        return SECFailure;
941
0
    }
942
943
    /* convert DER not-before time */
944
0
    rv = DER_DecodeTimeChoice(notBefore, &c->validity.notBefore);
945
0
    if (rv) {
946
0
        return (SECFailure);
947
0
    }
948
949
    /* convert DER not-after time */
950
0
    rv = DER_DecodeTimeChoice(notAfter, &c->validity.notAfter);
951
0
    if (rv) {
952
0
        return (SECFailure);
953
0
    }
954
955
0
    return (SECSuccess);
956
0
}
957
958
/*
959
 * Check the validity times of a certificate
960
 */
961
SECCertTimeValidity
962
CERT_CheckCertValidTimes(const CERTCertificate *c, PRTime t,
963
                         PRBool allowOverride)
964
0
{
965
0
    PRTime notBefore, notAfter, llPendingSlop, tmp1;
966
0
    SECStatus rv;
967
968
0
    if (!c) {
969
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
970
0
        return (secCertTimeUndetermined);
971
0
    }
972
    /* if cert is already marked OK, then don't bother to check */
973
0
    if (allowOverride && c->timeOK) {
974
0
        return (secCertTimeValid);
975
0
    }
976
977
0
    rv = CERT_GetCertTimes(c, &notBefore, &notAfter);
978
979
0
    if (rv) {
980
0
        return (secCertTimeExpired); /*XXX is this the right thing to do here?*/
981
0
    }
982
983
0
    LL_I2L(llPendingSlop, pendingSlop);
984
    /* convert to micro seconds */
985
0
    LL_UI2L(tmp1, PR_USEC_PER_SEC);
986
0
    LL_MUL(llPendingSlop, llPendingSlop, tmp1);
987
0
    LL_SUB(notBefore, notBefore, llPendingSlop);
988
0
    if (LL_CMP(t, <, notBefore)) {
989
0
        PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
990
0
        return (secCertTimeNotValidYet);
991
0
    }
992
0
    if (LL_CMP(t, >, notAfter)) {
993
0
        PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
994
0
        return (secCertTimeExpired);
995
0
    }
996
997
0
    return (secCertTimeValid);
998
0
}
999
1000
SECStatus
1001
SEC_GetCrlTimes(CERTCrl *date, PRTime *notBefore, PRTime *notAfter)
1002
0
{
1003
0
    int rv;
1004
1005
    /* convert DER not-before time */
1006
0
    rv = DER_DecodeTimeChoice(notBefore, &date->lastUpdate);
1007
0
    if (rv) {
1008
0
        return (SECFailure);
1009
0
    }
1010
1011
    /* convert DER not-after time */
1012
0
    if (date->nextUpdate.data) {
1013
0
        rv = DER_DecodeTimeChoice(notAfter, &date->nextUpdate);
1014
0
        if (rv) {
1015
0
            return (SECFailure);
1016
0
        }
1017
0
    } else {
1018
0
        LL_I2L(*notAfter, 0L);
1019
0
    }
1020
0
    return (SECSuccess);
1021
0
}
1022
1023
/* These routines should probably be combined with the cert
1024
 * routines using an common extraction routine.
1025
 */
1026
SECCertTimeValidity
1027
SEC_CheckCrlTimes(CERTCrl *crl, PRTime t)
1028
0
{
1029
0
    PRTime notBefore, notAfter, llPendingSlop, tmp1;
1030
0
    SECStatus rv;
1031
1032
0
    if (!crl) {
1033
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1034
0
        return (secCertTimeUndetermined);
1035
0
    }
1036
1037
0
    rv = SEC_GetCrlTimes(crl, &notBefore, &notAfter);
1038
1039
0
    if (rv) {
1040
0
        return (secCertTimeExpired);
1041
0
    }
1042
1043
0
    LL_I2L(llPendingSlop, pendingSlop);
1044
    /* convert to micro seconds */
1045
0
    LL_I2L(tmp1, PR_USEC_PER_SEC);
1046
0
    LL_MUL(llPendingSlop, llPendingSlop, tmp1);
1047
0
    LL_SUB(notBefore, notBefore, llPendingSlop);
1048
0
    if (LL_CMP(t, <, notBefore)) {
1049
0
        PORT_SetError(SEC_ERROR_CRL_EXPIRED);
1050
0
        return (secCertTimeNotValidYet);
1051
0
    }
1052
1053
    /* If next update is omitted and the test for notBefore passes, then
1054
       we assume that the crl is up to date.
1055
     */
1056
0
    if (LL_IS_ZERO(notAfter)) {
1057
0
        return (secCertTimeValid);
1058
0
    }
1059
1060
0
    if (LL_CMP(t, >, notAfter)) {
1061
0
        PORT_SetError(SEC_ERROR_CRL_EXPIRED);
1062
0
        return (secCertTimeExpired);
1063
0
    }
1064
1065
0
    return (secCertTimeValid);
1066
0
}
1067
1068
PRBool
1069
SEC_CrlIsNewer(CERTCrl *inNew, CERTCrl *old)
1070
0
{
1071
0
    PRTime newNotBefore, newNotAfter;
1072
0
    PRTime oldNotBefore, oldNotAfter;
1073
0
    SECStatus rv;
1074
1075
    /* problems with the new CRL? reject it */
1076
0
    rv = SEC_GetCrlTimes(inNew, &newNotBefore, &newNotAfter);
1077
0
    if (rv)
1078
0
        return PR_FALSE;
1079
1080
    /* problems with the old CRL? replace it */
1081
0
    rv = SEC_GetCrlTimes(old, &oldNotBefore, &oldNotAfter);
1082
0
    if (rv)
1083
0
        return PR_TRUE;
1084
1085
    /* Question: what about the notAfter's? */
1086
0
    return ((PRBool)LL_CMP(oldNotBefore, <, newNotBefore));
1087
0
}
1088
1089
/*
1090
 * return required key usage and cert type based on cert usage
1091
 */
1092
SECStatus
1093
CERT_KeyUsageAndTypeForCertUsage(SECCertUsage usage, PRBool ca,
1094
                                 unsigned int *retKeyUsage,
1095
                                 unsigned int *retCertType)
1096
0
{
1097
0
    unsigned int requiredKeyUsage = 0;
1098
0
    unsigned int requiredCertType = 0;
1099
1100
0
    if (ca) {
1101
0
        switch (usage) {
1102
0
            case certUsageSSLServerWithStepUp:
1103
0
                requiredKeyUsage = KU_NS_GOVT_APPROVED | KU_KEY_CERT_SIGN;
1104
0
                requiredCertType = NS_CERT_TYPE_SSL_CA;
1105
0
                break;
1106
0
            case certUsageSSLClient:
1107
0
                requiredKeyUsage = KU_KEY_CERT_SIGN;
1108
0
                requiredCertType = NS_CERT_TYPE_SSL_CA;
1109
0
                break;
1110
0
            case certUsageSSLServer:
1111
0
                requiredKeyUsage = KU_KEY_CERT_SIGN;
1112
0
                requiredCertType = NS_CERT_TYPE_SSL_CA;
1113
0
                break;
1114
0
            case certUsageIPsec:
1115
0
                requiredKeyUsage = KU_KEY_CERT_SIGN;
1116
0
                requiredCertType = NS_CERT_TYPE_IPSEC_CA;
1117
0
                break;
1118
0
            case certUsageSSLCA:
1119
0
                requiredKeyUsage = KU_KEY_CERT_SIGN;
1120
0
                requiredCertType = NS_CERT_TYPE_SSL_CA;
1121
0
                break;
1122
0
            case certUsageEmailSigner:
1123
0
                requiredKeyUsage = KU_KEY_CERT_SIGN;
1124
0
                requiredCertType = NS_CERT_TYPE_EMAIL_CA;
1125
0
                break;
1126
0
            case certUsageEmailRecipient:
1127
0
                requiredKeyUsage = KU_KEY_CERT_SIGN;
1128
0
                requiredCertType = NS_CERT_TYPE_EMAIL_CA;
1129
0
                break;
1130
0
            case certUsageObjectSigner:
1131
0
                requiredKeyUsage = KU_KEY_CERT_SIGN;
1132
0
                requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA;
1133
0
                break;
1134
0
            case certUsageAnyCA:
1135
0
            case certUsageVerifyCA:
1136
0
            case certUsageStatusResponder:
1137
0
                requiredKeyUsage = KU_KEY_CERT_SIGN;
1138
0
                requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA |
1139
0
                                   NS_CERT_TYPE_EMAIL_CA | NS_CERT_TYPE_SSL_CA;
1140
0
                break;
1141
0
            default:
1142
0
                PORT_Assert(0);
1143
0
                goto loser;
1144
0
        }
1145
0
    } else {
1146
0
        switch (usage) {
1147
0
            case certUsageSSLClient:
1148
                /*
1149
                 * RFC 5280 lists digitalSignature and keyAgreement for
1150
                 * id-kp-clientAuth.  NSS does not support the *_fixed_dh and
1151
                 * *_fixed_ecdh client certificate types.
1152
                 */
1153
0
                requiredKeyUsage = KU_DIGITAL_SIGNATURE;
1154
0
                requiredCertType = NS_CERT_TYPE_SSL_CLIENT;
1155
0
                break;
1156
0
            case certUsageSSLServer:
1157
0
                requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
1158
0
                requiredCertType = NS_CERT_TYPE_SSL_SERVER;
1159
0
                break;
1160
0
            case certUsageIPsec:
1161
                /* RFC 4945 Section 5.1.3.2 */
1162
0
                requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
1163
0
                requiredCertType = NS_CERT_TYPE_IPSEC;
1164
0
                break;
1165
0
            case certUsageSSLServerWithStepUp:
1166
0
                requiredKeyUsage =
1167
0
                    KU_KEY_AGREEMENT_OR_ENCIPHERMENT | KU_NS_GOVT_APPROVED;
1168
0
                requiredCertType = NS_CERT_TYPE_SSL_SERVER;
1169
0
                break;
1170
0
            case certUsageSSLCA:
1171
0
                requiredKeyUsage = KU_KEY_CERT_SIGN;
1172
0
                requiredCertType = NS_CERT_TYPE_SSL_CA;
1173
0
                break;
1174
0
            case certUsageEmailSigner:
1175
0
                requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
1176
0
                requiredCertType = NS_CERT_TYPE_EMAIL;
1177
0
                break;
1178
0
            case certUsageEmailRecipient:
1179
0
                requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
1180
0
                requiredCertType = NS_CERT_TYPE_EMAIL;
1181
0
                break;
1182
0
            case certUsageObjectSigner:
1183
                /* RFC 5280 lists only digitalSignature for id-kp-codeSigning.
1184
                 */
1185
0
                requiredKeyUsage = KU_DIGITAL_SIGNATURE;
1186
0
                requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING;
1187
0
                break;
1188
0
            case certUsageStatusResponder:
1189
0
                requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
1190
0
                requiredCertType = EXT_KEY_USAGE_STATUS_RESPONDER;
1191
0
                break;
1192
0
            default:
1193
0
                PORT_Assert(0);
1194
0
                goto loser;
1195
0
        }
1196
0
    }
1197
1198
0
    if (retKeyUsage != NULL) {
1199
0
        *retKeyUsage = requiredKeyUsage;
1200
0
    }
1201
0
    if (retCertType != NULL) {
1202
0
        *retCertType = requiredCertType;
1203
0
    }
1204
1205
0
    return (SECSuccess);
1206
0
loser:
1207
0
    return (SECFailure);
1208
0
}
1209
1210
/*
1211
 * check the key usage of a cert against a set of required values
1212
 */
1213
SECStatus
1214
CERT_CheckKeyUsage(CERTCertificate *cert, unsigned int requiredUsage)
1215
0
{
1216
0
    if (!cert) {
1217
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1218
0
        return SECFailure;
1219
0
    }
1220
    /* choose between key agreement or key encipherment based on key
1221
     * type in cert
1222
     */
1223
0
    if (requiredUsage & KU_KEY_AGREEMENT_OR_ENCIPHERMENT) {
1224
0
        KeyType keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo);
1225
        /* turn off the special bit */
1226
0
        requiredUsage &= (~KU_KEY_AGREEMENT_OR_ENCIPHERMENT);
1227
1228
0
        switch (keyType) {
1229
0
            case rsaKey:
1230
0
                requiredUsage |= KU_KEY_ENCIPHERMENT;
1231
0
                break;
1232
0
            case rsaPssKey:
1233
0
            case dsaKey:
1234
0
                requiredUsage |= KU_DIGITAL_SIGNATURE;
1235
0
                break;
1236
0
            case dhKey:
1237
0
                requiredUsage |= KU_KEY_AGREEMENT;
1238
0
                break;
1239
0
            case ecKey:
1240
                /* Accept either signature or agreement. */
1241
0
                if (!(cert->keyUsage &
1242
0
                      (KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT)))
1243
0
                    goto loser;
1244
0
                break;
1245
0
            default:
1246
0
                goto loser;
1247
0
        }
1248
0
    }
1249
1250
    /* Allow either digital signature or non-repudiation */
1251
0
    if (requiredUsage & KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION) {
1252
        /* turn off the special bit */
1253
0
        requiredUsage &= (~KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION);
1254
1255
0
        if (!(cert->keyUsage & (KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION)))
1256
0
            goto loser;
1257
0
    }
1258
1259
0
    if ((cert->keyUsage & requiredUsage) == requiredUsage)
1260
0
        return SECSuccess;
1261
1262
0
loser:
1263
0
    PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
1264
0
    return SECFailure;
1265
0
}
1266
1267
CERTCertificate *
1268
CERT_DupCertificate(CERTCertificate *c)
1269
0
{
1270
0
    if (c) {
1271
0
        NSSCertificate *tmp = STAN_GetNSSCertificate(c);
1272
0
        nssCertificate_AddRef(tmp);
1273
0
    }
1274
0
    return c;
1275
0
}
1276
1277
SECStatus
1278
CERT_GetCertificateDer(const CERTCertificate *c, SECItem *der)
1279
0
{
1280
0
    if (!c || !der) {
1281
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1282
0
        return SECFailure;
1283
0
    }
1284
0
    *der = c->derCert;
1285
0
    return SECSuccess;
1286
0
}
1287
1288
/*
1289
 * Allow use of default cert database, so that apps(such as mozilla) don't
1290
 * have to pass the handle all over the place.
1291
 */
1292
static CERTCertDBHandle *default_cert_db_handle = 0;
1293
1294
void
1295
CERT_SetDefaultCertDB(CERTCertDBHandle *handle)
1296
0
{
1297
0
    default_cert_db_handle = handle;
1298
1299
0
    return;
1300
0
}
1301
1302
CERTCertDBHandle *
1303
CERT_GetDefaultCertDB(void)
1304
0
{
1305
0
    return (default_cert_db_handle);
1306
0
}
1307
1308
/* XXX this would probably be okay/better as an xp routine? */
1309
static void
1310
sec_lower_string(char *s)
1311
0
{
1312
0
    if (s == NULL) {
1313
0
        return;
1314
0
    }
1315
1316
0
    while (*s) {
1317
0
        *s = PORT_Tolower((unsigned char)*s);
1318
0
        s++;
1319
0
    }
1320
1321
0
    return;
1322
0
}
1323
1324
static PRBool
1325
cert_IsIPAddr(const char *hn)
1326
0
{
1327
0
    PRBool isIPaddr = PR_FALSE;
1328
0
    PRNetAddr netAddr;
1329
0
    isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
1330
0
    return isIPaddr;
1331
0
}
1332
1333
/*
1334
** Add a domain name to the list of names that the user has explicitly
1335
** allowed (despite cert name mismatches) for use with a server cert.
1336
*/
1337
SECStatus
1338
CERT_AddOKDomainName(CERTCertificate *cert, const char *hn)
1339
0
{
1340
0
    CERTOKDomainName *domainOK;
1341
0
    int newNameLen;
1342
1343
0
    if (!hn || !(newNameLen = strlen(hn))) {
1344
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1345
0
        return SECFailure;
1346
0
    }
1347
0
    domainOK = (CERTOKDomainName *)PORT_ArenaZAlloc(cert->arena, sizeof(*domainOK));
1348
0
    if (!domainOK) {
1349
0
        return SECFailure; /* error code is already set. */
1350
0
    }
1351
0
    domainOK->name = (char *)PORT_ArenaZAlloc(cert->arena, newNameLen + 1);
1352
0
    if (!domainOK->name) {
1353
0
        return SECFailure; /* error code is already set. */
1354
0
    }
1355
1356
0
    PORT_Strncpy(domainOK->name, hn, newNameLen + 1);
1357
0
    sec_lower_string(domainOK->name);
1358
1359
    /* put at head of list. */
1360
0
    domainOK->next = cert->domainOK;
1361
0
    cert->domainOK = domainOK;
1362
0
    return SECSuccess;
1363
0
}
1364
1365
/* returns SECSuccess if hn matches pattern cn,
1366
** returns SECFailure with SSL_ERROR_BAD_CERT_DOMAIN if no match,
1367
** returns SECFailure with some other error code if another error occurs.
1368
**
1369
** This function may modify string cn, so caller must pass a modifiable copy.
1370
*/
1371
static SECStatus
1372
cert_TestHostName(char *cn, const char *hn)
1373
0
{
1374
0
    static int useShellExp = -1;
1375
1376
0
    if (useShellExp < 0) {
1377
0
        useShellExp = (NULL != PR_GetEnvSecure("NSS_USE_SHEXP_IN_CERT_NAME"));
1378
0
    }
1379
0
    if (useShellExp) {
1380
        /* Backward compatible code, uses Shell Expressions (SHEXP). */
1381
0
        int regvalid = PORT_RegExpValid(cn);
1382
0
        if (regvalid != NON_SXP) {
1383
0
            SECStatus rv;
1384
            /* cn is a regular expression, try to match the shexp */
1385
0
            int match = PORT_RegExpCaseSearch(hn, cn);
1386
1387
0
            if (match == 0) {
1388
0
                rv = SECSuccess;
1389
0
            } else {
1390
0
                PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
1391
0
                rv = SECFailure;
1392
0
            }
1393
0
            return rv;
1394
0
        }
1395
0
    } else {
1396
        /* New approach conforms to RFC 6125. */
1397
0
        char *wildcard = PORT_Strchr(cn, '*');
1398
0
        char *firstcndot = PORT_Strchr(cn, '.');
1399
0
        char *secondcndot =
1400
0
            firstcndot ? PORT_Strchr(firstcndot + 1, '.') : NULL;
1401
0
        char *firsthndot = PORT_Strchr(hn, '.');
1402
1403
        /* For a cn pattern to be considered valid, the wildcard character...
1404
         * - may occur only in a DNS name with at least 3 components, and
1405
         * - may occur only as last character in the first component, and
1406
         * - may be preceded by additional characters, and
1407
         * - must not be preceded by an IDNA ACE prefix (xn--)
1408
         */
1409
0
        if (wildcard && secondcndot && secondcndot[1] && firsthndot &&
1410
0
            firstcndot - wildcard == 1           /* wildcard is last char in first component */
1411
0
            && secondcndot - firstcndot > 1      /* second component is non-empty */
1412
0
            && PORT_Strrchr(cn, '*') == wildcard /* only one wildcard in cn */
1413
0
            && !PORT_Strncasecmp(cn, hn, wildcard - cn) &&
1414
0
            !PORT_Strcasecmp(firstcndot, firsthndot)
1415
            /* If hn starts with xn--, then cn must start with wildcard */
1416
0
            && (PORT_Strncasecmp(hn, "xn--", 4) || wildcard == cn)) {
1417
            /* valid wildcard pattern match */
1418
0
            return SECSuccess;
1419
0
        }
1420
0
    }
1421
    /* String cn has no wildcard or shell expression.
1422
     * Compare entire string hn with cert name.
1423
     */
1424
0
    if (PORT_Strcasecmp(hn, cn) == 0) {
1425
0
        return SECSuccess;
1426
0
    }
1427
1428
0
    PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
1429
0
    return SECFailure;
1430
0
}
1431
1432
SECStatus
1433
cert_VerifySubjectAltName(const CERTCertificate *cert, const char *hn)
1434
0
{
1435
0
    PLArenaPool *arena = NULL;
1436
0
    CERTGeneralName *nameList = NULL;
1437
0
    CERTGeneralName *current;
1438
0
    char *cn;
1439
0
    int cnBufLen;
1440
0
    int DNSextCount = 0;
1441
0
    int IPextCount = 0;
1442
0
    PRBool isIPaddr = PR_FALSE;
1443
0
    SECStatus rv = SECFailure;
1444
0
    SECItem subAltName;
1445
0
    PRNetAddr netAddr;
1446
0
    char cnbuf[128];
1447
1448
0
    subAltName.data = NULL;
1449
0
    cn = cnbuf;
1450
0
    cnBufLen = sizeof cnbuf;
1451
1452
0
    rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
1453
0
                                &subAltName);
1454
0
    if (rv != SECSuccess) {
1455
0
        goto fail;
1456
0
    }
1457
0
    isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
1458
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1459
0
    if (!arena)
1460
0
        goto fail;
1461
1462
0
    nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
1463
0
    if (!current)
1464
0
        goto fail;
1465
1466
0
    do {
1467
0
        switch (current->type) {
1468
0
            case certDNSName:
1469
0
                if (!isIPaddr) {
1470
                    /* DNS name current->name.other.data is not null terminated.
1471
                    ** so must copy it.
1472
                    */
1473
0
                    int cnLen = current->name.other.len;
1474
0
                    rv = CERT_RFC1485_EscapeAndQuote(
1475
0
                        cn, cnBufLen, (char *)current->name.other.data, cnLen);
1476
0
                    if (rv != SECSuccess &&
1477
0
                        PORT_GetError() == SEC_ERROR_OUTPUT_LEN) {
1478
0
                        cnBufLen =
1479
0
                            cnLen * 3 + 3; /* big enough for worst case */
1480
0
                        cn = (char *)PORT_ArenaAlloc(arena, cnBufLen);
1481
0
                        if (!cn)
1482
0
                            goto fail;
1483
0
                        rv = CERT_RFC1485_EscapeAndQuote(
1484
0
                            cn, cnBufLen, (char *)current->name.other.data,
1485
0
                            cnLen);
1486
0
                    }
1487
0
                    if (rv == SECSuccess)
1488
0
                        rv = cert_TestHostName(cn, hn);
1489
0
                    if (rv == SECSuccess)
1490
0
                        goto finish;
1491
0
                }
1492
0
                DNSextCount++;
1493
0
                break;
1494
0
            case certIPAddress:
1495
0
                if (isIPaddr) {
1496
0
                    int match = 0;
1497
0
                    PRIPv6Addr v6Addr;
1498
0
                    if (current->name.other.len == 4 && /* IP v4 address */
1499
0
                        netAddr.inet.family == PR_AF_INET) {
1500
0
                        match = !memcmp(&netAddr.inet.ip,
1501
0
                                        current->name.other.data, 4);
1502
0
                    } else if (current->name.other.len ==
1503
0
                                   16 && /* IP v6 address */
1504
0
                               netAddr.ipv6.family == PR_AF_INET6) {
1505
0
                        match = !memcmp(&netAddr.ipv6.ip,
1506
0
                                        current->name.other.data, 16);
1507
0
                    } else if (current->name.other.len ==
1508
0
                                   16 && /* IP v6 address */
1509
0
                               netAddr.inet.family == PR_AF_INET) {
1510
                        /* convert netAddr to ipv6, then compare. */
1511
                        /* ipv4 must be in Network Byte Order on input. */
1512
0
                        PR_ConvertIPv4AddrToIPv6(netAddr.inet.ip, &v6Addr);
1513
0
                        match = !memcmp(&v6Addr, current->name.other.data, 16);
1514
0
                    } else if (current->name.other.len == 4 && /* IP v4 address */
1515
0
                               netAddr.inet.family == PR_AF_INET6) {
1516
                        /* convert netAddr to ipv6, then compare. */
1517
0
                        PRUint32 ipv4 = (current->name.other.data[0] << 24) |
1518
0
                                        (current->name.other.data[1] << 16) |
1519
0
                                        (current->name.other.data[2] << 8) |
1520
0
                                        current->name.other.data[3];
1521
                        /* ipv4 must be in Network Byte Order on input. */
1522
0
                        PR_ConvertIPv4AddrToIPv6(PR_htonl(ipv4), &v6Addr);
1523
0
                        match = !memcmp(&netAddr.ipv6.ip, &v6Addr, 16);
1524
0
                    }
1525
0
                    if (match) {
1526
0
                        rv = SECSuccess;
1527
0
                        goto finish;
1528
0
                    }
1529
0
                }
1530
0
                IPextCount++;
1531
0
                break;
1532
0
            default:
1533
0
                break;
1534
0
        }
1535
0
        current = CERT_GetNextGeneralName(current);
1536
0
    } while (current != nameList);
1537
1538
0
fail:
1539
1540
0
    if (!(isIPaddr ? IPextCount : DNSextCount)) {
1541
        /* no relevant value in the extension was found. */
1542
0
        PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
1543
0
    } else {
1544
0
        PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
1545
0
    }
1546
0
    rv = SECFailure;
1547
1548
0
finish:
1549
1550
    /* Don't free nameList, it's part of the arena. */
1551
0
    if (arena) {
1552
0
        PORT_FreeArena(arena, PR_FALSE);
1553
0
    }
1554
1555
0
    if (subAltName.data) {
1556
0
        SECITEM_FreeItem(&subAltName, PR_FALSE);
1557
0
    }
1558
1559
0
    return rv;
1560
0
}
1561
1562
/*
1563
 * If found:
1564
 *   - subAltName contains the extension (caller must free)
1565
 *   - return value is the decoded namelist (allocated off arena)
1566
 * if not found, or if failure to decode:
1567
 *   - return value is NULL
1568
 */
1569
CERTGeneralName *
1570
cert_GetSubjectAltNameList(const CERTCertificate *cert, PLArenaPool *arena)
1571
0
{
1572
0
    CERTGeneralName *nameList = NULL;
1573
0
    SECStatus rv = SECFailure;
1574
0
    SECItem subAltName;
1575
1576
0
    if (!cert || !arena)
1577
0
        return NULL;
1578
1579
0
    subAltName.data = NULL;
1580
1581
0
    rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
1582
0
                                &subAltName);
1583
0
    if (rv != SECSuccess)
1584
0
        return NULL;
1585
1586
0
    nameList = CERT_DecodeAltNameExtension(arena, &subAltName);
1587
0
    SECITEM_FreeItem(&subAltName, PR_FALSE);
1588
0
    return nameList;
1589
0
}
1590
1591
PRUint32
1592
cert_CountDNSPatterns(CERTGeneralName *firstName)
1593
0
{
1594
0
    CERTGeneralName *current;
1595
0
    PRUint32 count = 0;
1596
1597
0
    if (!firstName)
1598
0
        return 0;
1599
1600
0
    current = firstName;
1601
0
    do {
1602
0
        switch (current->type) {
1603
0
            case certDNSName:
1604
0
            case certIPAddress:
1605
0
                ++count;
1606
0
                break;
1607
0
            default:
1608
0
                break;
1609
0
        }
1610
0
        current = CERT_GetNextGeneralName(current);
1611
0
    } while (current != firstName);
1612
1613
0
    return count;
1614
0
}
1615
1616
#ifndef INET6_ADDRSTRLEN
1617
#define INET6_ADDRSTRLEN 46
1618
#endif
1619
1620
/* will fill nickNames,
1621
 * will allocate all data from nickNames->arena,
1622
 * numberOfGeneralNames should have been obtained from cert_CountDNSPatterns,
1623
 * will ensure the numberOfGeneralNames matches the number of output entries.
1624
 */
1625
SECStatus
1626
cert_GetDNSPatternsFromGeneralNames(CERTGeneralName *firstName,
1627
                                    PRUint32 numberOfGeneralNames,
1628
                                    CERTCertNicknames *nickNames)
1629
0
{
1630
0
    CERTGeneralName *currentInput;
1631
0
    char **currentOutput;
1632
1633
0
    if (!firstName || !nickNames || !numberOfGeneralNames)
1634
0
        return SECFailure;
1635
1636
0
    nickNames->numnicknames = numberOfGeneralNames;
1637
0
    nickNames->nicknames = PORT_ArenaAlloc(
1638
0
        nickNames->arena, sizeof(char *) * numberOfGeneralNames);
1639
0
    if (!nickNames->nicknames)
1640
0
        return SECFailure;
1641
1642
0
    currentInput = firstName;
1643
0
    currentOutput = nickNames->nicknames;
1644
0
    do {
1645
0
        char *cn = NULL;
1646
0
        char ipbuf[INET6_ADDRSTRLEN];
1647
0
        PRNetAddr addr;
1648
1649
0
        if (numberOfGeneralNames < 1) {
1650
            /* internal consistency error */
1651
0
            return SECFailure;
1652
0
        }
1653
1654
0
        switch (currentInput->type) {
1655
0
            case certDNSName:
1656
                /* DNS name currentInput->name.other.data is not null
1657
                 *terminated.
1658
                 ** so must copy it.
1659
                 */
1660
0
                cn = (char *)PORT_ArenaAlloc(nickNames->arena,
1661
0
                                             currentInput->name.other.len + 1);
1662
0
                if (!cn)
1663
0
                    return SECFailure;
1664
0
                PORT_Memcpy(cn, currentInput->name.other.data,
1665
0
                            currentInput->name.other.len);
1666
0
                cn[currentInput->name.other.len] = 0;
1667
0
                break;
1668
0
            case certIPAddress:
1669
0
                if (currentInput->name.other.len == 4) {
1670
0
                    addr.inet.family = PR_AF_INET;
1671
0
                    memcpy(&addr.inet.ip, currentInput->name.other.data,
1672
0
                           currentInput->name.other.len);
1673
0
                } else if (currentInput->name.other.len == 16) {
1674
0
                    addr.ipv6.family = PR_AF_INET6;
1675
0
                    memcpy(&addr.ipv6.ip, currentInput->name.other.data,
1676
0
                           currentInput->name.other.len);
1677
0
                }
1678
0
                if (PR_NetAddrToString(&addr, ipbuf, sizeof(ipbuf)) ==
1679
0
                    PR_FAILURE)
1680
0
                    return SECFailure;
1681
0
                cn = PORT_ArenaStrdup(nickNames->arena, ipbuf);
1682
0
                if (!cn)
1683
0
                    return SECFailure;
1684
0
                break;
1685
0
            default:
1686
0
                break;
1687
0
        }
1688
0
        if (cn) {
1689
0
            *currentOutput = cn;
1690
0
            nickNames->totallen += PORT_Strlen(cn);
1691
0
            ++currentOutput;
1692
0
            --numberOfGeneralNames;
1693
0
        }
1694
0
        currentInput = CERT_GetNextGeneralName(currentInput);
1695
0
    } while (currentInput != firstName);
1696
1697
0
    return (numberOfGeneralNames == 0) ? SECSuccess : SECFailure;
1698
0
}
1699
1700
/*
1701
 * Collect all valid DNS names from the given cert.
1702
 * The output arena will reference some temporaray data,
1703
 * but this saves us from dealing with two arenas.
1704
 * The caller may free all data by freeing CERTCertNicknames->arena.
1705
 */
1706
CERTCertNicknames *
1707
CERT_GetValidDNSPatternsFromCert(CERTCertificate *cert)
1708
0
{
1709
0
    CERTGeneralName *generalNames;
1710
0
    CERTCertNicknames *nickNames;
1711
0
    PLArenaPool *arena;
1712
0
    char *singleName;
1713
1714
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1715
0
    if (!arena) {
1716
0
        return NULL;
1717
0
    }
1718
1719
0
    nickNames = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
1720
0
    if (!nickNames) {
1721
0
        PORT_FreeArena(arena, PR_FALSE);
1722
0
        return NULL;
1723
0
    }
1724
1725
    /* init the structure */
1726
0
    nickNames->arena = arena;
1727
0
    nickNames->head = NULL;
1728
0
    nickNames->numnicknames = 0;
1729
0
    nickNames->nicknames = NULL;
1730
0
    nickNames->totallen = 0;
1731
1732
0
    generalNames = cert_GetSubjectAltNameList(cert, arena);
1733
0
    if (generalNames) {
1734
0
        SECStatus rv_getnames = SECFailure;
1735
0
        PRUint32 numNames = cert_CountDNSPatterns(generalNames);
1736
1737
0
        if (numNames) {
1738
0
            rv_getnames = cert_GetDNSPatternsFromGeneralNames(
1739
0
                generalNames, numNames, nickNames);
1740
0
        }
1741
1742
        /* if there were names, we'll exit now, either with success or failure
1743
         */
1744
0
        if (numNames) {
1745
0
            if (rv_getnames == SECSuccess) {
1746
0
                return nickNames;
1747
0
            }
1748
1749
            /* failure to produce output */
1750
0
            PORT_FreeArena(arena, PR_FALSE);
1751
0
            return NULL;
1752
0
        }
1753
0
    }
1754
1755
    /* no SAN extension or no names found in extension */
1756
0
    singleName = CERT_GetCommonName(&cert->subject);
1757
0
    if (singleName) {
1758
0
        nickNames->numnicknames = 1;
1759
0
        nickNames->nicknames = PORT_ArenaAlloc(arena, sizeof(char *));
1760
0
        if (nickNames->nicknames) {
1761
0
            *nickNames->nicknames = PORT_ArenaStrdup(arena, singleName);
1762
0
        }
1763
0
        PORT_Free(singleName);
1764
1765
        /* Did we allocate both the buffer of pointers and the string? */
1766
0
        if (nickNames->nicknames && *nickNames->nicknames) {
1767
0
            return nickNames;
1768
0
        }
1769
0
    }
1770
1771
0
    PORT_FreeArena(arena, PR_FALSE);
1772
0
    return NULL;
1773
0
}
1774
1775
/* Make sure that the name of the host we are connecting to matches the
1776
 * name that is incoded in the common-name component of the certificate
1777
 * that they are using.
1778
 */
1779
SECStatus
1780
CERT_VerifyCertName(const CERTCertificate *cert, const char *hn)
1781
0
{
1782
0
    char *cn;
1783
0
    SECStatus rv;
1784
0
    CERTOKDomainName *domainOK;
1785
1786
0
    if (!hn || !strlen(hn)) {
1787
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1788
0
        return SECFailure;
1789
0
    }
1790
1791
    /* if the name is one that the user has already approved, it's OK. */
1792
0
    for (domainOK = cert->domainOK; domainOK; domainOK = domainOK->next) {
1793
0
        if (0 == PORT_Strcasecmp(hn, domainOK->name)) {
1794
0
            return SECSuccess;
1795
0
        }
1796
0
    }
1797
1798
    /* Per RFC 2818, if the SubjectAltName extension is present, it must
1799
    ** be used as the cert's identity.
1800
    */
1801
0
    rv = cert_VerifySubjectAltName(cert, hn);
1802
0
    if (rv == SECSuccess || PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND)
1803
0
        return rv;
1804
1805
0
    cn = CERT_GetCommonName(&cert->subject);
1806
0
    if (cn) {
1807
0
        PRBool isIPaddr = cert_IsIPAddr(hn);
1808
0
        if (isIPaddr) {
1809
0
            if (PORT_Strcasecmp(hn, cn) == 0) {
1810
0
                rv = SECSuccess;
1811
0
            } else {
1812
0
                PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
1813
0
                rv = SECFailure;
1814
0
            }
1815
0
        } else {
1816
0
            rv = cert_TestHostName(cn, hn);
1817
0
        }
1818
0
        PORT_Free(cn);
1819
0
    } else
1820
0
        PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
1821
0
    return rv;
1822
0
}
1823
1824
PRBool
1825
CERT_CompareCerts(const CERTCertificate *c1, const CERTCertificate *c2)
1826
0
{
1827
0
    SECComparison comp;
1828
1829
0
    comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
1830
0
    if (comp == SECEqual) { /* certs are the same */
1831
0
        return (PR_TRUE);
1832
0
    } else {
1833
0
        return (PR_FALSE);
1834
0
    }
1835
0
}
1836
1837
static SECStatus
1838
StringsEqual(char *s1, char *s2)
1839
0
{
1840
0
    if ((s1 == NULL) || (s2 == NULL)) {
1841
0
        if (s1 != s2) { /* only one is null */
1842
0
            return (SECFailure);
1843
0
        }
1844
0
        return (SECSuccess); /* both are null */
1845
0
    }
1846
1847
0
    if (PORT_Strcmp(s1, s2) != 0) {
1848
0
        return (SECFailure); /* not equal */
1849
0
    }
1850
1851
0
    return (SECSuccess); /* strings are equal */
1852
0
}
1853
1854
PRBool
1855
CERT_CompareCertsForRedirection(CERTCertificate *c1, CERTCertificate *c2)
1856
0
{
1857
0
    SECComparison comp;
1858
0
    char *c1str, *c2str;
1859
0
    SECStatus eq;
1860
1861
0
    comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
1862
0
    if (comp == SECEqual) { /* certs are the same */
1863
0
        return (PR_TRUE);
1864
0
    }
1865
1866
    /* check if they are issued by the same CA */
1867
0
    comp = SECITEM_CompareItem(&c1->derIssuer, &c2->derIssuer);
1868
0
    if (comp != SECEqual) { /* different issuer */
1869
0
        return (PR_FALSE);
1870
0
    }
1871
1872
    /* check country name */
1873
0
    c1str = CERT_GetCountryName(&c1->subject);
1874
0
    c2str = CERT_GetCountryName(&c2->subject);
1875
0
    eq = StringsEqual(c1str, c2str);
1876
0
    PORT_Free(c1str);
1877
0
    PORT_Free(c2str);
1878
0
    if (eq != SECSuccess) {
1879
0
        return (PR_FALSE);
1880
0
    }
1881
1882
    /* check locality name */
1883
0
    c1str = CERT_GetLocalityName(&c1->subject);
1884
0
    c2str = CERT_GetLocalityName(&c2->subject);
1885
0
    eq = StringsEqual(c1str, c2str);
1886
0
    PORT_Free(c1str);
1887
0
    PORT_Free(c2str);
1888
0
    if (eq != SECSuccess) {
1889
0
        return (PR_FALSE);
1890
0
    }
1891
1892
    /* check state name */
1893
0
    c1str = CERT_GetStateName(&c1->subject);
1894
0
    c2str = CERT_GetStateName(&c2->subject);
1895
0
    eq = StringsEqual(c1str, c2str);
1896
0
    PORT_Free(c1str);
1897
0
    PORT_Free(c2str);
1898
0
    if (eq != SECSuccess) {
1899
0
        return (PR_FALSE);
1900
0
    }
1901
1902
    /* check org name */
1903
0
    c1str = CERT_GetOrgName(&c1->subject);
1904
0
    c2str = CERT_GetOrgName(&c2->subject);
1905
0
    eq = StringsEqual(c1str, c2str);
1906
0
    PORT_Free(c1str);
1907
0
    PORT_Free(c2str);
1908
0
    if (eq != SECSuccess) {
1909
0
        return (PR_FALSE);
1910
0
    }
1911
1912
#ifdef NOTDEF
1913
    /* check orgUnit name */
1914
    /*
1915
     * We need to revisit this and decide which fields should be allowed to be
1916
     * different
1917
     */
1918
    c1str = CERT_GetOrgUnitName(&c1->subject);
1919
    c2str = CERT_GetOrgUnitName(&c2->subject);
1920
    eq = StringsEqual(c1str, c2str);
1921
    PORT_Free(c1str);
1922
    PORT_Free(c2str);
1923
    if (eq != SECSuccess) {
1924
        return (PR_FALSE);
1925
    }
1926
#endif
1927
1928
0
    return (PR_TRUE); /* all fields but common name are the same */
1929
0
}
1930
1931
/* CERT_CertChainFromCert and CERT_DestroyCertificateList moved
1932
   to certhigh.c */
1933
1934
CERTIssuerAndSN *
1935
CERT_GetCertIssuerAndSN(PLArenaPool *arena, CERTCertificate *cert)
1936
0
{
1937
0
    CERTIssuerAndSN *result;
1938
0
    SECStatus rv;
1939
1940
0
    if (arena == NULL) {
1941
0
        arena = cert->arena;
1942
0
    }
1943
1944
0
    result = (CERTIssuerAndSN *)PORT_ArenaZAlloc(arena, sizeof(*result));
1945
0
    if (result == NULL) {
1946
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
1947
0
        return NULL;
1948
0
    }
1949
1950
0
    rv = SECITEM_CopyItem(arena, &result->derIssuer, &cert->derIssuer);
1951
0
    if (rv != SECSuccess)
1952
0
        return NULL;
1953
1954
0
    rv = CERT_CopyName(arena, &result->issuer, &cert->issuer);
1955
0
    if (rv != SECSuccess)
1956
0
        return NULL;
1957
1958
0
    rv = SECITEM_CopyItem(arena, &result->serialNumber, &cert->serialNumber);
1959
0
    if (rv != SECSuccess)
1960
0
        return NULL;
1961
1962
0
    return result;
1963
0
}
1964
1965
char *
1966
CERT_MakeCANickname(CERTCertificate *cert)
1967
0
{
1968
0
    char *firstname = NULL;
1969
0
    char *org = NULL;
1970
0
    char *nickname = NULL;
1971
0
    int count;
1972
0
    CERTCertificate *dummycert;
1973
1974
0
    firstname = CERT_GetCommonName(&cert->subject);
1975
0
    if (firstname == NULL) {
1976
0
        firstname = CERT_GetOrgUnitName(&cert->subject);
1977
0
    }
1978
1979
0
    org = CERT_GetOrgName(&cert->issuer);
1980
0
    if (org == NULL) {
1981
0
        org = CERT_GetDomainComponentName(&cert->issuer);
1982
0
        if (org == NULL) {
1983
0
            if (firstname) {
1984
0
                org = firstname;
1985
0
                firstname = NULL;
1986
0
            } else {
1987
0
                org = PORT_Strdup("Unknown CA");
1988
0
            }
1989
0
        }
1990
0
    }
1991
1992
    /* can only fail if PORT_Strdup fails, in which case
1993
     * we're having memory problems. */
1994
0
    if (org == NULL) {
1995
0
        goto done;
1996
0
    }
1997
1998
0
    count = 1;
1999
0
    while (1) {
2000
2001
0
        if (firstname) {
2002
0
            if (count == 1) {
2003
0
                nickname = PR_smprintf("%s - %s", firstname, org);
2004
0
            } else {
2005
0
                nickname = PR_smprintf("%s - %s #%d", firstname, org, count);
2006
0
            }
2007
0
        } else {
2008
0
            if (count == 1) {
2009
0
                nickname = PR_smprintf("%s", org);
2010
0
            } else {
2011
0
                nickname = PR_smprintf("%s #%d", org, count);
2012
0
            }
2013
0
        }
2014
0
        if (nickname == NULL) {
2015
0
            goto done;
2016
0
        }
2017
2018
        /* look up the nickname to make sure it isn't in use already */
2019
0
        dummycert = CERT_FindCertByNickname(cert->dbhandle, nickname);
2020
2021
0
        if (dummycert == NULL) {
2022
0
            goto done;
2023
0
        }
2024
2025
        /* found a cert, destroy it and loop */
2026
0
        CERT_DestroyCertificate(dummycert);
2027
2028
        /* free the nickname */
2029
0
        PORT_Free(nickname);
2030
2031
0
        count++;
2032
0
    }
2033
2034
0
done:
2035
0
    if (firstname) {
2036
0
        PORT_Free(firstname);
2037
0
    }
2038
0
    if (org) {
2039
0
        PORT_Free(org);
2040
0
    }
2041
2042
0
    return (nickname);
2043
0
}
2044
2045
/* CERT_Import_CAChain moved to certhigh.c */
2046
2047
void
2048
CERT_DestroyCrl(CERTSignedCrl *crl)
2049
0
{
2050
0
    SEC_DestroyCrl(crl);
2051
0
}
2052
2053
static int
2054
cert_Version(CERTCertificate *cert)
2055
0
{
2056
0
    int version = 0;
2057
0
    if (cert && cert->version.data && cert->version.len) {
2058
0
        version = DER_GetInteger(&cert->version);
2059
0
        if (version < 0)
2060
0
            version = 0;
2061
0
    }
2062
0
    return version;
2063
0
}
2064
2065
static unsigned int
2066
cert_ComputeTrustOverrides(CERTCertificate *cert, unsigned int cType)
2067
0
{
2068
0
    CERTCertTrust trust;
2069
0
    SECStatus rv = SECFailure;
2070
2071
0
    rv = CERT_GetCertTrust(cert, &trust);
2072
2073
0
    if (rv == SECSuccess &&
2074
0
        (trust.sslFlags | trust.emailFlags | trust.objectSigningFlags)) {
2075
2076
0
        if (trust.sslFlags & (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED))
2077
0
            cType |= NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_SSL_CLIENT;
2078
0
        if (trust.sslFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA))
2079
0
            cType |= NS_CERT_TYPE_SSL_CA;
2080
#if defined(CERTDB_NOT_TRUSTED)
2081
        if (trust.sslFlags & CERTDB_NOT_TRUSTED)
2082
            cType &= ~(NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_SSL_CLIENT |
2083
                       NS_CERT_TYPE_SSL_CA);
2084
#endif
2085
0
        if (trust.emailFlags & (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED))
2086
0
            cType |= NS_CERT_TYPE_EMAIL;
2087
0
        if (trust.emailFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA))
2088
0
            cType |= NS_CERT_TYPE_EMAIL_CA;
2089
#if defined(CERTDB_NOT_TRUSTED)
2090
        if (trust.emailFlags & CERTDB_NOT_TRUSTED)
2091
            cType &= ~(NS_CERT_TYPE_EMAIL | NS_CERT_TYPE_EMAIL_CA);
2092
#endif
2093
0
        if (trust.objectSigningFlags &
2094
0
            (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED))
2095
0
            cType |= NS_CERT_TYPE_OBJECT_SIGNING;
2096
0
        if (trust.objectSigningFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA))
2097
0
            cType |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
2098
#if defined(CERTDB_NOT_TRUSTED)
2099
        if (trust.objectSigningFlags & CERTDB_NOT_TRUSTED)
2100
            cType &=
2101
                ~(NS_CERT_TYPE_OBJECT_SIGNING | NS_CERT_TYPE_OBJECT_SIGNING_CA);
2102
#endif
2103
0
    }
2104
0
    return cType;
2105
0
}
2106
2107
/*
2108
 * Does a cert belong to a CA?  We decide based on perm database trust
2109
 * flags, Netscape Cert Type Extension, and KeyUsage Extension.
2110
 */
2111
PRBool
2112
CERT_IsCACert(CERTCertificate *cert, unsigned int *rettype)
2113
0
{
2114
0
    unsigned int cType = cert->nsCertType;
2115
0
    PRBool ret = PR_FALSE;
2116
2117
    /*
2118
     * Check if the constraints are available and it's a CA, OR if it's
2119
     * a X.509 v1 Root CA.
2120
     */
2121
0
    CERTBasicConstraints constraints;
2122
0
    if ((CERT_FindBasicConstraintExten(cert, &constraints) == SECSuccess &&
2123
0
         constraints.isCA) ||
2124
0
        (cert->isRoot && cert_Version(cert) < SEC_CERTIFICATE_VERSION_3))
2125
0
        cType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
2126
2127
    /*
2128
     * Apply trust overrides, if any.
2129
     */
2130
0
    cType = cert_ComputeTrustOverrides(cert, cType);
2131
0
    ret = (cType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
2132
0
                    NS_CERT_TYPE_OBJECT_SIGNING_CA))
2133
0
              ? PR_TRUE
2134
0
              : PR_FALSE;
2135
2136
0
    if (rettype) {
2137
0
        *rettype = cType;
2138
0
    }
2139
2140
0
    return ret;
2141
0
}
2142
2143
PRBool
2144
CERT_IsCADERCert(SECItem *derCert, unsigned int *type)
2145
0
{
2146
0
    CERTCertificate *cert;
2147
0
    PRBool isCA;
2148
2149
    /* This is okay -- only looks at extensions */
2150
0
    cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
2151
0
    if (cert == NULL)
2152
0
        return PR_FALSE;
2153
2154
0
    isCA = CERT_IsCACert(cert, type);
2155
0
    CERT_DestroyCertificate(cert);
2156
0
    return isCA;
2157
0
}
2158
2159
PRBool
2160
CERT_IsRootDERCert(SECItem *derCert)
2161
0
{
2162
0
    CERTCertificate *cert;
2163
0
    PRBool isRoot;
2164
2165
    /* This is okay -- only looks at extensions */
2166
0
    cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
2167
0
    if (cert == NULL)
2168
0
        return PR_FALSE;
2169
2170
0
    isRoot = cert->isRoot;
2171
0
    CERT_DestroyCertificate(cert);
2172
0
    return isRoot;
2173
0
}
2174
2175
CERTCompareValidityStatus
2176
CERT_CompareValidityTimes(CERTValidity *val_a, CERTValidity *val_b)
2177
0
{
2178
0
    PRTime notBeforeA, notBeforeB, notAfterA, notAfterB;
2179
2180
0
    if (!val_a || !val_b) {
2181
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2182
0
        return certValidityUndetermined;
2183
0
    }
2184
2185
0
    if (SECSuccess != DER_DecodeTimeChoice(&notBeforeA, &val_a->notBefore) ||
2186
0
        SECSuccess != DER_DecodeTimeChoice(&notBeforeB, &val_b->notBefore) ||
2187
0
        SECSuccess != DER_DecodeTimeChoice(&notAfterA, &val_a->notAfter) ||
2188
0
        SECSuccess != DER_DecodeTimeChoice(&notAfterB, &val_b->notAfter)) {
2189
0
        return certValidityUndetermined;
2190
0
    }
2191
2192
    /* sanity check */
2193
0
    if (LL_CMP(notBeforeA, >, notAfterA) || LL_CMP(notBeforeB, >, notAfterB)) {
2194
0
        PORT_SetError(SEC_ERROR_INVALID_TIME);
2195
0
        return certValidityUndetermined;
2196
0
    }
2197
2198
0
    if (LL_CMP(notAfterA, !=, notAfterB)) {
2199
        /* one cert validity goes farther into the future, select it */
2200
0
        return LL_CMP(notAfterA, <, notAfterB) ? certValidityChooseB
2201
0
                                               : certValidityChooseA;
2202
0
    }
2203
    /* the two certs have the same expiration date */
2204
0
    PORT_Assert(LL_CMP(notAfterA, ==, notAfterB));
2205
    /* do they also have the same start date ? */
2206
0
    if (LL_CMP(notBeforeA, ==, notBeforeB)) {
2207
0
        return certValidityEqual;
2208
0
    }
2209
    /* choose cert with the later start date */
2210
0
    return LL_CMP(notBeforeA, <, notBeforeB) ? certValidityChooseB
2211
0
                                             : certValidityChooseA;
2212
0
}
2213
2214
/*
2215
 * is certa newer than certb?  If one is expired, pick the other one.
2216
 */
2217
PRBool
2218
CERT_IsNewer(CERTCertificate *certa, CERTCertificate *certb)
2219
0
{
2220
0
    PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now;
2221
0
    SECStatus rv;
2222
0
    PRBool newerbefore, newerafter;
2223
2224
0
    rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
2225
0
    if (rv != SECSuccess) {
2226
0
        return (PR_FALSE);
2227
0
    }
2228
2229
0
    rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
2230
0
    if (rv != SECSuccess) {
2231
0
        return (PR_TRUE);
2232
0
    }
2233
2234
0
    newerbefore = PR_FALSE;
2235
0
    if (LL_CMP(notBeforeA, >, notBeforeB)) {
2236
0
        newerbefore = PR_TRUE;
2237
0
    }
2238
2239
0
    newerafter = PR_FALSE;
2240
0
    if (LL_CMP(notAfterA, >, notAfterB)) {
2241
0
        newerafter = PR_TRUE;
2242
0
    }
2243
2244
0
    if (newerbefore && newerafter) {
2245
0
        return (PR_TRUE);
2246
0
    }
2247
2248
0
    if ((!newerbefore) && (!newerafter)) {
2249
0
        return (PR_FALSE);
2250
0
    }
2251
2252
    /* get current time */
2253
0
    now = PR_Now();
2254
2255
0
    if (newerbefore) {
2256
        /* cert A was issued after cert B, but expires sooner */
2257
        /* if A is expired, then pick B */
2258
0
        if (LL_CMP(notAfterA, <, now)) {
2259
0
            return (PR_FALSE);
2260
0
        }
2261
0
        return (PR_TRUE);
2262
0
    } else {
2263
        /* cert B was issued after cert A, but expires sooner */
2264
        /* if B is expired, then pick A */
2265
0
        if (LL_CMP(notAfterB, <, now)) {
2266
0
            return (PR_TRUE);
2267
0
        }
2268
0
        return (PR_FALSE);
2269
0
    }
2270
0
}
2271
2272
void
2273
CERT_DestroyCertArray(CERTCertificate **certs, unsigned int ncerts)
2274
0
{
2275
0
    unsigned int i;
2276
2277
0
    if (certs) {
2278
0
        for (i = 0; i < ncerts; i++) {
2279
0
            if (certs[i]) {
2280
0
                CERT_DestroyCertificate(certs[i]);
2281
0
            }
2282
0
        }
2283
2284
0
        PORT_Free(certs);
2285
0
    }
2286
2287
0
    return;
2288
0
}
2289
2290
char *
2291
CERT_FixupEmailAddr(const char *emailAddr)
2292
0
{
2293
0
    char *retaddr;
2294
0
    char *str;
2295
2296
0
    if (emailAddr == NULL) {
2297
0
        return (NULL);
2298
0
    }
2299
2300
    /* copy the string */
2301
0
    str = retaddr = PORT_Strdup(emailAddr);
2302
0
    if (str == NULL) {
2303
0
        return (NULL);
2304
0
    }
2305
2306
    /* make it lower case */
2307
0
    while (*str) {
2308
0
        *str = tolower((unsigned char)*str);
2309
0
        str++;
2310
0
    }
2311
2312
0
    return (retaddr);
2313
0
}
2314
2315
/*
2316
 * NOTE - don't allow encode of govt-approved or invisible bits
2317
 */
2318
SECStatus
2319
CERT_DecodeTrustString(CERTCertTrust *trust, const char *trusts)
2320
0
{
2321
0
    unsigned int i;
2322
0
    unsigned int *pflags;
2323
2324
0
    if (!trust) {
2325
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2326
0
        return SECFailure;
2327
0
    }
2328
0
    trust->sslFlags = 0;
2329
0
    trust->emailFlags = 0;
2330
0
    trust->objectSigningFlags = 0;
2331
0
    if (!trusts) {
2332
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2333
0
        return SECFailure;
2334
0
    }
2335
2336
0
    pflags = &trust->sslFlags;
2337
2338
0
    for (i = 0; i < PORT_Strlen(trusts); i++) {
2339
0
        switch (trusts[i]) {
2340
0
            case 'p':
2341
0
                *pflags = *pflags | CERTDB_TERMINAL_RECORD;
2342
0
                break;
2343
2344
0
            case 'P':
2345
0
                *pflags = *pflags | CERTDB_TRUSTED | CERTDB_TERMINAL_RECORD;
2346
0
                break;
2347
2348
0
            case 'w':
2349
0
                *pflags = *pflags | CERTDB_SEND_WARN;
2350
0
                break;
2351
2352
0
            case 'c':
2353
0
                *pflags = *pflags | CERTDB_VALID_CA;
2354
0
                break;
2355
2356
0
            case 'T':
2357
0
                *pflags = *pflags | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA;
2358
0
                break;
2359
2360
0
            case 'C':
2361
0
                *pflags = *pflags | CERTDB_TRUSTED_CA | CERTDB_VALID_CA;
2362
0
                break;
2363
2364
0
            case 'u':
2365
0
                *pflags = *pflags | CERTDB_USER;
2366
0
                break;
2367
2368
0
            case 'i':
2369
0
                *pflags = *pflags | CERTDB_INVISIBLE_CA;
2370
0
                break;
2371
0
            case 'g':
2372
0
                *pflags = *pflags | CERTDB_GOVT_APPROVED_CA;
2373
0
                break;
2374
2375
0
            case ',':
2376
0
                if (pflags == &trust->sslFlags) {
2377
0
                    pflags = &trust->emailFlags;
2378
0
                } else {
2379
0
                    pflags = &trust->objectSigningFlags;
2380
0
                }
2381
0
                break;
2382
0
            default:
2383
0
                PORT_SetError(SEC_ERROR_INVALID_ARGS);
2384
0
                return SECFailure;
2385
0
        }
2386
0
    }
2387
2388
0
    return SECSuccess;
2389
0
}
2390
2391
static void
2392
EncodeFlags(char *trusts, unsigned int flags)
2393
0
{
2394
0
    if (flags & CERTDB_VALID_CA)
2395
0
        if (!(flags & CERTDB_TRUSTED_CA) && !(flags & CERTDB_TRUSTED_CLIENT_CA))
2396
0
            PORT_Strcat(trusts, "c");
2397
0
    if (flags & CERTDB_TERMINAL_RECORD)
2398
0
        if (!(flags & CERTDB_TRUSTED))
2399
0
            PORT_Strcat(trusts, "p");
2400
0
    if (flags & CERTDB_TRUSTED_CA)
2401
0
        PORT_Strcat(trusts, "C");
2402
0
    if (flags & CERTDB_TRUSTED_CLIENT_CA)
2403
0
        PORT_Strcat(trusts, "T");
2404
0
    if (flags & CERTDB_TRUSTED)
2405
0
        PORT_Strcat(trusts, "P");
2406
0
    if (flags & CERTDB_USER)
2407
0
        PORT_Strcat(trusts, "u");
2408
0
    if (flags & CERTDB_SEND_WARN)
2409
0
        PORT_Strcat(trusts, "w");
2410
0
    if (flags & CERTDB_INVISIBLE_CA)
2411
0
        PORT_Strcat(trusts, "I");
2412
0
    if (flags & CERTDB_GOVT_APPROVED_CA)
2413
0
        PORT_Strcat(trusts, "G");
2414
0
    return;
2415
0
}
2416
2417
char *
2418
CERT_EncodeTrustString(CERTCertTrust *trust)
2419
0
{
2420
0
    char tmpTrustSSL[32];
2421
0
    char tmpTrustEmail[32];
2422
0
    char tmpTrustSigning[32];
2423
0
    char *retstr = NULL;
2424
2425
0
    if (trust) {
2426
0
        tmpTrustSSL[0] = '\0';
2427
0
        tmpTrustEmail[0] = '\0';
2428
0
        tmpTrustSigning[0] = '\0';
2429
2430
0
        EncodeFlags(tmpTrustSSL, trust->sslFlags);
2431
0
        EncodeFlags(tmpTrustEmail, trust->emailFlags);
2432
0
        EncodeFlags(tmpTrustSigning, trust->objectSigningFlags);
2433
2434
0
        retstr = PR_smprintf("%s,%s,%s", tmpTrustSSL, tmpTrustEmail,
2435
0
                             tmpTrustSigning);
2436
0
    }
2437
2438
0
    return (retstr);
2439
0
}
2440
2441
SECStatus
2442
CERT_ImportCerts(CERTCertDBHandle *certdb, SECCertUsage usage,
2443
                 unsigned int ncerts, SECItem **derCerts,
2444
                 CERTCertificate ***retCerts, PRBool keepCerts, PRBool caOnly,
2445
                 char *nickname)
2446
0
{
2447
0
    unsigned int i;
2448
0
    CERTCertificate **certs = NULL;
2449
0
    unsigned int fcerts = 0;
2450
2451
0
    if (ncerts) {
2452
0
        certs = PORT_ZNewArray(CERTCertificate *, ncerts);
2453
0
        if (certs == NULL) {
2454
0
            return (SECFailure);
2455
0
        }
2456
2457
        /* decode all of the certs into the temporary DB */
2458
0
        for (i = 0, fcerts = 0; i < ncerts; i++) {
2459
0
            certs[fcerts] = CERT_NewTempCertificate(certdb, derCerts[i], NULL,
2460
0
                                                    PR_FALSE, PR_TRUE);
2461
0
            if (certs[fcerts]) {
2462
0
                SECItem subjKeyID = { siBuffer, NULL, 0 };
2463
0
                if (CERT_FindSubjectKeyIDExtension(certs[fcerts], &subjKeyID) ==
2464
0
                    SECSuccess) {
2465
0
                    if (subjKeyID.data) {
2466
0
                        cert_AddSubjectKeyIDMapping(&subjKeyID, certs[fcerts]);
2467
0
                    }
2468
0
                    SECITEM_FreeItem(&subjKeyID, PR_FALSE);
2469
0
                }
2470
0
                fcerts++;
2471
0
            }
2472
0
        }
2473
2474
0
        if (keepCerts) {
2475
0
            for (i = 0; i < fcerts; i++) {
2476
0
                char *canickname = NULL;
2477
0
                PRBool isCA;
2478
2479
0
                SECKEY_UpdateCertPQG(certs[i]);
2480
2481
0
                isCA = CERT_IsCACert(certs[i], NULL);
2482
0
                if (isCA) {
2483
0
                    canickname = CERT_MakeCANickname(certs[i]);
2484
0
                }
2485
2486
0
                if (isCA && (fcerts > 1)) {
2487
                    /* if we are importing only a single cert and specifying
2488
                     * a nickname, we want to use that nickname if it a CA,
2489
                     * otherwise if there are more than one cert, we don't
2490
                     * know which cert it belongs to. But we still may try
2491
                     * the individual canickname from the cert itself.
2492
                     */
2493
                    /* Bug 1192442 - propagate errors from these calls. */
2494
0
                    (void)CERT_AddTempCertToPerm(certs[i], canickname, NULL);
2495
0
                } else {
2496
0
                    (void)CERT_AddTempCertToPerm(
2497
0
                        certs[i], nickname ? nickname : canickname, NULL);
2498
0
                }
2499
2500
0
                PORT_Free(canickname);
2501
                /* don't care if it fails - keep going */
2502
0
            }
2503
0
        }
2504
0
    }
2505
2506
0
    if (retCerts) {
2507
0
        *retCerts = certs;
2508
0
    } else {
2509
0
        if (certs) {
2510
0
            CERT_DestroyCertArray(certs, fcerts);
2511
0
        }
2512
0
    }
2513
2514
0
    return (fcerts || !ncerts) ? SECSuccess : SECFailure;
2515
0
}
2516
2517
/*
2518
 * a real list of certificates - need to convert CERTCertificateList
2519
 * stuff and ASN 1 encoder/decoder over to using this...
2520
 */
2521
CERTCertList *
2522
CERT_NewCertList(void)
2523
0
{
2524
0
    PLArenaPool *arena = NULL;
2525
0
    CERTCertList *ret = NULL;
2526
2527
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2528
0
    if (arena == NULL) {
2529
0
        goto loser;
2530
0
    }
2531
2532
0
    ret = (CERTCertList *)PORT_ArenaZAlloc(arena, sizeof(CERTCertList));
2533
0
    if (ret == NULL) {
2534
0
        goto loser;
2535
0
    }
2536
2537
0
    ret->arena = arena;
2538
2539
0
    PR_INIT_CLIST(&ret->list);
2540
2541
0
    return (ret);
2542
2543
0
loser:
2544
0
    if (arena != NULL) {
2545
0
        PORT_FreeArena(arena, PR_FALSE);
2546
0
    }
2547
2548
0
    return (NULL);
2549
0
}
2550
2551
void
2552
CERT_DestroyCertList(CERTCertList *certs)
2553
0
{
2554
0
    PRCList *node;
2555
2556
0
    if (!certs) {
2557
0
        return;
2558
0
    }
2559
2560
0
    while (!PR_CLIST_IS_EMPTY(&certs->list)) {
2561
0
        node = PR_LIST_HEAD(&certs->list);
2562
0
        CERT_DestroyCertificate(((CERTCertListNode *)node)->cert);
2563
0
        PR_REMOVE_LINK(node);
2564
0
    }
2565
2566
0
    PORT_FreeArena(certs->arena, PR_FALSE);
2567
2568
0
    return;
2569
0
}
2570
2571
void
2572
CERT_RemoveCertListNode(CERTCertListNode *node)
2573
0
{
2574
0
    CERT_DestroyCertificate(node->cert);
2575
0
    PR_REMOVE_LINK(&node->links);
2576
0
    return;
2577
0
}
2578
2579
SECStatus
2580
CERT_AddCertToListTailWithData(CERTCertList *certs, CERTCertificate *cert,
2581
                               void *appData)
2582
0
{
2583
0
    CERTCertListNode *node;
2584
2585
0
    node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
2586
0
                                                sizeof(CERTCertListNode));
2587
0
    if (node == NULL) {
2588
0
        goto loser;
2589
0
    }
2590
2591
0
    PR_INSERT_BEFORE(&node->links, &certs->list);
2592
    /* certs->count++; */
2593
0
    node->cert = cert;
2594
0
    node->appData = appData;
2595
0
    return (SECSuccess);
2596
2597
0
loser:
2598
0
    return (SECFailure);
2599
0
}
2600
2601
SECStatus
2602
CERT_AddCertToListTail(CERTCertList *certs, CERTCertificate *cert)
2603
0
{
2604
0
    return CERT_AddCertToListTailWithData(certs, cert, NULL);
2605
0
}
2606
2607
SECStatus
2608
CERT_AddCertToListHeadWithData(CERTCertList *certs, CERTCertificate *cert,
2609
                               void *appData)
2610
0
{
2611
0
    CERTCertListNode *node;
2612
0
    CERTCertListNode *head;
2613
2614
0
    head = CERT_LIST_HEAD(certs);
2615
0
    if (head == NULL) {
2616
0
        goto loser;
2617
0
    }
2618
2619
0
    node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
2620
0
                                                sizeof(CERTCertListNode));
2621
0
    if (node == NULL) {
2622
0
        goto loser;
2623
0
    }
2624
2625
0
    PR_INSERT_BEFORE(&node->links, &head->links);
2626
    /* certs->count++; */
2627
0
    node->cert = cert;
2628
0
    node->appData = appData;
2629
0
    return (SECSuccess);
2630
2631
0
loser:
2632
0
    return (SECFailure);
2633
0
}
2634
2635
SECStatus
2636
CERT_AddCertToListHead(CERTCertList *certs, CERTCertificate *cert)
2637
0
{
2638
0
    return CERT_AddCertToListHeadWithData(certs, cert, NULL);
2639
0
}
2640
2641
/*
2642
 * Sort callback function to determine if cert a is newer than cert b.
2643
 * Not valid certs are considered older than valid certs.
2644
 */
2645
PRBool
2646
CERT_SortCBValidity(CERTCertificate *certa, CERTCertificate *certb, void *arg)
2647
0
{
2648
0
    PRTime sorttime;
2649
0
    PRTime notBeforeA, notAfterA, notBeforeB, notAfterB;
2650
0
    SECStatus rv;
2651
0
    PRBool newerbefore, newerafter;
2652
0
    PRBool aNotValid = PR_FALSE, bNotValid = PR_FALSE;
2653
2654
0
    sorttime = *(PRTime *)arg;
2655
2656
0
    rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
2657
0
    if (rv != SECSuccess) {
2658
0
        return (PR_FALSE);
2659
0
    }
2660
2661
0
    rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
2662
0
    if (rv != SECSuccess) {
2663
0
        return (PR_TRUE);
2664
0
    }
2665
0
    newerbefore = PR_FALSE;
2666
0
    if (LL_CMP(notBeforeA, >, notBeforeB)) {
2667
0
        newerbefore = PR_TRUE;
2668
0
    }
2669
0
    newerafter = PR_FALSE;
2670
0
    if (LL_CMP(notAfterA, >, notAfterB)) {
2671
0
        newerafter = PR_TRUE;
2672
0
    }
2673
2674
    /* check if A is valid at sorttime */
2675
0
    if (CERT_CheckCertValidTimes(certa, sorttime, PR_FALSE) !=
2676
0
        secCertTimeValid) {
2677
0
        aNotValid = PR_TRUE;
2678
0
    }
2679
2680
    /* check if B is valid at sorttime */
2681
0
    if (CERT_CheckCertValidTimes(certb, sorttime, PR_FALSE) !=
2682
0
        secCertTimeValid) {
2683
0
        bNotValid = PR_TRUE;
2684
0
    }
2685
2686
    /* a is valid, b is not */
2687
0
    if (bNotValid && (!aNotValid)) {
2688
0
        return (PR_TRUE);
2689
0
    }
2690
2691
    /* b is valid, a is not */
2692
0
    if (aNotValid && (!bNotValid)) {
2693
0
        return (PR_FALSE);
2694
0
    }
2695
2696
    /* a and b are either valid or not valid */
2697
0
    if (newerbefore && newerafter) {
2698
0
        return (PR_TRUE);
2699
0
    }
2700
2701
0
    if ((!newerbefore) && (!newerafter)) {
2702
0
        return (PR_FALSE);
2703
0
    }
2704
2705
0
    if (newerbefore) {
2706
        /* cert A was issued after cert B, but expires sooner */
2707
0
        return (PR_TRUE);
2708
0
    } else {
2709
        /* cert B was issued after cert A, but expires sooner */
2710
0
        return (PR_FALSE);
2711
0
    }
2712
0
}
2713
2714
SECStatus
2715
CERT_AddCertToListSorted(CERTCertList *certs, CERTCertificate *cert,
2716
                         CERTSortCallback f, void *arg)
2717
0
{
2718
0
    CERTCertListNode *node;
2719
0
    CERTCertListNode *head;
2720
0
    PRBool ret;
2721
2722
0
    node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
2723
0
                                                sizeof(CERTCertListNode));
2724
0
    if (node == NULL) {
2725
0
        goto loser;
2726
0
    }
2727
2728
0
    head = CERT_LIST_HEAD(certs);
2729
2730
0
    while (!CERT_LIST_END(head, certs)) {
2731
2732
        /* if cert is already in the list, then don't add it again */
2733
0
        if (cert == head->cert) {
2734
            /*XXX*/
2735
            /* don't keep a reference */
2736
0
            CERT_DestroyCertificate(cert);
2737
0
            goto done;
2738
0
        }
2739
2740
0
        ret = (*f)(cert, head->cert, arg);
2741
        /* if sort function succeeds, then insert before current node */
2742
0
        if (ret) {
2743
0
            PR_INSERT_BEFORE(&node->links, &head->links);
2744
0
            goto done;
2745
0
        }
2746
2747
0
        head = CERT_LIST_NEXT(head);
2748
0
    }
2749
    /* if we get to the end, then just insert it at the tail */
2750
0
    PR_INSERT_BEFORE(&node->links, &certs->list);
2751
2752
0
done:
2753
    /* certs->count++; */
2754
0
    node->cert = cert;
2755
0
    return (SECSuccess);
2756
2757
0
loser:
2758
0
    return (SECFailure);
2759
0
}
2760
2761
/* This routine is here because pcertdb.c still has a call to it.
2762
 * The SMIME profile code in pcertdb.c should be split into high (find
2763
 * the email cert) and low (store the profile) code.  At that point, we
2764
 * can move this to certhigh.c where it belongs.
2765
 *
2766
 * remove certs from a list that don't have keyUsage and certType
2767
 * that match the given usage.
2768
 */
2769
SECStatus
2770
CERT_FilterCertListByUsage(CERTCertList *certList, SECCertUsage usage,
2771
                           PRBool ca)
2772
0
{
2773
0
    unsigned int requiredKeyUsage;
2774
0
    unsigned int requiredCertType;
2775
0
    CERTCertListNode *node, *savenode;
2776
0
    SECStatus rv;
2777
2778
0
    if (certList == NULL)
2779
0
        goto loser;
2780
2781
0
    rv = CERT_KeyUsageAndTypeForCertUsage(usage, ca, &requiredKeyUsage,
2782
0
                                          &requiredCertType);
2783
0
    if (rv != SECSuccess) {
2784
0
        goto loser;
2785
0
    }
2786
2787
0
    node = CERT_LIST_HEAD(certList);
2788
2789
0
    while (!CERT_LIST_END(node, certList)) {
2790
2791
0
        PRBool bad = (PRBool)(!node->cert);
2792
2793
        /* bad key usage ? */
2794
0
        if (!bad &&
2795
0
            CERT_CheckKeyUsage(node->cert, requiredKeyUsage) != SECSuccess) {
2796
0
            bad = PR_TRUE;
2797
0
        }
2798
        /* bad cert type ? */
2799
0
        if (!bad) {
2800
0
            unsigned int certType = 0;
2801
0
            if (ca) {
2802
                /* This function returns a more comprehensive cert type that
2803
                 * takes trust flags into consideration.  Should probably
2804
                 * fix the cert decoding code to do this.
2805
                 */
2806
0
                (void)CERT_IsCACert(node->cert, &certType);
2807
0
            } else {
2808
0
                certType = node->cert->nsCertType;
2809
0
            }
2810
0
            if (!(certType & requiredCertType)) {
2811
0
                bad = PR_TRUE;
2812
0
            }
2813
0
        }
2814
2815
0
        if (bad) {
2816
            /* remove the node if it is bad */
2817
0
            savenode = CERT_LIST_NEXT(node);
2818
0
            CERT_RemoveCertListNode(node);
2819
0
            node = savenode;
2820
0
        } else {
2821
0
            node = CERT_LIST_NEXT(node);
2822
0
        }
2823
0
    }
2824
0
    return (SECSuccess);
2825
2826
0
loser:
2827
0
    return (SECFailure);
2828
0
}
2829
2830
PRBool
2831
CERT_IsUserCert(CERTCertificate *cert)
2832
0
{
2833
0
    CERTCertTrust trust;
2834
0
    SECStatus rv = SECFailure;
2835
2836
0
    rv = CERT_GetCertTrust(cert, &trust);
2837
0
    if (rv == SECSuccess &&
2838
0
        ((trust.sslFlags & CERTDB_USER) || (trust.emailFlags & CERTDB_USER) ||
2839
0
         (trust.objectSigningFlags & CERTDB_USER))) {
2840
0
        return PR_TRUE;
2841
0
    } else {
2842
0
        return PR_FALSE;
2843
0
    }
2844
0
}
2845
2846
SECStatus
2847
CERT_FilterCertListForUserCerts(CERTCertList *certList)
2848
0
{
2849
0
    CERTCertListNode *node, *freenode;
2850
0
    CERTCertificate *cert;
2851
2852
0
    if (!certList) {
2853
0
        return SECFailure;
2854
0
    }
2855
2856
0
    node = CERT_LIST_HEAD(certList);
2857
2858
0
    while (!CERT_LIST_END(node, certList)) {
2859
0
        cert = node->cert;
2860
0
        if (PR_TRUE != CERT_IsUserCert(cert)) {
2861
            /* Not a User Cert, so remove this cert from the list */
2862
0
            freenode = node;
2863
0
            node = CERT_LIST_NEXT(node);
2864
0
            CERT_RemoveCertListNode(freenode);
2865
0
        } else {
2866
            /* Is a User cert, so leave it in the list */
2867
0
            node = CERT_LIST_NEXT(node);
2868
0
        }
2869
0
    }
2870
2871
0
    return (SECSuccess);
2872
0
}
2873
2874
/* return true if cert is in the list */
2875
PRBool
2876
CERT_IsInList(const CERTCertificate *cert, const CERTCertList *certList)
2877
0
{
2878
0
    CERTCertListNode *node;
2879
0
    for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
2880
0
         node = CERT_LIST_NEXT(node)) {
2881
0
        if (node->cert == cert) {
2882
0
            return PR_TRUE;
2883
0
        }
2884
0
    }
2885
0
    return PR_FALSE;
2886
0
}
2887
2888
/* returned certList is the intersection of the certs on certList and the
2889
 * certs on filterList */
2890
SECStatus
2891
CERT_FilterCertListByCertList(CERTCertList *certList,
2892
                              const CERTCertList *filterList)
2893
0
{
2894
0
    CERTCertListNode *node, *freenode;
2895
0
    CERTCertificate *cert;
2896
2897
0
    if (!certList) {
2898
0
        return SECFailure;
2899
0
    }
2900
2901
0
    if (!filterList || CERT_LIST_EMPTY(certList)) {
2902
        /* if the filterList is empty, just clear out certList and return */
2903
0
        for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);) {
2904
0
            freenode = node;
2905
0
            node = CERT_LIST_NEXT(node);
2906
0
            CERT_RemoveCertListNode(freenode);
2907
0
        }
2908
0
        return SECSuccess;
2909
0
    }
2910
2911
0
    node = CERT_LIST_HEAD(certList);
2912
2913
0
    while (!CERT_LIST_END(node, certList)) {
2914
0
        cert = node->cert;
2915
0
        if (!CERT_IsInList(cert, filterList)) {
2916
            // no matching cert on filter list, remove it from certlist */
2917
0
            freenode = node;
2918
0
            node = CERT_LIST_NEXT(node);
2919
0
            CERT_RemoveCertListNode(freenode);
2920
0
        } else {
2921
            /* matching cert, keep it around */
2922
0
            node = CERT_LIST_NEXT(node);
2923
0
        }
2924
0
    }
2925
2926
0
    return (SECSuccess);
2927
0
}
2928
2929
SECStatus
2930
CERT_FilterCertListByNickname(CERTCertList *certList, char *nickname,
2931
                              void *pwarg)
2932
0
{
2933
0
    CERTCertList *nameList;
2934
0
    SECStatus rv;
2935
2936
0
    if (!certList) {
2937
0
        return SECFailure;
2938
0
    }
2939
2940
    /* we could try to match the nickname to the individual cert,
2941
     * but nickname parsing is quite complicated, so it's best just
2942
     * to use the existing code and get a list of certs that match the
2943
     * nickname. We can then compare that list with our input cert list
2944
     * and return only those certs that are on both. */
2945
0
    nameList = PK11_FindCertsFromNickname(nickname, pwarg);
2946
2947
    /* namelist could be NULL, this will force certList to become empty */
2948
0
    rv = CERT_FilterCertListByCertList(certList, nameList);
2949
    /* CERT_DestroyCertList can now accept a NULL pointer */
2950
0
    CERT_DestroyCertList(nameList);
2951
0
    return rv;
2952
0
}
2953
2954
static PZLock *certRefCountLock = NULL;
2955
2956
/*
2957
 * Acquire the cert reference count lock
2958
 * There is currently one global lock for all certs, but I'm putting a cert
2959
 * arg here so that it will be easy to make it per-cert in the future if
2960
 * that turns out to be necessary.
2961
 */
2962
void
2963
CERT_LockCertRefCount(CERTCertificate *cert)
2964
0
{
2965
0
    PORT_Assert(certRefCountLock != NULL);
2966
0
    PZ_Lock(certRefCountLock);
2967
0
    return;
2968
0
}
2969
2970
/*
2971
 * Free the cert reference count lock
2972
 */
2973
void
2974
CERT_UnlockCertRefCount(CERTCertificate *cert)
2975
0
{
2976
0
    PORT_Assert(certRefCountLock != NULL);
2977
0
    PRStatus prstat = PZ_Unlock(certRefCountLock);
2978
0
    PORT_AssertArg(prstat == PR_SUCCESS);
2979
0
}
2980
2981
static PZLock *certTrustLock = NULL;
2982
2983
/*
2984
 * Acquire the cert trust lock
2985
 * There is currently one global lock for all certs, but I'm putting a cert
2986
 * arg here so that it will be easy to make it per-cert in the future if
2987
 * that turns out to be necessary.
2988
 */
2989
void
2990
CERT_LockCertTrust(const CERTCertificate *cert)
2991
0
{
2992
0
    PORT_Assert(certTrustLock != NULL);
2993
0
    PZ_Lock(certTrustLock);
2994
0
}
2995
2996
static PZLock *certTempPermCertLock = NULL;
2997
2998
/*
2999
 * Acquire the cert temp/perm/nssCert lock
3000
 */
3001
void
3002
CERT_LockCertTempPerm(const CERTCertificate *cert)
3003
0
{
3004
0
    PORT_Assert(certTempPermCertLock != NULL);
3005
0
    PZ_Lock(certTempPermCertLock);
3006
0
}
3007
3008
/* Maybe[Lock, Unlock] variants are only to be used by
3009
 * CERT_DestroyCertificate, since an application could
3010
 * call this after NSS_Shutdown destroys cert locks. */
3011
void
3012
CERT_MaybeLockCertTempPerm(const CERTCertificate *cert)
3013
0
{
3014
0
    if (certTempPermCertLock) {
3015
0
        PZ_Lock(certTempPermCertLock);
3016
0
    }
3017
0
}
3018
3019
SECStatus
3020
cert_InitLocks(void)
3021
0
{
3022
0
    if (certRefCountLock == NULL) {
3023
0
        certRefCountLock = PZ_NewLock(nssILockRefLock);
3024
0
        PORT_Assert(certRefCountLock != NULL);
3025
0
        if (!certRefCountLock) {
3026
0
            return SECFailure;
3027
0
        }
3028
0
    }
3029
3030
0
    if (certTrustLock == NULL) {
3031
0
        certTrustLock = PZ_NewLock(nssILockCertDB);
3032
0
        PORT_Assert(certTrustLock != NULL);
3033
0
        if (!certTrustLock) {
3034
0
            PZ_DestroyLock(certRefCountLock);
3035
0
            certRefCountLock = NULL;
3036
0
            return SECFailure;
3037
0
        }
3038
0
    }
3039
3040
0
    if (certTempPermCertLock == NULL) {
3041
0
        certTempPermCertLock = PZ_NewLock(nssILockCertDB);
3042
0
        PORT_Assert(certTempPermCertLock != NULL);
3043
0
        if (!certTempPermCertLock) {
3044
0
            PZ_DestroyLock(certTrustLock);
3045
0
            PZ_DestroyLock(certRefCountLock);
3046
0
            certRefCountLock = NULL;
3047
0
            certTrustLock = NULL;
3048
0
            return SECFailure;
3049
0
        }
3050
0
    }
3051
3052
0
    return SECSuccess;
3053
0
}
3054
3055
SECStatus
3056
cert_DestroyLocks(void)
3057
0
{
3058
0
    SECStatus rv = SECSuccess;
3059
3060
0
    PORT_Assert(certRefCountLock != NULL);
3061
0
    if (certRefCountLock) {
3062
0
        PZ_DestroyLock(certRefCountLock);
3063
0
        certRefCountLock = NULL;
3064
0
    } else {
3065
0
        rv = SECFailure;
3066
0
    }
3067
3068
0
    PORT_Assert(certTrustLock != NULL);
3069
0
    if (certTrustLock) {
3070
0
        PZ_DestroyLock(certTrustLock);
3071
0
        certTrustLock = NULL;
3072
0
    } else {
3073
0
        rv = SECFailure;
3074
0
    }
3075
3076
0
    PORT_Assert(certTempPermCertLock != NULL);
3077
0
    if (certTempPermCertLock) {
3078
0
        PZ_DestroyLock(certTempPermCertLock);
3079
0
        certTempPermCertLock = NULL;
3080
0
    } else {
3081
0
        rv = SECFailure;
3082
0
    }
3083
0
    return rv;
3084
0
}
3085
3086
/*
3087
 * Free the cert trust lock
3088
 */
3089
void
3090
CERT_UnlockCertTrust(const CERTCertificate *cert)
3091
0
{
3092
0
    PORT_Assert(certTrustLock != NULL);
3093
0
    PRStatus prstat = PZ_Unlock(certTrustLock);
3094
0
    PORT_AssertArg(prstat == PR_SUCCESS);
3095
0
}
3096
3097
/*
3098
 * Free the temp/perm/nssCert lock
3099
 */
3100
void
3101
CERT_UnlockCertTempPerm(const CERTCertificate *cert)
3102
0
{
3103
0
    PORT_Assert(certTempPermCertLock != NULL);
3104
0
    PRStatus prstat = PZ_Unlock(certTempPermCertLock);
3105
0
    PORT_AssertArg(prstat == PR_SUCCESS);
3106
0
}
3107
3108
void
3109
CERT_MaybeUnlockCertTempPerm(const CERTCertificate *cert)
3110
0
{
3111
0
    if (certTempPermCertLock) {
3112
0
        PZ_Unlock(certTempPermCertLock);
3113
0
    }
3114
0
}
3115
3116
/*
3117
 * Get the StatusConfig data for this handle
3118
 */
3119
CERTStatusConfig *
3120
CERT_GetStatusConfig(CERTCertDBHandle *handle)
3121
0
{
3122
0
    return handle->statusConfig;
3123
0
}
3124
3125
/*
3126
 * Set the StatusConfig data for this handle.  There
3127
 * should not be another configuration set.
3128
 */
3129
void
3130
CERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *statusConfig)
3131
0
{
3132
0
    PORT_Assert(handle->statusConfig == NULL);
3133
0
    handle->statusConfig = statusConfig;
3134
0
}
3135
3136
/*
3137
 * Code for dealing with subjKeyID to cert mappings.
3138
 */
3139
3140
static PLHashTable *gSubjKeyIDHash = NULL;
3141
static PRLock *gSubjKeyIDLock = NULL;
3142
static PLHashTable *gSubjKeyIDSlotCheckHash = NULL;
3143
static PRLock *gSubjKeyIDSlotCheckLock = NULL;
3144
3145
static void *
3146
cert_AllocTable(void *pool, PRSize size)
3147
0
{
3148
0
    return PORT_Alloc(size);
3149
0
}
3150
3151
static void
3152
cert_FreeTable(void *pool, void *item)
3153
0
{
3154
0
    PORT_Free(item);
3155
0
}
3156
3157
static PLHashEntry *
3158
cert_AllocEntry(void *pool, const void *key)
3159
0
{
3160
0
    return PORT_New(PLHashEntry);
3161
0
}
3162
3163
static void
3164
cert_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
3165
0
{
3166
0
    SECITEM_FreeItem((SECItem *)(he->value), PR_TRUE);
3167
0
    if (flag == HT_FREE_ENTRY) {
3168
0
        SECITEM_FreeItem((SECItem *)(he->key), PR_TRUE);
3169
0
        PORT_Free(he);
3170
0
    }
3171
0
}
3172
3173
static PLHashAllocOps cert_AllocOps = { cert_AllocTable, cert_FreeTable,
3174
                                        cert_AllocEntry, cert_FreeEntry };
3175
3176
SECStatus
3177
cert_CreateSubjectKeyIDSlotCheckHash(void)
3178
0
{
3179
    /*
3180
     * This hash is used to remember the series of a slot
3181
     * when we last checked for user certs
3182
     */
3183
0
    gSubjKeyIDSlotCheckHash =
3184
0
        PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
3185
0
                        SECITEM_HashCompare, &cert_AllocOps, NULL);
3186
0
    if (!gSubjKeyIDSlotCheckHash) {
3187
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3188
0
        return SECFailure;
3189
0
    }
3190
0
    gSubjKeyIDSlotCheckLock = PR_NewLock();
3191
0
    if (!gSubjKeyIDSlotCheckLock) {
3192
0
        PL_HashTableDestroy(gSubjKeyIDSlotCheckHash);
3193
0
        gSubjKeyIDSlotCheckHash = NULL;
3194
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3195
0
        return SECFailure;
3196
0
    }
3197
0
    return SECSuccess;
3198
0
}
3199
3200
SECStatus
3201
cert_CreateSubjectKeyIDHashTable(void)
3202
0
{
3203
0
    gSubjKeyIDHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
3204
0
                                     SECITEM_HashCompare, &cert_AllocOps, NULL);
3205
0
    if (!gSubjKeyIDHash) {
3206
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3207
0
        return SECFailure;
3208
0
    }
3209
0
    gSubjKeyIDLock = PR_NewLock();
3210
0
    if (!gSubjKeyIDLock) {
3211
0
        PL_HashTableDestroy(gSubjKeyIDHash);
3212
0
        gSubjKeyIDHash = NULL;
3213
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3214
0
        return SECFailure;
3215
0
    }
3216
    /* initialize the companion hash (for remembering slot series) */
3217
0
    if (cert_CreateSubjectKeyIDSlotCheckHash() != SECSuccess) {
3218
0
        cert_DestroySubjectKeyIDHashTable();
3219
0
        return SECFailure;
3220
0
    }
3221
0
    return SECSuccess;
3222
0
}
3223
3224
SECStatus
3225
cert_AddSubjectKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert)
3226
0
{
3227
0
    SECItem *newKeyID, *oldVal, *newVal;
3228
0
    SECStatus rv = SECFailure;
3229
3230
0
    if (!gSubjKeyIDLock) {
3231
        /* If one is created, then both are there.  So only check for one. */
3232
0
        return SECFailure;
3233
0
    }
3234
3235
0
    newVal = SECITEM_DupItem(&cert->derCert);
3236
0
    if (!newVal) {
3237
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3238
0
        goto done;
3239
0
    }
3240
0
    newKeyID = SECITEM_DupItem(subjKeyID);
3241
0
    if (!newKeyID) {
3242
0
        SECITEM_FreeItem(newVal, PR_TRUE);
3243
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3244
0
        goto done;
3245
0
    }
3246
3247
0
    PR_Lock(gSubjKeyIDLock);
3248
    /* The hash table implementation does not free up the memory
3249
     * associated with the key of an already existing entry if we add a
3250
     * duplicate, so we would wind up leaking the previously allocated
3251
     * key if we don't remove before adding.
3252
     */
3253
0
    oldVal = (SECItem *)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
3254
0
    if (oldVal) {
3255
0
        PL_HashTableRemove(gSubjKeyIDHash, subjKeyID);
3256
0
    }
3257
3258
0
    rv = (PL_HashTableAdd(gSubjKeyIDHash, newKeyID, newVal)) ? SECSuccess
3259
0
                                                             : SECFailure;
3260
0
    PR_Unlock(gSubjKeyIDLock);
3261
0
done:
3262
0
    return rv;
3263
0
}
3264
3265
SECStatus
3266
cert_RemoveSubjectKeyIDMapping(SECItem *subjKeyID)
3267
0
{
3268
0
    SECStatus rv;
3269
0
    if (!gSubjKeyIDLock)
3270
0
        return SECFailure;
3271
3272
0
    PR_Lock(gSubjKeyIDLock);
3273
0
    rv = (PL_HashTableRemove(gSubjKeyIDHash, subjKeyID)) ? SECSuccess
3274
0
                                                         : SECFailure;
3275
0
    PR_Unlock(gSubjKeyIDLock);
3276
0
    return rv;
3277
0
}
3278
3279
SECStatus
3280
cert_UpdateSubjectKeyIDSlotCheck(SECItem *slotid, int series)
3281
0
{
3282
0
    SECItem *oldSeries, *newSlotid, *newSeries;
3283
0
    SECStatus rv = SECFailure;
3284
3285
0
    if (!gSubjKeyIDSlotCheckLock) {
3286
0
        return rv;
3287
0
    }
3288
3289
0
    newSlotid = SECITEM_DupItem(slotid);
3290
0
    newSeries = SECITEM_AllocItem(NULL, NULL, sizeof(int));
3291
0
    if (!newSlotid || !newSeries) {
3292
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3293
0
        goto loser;
3294
0
    }
3295
0
    PORT_Memcpy(newSeries->data, &series, sizeof(int));
3296
3297
0
    PR_Lock(gSubjKeyIDSlotCheckLock);
3298
0
    oldSeries = (SECItem *)PL_HashTableLookup(gSubjKeyIDSlotCheckHash, slotid);
3299
0
    if (oldSeries) {
3300
        /*
3301
         * make sure we don't leak the key of an existing entry
3302
         * (similar to cert_AddSubjectKeyIDMapping, see comment there)
3303
         */
3304
0
        PL_HashTableRemove(gSubjKeyIDSlotCheckHash, slotid);
3305
0
    }
3306
0
    rv = (PL_HashTableAdd(gSubjKeyIDSlotCheckHash, newSlotid, newSeries))
3307
0
             ? SECSuccess
3308
0
             : SECFailure;
3309
0
    PR_Unlock(gSubjKeyIDSlotCheckLock);
3310
0
    if (rv == SECSuccess) {
3311
0
        return rv;
3312
0
    }
3313
3314
0
loser:
3315
0
    if (newSlotid) {
3316
0
        SECITEM_FreeItem(newSlotid, PR_TRUE);
3317
0
    }
3318
0
    if (newSeries) {
3319
0
        SECITEM_FreeItem(newSeries, PR_TRUE);
3320
0
    }
3321
0
    return rv;
3322
0
}
3323
3324
int
3325
cert_SubjectKeyIDSlotCheckSeries(SECItem *slotid)
3326
0
{
3327
0
    SECItem *seriesItem = NULL;
3328
0
    int series;
3329
3330
0
    if (!gSubjKeyIDSlotCheckLock) {
3331
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
3332
0
        return -1;
3333
0
    }
3334
3335
0
    PR_Lock(gSubjKeyIDSlotCheckLock);
3336
0
    seriesItem = (SECItem *)PL_HashTableLookup(gSubjKeyIDSlotCheckHash, slotid);
3337
0
    PR_Unlock(gSubjKeyIDSlotCheckLock);
3338
    /* getting a null series just means we haven't registered one yet,
3339
     * just return 0 */
3340
0
    if (seriesItem == NULL) {
3341
0
        return 0;
3342
0
    }
3343
    /* if we got a series back, assert if it's not the proper length. */
3344
0
    PORT_Assert(seriesItem->len == sizeof(int));
3345
0
    if (seriesItem->len != sizeof(int)) {
3346
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
3347
0
        return -1;
3348
0
    }
3349
0
    PORT_Memcpy(&series, seriesItem->data, sizeof(int));
3350
0
    return series;
3351
0
}
3352
3353
SECStatus
3354
cert_DestroySubjectKeyIDSlotCheckHash(void)
3355
0
{
3356
0
    if (gSubjKeyIDSlotCheckHash) {
3357
0
        PR_Lock(gSubjKeyIDSlotCheckLock);
3358
0
        PL_HashTableDestroy(gSubjKeyIDSlotCheckHash);
3359
0
        gSubjKeyIDSlotCheckHash = NULL;
3360
0
        PR_Unlock(gSubjKeyIDSlotCheckLock);
3361
0
        PR_DestroyLock(gSubjKeyIDSlotCheckLock);
3362
0
        gSubjKeyIDSlotCheckLock = NULL;
3363
0
    }
3364
0
    return SECSuccess;
3365
0
}
3366
3367
SECStatus
3368
cert_DestroySubjectKeyIDHashTable(void)
3369
0
{
3370
0
    if (gSubjKeyIDHash) {
3371
0
        PR_Lock(gSubjKeyIDLock);
3372
0
        PL_HashTableDestroy(gSubjKeyIDHash);
3373
0
        gSubjKeyIDHash = NULL;
3374
0
        PR_Unlock(gSubjKeyIDLock);
3375
0
        PR_DestroyLock(gSubjKeyIDLock);
3376
0
        gSubjKeyIDLock = NULL;
3377
0
    }
3378
0
    cert_DestroySubjectKeyIDSlotCheckHash();
3379
0
    return SECSuccess;
3380
0
}
3381
3382
SECItem *
3383
cert_FindDERCertBySubjectKeyID(SECItem *subjKeyID)
3384
0
{
3385
0
    SECItem *val;
3386
3387
0
    if (!gSubjKeyIDLock)
3388
0
        return NULL;
3389
3390
0
    PR_Lock(gSubjKeyIDLock);
3391
0
    val = (SECItem *)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
3392
0
    if (val) {
3393
0
        val = SECITEM_DupItem(val);
3394
0
    }
3395
0
    PR_Unlock(gSubjKeyIDLock);
3396
0
    return val;
3397
0
}
3398
3399
CERTCertificate *
3400
CERT_FindCertBySubjectKeyID(CERTCertDBHandle *handle, SECItem *subjKeyID)
3401
0
{
3402
0
    CERTCertificate *cert = NULL;
3403
0
    SECItem *derCert;
3404
3405
0
    derCert = cert_FindDERCertBySubjectKeyID(subjKeyID);
3406
0
    if (derCert) {
3407
0
        cert = CERT_FindCertByDERCert(handle, derCert);
3408
0
        SECITEM_FreeItem(derCert, PR_TRUE);
3409
0
    }
3410
0
    return cert;
3411
0
}