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