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