Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: nss/lib/certdb/certdb.c

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

Powered by Google App Engine
This is Rietveld 408576698