1 // Copyright 2020 Paul Spooren <mail@aparcar.org>
3 // SPDX-License-Identifier: GPL-2.0-or-later
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>
20 #define HEAP_HINT NULL
22 #define WOLFSSL_MIN_RSA_BITS 2048
29 int write_file(byte
*buf
, int bufSz
, char *path
, bool cert
) {
30 mode_t mode
= S_IRUSR
| S_IWUSR
;
36 mode
|= S_IRGRP
| S_IROTH
;
39 fd
= open(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
41 perror("Error opening file");
47 written
= write(fd
, buf
, bufSz
);
48 if (written
!= bufSz
) {
49 perror("Error write file");
54 perror("Error fsync file");
63 int write_key(ecc_key
*ecKey
, RsaKey
*rsaKey
, int type
, int keySz
, char *fName
,
66 byte der
[FOURK_SZ
] = {};
67 byte pem
[FOURK_SZ
] = {};
69 if (type
== EC_KEY_TYPE
) {
70 ret
= wc_EccKeyToDer(ecKey
, der
, sizeof(der
));
72 ret
= wc_RsaKeyToDer(rsaKey
, der
, sizeof(der
));
75 fprintf(stderr
, "Key To DER failed: %d\n", ret
);
80 if (type
== EC_KEY_TYPE
) {
81 ret
= wc_DerToPem(der
, derSz
, pem
, sizeof(pem
), ECC_PRIVATEKEY_TYPE
);
83 ret
= wc_DerToPem(der
, derSz
, pem
, sizeof(pem
), PRIVATEKEY_TYPE
);
86 fprintf(stderr
, "DER to PEM failed: %d\n", ret
);
89 ret
= write_file(pem
, pemSz
, fName
, false);
91 ret
= write_file(der
, derSz
, fName
, false);
96 int gen_key(WC_RNG
*rng
, ecc_key
*ecKey
, RsaKey
*rsaKey
, int type
, int keySz
,
97 long exp
, int curve
) {
100 if (type
== EC_KEY_TYPE
) {
101 ret
= wc_ecc_init(ecKey
);
104 ret
= wc_InitRsaKey(rsaKey
, NULL
);
108 fprintf(stderr
, "Key initialization failed: %d\n", ret
);
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
);
116 fprintf(stderr
, "Generating RSA private key, %i bit long modulus\n", keySz
);
117 ret
= wc_MakeRsaKey(rsaKey
, keySz
, WC_RSA_EXPONENT
, rng
);
120 fprintf(stderr
, "Key generation failed: %d\n", ret
);
125 int selfsigned(WC_RNG
*rng
, char **arg
) {
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];
139 #ifdef __USE_TIME_BITS64
140 time_t to
, from
= time(NULL
);
142 unsigned long to
, from
= time(NULL
);
144 byte derBuf
[FOURK_SZ
] = {};
145 byte pemBuf
[FOURK_SZ
] = {};
148 char *key
, *val
, *tmp
;
150 ret
= wc_InitCert(&newCert
);
152 fprintf(stderr
, "Init Cert failed: %d\n", ret
);
157 while (*arg
&& **arg
== '-') {
158 if (!strcmp(*arg
, "-der")) {
160 } else if (!strcmp(*arg
, "-newkey") && arg
[1]) {
161 if (!strncmp(arg
[1], "rsa:", 4)) {
163 keySz
= atoi(arg
[1] + 4);
164 } else if (!strcmp(arg
[1], "ec")) {
167 fprintf(stderr
, "error: invalid algorithm\n");
171 } else if (!strcmp(*arg
, "-days") && arg
[1]) {
172 days
= (unsigned int)atoi(arg
[1]);
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]);
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
;
186 fprintf(stderr
, "error: invalid curve name: %s\n", arg
[1] + 18);
190 } else if (!strcmp(*arg
, "-keyout") && arg
[1]) {
193 } else if (!strcmp(*arg
, "-out") && arg
[1]) {
196 } else if (!strcmp(*arg
, "-subj") && arg
[1]) {
197 subject
= strdupa(arg
[1]);
200 tmp
= strchr(key
, '/');
204 val
= strchr(key
, '=');
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
);
222 #ifdef WOLFSSL_ALT_NAMES
223 if(strlen(val
) + 2 > 256) {
224 fprintf(stderr
, "error: CN is too long: %s\n", val
);
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;
236 else if (!strcmp(key
, "EMAIL"))
237 strncpy(newCert
.subject
.email
, val
, CTC_NAME_SIZE
);
239 printf("warning: unknown attribute %s=%s\n", key
, val
);
241 } while (tmp
&& (key
= ++tmp
));
245 newCert
.daysValid
= days
;
247 newCert
.keyUsage
= KEYUSE_DIGITAL_SIG
| KEYUSE_CONTENT_COMMIT
| KEYUSE_KEY_ENCIPHER
;
248 newCert
.extKeyUsage
= EXTKEYUSE_SERVER_AUTH
;
250 gen_key(rng
, &ecKey
, &rsaKey
, type
, keySz
, exp
, curve
);
251 write_key(&ecKey
, &rsaKey
, type
, keySz
, keypath
, pem
);
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
;
258 strftime(tstr
, sizeof(tstr
), "%Y%m%d%H%M%S", gmtime(&to
));
261 "Generating selfsigned certificate with subject '%s'"
262 " and validity %s-%s\n",
263 subject
, fstr
, tstr
);
265 if (type
== EC_KEY_TYPE
) {
266 newCert
.sigType
= CTC_SHA256wECDSA
;
267 ret
= wc_MakeCert(&newCert
, derBuf
, sizeof(derBuf
), NULL
, &ecKey
, rng
);
269 newCert
.sigType
= CTC_SHA256wRSA
;
270 ret
= wc_MakeCert(&newCert
, derBuf
, sizeof(derBuf
), &rsaKey
, NULL
, rng
);
273 fprintf(stderr
, "Make Cert failed: %d\n", ret
);
277 if (type
== EC_KEY_TYPE
) {
278 ret
= wc_SignCert(newCert
.bodySz
, newCert
.sigType
, derBuf
, sizeof(derBuf
),
281 ret
= wc_SignCert(newCert
.bodySz
, newCert
.sigType
, derBuf
, sizeof(derBuf
),
285 fprintf(stderr
, "Sign Cert failed: %d\n", ret
);
290 ret
= wc_DerToPem(derBuf
, derSz
, pemBuf
, sizeof(pemBuf
), CERT_TYPE
);
292 fprintf(stderr
, "DER to PEM failed: %d\n", ret
);
297 ret
= write_file(pemBuf
, pemSz
, certpath
, true);
299 fprintf(stderr
, "Write Cert failed: %d\n", ret
);
303 if (type
== EC_KEY_TYPE
) {
306 wc_FreeRsaKey(&rsaKey
);
311 int dokey(WC_RNG
*rng
, int type
, char **arg
) {
315 int curve
= ECC_SECP256R1
;
316 int keySz
= WOLFSSL_MIN_RSA_BITS
;
317 int exp
= WC_RSA_EXPONENT
;
321 while (*arg
&& **arg
== '-') {
322 if (!strcmp(*arg
, "-out") && arg
[1]) {
325 } else if (!strcmp(*arg
, "-3")) {
327 } else if (!strcmp(*arg
, "-der")) {
333 if (*arg
&& type
== RSA_KEY_TYPE
) {
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
;
343 fprintf(stderr
, "Invalid Curve Name: %s\n", *arg
);
348 ret
= gen_key(rng
, &ecKey
, &rsaKey
, type
, keySz
, exp
, curve
);
352 ret
= write_key(&ecKey
, &rsaKey
, type
, keySz
, path
, pem
);
354 if (type
== EC_KEY_TYPE
) {
357 wc_FreeRsaKey(&rsaKey
);
362 int main(int argc
, char *argv
[]) {
365 ret
= wc_InitRng(&rng
);
367 fprintf(stderr
, "Init Rng failed: %d\n", ret
);
372 if (!strcmp(argv
[1], "eckey"))
373 return dokey(&rng
, EC_KEY_TYPE
, argv
+ 2);
375 if (!strcmp(argv
[1], "rsakey"))
376 return dokey(&rng
, RSA_KEY_TYPE
, argv
+ 2);
378 if (!strcmp(argv
[1], "selfsigned"))
379 return selfsigned(&rng
, argv
+ 2);
382 fprintf(stderr
, "PX5G X.509 Certificate Generator Utilit using WolfSSL\n\n");
383 fprintf(stderr
, "Usage: [eckey|rsakey|selfsigned]\n");