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