4f0602498d1262f75255601fa8859e4fdab605ae
[strongswan.git] / src / charon / plugins / stroke / stroke_list.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "stroke_list.h"
19
20 #include <daemon.h>
21 #include <utils/linked_list.h>
22 #include <credentials/certificates/x509.h>
23 #include <credentials/certificates/ac.h>
24 #include <credentials/certificates/crl.h>
25
26 /* warning intervals for list functions */
27 #define CERT_WARNING_INTERVAL 30 /* days */
28 #define CRL_WARNING_INTERVAL 7 /* days */
29 #define AC_WARNING_INTERVAL 1 /* day */
30
31 typedef struct private_stroke_list_t private_stroke_list_t;
32
33 /**
34 * private data of stroke_list
35 */
36 struct private_stroke_list_t {
37
38 /**
39 * public functions
40 */
41 stroke_list_t public;
42
43 /**
44 * timestamp of daemon start
45 */
46 time_t uptime;
47 };
48
49 /**
50 * log an IKE_SA to out
51 */
52 static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
53 {
54 ike_sa_id_t *id = ike_sa->get_id(ike_sa);
55 u_int32_t rekey, reauth;
56
57 fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n",
58 ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
59 ike_sa_state_names, ike_sa->get_state(ike_sa),
60 ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
61 ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
62
63 if (all)
64 {
65 fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s",
66 ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
67 id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
68 id->get_responder_spi(id), id->is_initiator(id) ? "" : "*");
69
70 rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME);
71 reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME);
72 if (rekey)
73 {
74 fprintf(out, ", rekeying in %V", &rekey);
75 }
76 if (reauth)
77 {
78 fprintf(out, ", reauthentication in %V", &reauth);
79 }
80 if (!rekey && !reauth)
81 {
82 fprintf(out, ", rekeying disabled");
83 }
84 fprintf(out, "\n");
85 }
86 }
87
88 /**
89 * log an CHILD_SA to out
90 */
91 static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
92 {
93 u_int32_t rekey, now = time(NULL);
94 u_int32_t use_in, use_out, use_fwd;
95 encryption_algorithm_t encr_alg;
96 integrity_algorithm_t int_alg;
97 size_t encr_len, int_len;
98 mode_t mode;
99
100 child_sa->get_stats(child_sa, &mode, &encr_alg, &encr_len,
101 &int_alg, &int_len, &rekey, &use_in, &use_out,
102 &use_fwd);
103
104 fprintf(out, "%12s{%d}: %N, %N",
105 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
106 child_sa_state_names, child_sa->get_state(child_sa),
107 mode_names, mode);
108
109 if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
110 {
111 fprintf(out, ", %N SPIs: %.8x_i %.8x_o",
112 protocol_id_names, child_sa->get_protocol(child_sa),
113 htonl(child_sa->get_spi(child_sa, TRUE)),
114 htonl(child_sa->get_spi(child_sa, FALSE)));
115
116 if (all)
117 {
118 fprintf(out, "\n%12s{%d}: ", child_sa->get_name(child_sa),
119 child_sa->get_reqid(child_sa));
120
121
122 if (child_sa->get_protocol(child_sa) == PROTO_ESP)
123 {
124 fprintf(out, "%N", encryption_algorithm_names, encr_alg);
125
126 if (encr_len)
127 {
128 fprintf(out, "-%d", encr_len);
129 }
130 if (int_alg != AUTH_UNDEFINED)
131 {
132 fprintf(out, "/");
133 }
134 }
135
136 if (int_alg != AUTH_UNDEFINED)
137 {
138 fprintf(out, "%N", integrity_algorithm_names, int_alg);
139 if (int_len)
140 {
141 fprintf(out, "-%d", int_len);
142 }
143 }
144 fprintf(out, ", rekeying ");
145
146 if (rekey)
147 {
148 fprintf(out, "in %#V", &now, &rekey);
149 }
150 else
151 {
152 fprintf(out, "disabled");
153 }
154
155 fprintf(out, ", last use: ");
156 use_in = max(use_in, use_fwd);
157 if (use_in)
158 {
159 fprintf(out, "%ds_i ", now - use_in);
160 }
161 else
162 {
163 fprintf(out, "no_i ");
164 }
165 if (use_out)
166 {
167 fprintf(out, "%ds_o ", now - use_out);
168 }
169 else
170 {
171 fprintf(out, "no_o ");
172 }
173 }
174 }
175
176 fprintf(out, "\n%12s{%d}: %#R=== %#R\n",
177 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
178 child_sa->get_traffic_selectors(child_sa, TRUE),
179 child_sa->get_traffic_selectors(child_sa, FALSE));
180 }
181
182 /**
183 * Implementation of stroke_list_t.status.
184 */
185 static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bool all)
186 {
187 enumerator_t *enumerator, *children;
188 iterator_t *iterator;
189 host_t *host;
190 peer_cfg_t *peer_cfg;
191 ike_cfg_t *ike_cfg;
192 child_cfg_t *child_cfg;
193 ike_sa_t *ike_sa;
194 char *name = NULL;
195 bool found = FALSE;
196 time_t uptime;
197
198 name = msg->status.name;
199
200 if (all)
201 {
202 uptime = time(NULL) - this->uptime;
203 fprintf(out, "Performance:\n");
204 fprintf(out, " uptime: %V, since %#T\n", &uptime, &this->uptime, FALSE);
205 fprintf(out, " worker threads: %d idle of %d,",
206 charon->processor->get_idle_threads(charon->processor),
207 charon->processor->get_total_threads(charon->processor));
208 fprintf(out, " job queue load: %d,",
209 charon->processor->get_job_load(charon->processor));
210 fprintf(out, " scheduled events: %d\n",
211 charon->scheduler->get_job_load(charon->scheduler));
212 iterator = charon->kernel_interface->create_address_iterator(
213 charon->kernel_interface);
214 fprintf(out, "Listening IP addresses:\n");
215 while (iterator->iterate(iterator, (void**)&host))
216 {
217 fprintf(out, " %H\n", host);
218 }
219 iterator->destroy(iterator);
220
221 fprintf(out, "Connections:\n");
222 enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends);
223 while (enumerator->enumerate(enumerator, (void**)&peer_cfg))
224 {
225 if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
226 (name && !streq(name, peer_cfg->get_name(peer_cfg))))
227 {
228 continue;
229 }
230
231 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
232 fprintf(out, "%12s: %s[%D]...%s[%D]\n", peer_cfg->get_name(peer_cfg),
233 ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg),
234 ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg));
235 /* TODO: list CAs and groups */
236 children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
237 while (children->enumerate(children, &child_cfg))
238 {
239 linked_list_t *my_ts, *other_ts;
240 my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
241 other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
242 fprintf(out, "%12s: %#R=== %#R\n", child_cfg->get_name(child_cfg),
243 my_ts, other_ts);
244 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
245 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
246 }
247 children->destroy(children);
248 }
249 enumerator->destroy(enumerator);
250 }
251
252 fprintf(out, "Security Associations:\n");
253 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
254 while (enumerator->enumerate(enumerator, &ike_sa))
255 {
256 bool ike_printed = FALSE;
257 child_sa_t *child_sa;
258 iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
259
260 if (name == NULL || streq(name, ike_sa->get_name(ike_sa)))
261 {
262 log_ike_sa(out, ike_sa, all);
263 found = TRUE;
264 ike_printed = TRUE;
265 }
266
267 while (children->iterate(children, (void**)&child_sa))
268 {
269 if (name == NULL || streq(name, child_sa->get_name(child_sa)))
270 {
271 if (!ike_printed)
272 {
273 log_ike_sa(out, ike_sa, all);
274 found = TRUE;
275 ike_printed = TRUE;
276 }
277 log_child_sa(out, child_sa, all);
278 }
279 }
280 children->destroy(children);
281 }
282 enumerator->destroy(enumerator);
283
284 if (!found)
285 {
286 if (name)
287 {
288 fprintf(out, " no match\n");
289 }
290 else
291 {
292 fprintf(out, " none\n");
293 }
294 }
295 }
296
297 /**
298 * create a unique certificate list without duplicates
299 * certicates having the same issuer are grouped together.
300 */
301 static linked_list_t* create_unique_cert_list(certificate_type_t type)
302 {
303 linked_list_t *list = linked_list_create();
304 enumerator_t *enumerator = charon->credentials->create_cert_enumerator(
305 charon->credentials, type, KEY_ANY,
306 NULL, FALSE);
307 certificate_t *cert;
308
309 while (enumerator->enumerate(enumerator, (void**)&cert))
310 {
311 iterator_t *iterator = list->create_iterator(list, TRUE);
312 identification_t *issuer = cert->get_issuer(cert);
313 bool previous_same, same = FALSE, last = TRUE;
314 certificate_t *list_cert;
315
316 while (iterator->iterate(iterator, (void**)&list_cert))
317 {
318 /* exit if we have a duplicate? */
319 if (list_cert->equals(list_cert, cert))
320 {
321 last = FALSE;
322 break;
323 }
324 /* group certificates with same issuer */
325 previous_same = same;
326 same = list_cert->has_issuer(list_cert, issuer);
327 if (previous_same && !same)
328 {
329 iterator->insert_before(iterator, (void *)cert->get_ref(cert));
330 last = FALSE;
331 break;
332 }
333 }
334 iterator->destroy(iterator);
335
336 if (last)
337 {
338 list->insert_last(list, (void *)cert->get_ref(cert));
339 }
340 }
341 enumerator->destroy(enumerator);
342 return list;
343 }
344
345 /**
346 * list all X.509 certificates matching the flags
347 */
348 static void stroke_list_certs(linked_list_t *list, char *label,
349 x509_flag_t flags, bool utc, FILE *out)
350 {
351 bool first = TRUE;
352 time_t now = time(NULL);
353 enumerator_t *enumerator = list->create_enumerator(list);
354 certificate_t *cert;
355
356 while (enumerator->enumerate(enumerator, (void**)&cert))
357 {
358 x509_t *x509 = (x509_t*)cert;
359 x509_flag_t x509_flags = x509->get_flags(x509);
360
361 /* list only if flag is set, or flags == 0 (ignoring self-signed) */
362 if ((x509_flags & flags) || (flags == (x509_flags & ~X509_SELF_SIGNED)))
363 {
364 enumerator_t *enumerator;
365 identification_t *altName;
366 bool first_altName = TRUE;
367 chunk_t serial = x509->get_serial(x509);
368 identification_t *authkey = x509->get_authKeyIdentifier(x509);
369 time_t notBefore, notAfter;
370 public_key_t *public = cert->get_public_key(cert);
371
372 if (first)
373 {
374 fprintf(out, "\n");
375 fprintf(out, "List of %s:\n", label);
376 first = FALSE;
377 }
378 fprintf(out, "\n");
379
380 /* list subjectAltNames */
381 enumerator = x509->create_subjectAltName_enumerator(x509);
382 while (enumerator->enumerate(enumerator, (void**)&altName))
383 {
384 if (first_altName)
385 {
386 fprintf(out, " altNames: ");
387 first_altName = FALSE;
388 }
389 else
390 {
391 fprintf(out, ", ");
392 }
393 fprintf(out, "%D", altName);
394 }
395 if (!first_altName)
396 {
397 fprintf(out, "\n");
398 }
399 enumerator->destroy(enumerator);
400
401 fprintf(out, " subject: \"%D\"\n", cert->get_subject(cert));
402 fprintf(out, " issuer: \"%D\"\n", cert->get_issuer(cert));
403 fprintf(out, " serial: %#B\n", &serial);
404
405 /* list validity */
406 cert->get_validity(cert, &now, &notBefore, &notAfter);
407 fprintf(out, " validity: not before %#T, ", &notBefore, utc);
408 if (now < notBefore)
409 {
410 fprintf(out, "not valid yet (valid in %#V)\n", &now, &notBefore);
411 }
412 else
413 {
414 fprintf(out, "ok\n");
415 }
416 fprintf(out, " not after %#T, ", &notAfter, utc);
417 if (now > notAfter)
418 {
419 fprintf(out, "expired (%#V ago)\n", &now, &notAfter);
420 }
421 else
422 {
423 fprintf(out, "ok");
424 if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24)
425 {
426 fprintf(out, " (expires in %#V)", &now, &notAfter);
427 }
428 fprintf(out, " \n");
429 }
430
431 /* list public key information */
432 if (public)
433 {
434 private_key_t *private = NULL;
435 identification_t *id, *keyid;
436
437 id = public->get_id(public, ID_PUBKEY_SHA1);
438 keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1);
439
440 private = charon->credentials->get_private(
441 charon->credentials,
442 public->get_type(public), keyid, NULL);
443 fprintf(out, " pubkey: %N %d bits%s\n",
444 key_type_names, public->get_type(public),
445 public->get_keysize(public) * 8,
446 private ? ", has private key" : "");
447 fprintf(out, " keyid: %D\n", keyid);
448 fprintf(out, " subjkey: %D\n", id);
449 DESTROY_IF(private);
450 public->destroy(public);
451 }
452
453 /* list optional authorityKeyIdentifier */
454 if (authkey)
455 {
456 fprintf(out, " authkey: %D\n", authkey);
457 }
458 }
459 }
460 enumerator->destroy(enumerator);
461 }
462
463 /**
464 * list all X.509 attribute certificates
465 */
466 static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out)
467 {
468 bool first = TRUE;
469 time_t thisUpdate, nextUpdate, now = time(NULL);
470 enumerator_t *enumerator = list->create_enumerator(list);
471 certificate_t *cert;
472
473 while (enumerator->enumerate(enumerator, (void**)&cert))
474 {
475 ac_t *ac = (ac_t*)cert;
476 chunk_t serial = ac->get_serial(ac);
477 chunk_t holderSerial = ac->get_holderSerial(ac);
478 identification_t *holderIssuer = ac->get_holderIssuer(ac);
479 identification_t *authkey = ac->get_authKeyIdentifier(ac);
480 identification_t *entityName = cert->get_subject(cert);
481
482 if (first)
483 {
484 fprintf(out, "\n");
485 fprintf(out, "List of X.509 Attribute Certificates:\n");
486 first = FALSE;
487 }
488 fprintf(out, "\n");
489
490 if (entityName)
491 {
492 fprintf(out, " holder: \"%D\"\n", entityName);
493 }
494 if (holderIssuer)
495 {
496 fprintf(out, " hissuer: \"%D\"\n", holderIssuer);
497 }
498 if (holderSerial.ptr)
499 {
500 fprintf(out, " hserial: %#B\n", &holderSerial);
501 }
502 fprintf(out, " issuer: \"%D\"\n", cert->get_issuer(cert));
503 fprintf(out, " serial: %#B\n", &serial);
504
505 /* list validity */
506 cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
507 fprintf(out, " updates: this %#T\n", &thisUpdate, utc);
508 fprintf(out, " next %#T, ", &nextUpdate, utc);
509 if (now > nextUpdate)
510 {
511 fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate);
512 }
513 else
514 {
515 fprintf(out, "ok");
516 if (now > nextUpdate - AC_WARNING_INTERVAL * 60 * 60 * 24)
517 {
518 fprintf(out, " (expires in %#V)", &now, &nextUpdate);
519 }
520 fprintf(out, " \n");
521 }
522
523 /* list optional authorityKeyIdentifier */
524 if (authkey)
525 {
526 fprintf(out, " authkey: %D\n", authkey);
527 }
528 }
529 enumerator->destroy(enumerator);
530 }
531
532 /**
533 * list all X.509 CRLs
534 */
535 static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out)
536 {
537 bool first = TRUE;
538 time_t thisUpdate, nextUpdate, now = time(NULL);
539 enumerator_t *enumerator = list->create_enumerator(list);
540 certificate_t *cert;
541
542 while (enumerator->enumerate(enumerator, (void**)&cert))
543 {
544 crl_t *crl = (crl_t*)cert;
545 chunk_t serial = crl->get_serial(crl);
546 identification_t *authkey = crl->get_authKeyIdentifier(crl);
547
548 if (first)
549 {
550 fprintf(out, "\n");
551 fprintf(out, "List of X.509 CRLs:\n");
552 first = FALSE;
553 }
554 fprintf(out, "\n");
555
556 fprintf(out, " issuer: \"%D\"\n", cert->get_issuer(cert));
557
558 /* list optional crlNumber */
559 if (serial.ptr)
560 {
561 fprintf(out, " serial: %#B\n", &serial);
562 }
563
564 /* count the number of revoked certificates */
565 {
566 int count = 0;
567 enumerator_t *enumerator = crl->create_enumerator(crl);
568
569 while (enumerator->enumerate(enumerator, NULL, NULL, NULL))
570 {
571 count++;
572 }
573 fprintf(out, " revoked: %d certificate%s\n", count,
574 (count == 1)? "" : "s");
575 enumerator->destroy(enumerator);
576 }
577
578 /* list validity */
579 cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
580 fprintf(out, " updates: this %#T\n", &thisUpdate, utc);
581 fprintf(out, " next %#T, ", &nextUpdate, utc);
582 if (now > nextUpdate)
583 {
584 fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate);
585 }
586 else
587 {
588 fprintf(out, "ok");
589 if (now > nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24)
590 {
591 fprintf(out, " (expires in %#V)", &now, &nextUpdate);
592 }
593 fprintf(out, " \n");
594 }
595
596 /* list optional authorityKeyIdentifier */
597 if (authkey)
598 {
599 fprintf(out, " authkey: %D\n", authkey);
600 }
601 }
602 enumerator->destroy(enumerator);
603 }
604
605 /**
606 * list all OCSP responses
607 */
608 static void stroke_list_ocsp(linked_list_t* list, bool utc, FILE *out)
609 {
610 bool first = TRUE;
611 enumerator_t *enumerator = list->create_enumerator(list);
612 certificate_t *cert;
613
614 while (enumerator->enumerate(enumerator, (void**)&cert))
615 {
616 if (first)
617 {
618 fprintf(out, "\n");
619 fprintf(out, "List of OCSP responses:\n");
620 fprintf(out, "\n");
621 first = FALSE;
622 }
623
624 fprintf(out, " signer: \"%D\"\n", cert->get_issuer(cert));
625 }
626 enumerator->destroy(enumerator);
627 }
628
629 /**
630 * Implementation of stroke_list_t.list.
631 */
632 static void list(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out)
633 {
634 linked_list_t *cert_list = NULL;
635
636 if (msg->list.flags & (LIST_CERTS | LIST_CACERTS | LIST_OCSPCERTS | LIST_AACERTS))
637 {
638 cert_list = create_unique_cert_list(CERT_X509);
639 }
640 if (msg->list.flags & LIST_CERTS)
641 {
642 stroke_list_certs(cert_list, "X.509 End Entity Certificates",
643 0, msg->list.utc, out);
644 }
645 if (msg->list.flags & LIST_CACERTS)
646 {
647 stroke_list_certs(cert_list, "X.509 CA Certificates",
648 X509_CA, msg->list.utc, out);
649 }
650 if (msg->list.flags & LIST_OCSPCERTS)
651 {
652 stroke_list_certs(cert_list, "X.509 OCSP Signer Certificates",
653 X509_OCSP_SIGNER, msg->list.utc, out);
654 }
655 if (msg->list.flags & LIST_AACERTS)
656 {
657 stroke_list_certs(cert_list, "X.509 AA Certificates",
658 X509_AA, msg->list.utc, out);
659 }
660 if (msg->list.flags & LIST_ACERTS)
661 {
662 linked_list_t *ac_list = create_unique_cert_list(CERT_X509_AC);
663
664 stroke_list_acerts(ac_list, msg->list.utc, out);
665 ac_list->destroy_offset(ac_list, offsetof(certificate_t, destroy));
666 }
667 if (msg->list.flags & LIST_CRLS)
668 {
669 linked_list_t *crl_list = create_unique_cert_list(CERT_X509_CRL);
670
671 stroke_list_crls(crl_list, msg->list.utc, out);
672 crl_list->destroy_offset(crl_list, offsetof(certificate_t, destroy));
673 }
674 if (msg->list.flags & LIST_OCSP)
675 {
676 linked_list_t *ocsp_list = create_unique_cert_list(CERT_X509_OCSP_RESPONSE);
677
678 stroke_list_ocsp(ocsp_list, msg->list.utc, out);
679 ocsp_list->destroy_offset(ocsp_list, offsetof(certificate_t, destroy));
680 }
681 DESTROY_OFFSET_IF(cert_list, offsetof(certificate_t, destroy));
682 }
683
684 /**
685 * Implementation of stroke_list_t.destroy
686 */
687 static void destroy(private_stroke_list_t *this)
688 {
689 free(this);
690 }
691
692 /*
693 * see header file
694 */
695 stroke_list_t *stroke_list_create()
696 {
697 private_stroke_list_t *this = malloc_thing(private_stroke_list_t);
698
699 this->public.list = (void(*)(stroke_list_t*, stroke_msg_t *msg, FILE *out))list;
700 this->public.status = (void(*)(stroke_list_t*, stroke_msg_t *msg, FILE *out,bool))status;
701 this->public.destroy = (void(*)(stroke_list_t*))destroy;
702
703 this->uptime = time(NULL);
704
705 return &this->public;
706 }
707