|
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 #include "nspr.h" |
|
5 #include "secerr.h" |
|
6 #include "secasn1.h" |
|
7 #include "seccomon.h" |
|
8 #include "pk11func.h" |
|
9 #include "certdb.h" |
|
10 #include "certt.h" |
|
11 #include "cert.h" |
|
12 #include "certxutl.h" |
|
13 |
|
14 #include "nsspki.h" |
|
15 #include "pki.h" |
|
16 #include "pkit.h" |
|
17 #include "pkitm.h" |
|
18 #include "pki3hack.h" |
|
19 |
|
20 |
|
21 PRBool |
|
22 CERT_MatchNickname(char *name1, char *name2) { |
|
23 char *nickname1= NULL; |
|
24 char *nickname2 = NULL; |
|
25 char *token1; |
|
26 char *token2; |
|
27 char *token = NULL; |
|
28 int len; |
|
29 |
|
30 /* first deal with the straight comparison */ |
|
31 if (PORT_Strcmp(name1, name2) == 0) { |
|
32 return PR_TRUE; |
|
33 } |
|
34 /* we need to handle the case where one name has an explicit token and the other |
|
35 * doesn't */ |
|
36 token1 = PORT_Strchr(name1,':'); |
|
37 token2 = PORT_Strchr(name2,':'); |
|
38 if ((token1 && token2) || (!token1 && !token2)) { |
|
39 /* either both token names are specified or neither are, not match */ |
|
40 return PR_FALSE; |
|
41 } |
|
42 if (token1) { |
|
43 token=name1; |
|
44 nickname1=token1; |
|
45 nickname2=name2; |
|
46 } else { |
|
47 token=name2; |
|
48 nickname1=token2; |
|
49 nickname2=name1; |
|
50 } |
|
51 len = nickname1-token; |
|
52 nickname1++; |
|
53 if (PORT_Strcmp(nickname1,nickname2) != 0) { |
|
54 return PR_FALSE; |
|
55 } |
|
56 /* compare the other token with the internal slot here */ |
|
57 return PR_TRUE; |
|
58 } |
|
59 |
|
60 /* |
|
61 * Find all user certificates that match the given criteria. |
|
62 * |
|
63 * "handle" - database to search |
|
64 * "usage" - certificate usage to match |
|
65 * "oneCertPerName" - if set then only return the "best" cert per |
|
66 * name |
|
67 * "validOnly" - only return certs that are curently valid |
|
68 * "proto_win" - window handle passed to pkcs11 |
|
69 */ |
|
70 CERTCertList * |
|
71 CERT_FindUserCertsByUsage(CERTCertDBHandle *handle, |
|
72 SECCertUsage usage, |
|
73 PRBool oneCertPerName, |
|
74 PRBool validOnly, |
|
75 void *proto_win) |
|
76 { |
|
77 CERTCertNicknames *nicknames = NULL; |
|
78 char **nnptr; |
|
79 int nn; |
|
80 CERTCertificate *cert = NULL; |
|
81 CERTCertList *certList = NULL; |
|
82 SECStatus rv; |
|
83 PRTime time; |
|
84 CERTCertListNode *node = NULL; |
|
85 CERTCertListNode *freenode = NULL; |
|
86 int n; |
|
87 |
|
88 time = PR_Now(); |
|
89 |
|
90 nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER, |
|
91 proto_win); |
|
92 |
|
93 if ( ( nicknames == NULL ) || ( nicknames->numnicknames == 0 ) ) { |
|
94 goto loser; |
|
95 } |
|
96 |
|
97 nnptr = nicknames->nicknames; |
|
98 nn = nicknames->numnicknames; |
|
99 |
|
100 while ( nn > 0 ) { |
|
101 cert = NULL; |
|
102 /* use the pk11 call so that we pick up any certs on tokens, |
|
103 * which may require login |
|
104 */ |
|
105 if ( proto_win != NULL ) { |
|
106 cert = PK11_FindCertFromNickname(*nnptr,proto_win); |
|
107 } |
|
108 |
|
109 /* Sigh, It turns out if the cert is already in the temp db, because |
|
110 * it's in the perm db, then the nickname lookup doesn't work. |
|
111 * since we already have the cert here, though, than we can just call |
|
112 * CERT_CreateSubjectCertList directly. For those cases where we didn't |
|
113 * find the cert in pkcs #11 (because we didn't have a password arg, |
|
114 * or because the nickname is for a peer, server, or CA cert, then we |
|
115 * go look the cert up. |
|
116 */ |
|
117 if (cert == NULL) { |
|
118 cert = CERT_FindCertByNickname(handle,*nnptr); |
|
119 } |
|
120 |
|
121 if ( cert != NULL ) { |
|
122 /* collect certs for this nickname, sorting them into the list */ |
|
123 certList = CERT_CreateSubjectCertList(certList, handle, |
|
124 &cert->derSubject, time, validOnly); |
|
125 |
|
126 CERT_FilterCertListForUserCerts(certList); |
|
127 |
|
128 /* drop the extra reference */ |
|
129 CERT_DestroyCertificate(cert); |
|
130 } |
|
131 |
|
132 nnptr++; |
|
133 nn--; |
|
134 } |
|
135 |
|
136 /* remove certs with incorrect usage */ |
|
137 rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); |
|
138 |
|
139 if ( rv != SECSuccess ) { |
|
140 goto loser; |
|
141 } |
|
142 |
|
143 /* remove any extra certs for each name */ |
|
144 if ( oneCertPerName ) { |
|
145 PRBool *flags; |
|
146 |
|
147 nn = nicknames->numnicknames; |
|
148 nnptr = nicknames->nicknames; |
|
149 |
|
150 flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn); |
|
151 if ( flags == NULL ) { |
|
152 goto loser; |
|
153 } |
|
154 |
|
155 node = CERT_LIST_HEAD(certList); |
|
156 |
|
157 /* treverse all certs in the list */ |
|
158 while ( !CERT_LIST_END(node, certList) ) { |
|
159 |
|
160 /* find matching nickname index */ |
|
161 for ( n = 0; n < nn; n++ ) { |
|
162 if ( CERT_MatchNickname(nnptr[n], node->cert->nickname) ) { |
|
163 /* We found a match. If this is the first one, then |
|
164 * set the flag and move on to the next cert. If this |
|
165 * is not the first one then delete it from the list. |
|
166 */ |
|
167 if ( flags[n] ) { |
|
168 /* We have already seen a cert with this nickname, |
|
169 * so delete this one. |
|
170 */ |
|
171 freenode = node; |
|
172 node = CERT_LIST_NEXT(node); |
|
173 CERT_RemoveCertListNode(freenode); |
|
174 } else { |
|
175 /* keep the first cert for each nickname, but set the |
|
176 * flag so we know to delete any others with the same |
|
177 * nickname. |
|
178 */ |
|
179 flags[n] = PR_TRUE; |
|
180 node = CERT_LIST_NEXT(node); |
|
181 } |
|
182 break; |
|
183 } |
|
184 } |
|
185 if ( n == nn ) { |
|
186 /* if we get here it means that we didn't find a matching |
|
187 * nickname, which should not happen. |
|
188 */ |
|
189 PORT_Assert(0); |
|
190 node = CERT_LIST_NEXT(node); |
|
191 } |
|
192 } |
|
193 PORT_Free(flags); |
|
194 } |
|
195 |
|
196 goto done; |
|
197 |
|
198 loser: |
|
199 if ( certList != NULL ) { |
|
200 CERT_DestroyCertList(certList); |
|
201 certList = NULL; |
|
202 } |
|
203 |
|
204 done: |
|
205 if ( nicknames != NULL ) { |
|
206 CERT_FreeNicknames(nicknames); |
|
207 } |
|
208 |
|
209 return(certList); |
|
210 } |
|
211 |
|
212 /* |
|
213 * Find a user certificate that matchs the given criteria. |
|
214 * |
|
215 * "handle" - database to search |
|
216 * "nickname" - nickname to match |
|
217 * "usage" - certificate usage to match |
|
218 * "validOnly" - only return certs that are curently valid |
|
219 * "proto_win" - window handle passed to pkcs11 |
|
220 */ |
|
221 CERTCertificate * |
|
222 CERT_FindUserCertByUsage(CERTCertDBHandle *handle, |
|
223 const char *nickname, |
|
224 SECCertUsage usage, |
|
225 PRBool validOnly, |
|
226 void *proto_win) |
|
227 { |
|
228 CERTCertificate *cert = NULL; |
|
229 CERTCertList *certList = NULL; |
|
230 SECStatus rv; |
|
231 PRTime time; |
|
232 |
|
233 time = PR_Now(); |
|
234 |
|
235 /* use the pk11 call so that we pick up any certs on tokens, |
|
236 * which may require login |
|
237 */ |
|
238 /* XXX - why is this restricted? */ |
|
239 if ( proto_win != NULL ) { |
|
240 cert = PK11_FindCertFromNickname(nickname,proto_win); |
|
241 } |
|
242 |
|
243 |
|
244 /* sigh, There are still problems find smart cards from the temp |
|
245 * db. This will get smart cards working again. The real fix |
|
246 * is to make sure we can search the temp db by their token nickname. |
|
247 */ |
|
248 if (cert == NULL) { |
|
249 cert = CERT_FindCertByNickname(handle,nickname); |
|
250 } |
|
251 |
|
252 if ( cert != NULL ) { |
|
253 unsigned int requiredKeyUsage; |
|
254 unsigned int requiredCertType; |
|
255 |
|
256 rv = CERT_KeyUsageAndTypeForCertUsage(usage, PR_FALSE, |
|
257 &requiredKeyUsage, &requiredCertType); |
|
258 if ( rv != SECSuccess ) { |
|
259 /* drop the extra reference */ |
|
260 CERT_DestroyCertificate(cert); |
|
261 cert = NULL; |
|
262 goto loser; |
|
263 } |
|
264 /* If we already found the right cert, just return it */ |
|
265 if ( (!validOnly || CERT_CheckCertValidTimes(cert, time, PR_FALSE) |
|
266 == secCertTimeValid) && |
|
267 (CERT_CheckKeyUsage(cert, requiredKeyUsage) == SECSuccess) && |
|
268 (cert->nsCertType & requiredCertType) && |
|
269 CERT_IsUserCert(cert) ) { |
|
270 return(cert); |
|
271 } |
|
272 |
|
273 /* collect certs for this nickname, sorting them into the list */ |
|
274 certList = CERT_CreateSubjectCertList(certList, handle, |
|
275 &cert->derSubject, time, validOnly); |
|
276 |
|
277 CERT_FilterCertListForUserCerts(certList); |
|
278 |
|
279 /* drop the extra reference */ |
|
280 CERT_DestroyCertificate(cert); |
|
281 cert = NULL; |
|
282 } |
|
283 |
|
284 if ( certList == NULL ) { |
|
285 goto loser; |
|
286 } |
|
287 |
|
288 /* remove certs with incorrect usage */ |
|
289 rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); |
|
290 |
|
291 if ( rv != SECSuccess ) { |
|
292 goto loser; |
|
293 } |
|
294 |
|
295 if ( ! CERT_LIST_END(CERT_LIST_HEAD(certList), certList) ) { |
|
296 cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert); |
|
297 } |
|
298 |
|
299 loser: |
|
300 if ( certList != NULL ) { |
|
301 CERT_DestroyCertList(certList); |
|
302 } |
|
303 |
|
304 return(cert); |
|
305 } |
|
306 |
|
307 CERTCertList * |
|
308 CERT_MatchUserCert(CERTCertDBHandle *handle, |
|
309 SECCertUsage usage, |
|
310 int nCANames, char **caNames, |
|
311 void *proto_win) |
|
312 { |
|
313 CERTCertList *certList = NULL; |
|
314 SECStatus rv; |
|
315 |
|
316 certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE, |
|
317 proto_win); |
|
318 if ( certList == NULL ) { |
|
319 goto loser; |
|
320 } |
|
321 |
|
322 rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage); |
|
323 if ( rv != SECSuccess ) { |
|
324 goto loser; |
|
325 } |
|
326 |
|
327 goto done; |
|
328 |
|
329 loser: |
|
330 if ( certList != NULL ) { |
|
331 CERT_DestroyCertList(certList); |
|
332 certList = NULL; |
|
333 } |
|
334 |
|
335 done: |
|
336 |
|
337 return(certList); |
|
338 } |
|
339 |
|
340 |
|
341 typedef struct stringNode { |
|
342 struct stringNode *next; |
|
343 char *string; |
|
344 } stringNode; |
|
345 |
|
346 static PRStatus |
|
347 CollectNicknames( NSSCertificate *c, void *data) |
|
348 { |
|
349 CERTCertNicknames *names; |
|
350 PRBool saveit = PR_FALSE; |
|
351 stringNode *node; |
|
352 int len; |
|
353 #ifdef notdef |
|
354 NSSTrustDomain *td; |
|
355 NSSTrust *trust; |
|
356 #endif |
|
357 char *stanNickname; |
|
358 char *nickname = NULL; |
|
359 |
|
360 names = (CERTCertNicknames *)data; |
|
361 |
|
362 stanNickname = nssCertificate_GetNickname(c,NULL); |
|
363 |
|
364 if ( stanNickname ) { |
|
365 nss_ZFreeIf(stanNickname); |
|
366 stanNickname = NULL; |
|
367 if (names->what == SEC_CERT_NICKNAMES_USER) { |
|
368 saveit = NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL); |
|
369 } |
|
370 #ifdef notdef |
|
371 else { |
|
372 td = NSSCertificate_GetTrustDomain(c); |
|
373 if (!td) { |
|
374 return PR_SUCCESS; |
|
375 } |
|
376 trust = nssTrustDomain_FindTrustForCertificate(td,c); |
|
377 |
|
378 switch(names->what) { |
|
379 case SEC_CERT_NICKNAMES_ALL: |
|
380 if ((trust->sslFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) || |
|
381 (trust->emailFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) || |
|
382 (trust->objectSigningFlags & |
|
383 (CERTDB_VALID_CA|CERTDB_VALID_PEER))) { |
|
384 saveit = PR_TRUE; |
|
385 } |
|
386 |
|
387 break; |
|
388 case SEC_CERT_NICKNAMES_SERVER: |
|
389 if ( trust->sslFlags & CERTDB_VALID_PEER ) { |
|
390 saveit = PR_TRUE; |
|
391 } |
|
392 |
|
393 break; |
|
394 case SEC_CERT_NICKNAMES_CA: |
|
395 if (((trust->sslFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA)|| |
|
396 ((trust->emailFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA) || |
|
397 ((trust->objectSigningFlags & CERTDB_VALID_CA ) |
|
398 == CERTDB_VALID_CA)) { |
|
399 saveit = PR_TRUE; |
|
400 } |
|
401 break; |
|
402 } |
|
403 } |
|
404 #endif |
|
405 } |
|
406 |
|
407 /* traverse the list of collected nicknames and make sure we don't make |
|
408 * a duplicate |
|
409 */ |
|
410 if ( saveit ) { |
|
411 nickname = STAN_GetCERTCertificateName(NULL, c); |
|
412 /* nickname can only be NULL here if we are having memory |
|
413 * alloc problems */ |
|
414 if (nickname == NULL) { |
|
415 return PR_FAILURE; |
|
416 } |
|
417 node = (stringNode *)names->head; |
|
418 while ( node != NULL ) { |
|
419 if ( PORT_Strcmp(nickname, node->string) == 0 ) { |
|
420 /* if the string matches, then don't save this one */ |
|
421 saveit = PR_FALSE; |
|
422 break; |
|
423 } |
|
424 node = node->next; |
|
425 } |
|
426 } |
|
427 |
|
428 if ( saveit ) { |
|
429 |
|
430 /* allocate the node */ |
|
431 node = (stringNode*)PORT_ArenaAlloc(names->arena, sizeof(stringNode)); |
|
432 if ( node == NULL ) { |
|
433 PORT_Free(nickname); |
|
434 return PR_FAILURE; |
|
435 } |
|
436 |
|
437 /* copy the string */ |
|
438 len = PORT_Strlen(nickname) + 1; |
|
439 node->string = (char*)PORT_ArenaAlloc(names->arena, len); |
|
440 if ( node->string == NULL ) { |
|
441 PORT_Free(nickname); |
|
442 return PR_FAILURE; |
|
443 } |
|
444 PORT_Memcpy(node->string, nickname, len); |
|
445 |
|
446 /* link it into the list */ |
|
447 node->next = (stringNode *)names->head; |
|
448 names->head = (void *)node; |
|
449 |
|
450 /* bump the count */ |
|
451 names->numnicknames++; |
|
452 } |
|
453 |
|
454 if (nickname) PORT_Free(nickname); |
|
455 return(PR_SUCCESS); |
|
456 } |
|
457 |
|
458 CERTCertNicknames * |
|
459 CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx) |
|
460 { |
|
461 PLArenaPool *arena; |
|
462 CERTCertNicknames *names; |
|
463 int i; |
|
464 stringNode *node; |
|
465 |
|
466 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
467 if ( arena == NULL ) { |
|
468 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
469 return(NULL); |
|
470 } |
|
471 |
|
472 names = (CERTCertNicknames *)PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames)); |
|
473 if ( names == NULL ) { |
|
474 goto loser; |
|
475 } |
|
476 |
|
477 names->arena = arena; |
|
478 names->head = NULL; |
|
479 names->numnicknames = 0; |
|
480 names->nicknames = NULL; |
|
481 names->what = what; |
|
482 names->totallen = 0; |
|
483 |
|
484 /* make sure we are logged in */ |
|
485 (void) pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx); |
|
486 |
|
487 NSSTrustDomain_TraverseCertificates(handle, |
|
488 CollectNicknames, (void *)names); |
|
489 if ( names->numnicknames ) { |
|
490 names->nicknames = (char**)PORT_ArenaAlloc(arena, |
|
491 names->numnicknames * sizeof(char *)); |
|
492 |
|
493 if ( names->nicknames == NULL ) { |
|
494 goto loser; |
|
495 } |
|
496 |
|
497 node = (stringNode *)names->head; |
|
498 |
|
499 for ( i = 0; i < names->numnicknames; i++ ) { |
|
500 PORT_Assert(node != NULL); |
|
501 |
|
502 names->nicknames[i] = node->string; |
|
503 names->totallen += PORT_Strlen(node->string); |
|
504 node = node->next; |
|
505 } |
|
506 |
|
507 PORT_Assert(node == NULL); |
|
508 } |
|
509 |
|
510 return(names); |
|
511 |
|
512 loser: |
|
513 PORT_FreeArena(arena, PR_FALSE); |
|
514 return(NULL); |
|
515 } |
|
516 |
|
517 void |
|
518 CERT_FreeNicknames(CERTCertNicknames *nicknames) |
|
519 { |
|
520 PORT_FreeArena(nicknames->arena, PR_FALSE); |
|
521 |
|
522 return; |
|
523 } |
|
524 |
|
525 /* [ FROM pcertdb.c ] */ |
|
526 |
|
527 typedef struct dnameNode { |
|
528 struct dnameNode *next; |
|
529 SECItem name; |
|
530 } dnameNode; |
|
531 |
|
532 void |
|
533 CERT_FreeDistNames(CERTDistNames *names) |
|
534 { |
|
535 PORT_FreeArena(names->arena, PR_FALSE); |
|
536 |
|
537 return; |
|
538 } |
|
539 |
|
540 static SECStatus |
|
541 CollectDistNames( CERTCertificate *cert, SECItem *k, void *data) |
|
542 { |
|
543 CERTDistNames *names; |
|
544 PRBool saveit = PR_FALSE; |
|
545 CERTCertTrust trust; |
|
546 dnameNode *node; |
|
547 int len; |
|
548 |
|
549 names = (CERTDistNames *)data; |
|
550 |
|
551 if ( CERT_GetCertTrust(cert, &trust) == SECSuccess ) { |
|
552 /* only collect names of CAs trusted for issuing SSL clients */ |
|
553 if ( trust.sslFlags & CERTDB_TRUSTED_CLIENT_CA ) { |
|
554 saveit = PR_TRUE; |
|
555 } |
|
556 } |
|
557 |
|
558 if ( saveit ) { |
|
559 /* allocate the node */ |
|
560 node = (dnameNode*)PORT_ArenaAlloc(names->arena, sizeof(dnameNode)); |
|
561 if ( node == NULL ) { |
|
562 return(SECFailure); |
|
563 } |
|
564 |
|
565 /* copy the name */ |
|
566 node->name.len = len = cert->derSubject.len; |
|
567 node->name.type = siBuffer; |
|
568 node->name.data = (unsigned char*)PORT_ArenaAlloc(names->arena, len); |
|
569 if ( node->name.data == NULL ) { |
|
570 return(SECFailure); |
|
571 } |
|
572 PORT_Memcpy(node->name.data, cert->derSubject.data, len); |
|
573 |
|
574 /* link it into the list */ |
|
575 node->next = (dnameNode *)names->head; |
|
576 names->head = (void *)node; |
|
577 |
|
578 /* bump the count */ |
|
579 names->nnames++; |
|
580 } |
|
581 |
|
582 return(SECSuccess); |
|
583 } |
|
584 |
|
585 /* |
|
586 * Return all of the CAs that are "trusted" for SSL. |
|
587 */ |
|
588 CERTDistNames * |
|
589 CERT_DupDistNames(CERTDistNames *orig) |
|
590 { |
|
591 PLArenaPool *arena; |
|
592 CERTDistNames *names; |
|
593 int i; |
|
594 SECStatus rv; |
|
595 |
|
596 /* allocate an arena to use */ |
|
597 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
598 if (arena == NULL) { |
|
599 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
600 return(NULL); |
|
601 } |
|
602 |
|
603 /* allocate the header structure */ |
|
604 names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames)); |
|
605 if (names == NULL) { |
|
606 goto loser; |
|
607 } |
|
608 |
|
609 /* initialize the header struct */ |
|
610 names->arena = arena; |
|
611 names->head = NULL; |
|
612 names->nnames = orig->nnames; |
|
613 names->names = NULL; |
|
614 |
|
615 /* construct the array from the list */ |
|
616 if (orig->nnames) { |
|
617 names->names = (SECItem*)PORT_ArenaNewArray(arena, SECItem, |
|
618 orig->nnames); |
|
619 if (names->names == NULL) { |
|
620 goto loser; |
|
621 } |
|
622 for (i = 0; i < orig->nnames; i++) { |
|
623 rv = SECITEM_CopyItem(arena, &names->names[i], &orig->names[i]); |
|
624 if (rv != SECSuccess) { |
|
625 goto loser; |
|
626 } |
|
627 } |
|
628 } |
|
629 return(names); |
|
630 |
|
631 loser: |
|
632 PORT_FreeArena(arena, PR_FALSE); |
|
633 return(NULL); |
|
634 } |
|
635 |
|
636 CERTDistNames * |
|
637 CERT_GetSSLCACerts(CERTCertDBHandle *handle) |
|
638 { |
|
639 PLArenaPool *arena; |
|
640 CERTDistNames *names; |
|
641 int i; |
|
642 SECStatus rv; |
|
643 dnameNode *node; |
|
644 |
|
645 /* allocate an arena to use */ |
|
646 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
647 if ( arena == NULL ) { |
|
648 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
649 return(NULL); |
|
650 } |
|
651 |
|
652 /* allocate the header structure */ |
|
653 names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames)); |
|
654 if ( names == NULL ) { |
|
655 goto loser; |
|
656 } |
|
657 |
|
658 /* initialize the header struct */ |
|
659 names->arena = arena; |
|
660 names->head = NULL; |
|
661 names->nnames = 0; |
|
662 names->names = NULL; |
|
663 |
|
664 /* collect the names from the database */ |
|
665 rv = PK11_TraverseSlotCerts(CollectDistNames, (void *)names, NULL); |
|
666 if ( rv ) { |
|
667 goto loser; |
|
668 } |
|
669 |
|
670 /* construct the array from the list */ |
|
671 if ( names->nnames ) { |
|
672 names->names = (SECItem*)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem)); |
|
673 |
|
674 if ( names->names == NULL ) { |
|
675 goto loser; |
|
676 } |
|
677 |
|
678 node = (dnameNode *)names->head; |
|
679 |
|
680 for ( i = 0; i < names->nnames; i++ ) { |
|
681 PORT_Assert(node != NULL); |
|
682 |
|
683 names->names[i] = node->name; |
|
684 node = node->next; |
|
685 } |
|
686 |
|
687 PORT_Assert(node == NULL); |
|
688 } |
|
689 |
|
690 return(names); |
|
691 |
|
692 loser: |
|
693 PORT_FreeArena(arena, PR_FALSE); |
|
694 return(NULL); |
|
695 } |
|
696 |
|
697 CERTDistNames * |
|
698 CERT_DistNamesFromCertList(CERTCertList *certList) |
|
699 { |
|
700 CERTDistNames * dnames = NULL; |
|
701 PLArenaPool * arena; |
|
702 CERTCertListNode *node = NULL; |
|
703 SECItem * names = NULL; |
|
704 int listLen = 0, i = 0; |
|
705 |
|
706 if (certList == NULL) { |
|
707 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
708 return NULL; |
|
709 } |
|
710 |
|
711 node = CERT_LIST_HEAD(certList); |
|
712 while ( ! CERT_LIST_END(node, certList) ) { |
|
713 listLen += 1; |
|
714 node = CERT_LIST_NEXT(node); |
|
715 } |
|
716 |
|
717 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
718 if (arena == NULL) goto loser; |
|
719 dnames = PORT_ArenaZNew(arena, CERTDistNames); |
|
720 if (dnames == NULL) goto loser; |
|
721 |
|
722 dnames->arena = arena; |
|
723 dnames->nnames = listLen; |
|
724 dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, listLen); |
|
725 if (names == NULL) goto loser; |
|
726 |
|
727 node = CERT_LIST_HEAD(certList); |
|
728 while ( ! CERT_LIST_END(node, certList) ) { |
|
729 CERTCertificate *cert = node->cert; |
|
730 SECStatus rv = SECITEM_CopyItem(arena, &names[i++], &cert->derSubject); |
|
731 if (rv == SECFailure) { |
|
732 goto loser; |
|
733 } |
|
734 node = CERT_LIST_NEXT(node); |
|
735 } |
|
736 return dnames; |
|
737 loser: |
|
738 if (arena) { |
|
739 PORT_FreeArena(arena, PR_FALSE); |
|
740 } |
|
741 return NULL; |
|
742 } |
|
743 |
|
744 CERTDistNames * |
|
745 CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames, |
|
746 int nnames) |
|
747 { |
|
748 CERTDistNames *dnames = NULL; |
|
749 PLArenaPool *arena; |
|
750 int i, rv; |
|
751 SECItem *names = NULL; |
|
752 CERTCertificate *cert = NULL; |
|
753 |
|
754 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
755 if (arena == NULL) goto loser; |
|
756 dnames = PORT_ArenaZNew(arena, CERTDistNames); |
|
757 if (dnames == NULL) goto loser; |
|
758 |
|
759 dnames->arena = arena; |
|
760 dnames->nnames = nnames; |
|
761 dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames); |
|
762 if (names == NULL) goto loser; |
|
763 |
|
764 for (i = 0; i < nnames; i++) { |
|
765 cert = CERT_FindCertByNicknameOrEmailAddr(handle, nicknames[i]); |
|
766 if (cert == NULL) goto loser; |
|
767 rv = SECITEM_CopyItem(arena, &names[i], &cert->derSubject); |
|
768 if (rv == SECFailure) goto loser; |
|
769 CERT_DestroyCertificate(cert); |
|
770 } |
|
771 return dnames; |
|
772 |
|
773 loser: |
|
774 if (cert != NULL) |
|
775 CERT_DestroyCertificate(cert); |
|
776 if (arena != NULL) |
|
777 PORT_FreeArena(arena, PR_FALSE); |
|
778 return NULL; |
|
779 } |
|
780 |
|
781 /* [ from pcertdb.c - calls Ascii to Name ] */ |
|
782 /* |
|
783 * Lookup a certificate in the database by name |
|
784 */ |
|
785 CERTCertificate * |
|
786 CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr) |
|
787 { |
|
788 CERTName *name; |
|
789 SECItem *nameItem; |
|
790 CERTCertificate *cert = NULL; |
|
791 PLArenaPool *arena = NULL; |
|
792 |
|
793 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
794 |
|
795 if ( arena == NULL ) { |
|
796 goto loser; |
|
797 } |
|
798 |
|
799 name = CERT_AsciiToName(nameStr); |
|
800 |
|
801 if ( name ) { |
|
802 nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name, |
|
803 CERT_NameTemplate); |
|
804 if ( nameItem != NULL ) { |
|
805 cert = CERT_FindCertByName(handle, nameItem); |
|
806 } |
|
807 CERT_DestroyName(name); |
|
808 } |
|
809 |
|
810 loser: |
|
811 if ( arena ) { |
|
812 PORT_FreeArena(arena, PR_FALSE); |
|
813 } |
|
814 |
|
815 return(cert); |
|
816 } |
|
817 |
|
818 /* From certv3.c */ |
|
819 |
|
820 CERTCrlDistributionPoints * |
|
821 CERT_FindCRLDistributionPoints (CERTCertificate *cert) |
|
822 { |
|
823 SECItem encodedExtenValue; |
|
824 SECStatus rv; |
|
825 CERTCrlDistributionPoints *dps; |
|
826 |
|
827 encodedExtenValue.data = NULL; |
|
828 encodedExtenValue.len = 0; |
|
829 |
|
830 rv = cert_FindExtension(cert->extensions, SEC_OID_X509_CRL_DIST_POINTS, |
|
831 &encodedExtenValue); |
|
832 if ( rv != SECSuccess ) { |
|
833 return (NULL); |
|
834 } |
|
835 |
|
836 dps = CERT_DecodeCRLDistributionPoints(cert->arena, &encodedExtenValue); |
|
837 |
|
838 PORT_Free(encodedExtenValue.data); |
|
839 |
|
840 return dps; |
|
841 } |
|
842 |
|
843 /* From crl.c */ |
|
844 CERTSignedCrl * CERT_ImportCRL |
|
845 (CERTCertDBHandle *handle, SECItem *derCRL, char *url, int type, void *wincx) |
|
846 { |
|
847 CERTSignedCrl* retCrl = NULL; |
|
848 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); |
|
849 retCrl = PK11_ImportCRL(slot, derCRL, url, type, wincx, |
|
850 CRL_IMPORT_DEFAULT_OPTIONS, NULL, CRL_DECODE_DEFAULT_OPTIONS); |
|
851 PK11_FreeSlot(slot); |
|
852 |
|
853 return retCrl; |
|
854 } |
|
855 |
|
856 /* From certdb.c */ |
|
857 static SECStatus |
|
858 cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted) |
|
859 { |
|
860 SECStatus rv; |
|
861 SECItem *derCert; |
|
862 CERTCertificate *cert = NULL; |
|
863 CERTCertificate *newcert = NULL; |
|
864 CERTCertDBHandle *handle; |
|
865 CERTCertTrust trust; |
|
866 PRBool isca; |
|
867 char *nickname; |
|
868 unsigned int certtype; |
|
869 |
|
870 handle = CERT_GetDefaultCertDB(); |
|
871 |
|
872 while (numcerts--) { |
|
873 derCert = certs; |
|
874 certs++; |
|
875 |
|
876 /* decode my certificate */ |
|
877 /* This use is ok -- only looks at decoded parts, calls NewTemp later */ |
|
878 newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); |
|
879 if ( newcert == NULL ) { |
|
880 goto loser; |
|
881 } |
|
882 |
|
883 if (!trusted) { |
|
884 /* make sure that cert is valid */ |
|
885 rv = CERT_CertTimesValid(newcert); |
|
886 if ( rv == SECFailure ) { |
|
887 goto endloop; |
|
888 } |
|
889 } |
|
890 |
|
891 /* does it have the CA extension */ |
|
892 |
|
893 /* |
|
894 * Make sure that if this is an intermediate CA in the chain that |
|
895 * it was given permission by its signer to be a CA. |
|
896 */ |
|
897 isca = CERT_IsCACert(newcert, &certtype); |
|
898 |
|
899 if ( !isca ) { |
|
900 if (!trusted) { |
|
901 goto endloop; |
|
902 } |
|
903 trust.sslFlags = CERTDB_VALID_CA; |
|
904 trust.emailFlags = CERTDB_VALID_CA; |
|
905 trust.objectSigningFlags = CERTDB_VALID_CA; |
|
906 } else { |
|
907 /* SSL ca's must have the ssl bit set */ |
|
908 if ( ( certUsage == certUsageSSLCA ) && |
|
909 (( certtype & NS_CERT_TYPE_SSL_CA ) != NS_CERT_TYPE_SSL_CA )) { |
|
910 goto endloop; |
|
911 } |
|
912 |
|
913 /* it passed all of the tests, so lets add it to the database */ |
|
914 /* mark it as a CA */ |
|
915 PORT_Memset((void *)&trust, 0, sizeof(trust)); |
|
916 switch ( certUsage ) { |
|
917 case certUsageSSLCA: |
|
918 trust.sslFlags = CERTDB_VALID_CA; |
|
919 break; |
|
920 case certUsageUserCertImport: |
|
921 if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) { |
|
922 trust.sslFlags = CERTDB_VALID_CA; |
|
923 } |
|
924 if ((certtype & NS_CERT_TYPE_EMAIL_CA) |
|
925 == NS_CERT_TYPE_EMAIL_CA ) { |
|
926 trust.emailFlags = CERTDB_VALID_CA; |
|
927 } |
|
928 if ( ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) == |
|
929 NS_CERT_TYPE_OBJECT_SIGNING_CA ) { |
|
930 trust.objectSigningFlags = CERTDB_VALID_CA; |
|
931 } |
|
932 break; |
|
933 default: |
|
934 PORT_Assert(0); |
|
935 break; |
|
936 } |
|
937 } |
|
938 |
|
939 cert = CERT_NewTempCertificate(handle, derCert, NULL, |
|
940 PR_FALSE, PR_FALSE); |
|
941 if ( cert == NULL ) { |
|
942 goto loser; |
|
943 } |
|
944 |
|
945 /* if the cert is temp, make it perm; otherwise we're done */ |
|
946 if (cert->istemp) { |
|
947 /* get a default nickname for it */ |
|
948 nickname = CERT_MakeCANickname(cert); |
|
949 |
|
950 rv = CERT_AddTempCertToPerm(cert, nickname, &trust); |
|
951 |
|
952 /* free the nickname */ |
|
953 if ( nickname ) { |
|
954 PORT_Free(nickname); |
|
955 } |
|
956 } else { |
|
957 rv = SECSuccess; |
|
958 } |
|
959 |
|
960 CERT_DestroyCertificate(cert); |
|
961 cert = NULL; |
|
962 |
|
963 if ( rv != SECSuccess ) { |
|
964 goto loser; |
|
965 } |
|
966 |
|
967 endloop: |
|
968 if ( newcert ) { |
|
969 CERT_DestroyCertificate(newcert); |
|
970 newcert = NULL; |
|
971 } |
|
972 |
|
973 } |
|
974 |
|
975 rv = SECSuccess; |
|
976 goto done; |
|
977 loser: |
|
978 rv = SECFailure; |
|
979 done: |
|
980 |
|
981 if ( newcert ) { |
|
982 CERT_DestroyCertificate(newcert); |
|
983 newcert = NULL; |
|
984 } |
|
985 |
|
986 if ( cert ) { |
|
987 CERT_DestroyCertificate(cert); |
|
988 cert = NULL; |
|
989 } |
|
990 |
|
991 return(rv); |
|
992 } |
|
993 |
|
994 SECStatus |
|
995 CERT_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage) |
|
996 { |
|
997 return cert_ImportCAChain(certs, numcerts, certUsage, PR_FALSE); |
|
998 } |
|
999 |
|
1000 SECStatus |
|
1001 CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage) { |
|
1002 return cert_ImportCAChain(certs, numcerts, certUsage, PR_TRUE); |
|
1003 } |
|
1004 |
|
1005 /* Moved from certdb.c */ |
|
1006 /* |
|
1007 ** CERT_CertChainFromCert |
|
1008 ** |
|
1009 ** Construct a CERTCertificateList consisting of the given certificate and all |
|
1010 ** of the issuer certs until we either get to a self-signed cert or can't find |
|
1011 ** an issuer. Since we don't know how many certs are in the chain we have to |
|
1012 ** build a linked list first as we count them. |
|
1013 */ |
|
1014 |
|
1015 typedef struct certNode { |
|
1016 struct certNode *next; |
|
1017 CERTCertificate *cert; |
|
1018 } certNode; |
|
1019 |
|
1020 CERTCertificateList * |
|
1021 CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage, |
|
1022 PRBool includeRoot) |
|
1023 { |
|
1024 CERTCertificateList *chain = NULL; |
|
1025 NSSCertificate **stanChain; |
|
1026 NSSCertificate *stanCert; |
|
1027 PLArenaPool *arena; |
|
1028 NSSUsage nssUsage; |
|
1029 int i, len; |
|
1030 NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); |
|
1031 NSSCryptoContext *cc = STAN_GetDefaultCryptoContext(); |
|
1032 |
|
1033 stanCert = STAN_GetNSSCertificate(cert); |
|
1034 if (!stanCert) { |
|
1035 /* error code is set */ |
|
1036 return NULL; |
|
1037 } |
|
1038 nssUsage.anyUsage = PR_FALSE; |
|
1039 nssUsage.nss3usage = usage; |
|
1040 nssUsage.nss3lookingForCA = PR_FALSE; |
|
1041 stanChain = NSSCertificate_BuildChain(stanCert, NULL, &nssUsage, NULL, NULL, |
|
1042 CERT_MAX_CERT_CHAIN, NULL, NULL, td, cc); |
|
1043 if (!stanChain) { |
|
1044 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); |
|
1045 return NULL; |
|
1046 } |
|
1047 |
|
1048 len = 0; |
|
1049 stanCert = stanChain[0]; |
|
1050 while (stanCert) { |
|
1051 stanCert = stanChain[++len]; |
|
1052 } |
|
1053 |
|
1054 arena = PORT_NewArena(4096); |
|
1055 if (arena == NULL) { |
|
1056 goto loser; |
|
1057 } |
|
1058 |
|
1059 chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, |
|
1060 sizeof(CERTCertificateList)); |
|
1061 if (!chain) goto loser; |
|
1062 chain->certs = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem)); |
|
1063 if (!chain->certs) goto loser; |
|
1064 i = 0; |
|
1065 stanCert = stanChain[i]; |
|
1066 while (stanCert) { |
|
1067 SECItem derCert; |
|
1068 CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert); |
|
1069 if (!cCert) { |
|
1070 goto loser; |
|
1071 } |
|
1072 derCert.len = (unsigned int)stanCert->encoding.size; |
|
1073 derCert.data = (unsigned char *)stanCert->encoding.data; |
|
1074 derCert.type = siBuffer; |
|
1075 SECITEM_CopyItem(arena, &chain->certs[i], &derCert); |
|
1076 stanCert = stanChain[++i]; |
|
1077 if (!stanCert && !cCert->isRoot) { |
|
1078 /* reached the end of the chain, but the final cert is |
|
1079 * not a root. Don't discard it. |
|
1080 */ |
|
1081 includeRoot = PR_TRUE; |
|
1082 } |
|
1083 CERT_DestroyCertificate(cCert); |
|
1084 } |
|
1085 if ( !includeRoot && len > 1) { |
|
1086 chain->len = len - 1; |
|
1087 } else { |
|
1088 chain->len = len; |
|
1089 } |
|
1090 |
|
1091 chain->arena = arena; |
|
1092 nss_ZFreeIf(stanChain); |
|
1093 return chain; |
|
1094 loser: |
|
1095 i = 0; |
|
1096 stanCert = stanChain[i]; |
|
1097 while (stanCert) { |
|
1098 CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert); |
|
1099 if (cCert) { |
|
1100 CERT_DestroyCertificate(cCert); |
|
1101 } |
|
1102 stanCert = stanChain[++i]; |
|
1103 } |
|
1104 nss_ZFreeIf(stanChain); |
|
1105 if (arena) { |
|
1106 PORT_FreeArena(arena, PR_FALSE); |
|
1107 } |
|
1108 return NULL; |
|
1109 } |
|
1110 |
|
1111 /* Builds a CERTCertificateList holding just one DER-encoded cert, namely |
|
1112 ** the one for the cert passed as an argument. |
|
1113 */ |
|
1114 CERTCertificateList * |
|
1115 CERT_CertListFromCert(CERTCertificate *cert) |
|
1116 { |
|
1117 CERTCertificateList *chain = NULL; |
|
1118 int rv; |
|
1119 PLArenaPool *arena; |
|
1120 |
|
1121 /* arena for SecCertificateList */ |
|
1122 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1123 if (arena == NULL) goto no_memory; |
|
1124 |
|
1125 /* build the CERTCertificateList */ |
|
1126 chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList)); |
|
1127 if (chain == NULL) goto no_memory; |
|
1128 chain->certs = (SECItem*)PORT_ArenaAlloc(arena, 1 * sizeof(SECItem)); |
|
1129 if (chain->certs == NULL) goto no_memory; |
|
1130 rv = SECITEM_CopyItem(arena, chain->certs, &(cert->derCert)); |
|
1131 if (rv < 0) goto loser; |
|
1132 chain->len = 1; |
|
1133 chain->arena = arena; |
|
1134 |
|
1135 return chain; |
|
1136 |
|
1137 no_memory: |
|
1138 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1139 loser: |
|
1140 if (arena != NULL) { |
|
1141 PORT_FreeArena(arena, PR_FALSE); |
|
1142 } |
|
1143 return NULL; |
|
1144 } |
|
1145 |
|
1146 CERTCertificateList * |
|
1147 CERT_DupCertList(const CERTCertificateList * oldList) |
|
1148 { |
|
1149 CERTCertificateList *newList = NULL; |
|
1150 PLArenaPool *arena = NULL; |
|
1151 SECItem *newItem; |
|
1152 SECItem *oldItem; |
|
1153 int len = oldList->len; |
|
1154 int rv; |
|
1155 |
|
1156 /* arena for SecCertificateList */ |
|
1157 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1158 if (arena == NULL) |
|
1159 goto no_memory; |
|
1160 |
|
1161 /* now build the CERTCertificateList */ |
|
1162 newList = PORT_ArenaNew(arena, CERTCertificateList); |
|
1163 if (newList == NULL) |
|
1164 goto no_memory; |
|
1165 newList->arena = arena; |
|
1166 newItem = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem)); |
|
1167 if (newItem == NULL) |
|
1168 goto no_memory; |
|
1169 newList->certs = newItem; |
|
1170 newList->len = len; |
|
1171 |
|
1172 for (oldItem = oldList->certs; len > 0; --len, ++newItem, ++oldItem) { |
|
1173 rv = SECITEM_CopyItem(arena, newItem, oldItem); |
|
1174 if (rv < 0) |
|
1175 goto loser; |
|
1176 } |
|
1177 return newList; |
|
1178 |
|
1179 no_memory: |
|
1180 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
1181 loser: |
|
1182 if (arena != NULL) { |
|
1183 PORT_FreeArena(arena, PR_FALSE); |
|
1184 } |
|
1185 return NULL; |
|
1186 } |
|
1187 |
|
1188 void |
|
1189 CERT_DestroyCertificateList(CERTCertificateList *list) |
|
1190 { |
|
1191 PORT_FreeArena(list->arena, PR_FALSE); |
|
1192 } |
|
1193 |