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