pki: Add command to export certificates and keys from PKCS#12 containers
[strongswan.git] / src / pki / commands / pkcs12.c
1 /*
2 * Copyright (C) 2014 Tobias Brunner
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
16 #include <errno.h>
17
18 #include "pki.h"
19
20 #include <credentials/certificates/x509.h>
21 #include <credentials/containers/pkcs12.h>
22
23 /**
24 * Show info about PKCS#12 container
25 */
26 static int show(pkcs12_t *pkcs12)
27 {
28 enumerator_t *enumerator;
29 certificate_t *cert;
30 private_key_t *key;
31 int index = 1;
32
33 printf("Certificates:\n");
34 enumerator = pkcs12->create_cert_enumerator(pkcs12);
35 while (enumerator->enumerate(enumerator, &cert))
36 {
37 x509_t *x509 = (x509_t*)cert;
38
39 if (x509->get_flags(x509) & X509_CA)
40 {
41 printf("[%2d] \"%Y\" (CA)\n", index++, cert->get_subject(cert));
42 }
43 else
44 {
45 printf("[%2d] \"%Y\"\n", index++, cert->get_subject(cert));
46 }
47 }
48 enumerator->destroy(enumerator);
49
50 printf("Private keys:\n");
51 enumerator = pkcs12->create_key_enumerator(pkcs12);
52 while (enumerator->enumerate(enumerator, &key))
53 {
54 printf("[%2d] %N %d bits\n", index++, key_type_names,
55 key->get_type(key), key->get_keysize(key));
56 }
57 enumerator->destroy(enumerator);
58 return 0;
59 }
60
61 static int export(pkcs12_t *pkcs12, int index, char *outform)
62 {
63 cred_encoding_type_t form;
64 enumerator_t *enumerator;
65 certificate_t *cert;
66 private_key_t *key;
67 chunk_t encoding;
68 int i = 1;
69
70 enumerator = pkcs12->create_cert_enumerator(pkcs12);
71 while (enumerator->enumerate(enumerator, &cert))
72 {
73 if (i++ == index)
74 {
75 form = CERT_ASN1_DER;
76 if (outform && !get_form(outform, &form, CRED_CERTIFICATE))
77 {
78 return command_usage("invalid output format");
79 }
80 if (cert->get_encoding(cert, form, &encoding))
81 {
82 set_file_mode(stdout, form);
83 if (fwrite(encoding.ptr, encoding.len, 1, stdout) == 1)
84 {
85 free(encoding.ptr);
86 enumerator->destroy(enumerator);
87 return 0;
88 }
89 free(encoding.ptr);
90 }
91 fprintf(stderr, "certificate export failed\n");
92 enumerator->destroy(enumerator);
93 return 1;
94 }
95 }
96 enumerator->destroy(enumerator);
97
98 enumerator = pkcs12->create_key_enumerator(pkcs12);
99 while (enumerator->enumerate(enumerator, &key))
100 {
101 if (i++ == index)
102 {
103 form = PRIVKEY_ASN1_DER;
104 if (outform && !get_form(outform, &form, CRED_PRIVATE_KEY))
105 {
106 return command_usage("invalid output format");
107 }
108 if (key->get_encoding(key, form, &encoding))
109 {
110 set_file_mode(stdout, form);
111 if (fwrite(encoding.ptr, encoding.len, 1, stdout) == 1)
112 {
113 free(encoding.ptr);
114 enumerator->destroy(enumerator);
115 return 0;
116 }
117 free(encoding.ptr);
118 }
119 fprintf(stderr, "private key export failed\n");
120 enumerator->destroy(enumerator);
121 return 0;
122 }
123 }
124 enumerator->destroy(enumerator);
125
126 fprintf(stderr, "invalid index %d\n", index);
127 return 1;
128 }
129
130
131 /**
132 * Handle PKCs#12 containers
133 */
134 static int pkcs12()
135 {
136 char *arg, *file = NULL, *outform = NULL;
137 pkcs12_t *p12 = NULL;
138 int res = 1, index = 0;
139 enum {
140 OP_NONE,
141 OP_LIST,
142 OP_EXPORT,
143 } op = OP_NONE;
144
145 while (TRUE)
146 {
147 switch (command_getopt(&arg))
148 {
149 case 'h':
150 return command_usage(NULL);
151 case 'i':
152 file = arg;
153 continue;
154 case 'l':
155 if (op != OP_NONE)
156 {
157 goto invalid;
158 }
159 op = OP_LIST;
160 continue;
161 case 'e':
162 if (op != OP_NONE)
163 {
164 goto invalid;
165 }
166 op = OP_EXPORT;
167 index = atoi(arg);
168 continue;
169 case 'f':
170 outform = arg;
171 continue;
172 case EOF:
173 break;
174 default:
175 invalid:
176 return command_usage("invalid --pkcs12 option");
177 }
178 break;
179 }
180
181 if (file)
182 {
183 p12 = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS12,
184 BUILD_FROM_FILE, file, BUILD_END);
185 }
186 else
187 {
188 chunk_t chunk;
189
190 set_file_mode(stdin, CERT_ASN1_DER);
191 if (!chunk_from_fd(0, &chunk))
192 {
193 fprintf(stderr, "reading input failed: %s\n", strerror(errno));
194 return 1;
195 }
196 p12 = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS12,
197 BUILD_BLOB, chunk, BUILD_END);
198 free(chunk.ptr);
199 }
200
201 if (!p12)
202 {
203 fprintf(stderr, "reading input failed!\n");
204 goto end;
205 }
206
207 switch (op)
208 {
209 case OP_LIST:
210 res = show(p12);
211 break;
212 case OP_EXPORT:
213 res = export(p12, index, outform);
214 break;
215 default:
216 p12->container.destroy(&p12->container);
217 return command_usage(NULL);
218 }
219
220 end:
221 if (p12)
222 {
223 p12->container.destroy(&p12->container);
224 }
225 return res;
226 }
227
228 /**
229 * Register the command.
230 */
231 static void __attribute__ ((constructor))reg()
232 {
233 command_register((command_t) {
234 pkcs12, 'u', "pkcs12", "PKCS#12 functions",
235 {"--export index|--list [--in file]",
236 "[--outform der|pem|dnskey|sshkey]"},
237 {
238 {"help", 'h', 0, "show usage information"},
239 {"in", 'i', 1, "input file, default: stdin"},
240 {"list", 'l', 0, "list certificates and keys"},
241 {"export", 'e', 1, "export the credential with the given index"},
242 {"outform", 'f', 1, "encoding of extracted public key, default: der"},
243 }
244 });
245 }