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