f3821a5588f46622d94f6f7c06652ec2736230ca
[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 <vici_version.h>
31 #include <vici_cert_info.h>
32
33 #include "command.h"
34
35 /**
36 * Current certificate type info
37 */
38 static vici_cert_info_t *current_cert_info = NULL;
39
40 /**
41 * Print PEM encoding of a certificate
42 */
43 static void print_pem(certificate_t *cert)
44 {
45 chunk_t encoding;
46
47 if (cert->get_encoding(cert, CERT_PEM, &encoding))
48 {
49 printf("%.*s", (int)encoding.len, encoding.ptr);
50 free(encoding.ptr);
51 }
52 else
53 {
54 fprintf(stderr, "PEM encoding certificate failed\n");
55 }
56 }
57
58 CALLBACK(list_cb, void,
59 command_format_options_t *format, char *name, vici_res_t *res)
60 {
61 certificate_t *cert;
62 certificate_printer_t *printer;
63 vici_version_t version;
64 vici_cert_info_t *cert_info;
65 bool detailed, utc, has_privkey, first = FALSE;
66 char *version_str, *type_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 version_str = vici_find_str(res, "1.0", "vici");
78 if (!enum_from_name(vici_version_names, version_str, &version) ||
79 version == VICI_1_0)
80 {
81 fprintf(stderr, "unsupported vici version '%s'\n", version_str);
82 return;
83 }
84
85 buf = vici_find(res, &len, "data");
86 if (!buf)
87 {
88 fprintf(stderr, "received incomplete certificate data\n");
89 return;
90 }
91 has_privkey = streq(vici_find_str(res, "no", "has_privkey"), "yes");
92
93 type_str = vici_find_str(res, "any", "type");
94 cert_info = vici_cert_info_retrieve(type_str);
95 if (!cert_info || cert_info->type == CERT_ANY)
96 {
97 fprintf(stderr, "unsupported certificate type '%s'\n", type_str);
98 return;
99 }
100
101 /* Detect change of certificate type */
102 if (cert_info != current_cert_info)
103 {
104 first = TRUE;
105 current_cert_info = cert_info;
106 }
107
108 /* Parse certificate data blob */
109 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, cert_info->type,
110 BUILD_BLOB_ASN1_DER, chunk_create(buf, len),
111 BUILD_END);
112 if (cert)
113 {
114 if (*format & COMMAND_FORMAT_PEM)
115 {
116 print_pem(cert);
117 }
118 else
119 {
120 if (first)
121 {
122 printf("\nList of %ss:\n", cert_info->caption);
123 }
124 printf("\n");
125 detailed = !(*format & COMMAND_FORMAT_SHORT);
126 utc = *format & COMMAND_FORMAT_UTC;
127 printer = certificate_printer_create(stdout, detailed, utc);
128 printer->print(printer, cert, has_privkey);
129 printer->destroy(printer);
130 }
131 cert->destroy(cert);
132 }
133 else
134 {
135 fprintf(stderr, "parsing certificate failed\n");
136 }
137 }
138
139 static int list_certs(vici_conn_t *conn)
140 {
141 vici_req_t *req;
142 vici_res_t *res;
143 command_format_options_t format = COMMAND_FORMAT_NONE;
144 char *arg, *subject = NULL, *type = NULL;
145 int ret;
146
147 while (TRUE)
148 {
149 switch (command_getopt(&arg))
150 {
151 case 'h':
152 return command_usage(NULL);
153 case 's':
154 subject = arg;
155 continue;
156 case 't':
157 type = arg;
158 continue;
159 case 'p':
160 format |= COMMAND_FORMAT_PEM;
161 continue;
162 case 'P':
163 format |= COMMAND_FORMAT_PRETTY;
164 /* fall through to raw */
165 case 'r':
166 format |= COMMAND_FORMAT_RAW;
167 continue;
168 case 'S':
169 format |= COMMAND_FORMAT_SHORT;
170 continue;
171 case 'U':
172 format |= COMMAND_FORMAT_UTC;
173 continue;
174 case EOF:
175 break;
176 default:
177 return command_usage("invalid --list-certs option");
178 }
179 break;
180 }
181 if (vici_register(conn, "list-cert", list_cb, &format) != 0)
182 {
183 ret = errno;
184 fprintf(stderr, "registering for certificates failed: %s\n",
185 strerror(errno));
186 return ret;
187 }
188 req = vici_begin("list-certs");
189 vici_add_version(req, VICI_VERSION);
190
191 if (type)
192 {
193 vici_add_key_valuef(req, "type", "%s", type);
194 }
195 if (subject)
196 {
197 vici_add_key_valuef(req, "subject", "%s", subject);
198 }
199
200 res = vici_submit(req, conn);
201 if (!res)
202 {
203 ret = errno;
204 fprintf(stderr, "list-certs request failed: %s\n", strerror(errno));
205 return ret;
206 }
207 if (format & COMMAND_FORMAT_RAW)
208 {
209 vici_dump(res, "list-certs reply", format & COMMAND_FORMAT_PRETTY,
210 stdout);
211 }
212 vici_free_res(res);
213 return 0;
214 }
215
216 /**
217 * Register the command.
218 */
219 static void __attribute__ ((constructor))reg()
220 {
221 command_register((command_t) {
222 list_certs, 'x', "list-certs", "list stored certificates",
223 {"[--subject <dn/san>] "
224 "[--type x509|x509ca|x509aa|x509ac|x509crl|x509ocsp|ocsp] "
225 "[--pem] [--raw|--pretty|--short|--utc]"},
226 {
227 {"help", 'h', 0, "show usage information"},
228 {"subject", 's', 1, "filter by certificate subject"},
229 {"type", 't', 1, "filter by certificate type"},
230 {"pem", 'p', 0, "print PEM encoding of certificate"},
231 {"raw", 'r', 0, "dump raw response message"},
232 {"pretty", 'P', 0, "dump raw response message in pretty print"},
233 {"short", 'S', 0, "omit some certificate details"},
234 {"utc", 'U', 0, "use UTC for time fields"},
235 }
236 });
237 }