px5g-wolfssl: Fix permission of private key
[openwrt/staging/jow.git] / package / utils / px5g-wolfssl / px5g-wolfssl.c
1 // Copyright 2020 Paul Spooren <mail@aparcar.org>
2 //
3 // SPDX-License-Identifier: GPL-2.0-or-later
4
5 #define _GNU_SOURCE
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <wolfssl/options.h>
13 #include <wolfssl/wolfcrypt/asn.h>
14 #include <wolfssl/wolfcrypt/asn_public.h>
15 #include <wolfssl/wolfcrypt/ecc.h>
16 #include <wolfssl/wolfcrypt/error-crypt.h>
17 #include <wolfssl/wolfcrypt/rsa.h>
18 #include <wolfssl/wolfcrypt/settings.h>
19
20 #define HEAP_HINT NULL
21 #define FOURK_SZ 4096
22 #define WOLFSSL_MIN_RSA_BITS 2048
23
24 enum {
25 EC_KEY_TYPE = 0,
26 RSA_KEY_TYPE = 1,
27 };
28
29 int write_file(byte *buf, int bufSz, char *path, bool cert) {
30 mode_t mode = S_IRUSR | S_IWUSR;
31 ssize_t written;
32 int err;
33 int fd;
34
35 if (cert)
36 mode |= S_IRGRP | S_IROTH;
37
38 if (path) {
39 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
40 if (fd < 0) {
41 perror("Error opening file");
42 exit(1);
43 }
44 } else {
45 fd = STDERR_FILENO;
46 }
47 written = write(fd, buf, bufSz);
48 if (written != bufSz) {
49 perror("Error write file");
50 exit(1);
51 }
52 err = fsync(fd);
53 if (err < 0) {
54 perror("Error fsync file");
55 exit(1);
56 }
57 if (path) {
58 close(fd);
59 }
60 return 0;
61 }
62
63 int write_key(ecc_key *ecKey, RsaKey *rsaKey, int type, int keySz, char *fName,
64 bool write_pem) {
65 int ret;
66 byte der[FOURK_SZ] = {};
67 byte pem[FOURK_SZ] = {};
68 int derSz, pemSz;
69 if (type == EC_KEY_TYPE) {
70 ret = wc_EccKeyToDer(ecKey, der, sizeof(der));
71 } else {
72 ret = wc_RsaKeyToDer(rsaKey, der, sizeof(der));
73 }
74 if (ret <= 0) {
75 fprintf(stderr, "Key To DER failed: %d\n", ret);
76 }
77 derSz = ret;
78
79 if (write_pem) {
80 if (type == EC_KEY_TYPE) {
81 ret = wc_DerToPem(der, derSz, pem, sizeof(pem), ECC_PRIVATEKEY_TYPE);
82 } else {
83 ret = wc_DerToPem(der, derSz, pem, sizeof(pem), PRIVATEKEY_TYPE);
84 }
85 if (ret <= 0) {
86 fprintf(stderr, "DER to PEM failed: %d\n", ret);
87 }
88 pemSz = ret;
89 ret = write_file(pem, pemSz, fName, false);
90 } else {
91 ret = write_file(der, derSz, fName, false);
92 }
93 return ret;
94 }
95
96 int gen_key(WC_RNG *rng, ecc_key *ecKey, RsaKey *rsaKey, int type, int keySz,
97 long exp, int curve) {
98 int ret;
99
100 if (type == EC_KEY_TYPE) {
101 ret = wc_ecc_init(ecKey);
102 (void)rsaKey;
103 } else {
104 ret = wc_InitRsaKey(rsaKey, NULL);
105 (void)ecKey;
106 }
107 if (ret != 0) {
108 fprintf(stderr, "Key initialization failed: %d\n", ret);
109 return ret;
110 }
111
112 if (type == EC_KEY_TYPE) {
113 fprintf(stderr, "Generating EC private key\n");
114 ret = wc_ecc_make_key_ex(rng, 32, ecKey, curve);
115 } else {
116 fprintf(stderr, "Generating RSA private key, %i bit long modulus\n", keySz);
117 ret = wc_MakeRsaKey(rsaKey, keySz, WC_RSA_EXPONENT, rng);
118 }
119 if (ret != 0) {
120 fprintf(stderr, "Key generation failed: %d\n", ret);
121 }
122 return ret;
123 }
124
125 int selfsigned(WC_RNG *rng, char **arg) {
126 ecc_key ecKey;
127 RsaKey rsaKey;
128 int ret;
129 char *subject = "";
130 int keySz = WOLFSSL_MIN_RSA_BITS;
131 int type = EC_KEY_TYPE;
132 int exp = WC_RSA_EXPONENT;
133 int curve = ECC_SECP256R1;
134 unsigned int days = 3653; // 10 years
135 char *keypath = NULL, *certpath = NULL;
136 char fstr[20], tstr[20];
137 bool pem = true;
138 Cert newCert;
139 #ifdef __USE_TIME_BITS64
140 time_t to, from = time(NULL);
141 #else
142 unsigned long to, from = time(NULL);
143 #endif
144 byte derBuf[FOURK_SZ] = {};
145 byte pemBuf[FOURK_SZ] = {};
146 int pemSz = -1;
147 int derSz = -1;
148 char *key, *val, *tmp;
149
150 ret = wc_InitCert(&newCert);
151 if (ret != 0) {
152 fprintf(stderr, "Init Cert failed: %d\n", ret);
153 return ret;
154 }
155 newCert.isCA = 0;
156
157 while (*arg && **arg == '-') {
158 if (!strcmp(*arg, "-der")) {
159 pem = false;
160 } else if (!strcmp(*arg, "-newkey") && arg[1]) {
161 if (!strncmp(arg[1], "rsa:", 4)) {
162 type = RSA_KEY_TYPE;
163 keySz = atoi(arg[1] + 4);
164 } else if (!strcmp(arg[1], "ec")) {
165 type = EC_KEY_TYPE;
166 } else {
167 fprintf(stderr, "error: invalid algorithm\n");
168 return 1;
169 }
170 arg++;
171 } else if (!strcmp(*arg, "-days") && arg[1]) {
172 days = (unsigned int)atoi(arg[1]);
173 arg++;
174 } else if (!strcmp(*arg, "-pkeyopt") && arg[1]) {
175 if (strncmp(arg[1], "ec_paramgen_curve:", 18)) {
176 fprintf(stderr, "error: invalid pkey option: %s\n", arg[1]);
177 return 1;
178 }
179 if (!strcmp(arg[1] + 18, "P-256")) {
180 curve = ECC_SECP256R1;
181 } else if (!strcmp(arg[1] + 18, "P-384")) {
182 curve = ECC_SECP384R1;
183 } else if (!strcmp(arg[1] + 18, "P-521")) {
184 curve = ECC_SECP521R1;
185 } else {
186 fprintf(stderr, "error: invalid curve name: %s\n", arg[1] + 18);
187 return 1;
188 }
189 arg++;
190 } else if (!strcmp(*arg, "-keyout") && arg[1]) {
191 keypath = arg[1];
192 arg++;
193 } else if (!strcmp(*arg, "-out") && arg[1]) {
194 certpath = arg[1];
195 arg++;
196 } else if (!strcmp(*arg, "-subj") && arg[1]) {
197 subject = strdupa(arg[1]);
198 key = arg[1];
199 do {
200 tmp = strchr(key, '/');
201 if (tmp)
202 *tmp = '\0';
203
204 val = strchr(key, '=');
205 if (val) {
206 *val = '\0';
207 ++val;
208
209 if (!strcmp(key, "C"))
210 strncpy(newCert.subject.country, val, CTC_NAME_SIZE);
211 else if (!strcmp(key, "ST"))
212 strncpy(newCert.subject.state, val, CTC_NAME_SIZE);
213 else if (!strcmp(key, "L"))
214 strncpy(newCert.subject.locality, val, CTC_NAME_SIZE);
215 else if (!strcmp(key, "O"))
216 strncpy(newCert.subject.org, val, CTC_NAME_SIZE);
217 else if (!strcmp(key, "OU"))
218 strncpy(newCert.subject.unit, val, CTC_NAME_SIZE);
219 else if (!strcmp(key, "CN")) {
220 strncpy(newCert.subject.commonName, val, CTC_NAME_SIZE);
221
222 #ifdef WOLFSSL_ALT_NAMES
223 if(strlen(val) + 2 > 256) {
224 fprintf(stderr, "error: CN is too long: %s\n", val);
225 return 1;
226 }
227
228 newCert.altNames[0] = 0x30; //Sequence with one element
229 newCert.altNames[1] = strlen(val) + 2; // Length of entire sequence
230 newCert.altNames[2] = 0x82; //8 - String, 2 - DNS Name
231 newCert.altNames[3] = strlen(val); //DNS Name length
232 memcpy(newCert.altNames + 4, val, strlen(val)); //DNS Name
233 newCert.altNamesSz = strlen(val) + 4;
234 #endif
235 }
236 else if (!strcmp(key, "EMAIL"))
237 strncpy(newCert.subject.email, val, CTC_NAME_SIZE);
238 else
239 printf("warning: unknown attribute %s=%s\n", key, val);
240 }
241 } while (tmp && (key = ++tmp));
242 }
243 arg++;
244 }
245 newCert.daysValid = days;
246
247 newCert.keyUsage = KEYUSE_DIGITAL_SIG | KEYUSE_CONTENT_COMMIT | KEYUSE_KEY_ENCIPHER;
248 newCert.extKeyUsage = EXTKEYUSE_SERVER_AUTH;
249
250 gen_key(rng, &ecKey, &rsaKey, type, keySz, exp, curve);
251 write_key(&ecKey, &rsaKey, type, keySz, keypath, pem);
252
253 from = (from < 1000000000) ? 1000000000 : from;
254 strftime(fstr, sizeof(fstr), "%Y%m%d%H%M%S", gmtime(&from));
255 to = from + 60 * 60 * 24 * days;
256 if (to < from)
257 to = INT_MAX;
258 strftime(tstr, sizeof(tstr), "%Y%m%d%H%M%S", gmtime(&to));
259
260 fprintf(stderr,
261 "Generating selfsigned certificate with subject '%s'"
262 " and validity %s-%s\n",
263 subject, fstr, tstr);
264
265 if (type == EC_KEY_TYPE) {
266 newCert.sigType = CTC_SHA256wECDSA;
267 ret = wc_MakeCert(&newCert, derBuf, sizeof(derBuf), NULL, &ecKey, rng);
268 } else {
269 newCert.sigType = CTC_SHA256wRSA;
270 ret = wc_MakeCert(&newCert, derBuf, sizeof(derBuf), &rsaKey, NULL, rng);
271 }
272 if (ret <= 0) {
273 fprintf(stderr, "Make Cert failed: %d\n", ret);
274 return ret;
275 }
276
277 if (type == EC_KEY_TYPE) {
278 ret = wc_SignCert(newCert.bodySz, newCert.sigType, derBuf, sizeof(derBuf),
279 NULL, &ecKey, rng);
280 } else {
281 ret = wc_SignCert(newCert.bodySz, newCert.sigType, derBuf, sizeof(derBuf),
282 &rsaKey, NULL, rng);
283 }
284 if (ret <= 0) {
285 fprintf(stderr, "Sign Cert failed: %d\n", ret);
286 return ret;
287 }
288 derSz = ret;
289
290 ret = wc_DerToPem(derBuf, derSz, pemBuf, sizeof(pemBuf), CERT_TYPE);
291 if (ret <= 0) {
292 fprintf(stderr, "DER to PEM failed: %d\n", ret);
293 return ret;
294 }
295 pemSz = ret;
296
297 ret = write_file(pemBuf, pemSz, certpath, true);
298 if (ret != 0) {
299 fprintf(stderr, "Write Cert failed: %d\n", ret);
300 return ret;
301 }
302
303 if (type == EC_KEY_TYPE) {
304 wc_ecc_free(&ecKey);
305 } else {
306 wc_FreeRsaKey(&rsaKey);
307 }
308 return 0;
309 }
310
311 int dokey(WC_RNG *rng, int type, char **arg) {
312 ecc_key ecKey;
313 RsaKey rsaKey;
314 int ret;
315 int curve = ECC_SECP256R1;
316 int keySz = WOLFSSL_MIN_RSA_BITS;
317 int exp = WC_RSA_EXPONENT;
318 char *path = NULL;
319 bool pem = true;
320
321 while (*arg && **arg == '-') {
322 if (!strcmp(*arg, "-out") && arg[1]) {
323 path = arg[1];
324 arg++;
325 } else if (!strcmp(*arg, "-3")) {
326 exp = 3;
327 } else if (!strcmp(*arg, "-der")) {
328 pem = false;
329 }
330 arg++;
331 }
332
333 if (*arg && type == RSA_KEY_TYPE) {
334 keySz = atoi(*arg);
335 } else if (*arg) {
336 if (!strcmp(*arg, "P-256")) {
337 curve = ECC_SECP256R1;
338 } else if (!strcmp(*arg, "P-384")) {
339 curve = ECC_SECP384R1;
340 } else if (!strcmp(*arg, "P-521")) {
341 curve = ECC_SECP521R1;
342 } else {
343 fprintf(stderr, "Invalid Curve Name: %s\n", *arg);
344 return 1;
345 }
346 }
347
348 ret = gen_key(rng, &ecKey, &rsaKey, type, keySz, exp, curve);
349 if (ret != 0)
350 return ret;
351
352 ret = write_key(&ecKey, &rsaKey, type, keySz, path, pem);
353
354 if (type == EC_KEY_TYPE) {
355 wc_ecc_free(&ecKey);
356 } else {
357 wc_FreeRsaKey(&rsaKey);
358 }
359 return ret;
360 }
361
362 int main(int argc, char *argv[]) {
363 int ret;
364 WC_RNG rng;
365 ret = wc_InitRng(&rng);
366 if (ret != 0) {
367 fprintf(stderr, "Init Rng failed: %d\n", ret);
368 return ret;
369 }
370
371 if (argv[1]) {
372 if (!strcmp(argv[1], "eckey"))
373 return dokey(&rng, EC_KEY_TYPE, argv + 2);
374
375 if (!strcmp(argv[1], "rsakey"))
376 return dokey(&rng, RSA_KEY_TYPE, argv + 2);
377
378 if (!strcmp(argv[1], "selfsigned"))
379 return selfsigned(&rng, argv + 2);
380 }
381
382 fprintf(stderr, "PX5G X.509 Certificate Generator Utilit using WolfSSL\n\n");
383 fprintf(stderr, "Usage: [eckey|rsakey|selfsigned]\n");
384 return 1;
385 }