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

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

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

Powered by Google App Engine
This is Rietveld 408576698