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