comparison nss/lib/certdb/certdb.c @ 0:1e5118fa0cb1

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