vici: list-cert sends subject, not-before and not-after attributes for pubkeys
[strongswan.git] / src / swanctl / commands / list_certs.c
1 /*
2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
4 *
5 * Copyright (C) 2015 Andreas Steffen
6 * HSR Hochschule fuer Technik Rapperswil
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #define _GNU_SOURCE
20 #include <stdio.h>
21 #include <errno.h>
22 #include <time.h>
23
24 #include <asn1/asn1.h>
25 #include <asn1/oid.h>
26 #include <credentials/certificates/certificate.h>
27 #include <credentials/certificates/certificate_printer.h>
28 #include <selectors/traffic_selector.h>
29
30 #include "command.h"
31
32 /**
33 * Static certificate printer object
34 */
35 static certificate_printer_t *cert_printer = NULL;
36
37 /**
38 * Print PEM encoding of a certificate
39 */
40 static void print_pem(certificate_t *cert)
41 {
42 chunk_t encoding;
43
44 if (cert->get_encoding(cert, CERT_PEM, &encoding))
45 {
46 printf("%.*s", (int)encoding.len, encoding.ptr);
47 free(encoding.ptr);
48 }
49 else
50 {
51 fprintf(stderr, "PEM encoding certificate failed\n");
52 }
53 }
54
55 CALLBACK(list_cb, void,
56 command_format_options_t *format, char *name, vici_res_t *res)
57 {
58 certificate_t *cert;
59 certificate_type_t type;
60 x509_flag_t flag = X509_NONE;
61 identification_t *subject = NULL;
62 time_t not_before = UNDEFINED_TIME;
63 time_t not_after = UNDEFINED_TIME;
64 chunk_t t_ch;
65 bool has_privkey;
66 char *str;
67 void *buf;
68 int len;
69
70 if (*format & COMMAND_FORMAT_RAW)
71 {
72 vici_dump(res, "list-cert event", *format & COMMAND_FORMAT_PRETTY,
73 stdout);
74 return;
75 }
76
77 buf = vici_find(res, &len, "data");
78 if (!buf)
79 {
80 fprintf(stderr, "received incomplete certificate data\n");
81 return;
82 }
83 has_privkey = streq(vici_find_str(res, "no", "has_privkey"), "yes");
84
85 str = vici_find_str(res, "ANY", "type");
86 if (!enum_from_name(certificate_type_names, str, &type) || type == CERT_ANY)
87 {
88 fprintf(stderr, "unsupported certificate type '%s'\n", str);
89 return;
90 }
91 if (type == CERT_X509)
92 {
93 str = vici_find_str(res, "ANY", "flag");
94 if (!enum_from_name(x509_flag_names, str, &flag) || flag == X509_ANY)
95 {
96 fprintf(stderr, "unsupported certificate flag '%s'\n", str);
97 return;
98 }
99 }
100 if (type == CERT_TRUSTED_PUBKEY)
101 {
102 str = vici_find_str(res, NULL, "subject");
103 if (str)
104 {
105 subject = identification_create_from_string(str);
106 }
107 str = vici_find_str(res, NULL, "not-before");
108 if (str)
109 {
110 t_ch = chunk_from_str(str);
111 not_before = asn1_to_time(&t_ch, ASN1_GENERALIZEDTIME);
112 }
113 str = vici_find_str(res, NULL, "not-after");
114 if (str)
115 {
116 t_ch = chunk_from_str(str);
117 not_after = asn1_to_time(&t_ch, ASN1_GENERALIZEDTIME);
118 }
119 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, type,
120 BUILD_BLOB_ASN1_DER, chunk_create(buf, len),
121 BUILD_NOT_BEFORE_TIME, not_before,
122 BUILD_NOT_AFTER_TIME, not_after,
123 BUILD_SUBJECT, subject, BUILD_END);
124 DESTROY_IF(subject);
125 }
126 else
127 {
128 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, type,
129 BUILD_BLOB_ASN1_DER, chunk_create(buf, len),
130 BUILD_END);
131 }
132 if (cert)
133 {
134 if (*format & COMMAND_FORMAT_PEM)
135 {
136 print_pem(cert);
137 }
138 else
139 {
140 cert_printer->print_caption(cert_printer, type, flag);
141 cert_printer->print(cert_printer, cert, has_privkey);
142 }
143 cert->destroy(cert);
144 }
145 else
146 {
147 fprintf(stderr, "parsing certificate failed\n");
148 }
149 }
150
151 static int list_certs(vici_conn_t *conn)
152 {
153 vici_req_t *req;
154 vici_res_t *res;
155 command_format_options_t format = COMMAND_FORMAT_NONE;
156 char *arg, *subject = NULL, *type = NULL, *flag = NULL;
157 bool detailed = TRUE, utc = FALSE;
158 int ret;
159
160 while (TRUE)
161 {
162 switch (command_getopt(&arg))
163 {
164 case 'h':
165 return command_usage(NULL);
166 case 's':
167 subject = arg;
168 continue;
169 case 't':
170 type = arg;
171 continue;
172 case 'f':
173 flag = arg;
174 continue;
175 case 'p':
176 format |= COMMAND_FORMAT_PEM;
177 continue;
178 case 'P':
179 format |= COMMAND_FORMAT_PRETTY;
180 /* fall through to raw */
181 case 'r':
182 format |= COMMAND_FORMAT_RAW;
183 continue;
184 case 'S':
185 detailed = FALSE;
186 continue;
187 case 'U':
188 utc = TRUE;
189 continue;
190 case EOF:
191 break;
192 default:
193 return command_usage("invalid --list-certs option");
194 }
195 break;
196 }
197 if (vici_register(conn, "list-cert", list_cb, &format) != 0)
198 {
199 ret = errno;
200 fprintf(stderr, "registering for certificates failed: %s\n",
201 strerror(errno));
202 return ret;
203 }
204 req = vici_begin("list-certs");
205
206 if (type)
207 {
208 vici_add_key_valuef(req, "type", "%s", type);
209 }
210 if (flag)
211 {
212 vici_add_key_valuef(req, "flag", "%s", flag);
213 }
214 if (subject)
215 {
216 vici_add_key_valuef(req, "subject", "%s", subject);
217 }
218 cert_printer = certificate_printer_create(stdout, detailed, utc);
219
220 res = vici_submit(req, conn);
221 if (!res)
222 {
223 ret = errno;
224 fprintf(stderr, "list-certs request failed: %s\n", strerror(errno));
225 cert_printer->destroy(cert_printer);
226 cert_printer = NULL;
227 return ret;
228 }
229 if (format & COMMAND_FORMAT_RAW)
230 {
231 vici_dump(res, "list-certs reply", format & COMMAND_FORMAT_PRETTY,
232 stdout);
233 }
234 vici_free_res(res);
235
236 cert_printer->destroy(cert_printer);
237 cert_printer = NULL;
238 return 0;
239 }
240
241 /**
242 * Register the command.
243 */
244 static void __attribute__ ((constructor))reg()
245 {
246 command_register((command_t) {
247 list_certs, 'x', "list-certs", "list stored certificates",
248 {"[--subject <dn/san>] [--pem]",
249 "[--type x509|x509_ac|x509_crl|ocsp_response|pubkey]",
250 "[--flag none|ca|aa|ocsp|any] [--raw|--pretty|--short|--utc]"},
251 {
252 {"help", 'h', 0, "show usage information"},
253 {"subject", 's', 1, "filter by certificate subject"},
254 {"type", 't', 1, "filter by certificate type"},
255 {"flag", 'f', 1, "filter by X.509 certificate flag"},
256 {"pem", 'p', 0, "print PEM encoding of certificate"},
257 {"raw", 'r', 0, "dump raw response message"},
258 {"pretty", 'P', 0, "dump raw response message in pretty print"},
259 {"short", 'S', 0, "omit some certificate details"},
260 {"utc", 'U', 0, "use UTC for time fields"},
261 }
262 });
263 }