Coverage Report

Created: 2018-09-25 14:53

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