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