pki: Properly clean up if output format for --pkcs12 is wrong
[strongswan.git] / src / pki / commands / req.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Copyright (C) 2009 Andreas Steffen
4 *
5 * HSR Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <time.h>
19 #include <errno.h>
20
21 #include "pki.h"
22
23 #include <collections/linked_list.h>
24 #include <credentials/certificates/certificate.h>
25
26 /**
27 * Create a self-signed PKCS#10 certificate requesst.
28 */
29 static int req()
30 {
31 cred_encoding_type_t form = CERT_ASN1_DER;
32 key_type_t type = KEY_RSA;
33 hash_algorithm_t digest = HASH_SHA1;
34 certificate_t *cert = NULL;
35 private_key_t *private = NULL;
36 char *file = NULL, *dn = NULL, *error = NULL;
37 identification_t *id = NULL;
38 linked_list_t *san;
39 chunk_t encoding = chunk_empty;
40 chunk_t challenge_password = chunk_empty;
41 char *arg;
42
43 san = linked_list_create();
44
45 while (TRUE)
46 {
47 switch (command_getopt(&arg))
48 {
49 case 'h':
50 goto usage;
51 case 't':
52 if (streq(arg, "rsa"))
53 {
54 type = KEY_RSA;
55 }
56 else if (streq(arg, "ecdsa"))
57 {
58 type = KEY_ECDSA;
59 }
60 else if (streq(arg, "bliss"))
61 {
62 type = KEY_BLISS;
63 }
64 else
65 {
66 error = "invalid input type";
67 goto usage;
68 }
69 continue;
70 case 'g':
71 if (!enum_from_name(hash_algorithm_short_names, arg, &digest))
72 {
73 error = "invalid --digest type";
74 goto usage;
75 }
76 continue;
77 case 'i':
78 file = arg;
79 continue;
80 case 'd':
81 dn = arg;
82 continue;
83 case 'a':
84 san->insert_last(san, identification_create_from_string(arg));
85 continue;
86 case 'p':
87 challenge_password = chunk_create(arg, strlen(arg));
88 continue;
89 case 'f':
90 if (!get_form(arg, &form, CRED_CERTIFICATE))
91 {
92 error = "invalid output format";
93 goto usage;
94 }
95 continue;
96 case EOF:
97 break;
98 default:
99 error = "invalid --req option";
100 goto usage;
101 }
102 break;
103 }
104
105 if (type == KEY_BLISS)
106 {
107 /* currently only SHA-512 is supported */
108 digest = HASH_SHA512;
109 }
110 if (!dn)
111 {
112 error = "--dn is required";
113 goto usage;
114 }
115 id = identification_create_from_string(dn);
116 if (id->get_type(id) != ID_DER_ASN1_DN)
117 {
118 error = "supplied --dn is not a distinguished name";
119 goto end;
120 }
121 if (file)
122 {
123 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
124 BUILD_FROM_FILE, file, BUILD_END);
125 }
126 else
127 {
128 chunk_t chunk;
129
130 set_file_mode(stdin, CERT_ASN1_DER);
131 if (!chunk_from_fd(0, &chunk))
132 {
133 fprintf(stderr, "reading private key failed: %s\n", strerror(errno));
134 error = "";
135 goto end;
136 }
137 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
138 BUILD_BLOB, chunk, BUILD_END);
139 free(chunk.ptr);
140 }
141 if (!private)
142 {
143 error = "parsing private key failed";
144 goto end;
145 }
146 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST,
147 BUILD_SIGNING_KEY, private,
148 BUILD_SUBJECT, id,
149 BUILD_SUBJECT_ALTNAMES, san,
150 BUILD_CHALLENGE_PWD, challenge_password,
151 BUILD_DIGEST_ALG, digest,
152 BUILD_END);
153 if (!cert)
154 {
155 error = "generating certificate request failed";
156 goto end;
157 }
158 if (!cert->get_encoding(cert, form, &encoding))
159 {
160 error = "encoding certificate request failed";
161 goto end;
162 }
163 set_file_mode(stdout, form);
164 if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
165 {
166 error = "writing certificate request failed";
167 goto end;
168 }
169
170 end:
171 DESTROY_IF(id);
172 DESTROY_IF(cert);
173 DESTROY_IF(private);
174 san->destroy_offset(san, offsetof(identification_t, destroy));
175 free(encoding.ptr);
176
177 if (error)
178 {
179 fprintf(stderr, "%s\n", error);
180 return 1;
181 }
182 return 0;
183
184 usage:
185 san->destroy_offset(san, offsetof(identification_t, destroy));
186 return command_usage(error);
187 }
188
189 /**
190 * Register the command.
191 */
192 static void __attribute__ ((constructor))reg()
193 {
194 command_register((command_t) {
195 req, 'r', "req",
196 "create a PKCS#10 certificate request",
197 {" [--in file] [--type rsa|ecdsa|bliss] --dn distinguished-name",
198 "[--san subjectAltName]+ [--password challengePassword]",
199 "[--digest md5|sha1|sha224|sha256|sha384|sha512] [--outform der|pem]"},
200 {
201 {"help", 'h', 0, "show usage information"},
202 {"in", 'i', 1, "private key input file, default: stdin"},
203 {"type", 't', 1, "type of input key, default: rsa"},
204 {"dn", 'd', 1, "subject distinguished name"},
205 {"san", 'a', 1, "subjectAltName to include in cert request"},
206 {"password",'p', 1, "challengePassword to include in cert request"},
207 {"digest", 'g', 1, "digest for signature creation, default: sha1"},
208 {"outform", 'f', 1, "encoding of generated request, default: der"},
209 }
210 });
211 }