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