]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/pki/commands/req.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / pki / commands / req.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Copyright (C) 2009-2017 Andreas Steffen
4 *
5 * Copyright (C) secunet Security Networks AG
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 request.
28 */
29 static int req()
30 {
31 cred_encoding_type_t form = CERT_ASN1_DER;
32 key_type_t type = KEY_ANY;
33 hash_algorithm_t digest = HASH_UNKNOWN;
34 signature_params_t *scheme = NULL;
35 certificate_t *cert = NULL;
36 private_key_t *private = NULL;
37 char *file = NULL, *keyid = NULL, *dn = NULL, *error = NULL;
38 identification_t *id = NULL;
39 linked_list_t *san;
40 chunk_t encoding = chunk_empty;
41 chunk_t challenge_password = chunk_empty;
42 char *arg;
43 bool pss = lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE,
44 lib->ns);
45
46 san = linked_list_create();
47
48 while (TRUE)
49 {
50 switch (command_getopt(&arg))
51 {
52 case 'h':
53 goto usage;
54 case 't':
55 if (streq(arg, "rsa"))
56 {
57 type = KEY_RSA;
58 }
59 else if (streq(arg, "ecdsa"))
60 {
61 type = KEY_ECDSA;
62 }
63 else if (streq(arg, "bliss"))
64 {
65 type = KEY_BLISS;
66 }
67 else if (streq(arg, "priv"))
68 {
69 type = KEY_ANY;
70 }
71 else
72 {
73 error = "invalid input type";
74 goto usage;
75 }
76 continue;
77 case 'g':
78 if (!enum_from_name(hash_algorithm_short_names, arg, &digest))
79 {
80 error = "invalid --digest type";
81 goto usage;
82 }
83 continue;
84 case 'R':
85 if (streq(arg, "pss"))
86 {
87 pss = TRUE;
88 }
89 else if (!streq(arg, "pkcs1"))
90 {
91 error = "invalid RSA padding";
92 goto usage;
93 }
94 continue;
95 case 'i':
96 file = arg;
97 continue;
98 case 'd':
99 dn = arg;
100 continue;
101 case 'a':
102 san->insert_last(san, identification_create_from_string(arg));
103 continue;
104 case 'p':
105 challenge_password = chunk_create(arg, strlen(arg));
106 continue;
107 case 'f':
108 if (!get_form(arg, &form, CRED_CERTIFICATE))
109 {
110 error = "invalid output format";
111 goto usage;
112 }
113 continue;
114 case 'x':
115 keyid = arg;
116 continue;
117 case EOF:
118 break;
119 default:
120 error = "invalid --req option";
121 goto usage;
122 }
123 break;
124 }
125
126 if (!dn)
127 {
128 error = "--dn is required";
129 goto usage;
130 }
131 id = identification_create_from_string(dn);
132 if (id->get_type(id) != ID_DER_ASN1_DN)
133 {
134 error = "supplied --dn is not a distinguished name";
135 goto end;
136 }
137 if (file)
138 {
139 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
140 BUILD_FROM_FILE, file, BUILD_END);
141 }
142 else if (keyid)
143 {
144 chunk_t chunk;
145
146 chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
147 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
148 BUILD_PKCS11_KEYID, chunk, BUILD_END);
149 free(chunk.ptr);
150 }
151 else
152 {
153 chunk_t chunk;
154
155 set_file_mode(stdin, CERT_ASN1_DER);
156 if (!chunk_from_fd(0, &chunk))
157 {
158 fprintf(stderr, "reading private key failed: %s\n", strerror(errno));
159 error = "";
160 goto end;
161 }
162 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
163 BUILD_BLOB, chunk, BUILD_END);
164 free(chunk.ptr);
165 }
166 if (!private)
167 {
168 error = "parsing private key failed";
169 goto end;
170 }
171 scheme = get_signature_scheme(private, digest, pss);
172 if (!scheme)
173 {
174 error = "no signature scheme found";
175 goto end;
176 }
177
178 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST,
179 BUILD_SIGNING_KEY, private,
180 BUILD_SUBJECT, id,
181 BUILD_SUBJECT_ALTNAMES, san,
182 BUILD_CHALLENGE_PWD, challenge_password,
183 BUILD_SIGNATURE_SCHEME, scheme,
184 BUILD_END);
185 if (!cert)
186 {
187 error = "generating certificate request failed";
188 goto end;
189 }
190 if (!cert->get_encoding(cert, form, &encoding))
191 {
192 error = "encoding certificate request failed";
193 goto end;
194 }
195 set_file_mode(stdout, form);
196 if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
197 {
198 error = "writing certificate request failed";
199 goto end;
200 }
201
202 end:
203 DESTROY_IF(id);
204 DESTROY_IF(cert);
205 DESTROY_IF(private);
206 san->destroy_offset(san, offsetof(identification_t, destroy));
207 signature_params_destroy(scheme);
208 free(encoding.ptr);
209
210 if (error)
211 {
212 fprintf(stderr, "%s\n", error);
213 return 1;
214 }
215 return 0;
216
217 usage:
218 san->destroy_offset(san, offsetof(identification_t, destroy));
219 return command_usage(error);
220 }
221
222 /**
223 * Register the command.
224 */
225 static void __attribute__ ((constructor))reg()
226 {
227 command_register((command_t) {
228 req, 'r', "req",
229 "create a PKCS#10 certificate request",
230 {"[--in file|--keyid hex] [--type rsa|ecdsa|bliss|priv] --dn distinguished-name",
231 "[--san subjectAltName]+ [--password challengePassword]",
232 "[--digest md5|sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]",
233 "[--rsa-padding pkcs1|pss]",
234 "[--outform der|pem]"},
235 {
236 {"help", 'h', 0, "show usage information"},
237 {"in", 'i', 1, "private key input file, default: stdin"},
238 {"keyid", 'x', 1, "smartcard or TPM private key object handle"},
239 {"type", 't', 1, "type of input key, default: priv"},
240 {"dn", 'd', 1, "subject distinguished name"},
241 {"san", 'a', 1, "subjectAltName to include in cert request"},
242 {"password", 'p', 1, "challengePassword to include in cert request"},
243 {"digest", 'g', 1, "digest for signature creation, default: key-specific"},
244 {"rsa-padding", 'R', 1, "padding for RSA signatures, default: pkcs1"},
245 {"outform", 'f', 1, "encoding of generated request, default: der"},
246 }
247 });
248 }