cd04a41dfb85a5968531b2ea1c9c2440d05e81d5
[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 <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 (!strcmp(*arg, "-der")) {
146 pem = false;
147 } else if (!strcmp(*arg, "-newkey") && arg[1]) {
148 if (!strncmp(arg[1], "rsa:", 4)) {
149 type = RSA_KEY_TYPE;
150 keySz = atoi(arg[1] + 4);
151 } else if (!strcmp(arg[1], "ec")) {
152 type = EC_KEY_TYPE;
153 } else {
154 fprintf(stderr, "error: invalid algorithm\n");
155 return 1;
156 }
157 arg++;
158 } else if (!strcmp(*arg, "-days") && arg[1]) {
159 days = (unsigned int)atoi(arg[1]);
160 arg++;
161 } else if (!strcmp(*arg, "-pkeyopt") && 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 (!strcmp(arg[1] + 18, "P-256")) {
167 curve = ECC_SECP256R1;
168 } else if (!strcmp(arg[1] + 18, "P-384")) {
169 curve = ECC_SECP384R1;
170 } else if (!strcmp(arg[1] + 18, "P-521")) {
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 (!strcmp(*arg, "-keyout") && arg[1]) {
178 keypath = arg[1];
179 arg++;
180 } else if (!strcmp(*arg, "-out") && 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
209 #ifdef WOLFSSL_ALT_NAMES
210 if(strlen(val) + 2 > 256) {
211 fprintf(stderr, "error: CN is too long: %s\n", val);
212 return 1;
213 }
214
215 newCert.altNames[0] = 0x30; //Sequence with one element
216 newCert.altNames[1] = strlen(val) + 2; // Length of entire sequence
217 newCert.altNames[2] = 0x82; //8 - String, 2 - DNS Name
218 newCert.altNames[3] = strlen(val); //DNS Name length
219 memcpy(newCert.altNames + 4, val, strlen(val)); //DNS Name
220 newCert.altNamesSz = strlen(val) + 4;
221 #endif
222 }
223 else if (!strcmp(key, "EMAIL"))
224 strncpy(newCert.subject.email, val, CTC_NAME_SIZE);
225 else
226 printf("warning: unknown attribute %s=%s\n", key, val);
227 }
228 } while (tmp && (key = ++tmp));
229 }
230 arg++;
231 }
232 newCert.daysValid = days;
233
234 newCert.keyUsage = KEYUSE_DIGITAL_SIG | KEYUSE_CONTENT_COMMIT | KEYUSE_KEY_ENCIPHER;
235 newCert.extKeyUsage = EXTKEYUSE_SERVER_AUTH;
236
237 gen_key(rng, &ecKey, &rsaKey, type, keySz, exp, curve);
238 write_key(&ecKey, &rsaKey, type, keySz, keypath, pem);
239
240 from = (from < 1000000000) ? 1000000000 : from;
241 strftime(fstr, sizeof(fstr), "%Y%m%d%H%M%S", gmtime(&from));
242 to = from + 60 * 60 * 24 * days;
243 if (to < from)
244 to = INT_MAX;
245 strftime(tstr, sizeof(tstr), "%Y%m%d%H%M%S", gmtime(&to));
246
247 fprintf(stderr,
248 "Generating selfsigned certificate with subject '%s'"
249 " and validity %s-%s\n",
250 subject, fstr, tstr);
251
252 if (type == EC_KEY_TYPE) {
253 newCert.sigType = CTC_SHA256wECDSA;
254 ret = wc_MakeCert(&newCert, derBuf, sizeof(derBuf), NULL, &ecKey, rng);
255 } else {
256 newCert.sigType = CTC_SHA256wRSA;
257 ret = wc_MakeCert(&newCert, derBuf, sizeof(derBuf), &rsaKey, NULL, rng);
258 }
259 if (ret <= 0) {
260 fprintf(stderr, "Make Cert failed: %d\n", ret);
261 return ret;
262 }
263
264 if (type == EC_KEY_TYPE) {
265 ret = wc_SignCert(newCert.bodySz, newCert.sigType, derBuf, sizeof(derBuf),
266 NULL, &ecKey, rng);
267 } else {
268 ret = wc_SignCert(newCert.bodySz, newCert.sigType, derBuf, sizeof(derBuf),
269 &rsaKey, NULL, rng);
270 }
271 if (ret <= 0) {
272 fprintf(stderr, "Sign Cert failed: %d\n", ret);
273 return ret;
274 }
275 derSz = ret;
276
277 ret = wc_DerToPem(derBuf, derSz, pemBuf, sizeof(pemBuf), CERT_TYPE);
278 if (ret <= 0) {
279 fprintf(stderr, "DER to PEM failed: %d\n", ret);
280 return ret;
281 }
282 pemSz = ret;
283
284 ret = write_file(pemBuf, pemSz, certpath);
285 if (ret != 0) {
286 fprintf(stderr, "Write Cert failed: %d\n", ret);
287 return ret;
288 }
289
290 if (type == EC_KEY_TYPE) {
291 wc_ecc_free(&ecKey);
292 } else {
293 wc_FreeRsaKey(&rsaKey);
294 }
295 return 0;
296 }
297
298 int dokey(WC_RNG *rng, int type, char **arg) {
299 ecc_key ecKey;
300 RsaKey rsaKey;
301 int ret;
302 int curve = ECC_SECP256R1;
303 int keySz = WOLFSSL_MIN_RSA_BITS;
304 int exp = WC_RSA_EXPONENT;
305 char *path = NULL;
306 bool pem = true;
307
308 while (*arg && **arg == '-') {
309 if (!strcmp(*arg, "-out") && arg[1]) {
310 path = arg[1];
311 arg++;
312 } else if (!strcmp(*arg, "-3")) {
313 exp = 3;
314 } else if (!strcmp(*arg, "-der")) {
315 pem = false;
316 }
317 arg++;
318 }
319
320 if (*arg && type == RSA_KEY_TYPE) {
321 keySz = atoi(*arg);
322 } else if (*arg) {
323 if (!strcmp(*arg, "P-256")) {
324 curve = ECC_SECP256R1;
325 } else if (!strcmp(*arg, "P-384")) {
326 curve = ECC_SECP384R1;
327 } else if (!strcmp(*arg, "P-521")) {
328 curve = ECC_SECP521R1;
329 } else {
330 fprintf(stderr, "Invalid Curve Name: %s\n", *arg);
331 return 1;
332 }
333 }
334
335 ret = gen_key(rng, &ecKey, &rsaKey, type, keySz, exp, curve);
336 if (ret != 0)
337 return ret;
338
339 ret = write_key(&ecKey, &rsaKey, type, keySz, path, pem);
340
341 if (type == EC_KEY_TYPE) {
342 wc_ecc_free(&ecKey);
343 } else {
344 wc_FreeRsaKey(&rsaKey);
345 }
346 return ret;
347 }
348
349 int main(int argc, char *argv[]) {
350 int ret;
351 WC_RNG rng;
352 ret = wc_InitRng(&rng);
353 if (ret != 0) {
354 fprintf(stderr, "Init Rng failed: %d\n", ret);
355 return ret;
356 }
357
358 if (argv[1]) {
359 if (!strcmp(argv[1], "eckey"))
360 return dokey(&rng, EC_KEY_TYPE, argv + 2);
361
362 if (!strcmp(argv[1], "rsakey"))
363 return dokey(&rng, RSA_KEY_TYPE, argv + 2);
364
365 if (!strcmp(argv[1], "selfsigned"))
366 return selfsigned(&rng, argv + 2);
367 }
368
369 fprintf(stderr, "PX5G X.509 Certificate Generator Utilit using WolfSSL\n\n");
370 fprintf(stderr, "Usage: [eckey|rsakey|selfsigned]\n");
371 return 1;
372 }