1 /*
2 * Certificate generation and signing
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 */
7
8 #include "mbedtls/build_info.h"
9
10 #include "mbedtls/platform.h"
11 /* md.h is included this early since MD_CAN_XXX macros are defined there. */
12 #include "mbedtls/md.h"
13
14 #if !defined(MBEDTLS_X509_CRT_WRITE_C) || \
15 !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_FS_IO) || \
16 !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
17 !defined(MBEDTLS_ERROR_C) || !defined(MBEDTLS_MD_CAN_SHA256) || \
18 !defined(MBEDTLS_PEM_WRITE_C) || !defined(MBEDTLS_MD_C)
main(void)19 int main(void)
20 {
21 mbedtls_printf("MBEDTLS_X509_CRT_WRITE_C and/or MBEDTLS_X509_CRT_PARSE_C and/or "
22 "MBEDTLS_FS_IO and/or MBEDTLS_MD_CAN_SHA256 and/or "
23 "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or "
24 "MBEDTLS_ERROR_C not defined.\n");
25 mbedtls_exit(0);
26 }
27 #else
28
29 #include "mbedtls/x509_crt.h"
30 #include "mbedtls/x509_csr.h"
31 #include "mbedtls/oid.h"
32 #include "mbedtls/entropy.h"
33 #include "mbedtls/ctr_drbg.h"
34 #include "mbedtls/error.h"
35 #include "test/helpers.h"
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <errno.h>
41
42 #define SET_OID(x, oid) \
43 do { x.len = MBEDTLS_OID_SIZE(oid); x.p = (unsigned char *) oid; } while (0)
44
45 #if defined(MBEDTLS_X509_CSR_PARSE_C)
46 #define USAGE_CSR \
47 " request_file=%%s default: (empty)\n" \
48 " If request_file is specified, subject_key,\n" \
49 " subject_pwd and subject_name are ignored!\n"
50 #else
51 #define USAGE_CSR ""
52 #endif /* MBEDTLS_X509_CSR_PARSE_C */
53
54 #define FORMAT_PEM 0
55 #define FORMAT_DER 1
56
57 #define DFL_ISSUER_CRT ""
58 #define DFL_REQUEST_FILE ""
59 #define DFL_SUBJECT_KEY "subject.key"
60 #define DFL_ISSUER_KEY "ca.key"
61 #define DFL_SUBJECT_PWD ""
62 #define DFL_ISSUER_PWD ""
63 #define DFL_OUTPUT_FILENAME "cert.crt"
64 #define DFL_SUBJECT_NAME "CN=Cert,O=mbed TLS,C=UK"
65 #define DFL_ISSUER_NAME "CN=CA,O=mbed TLS,C=UK"
66 #define DFL_NOT_BEFORE "20010101000000"
67 #define DFL_NOT_AFTER "20301231235959"
68 #define DFL_SERIAL "1"
69 #define DFL_SERIAL_HEX "1"
70 #define DFL_EXT_SUBJECTALTNAME ""
71 #define DFL_SELFSIGN 0
72 #define DFL_IS_CA 0
73 #define DFL_MAX_PATHLEN -1
74 #define DFL_SIG_ALG MBEDTLS_MD_SHA256
75 #define DFL_KEY_USAGE 0
76 #define DFL_EXT_KEY_USAGE NULL
77 #define DFL_NS_CERT_TYPE 0
78 #define DFL_VERSION 3
79 #define DFL_AUTH_IDENT 1
80 #define DFL_SUBJ_IDENT 1
81 #define DFL_CONSTRAINTS 1
82 #define DFL_DIGEST MBEDTLS_MD_SHA256
83 #define DFL_FORMAT FORMAT_PEM
84
85 #define USAGE \
86 "\n usage: cert_write param=<>...\n" \
87 "\n acceptable parameters:\n" \
88 USAGE_CSR \
89 " subject_key=%%s default: subject.key\n" \
90 " subject_pwd=%%s default: (empty)\n" \
91 " subject_name=%%s default: CN=Cert,O=mbed TLS,C=UK\n" \
92 "\n" \
93 " issuer_crt=%%s default: (empty)\n" \
94 " If issuer_crt is specified, issuer_name is\n" \
95 " ignored!\n" \
96 " issuer_name=%%s default: CN=CA,O=mbed TLS,C=UK\n" \
97 "\n" \
98 " selfsign=%%d default: 0 (false)\n" \
99 " If selfsign is enabled, issuer_name and\n" \
100 " issuer_key are required (issuer_crt and\n" \
101 " subject_* are ignored\n" \
102 " issuer_key=%%s default: ca.key\n" \
103 " issuer_pwd=%%s default: (empty)\n" \
104 " output_file=%%s default: cert.crt\n" \
105 " serial=%%s default: 1\n" \
106 " In decimal format; it can be used as\n" \
107 " alternative to serial_hex, but it's\n" \
108 " limited in max length to\n" \
109 " unsigned long long int\n" \
110 " serial_hex=%%s default: 1\n" \
111 " In hex format; it can be used as\n" \
112 " alternative to serial\n" \
113 " not_before=%%s default: 20010101000000\n" \
114 " not_after=%%s default: 20301231235959\n" \
115 " is_ca=%%d default: 0 (disabled)\n" \
116 " max_pathlen=%%d default: -1 (none)\n" \
117 " md=%%s default: SHA256\n" \
118 " Supported values (if enabled):\n" \
119 " MD5, RIPEMD160, SHA1,\n" \
120 " SHA224, SHA256, SHA384, SHA512\n" \
121 " version=%%d default: 3\n" \
122 " Possible values: 1, 2, 3\n" \
123 " subject_identifier=%%s default: 1\n" \
124 " Possible values: 0, 1\n" \
125 " (Considered for v3 only)\n" \
126 " san=%%s default: (none)\n" \
127 " Semicolon-separated-list of values:\n" \
128 " DNS:value\n" \
129 " URI:value\n" \
130 " RFC822:value\n" \
131 " IP:value (Only IPv4 is supported)\n" \
132 " DN:list of comma separated key=value pairs\n" \
133 " authority_identifier=%%s default: 1\n" \
134 " Possible values: 0, 1\n" \
135 " (Considered for v3 only)\n" \
136 " basic_constraints=%%d default: 1\n" \
137 " Possible values: 0, 1\n" \
138 " (Considered for v3 only)\n" \
139 " key_usage=%%s default: (empty)\n" \
140 " Comma-separated-list of values:\n" \
141 " digital_signature\n" \
142 " non_repudiation\n" \
143 " key_encipherment\n" \
144 " data_encipherment\n" \
145 " key_agreement\n" \
146 " key_cert_sign\n" \
147 " crl_sign\n" \
148 " (Considered for v3 only)\n" \
149 " ext_key_usage=%%s default: (empty)\n" \
150 " Comma-separated-list of values:\n" \
151 " serverAuth\n" \
152 " clientAuth\n" \
153 " codeSigning\n" \
154 " emailProtection\n" \
155 " timeStamping\n" \
156 " OCSPSigning\n" \
157 " ns_cert_type=%%s default: (empty)\n" \
158 " Comma-separated-list of values:\n" \
159 " ssl_client\n" \
160 " ssl_server\n" \
161 " email\n" \
162 " object_signing\n" \
163 " ssl_ca\n" \
164 " email_ca\n" \
165 " object_signing_ca\n" \
166 " format=pem|der default: pem\n" \
167 "\n"
168
169 typedef enum {
170 SERIAL_FRMT_UNSPEC,
171 SERIAL_FRMT_DEC,
172 SERIAL_FRMT_HEX
173 } serial_format_t;
174
175 /*
176 * global options
177 */
178 struct options {
179 const char *issuer_crt; /* filename of the issuer certificate */
180 const char *request_file; /* filename of the certificate request */
181 const char *subject_key; /* filename of the subject key file */
182 const char *issuer_key; /* filename of the issuer key file */
183 const char *subject_pwd; /* password for the subject key file */
184 const char *issuer_pwd; /* password for the issuer key file */
185 const char *output_file; /* where to store the constructed CRT */
186 const char *subject_name; /* subject name for certificate */
187 mbedtls_x509_san_list *san_list; /* subjectAltName for certificate */
188 const char *issuer_name; /* issuer name for certificate */
189 const char *not_before; /* validity period not before */
190 const char *not_after; /* validity period not after */
191 const char *serial; /* serial number string (decimal) */
192 const char *serial_hex; /* serial number string (hex) */
193 int selfsign; /* selfsign the certificate */
194 int is_ca; /* is a CA certificate */
195 int max_pathlen; /* maximum CA path length */
196 int authority_identifier; /* add authority identifier to CRT */
197 int subject_identifier; /* add subject identifier to CRT */
198 int basic_constraints; /* add basic constraints ext to CRT */
199 int version; /* CRT version */
200 mbedtls_md_type_t md; /* Hash used for signing */
201 unsigned char key_usage; /* key usage flags */
202 mbedtls_asn1_sequence *ext_key_usage; /* extended key usages */
203 unsigned char ns_cert_type; /* NS cert type */
204 int format; /* format */
205 } opt;
206
write_certificate(mbedtls_x509write_cert * crt,const char * output_file,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)207 int write_certificate(mbedtls_x509write_cert *crt, const char *output_file,
208 int (*f_rng)(void *, unsigned char *, size_t),
209 void *p_rng)
210 {
211 int ret;
212 FILE *f;
213 unsigned char output_buf[4096];
214 unsigned char *output_start;
215 size_t len = 0;
216
217 memset(output_buf, 0, 4096);
218 if (opt.format == FORMAT_DER) {
219 ret = mbedtls_x509write_crt_der(crt, output_buf, 4096,
220 f_rng, p_rng);
221 if (ret < 0) {
222 return ret;
223 }
224
225 len = ret;
226 output_start = output_buf + 4096 - len;
227 } else {
228 ret = mbedtls_x509write_crt_pem(crt, output_buf, 4096,
229 f_rng, p_rng);
230 if (ret < 0) {
231 return ret;
232 }
233
234 len = strlen((char *) output_buf);
235 output_start = output_buf;
236 }
237
238 if ((f = fopen(output_file, "w")) == NULL) {
239 return -1;
240 }
241
242 if (fwrite(output_start, 1, len, f) != len) {
243 fclose(f);
244 return -1;
245 }
246
247 fclose(f);
248
249 return 0;
250 }
251
parse_serial_decimal_format(unsigned char * obuf,size_t obufmax,const char * ibuf,size_t * len)252 int parse_serial_decimal_format(unsigned char *obuf, size_t obufmax,
253 const char *ibuf, size_t *len)
254 {
255 unsigned long long int dec;
256 unsigned int remaining_bytes = sizeof(dec);
257 unsigned char *p = obuf;
258 unsigned char val;
259 char *end_ptr = NULL;
260
261 errno = 0;
262 dec = strtoull(ibuf, &end_ptr, 10);
263
264 if ((errno != 0) || (end_ptr == ibuf)) {
265 return -1;
266 }
267
268 *len = 0;
269
270 while (remaining_bytes > 0) {
271 if (obufmax < (*len + 1)) {
272 return -1;
273 }
274
275 val = (dec >> ((remaining_bytes - 1) * 8)) & 0xFF;
276
277 /* Skip leading zeros */
278 if ((val != 0) || (*len != 0)) {
279 *p = val;
280 (*len)++;
281 p++;
282 }
283
284 remaining_bytes--;
285 }
286
287 return 0;
288 }
289
main(int argc,char * argv[])290 int main(int argc, char *argv[])
291 {
292 int ret = 1;
293 int exit_code = MBEDTLS_EXIT_FAILURE;
294 mbedtls_x509_crt issuer_crt;
295 mbedtls_pk_context loaded_issuer_key, loaded_subject_key;
296 mbedtls_pk_context *issuer_key = &loaded_issuer_key,
297 *subject_key = &loaded_subject_key;
298 char buf[1024];
299 char issuer_name[256];
300 int i;
301 char *p, *q, *r;
302 #if defined(MBEDTLS_X509_CSR_PARSE_C)
303 char subject_name[256];
304 mbedtls_x509_csr csr;
305 #endif
306 mbedtls_x509write_cert crt;
307 serial_format_t serial_frmt = SERIAL_FRMT_UNSPEC;
308 unsigned char serial[MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN];
309 size_t serial_len;
310 mbedtls_asn1_sequence *ext_key_usage;
311 mbedtls_entropy_context entropy;
312 mbedtls_ctr_drbg_context ctr_drbg;
313 const char *pers = "crt example app";
314 mbedtls_x509_san_list *cur, *prev;
315 uint8_t ip[4] = { 0 };
316 /*
317 * Set to sane values
318 */
319 mbedtls_x509write_crt_init(&crt);
320 mbedtls_pk_init(&loaded_issuer_key);
321 mbedtls_pk_init(&loaded_subject_key);
322 mbedtls_ctr_drbg_init(&ctr_drbg);
323 mbedtls_entropy_init(&entropy);
324 #if defined(MBEDTLS_X509_CSR_PARSE_C)
325 mbedtls_x509_csr_init(&csr);
326 #endif
327 mbedtls_x509_crt_init(&issuer_crt);
328 memset(buf, 0, sizeof(buf));
329 memset(serial, 0, sizeof(serial));
330
331 #if defined(MBEDTLS_USE_PSA_CRYPTO)
332 psa_status_t status = psa_crypto_init();
333 if (status != PSA_SUCCESS) {
334 mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
335 (int) status);
336 goto exit;
337 }
338 #endif /* MBEDTLS_USE_PSA_CRYPTO */
339
340 if (argc < 2) {
341 usage:
342 mbedtls_printf(USAGE);
343 goto exit;
344 }
345
346 opt.issuer_crt = DFL_ISSUER_CRT;
347 opt.request_file = DFL_REQUEST_FILE;
348 opt.subject_key = DFL_SUBJECT_KEY;
349 opt.issuer_key = DFL_ISSUER_KEY;
350 opt.subject_pwd = DFL_SUBJECT_PWD;
351 opt.issuer_pwd = DFL_ISSUER_PWD;
352 opt.output_file = DFL_OUTPUT_FILENAME;
353 opt.subject_name = DFL_SUBJECT_NAME;
354 opt.issuer_name = DFL_ISSUER_NAME;
355 opt.not_before = DFL_NOT_BEFORE;
356 opt.not_after = DFL_NOT_AFTER;
357 opt.serial = DFL_SERIAL;
358 opt.serial_hex = DFL_SERIAL_HEX;
359 opt.selfsign = DFL_SELFSIGN;
360 opt.is_ca = DFL_IS_CA;
361 opt.max_pathlen = DFL_MAX_PATHLEN;
362 opt.key_usage = DFL_KEY_USAGE;
363 opt.ext_key_usage = DFL_EXT_KEY_USAGE;
364 opt.ns_cert_type = DFL_NS_CERT_TYPE;
365 opt.version = DFL_VERSION - 1;
366 opt.md = DFL_DIGEST;
367 opt.subject_identifier = DFL_SUBJ_IDENT;
368 opt.authority_identifier = DFL_AUTH_IDENT;
369 opt.basic_constraints = DFL_CONSTRAINTS;
370 opt.format = DFL_FORMAT;
371 opt.san_list = NULL;
372
373 for (i = 1; i < argc; i++) {
374
375 p = argv[i];
376 if ((q = strchr(p, '=')) == NULL) {
377 goto usage;
378 }
379 *q++ = '\0';
380
381 if (strcmp(p, "request_file") == 0) {
382 opt.request_file = q;
383 } else if (strcmp(p, "subject_key") == 0) {
384 opt.subject_key = q;
385 } else if (strcmp(p, "issuer_key") == 0) {
386 opt.issuer_key = q;
387 } else if (strcmp(p, "subject_pwd") == 0) {
388 opt.subject_pwd = q;
389 } else if (strcmp(p, "issuer_pwd") == 0) {
390 opt.issuer_pwd = q;
391 } else if (strcmp(p, "issuer_crt") == 0) {
392 opt.issuer_crt = q;
393 } else if (strcmp(p, "output_file") == 0) {
394 opt.output_file = q;
395 } else if (strcmp(p, "subject_name") == 0) {
396 opt.subject_name = q;
397 } else if (strcmp(p, "issuer_name") == 0) {
398 opt.issuer_name = q;
399 } else if (strcmp(p, "not_before") == 0) {
400 opt.not_before = q;
401 } else if (strcmp(p, "not_after") == 0) {
402 opt.not_after = q;
403 } else if (strcmp(p, "serial") == 0) {
404 if (serial_frmt != SERIAL_FRMT_UNSPEC) {
405 mbedtls_printf("Invalid attempt to set the serial more than once\n");
406 goto usage;
407 }
408 serial_frmt = SERIAL_FRMT_DEC;
409 opt.serial = q;
410 } else if (strcmp(p, "serial_hex") == 0) {
411 if (serial_frmt != SERIAL_FRMT_UNSPEC) {
412 mbedtls_printf("Invalid attempt to set the serial more than once\n");
413 goto usage;
414 }
415 serial_frmt = SERIAL_FRMT_HEX;
416 opt.serial_hex = q;
417 } else if (strcmp(p, "authority_identifier") == 0) {
418 opt.authority_identifier = atoi(q);
419 if (opt.authority_identifier != 0 &&
420 opt.authority_identifier != 1) {
421 mbedtls_printf("Invalid argument for option %s\n", p);
422 goto usage;
423 }
424 } else if (strcmp(p, "subject_identifier") == 0) {
425 opt.subject_identifier = atoi(q);
426 if (opt.subject_identifier != 0 &&
427 opt.subject_identifier != 1) {
428 mbedtls_printf("Invalid argument for option %s\n", p);
429 goto usage;
430 }
431 } else if (strcmp(p, "basic_constraints") == 0) {
432 opt.basic_constraints = atoi(q);
433 if (opt.basic_constraints != 0 &&
434 opt.basic_constraints != 1) {
435 mbedtls_printf("Invalid argument for option %s\n", p);
436 goto usage;
437 }
438 } else if (strcmp(p, "md") == 0) {
439 const mbedtls_md_info_t *md_info =
440 mbedtls_md_info_from_string(q);
441 if (md_info == NULL) {
442 mbedtls_printf("Invalid argument for option %s\n", p);
443 goto usage;
444 }
445 opt.md = mbedtls_md_get_type(md_info);
446 } else if (strcmp(p, "version") == 0) {
447 opt.version = atoi(q);
448 if (opt.version < 1 || opt.version > 3) {
449 mbedtls_printf("Invalid argument for option %s\n", p);
450 goto usage;
451 }
452 opt.version--;
453 } else if (strcmp(p, "selfsign") == 0) {
454 opt.selfsign = atoi(q);
455 if (opt.selfsign < 0 || opt.selfsign > 1) {
456 mbedtls_printf("Invalid argument for option %s\n", p);
457 goto usage;
458 }
459 } else if (strcmp(p, "is_ca") == 0) {
460 opt.is_ca = atoi(q);
461 if (opt.is_ca < 0 || opt.is_ca > 1) {
462 mbedtls_printf("Invalid argument for option %s\n", p);
463 goto usage;
464 }
465 } else if (strcmp(p, "max_pathlen") == 0) {
466 opt.max_pathlen = atoi(q);
467 if (opt.max_pathlen < -1 || opt.max_pathlen > 127) {
468 mbedtls_printf("Invalid argument for option %s\n", p);
469 goto usage;
470 }
471 } else if (strcmp(p, "key_usage") == 0) {
472 while (q != NULL) {
473 if ((r = strchr(q, ',')) != NULL) {
474 *r++ = '\0';
475 }
476
477 if (strcmp(q, "digital_signature") == 0) {
478 opt.key_usage |= MBEDTLS_X509_KU_DIGITAL_SIGNATURE;
479 } else if (strcmp(q, "non_repudiation") == 0) {
480 opt.key_usage |= MBEDTLS_X509_KU_NON_REPUDIATION;
481 } else if (strcmp(q, "key_encipherment") == 0) {
482 opt.key_usage |= MBEDTLS_X509_KU_KEY_ENCIPHERMENT;
483 } else if (strcmp(q, "data_encipherment") == 0) {
484 opt.key_usage |= MBEDTLS_X509_KU_DATA_ENCIPHERMENT;
485 } else if (strcmp(q, "key_agreement") == 0) {
486 opt.key_usage |= MBEDTLS_X509_KU_KEY_AGREEMENT;
487 } else if (strcmp(q, "key_cert_sign") == 0) {
488 opt.key_usage |= MBEDTLS_X509_KU_KEY_CERT_SIGN;
489 } else if (strcmp(q, "crl_sign") == 0) {
490 opt.key_usage |= MBEDTLS_X509_KU_CRL_SIGN;
491 } else {
492 mbedtls_printf("Invalid argument for option %s\n", p);
493 goto usage;
494 }
495
496 q = r;
497 }
498 } else if (strcmp(p, "ext_key_usage") == 0) {
499 mbedtls_asn1_sequence **tail = &opt.ext_key_usage;
500
501 while (q != NULL) {
502 if ((r = strchr(q, ',')) != NULL) {
503 *r++ = '\0';
504 }
505
506 ext_key_usage = mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
507 ext_key_usage->buf.tag = MBEDTLS_ASN1_OID;
508 if (strcmp(q, "serverAuth") == 0) {
509 SET_OID(ext_key_usage->buf, MBEDTLS_OID_SERVER_AUTH);
510 } else if (strcmp(q, "clientAuth") == 0) {
511 SET_OID(ext_key_usage->buf, MBEDTLS_OID_CLIENT_AUTH);
512 } else if (strcmp(q, "codeSigning") == 0) {
513 SET_OID(ext_key_usage->buf, MBEDTLS_OID_CODE_SIGNING);
514 } else if (strcmp(q, "emailProtection") == 0) {
515 SET_OID(ext_key_usage->buf, MBEDTLS_OID_EMAIL_PROTECTION);
516 } else if (strcmp(q, "timeStamping") == 0) {
517 SET_OID(ext_key_usage->buf, MBEDTLS_OID_TIME_STAMPING);
518 } else if (strcmp(q, "OCSPSigning") == 0) {
519 SET_OID(ext_key_usage->buf, MBEDTLS_OID_OCSP_SIGNING);
520 } else if (strcmp(q, "any") == 0) {
521 SET_OID(ext_key_usage->buf, MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE);
522 } else {
523 mbedtls_printf("Invalid argument for option %s\n", p);
524 goto usage;
525 }
526
527 *tail = ext_key_usage;
528 tail = &ext_key_usage->next;
529
530 q = r;
531 }
532 } else if (strcmp(p, "san") == 0) {
533 char *subtype_value;
534 prev = NULL;
535
536 while (q != NULL) {
537 char *semicolon;
538 r = q;
539
540 /* Find the first non-escaped ; occurrence and remove escaped ones */
541 do {
542 if ((semicolon = strchr(r, ';')) != NULL) {
543 if (*(semicolon-1) != '\\') {
544 r = semicolon;
545 break;
546 }
547 /* Remove the escape character */
548 size_t size_left = strlen(semicolon);
549 memmove(semicolon-1, semicolon, size_left);
550 *(semicolon + size_left - 1) = '\0';
551 /* r will now point at the character after the semicolon */
552 r = semicolon;
553 }
554
555 } while (semicolon != NULL);
556
557 if (semicolon != NULL) {
558 *r++ = '\0';
559 } else {
560 r = NULL;
561 }
562
563 cur = mbedtls_calloc(1, sizeof(mbedtls_x509_san_list));
564 if (cur == NULL) {
565 mbedtls_printf("Not enough memory for subjectAltName list\n");
566 goto usage;
567 }
568
569 cur->next = NULL;
570
571 if ((subtype_value = strchr(q, ':')) != NULL) {
572 *subtype_value++ = '\0';
573 } else {
574 mbedtls_printf(
575 "Invalid argument for option SAN: Entry must be of the form TYPE:value\n");
576 goto usage;
577 }
578 if (strcmp(q, "RFC822") == 0) {
579 cur->node.type = MBEDTLS_X509_SAN_RFC822_NAME;
580 } else if (strcmp(q, "URI") == 0) {
581 cur->node.type = MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER;
582 } else if (strcmp(q, "DNS") == 0) {
583 cur->node.type = MBEDTLS_X509_SAN_DNS_NAME;
584 } else if (strcmp(q, "IP") == 0) {
585 size_t ip_addr_len = 0;
586 cur->node.type = MBEDTLS_X509_SAN_IP_ADDRESS;
587 ip_addr_len = mbedtls_x509_crt_parse_cn_inet_pton(subtype_value, ip);
588 if (ip_addr_len == 0) {
589 mbedtls_printf("mbedtls_x509_crt_parse_cn_inet_pton failed to parse %s\n",
590 subtype_value);
591 goto exit;
592 }
593 cur->node.san.unstructured_name.p = (unsigned char *) ip;
594 cur->node.san.unstructured_name.len = sizeof(ip);
595 } else if (strcmp(q, "DN") == 0) {
596 cur->node.type = MBEDTLS_X509_SAN_DIRECTORY_NAME;
597 cur->node.type = MBEDTLS_X509_SAN_DIRECTORY_NAME;
598 /* Work around an API mismatch between string_to names() and
599 * mbedtls_x509_subject_alternative_name, which holds an
600 * actual mbedtls_x509_name while a pointer to one would be
601 * more convenient here. (Note mbedtls_x509_name and
602 * mbedtls_ans1_named_data are synonymous, again
603 * string_to_names () uses one while
604 * cur->node.san.directory_name is nominally the other.) */
605 mbedtls_asn1_named_data *tmp_san_dirname = NULL;
606 if ((ret = mbedtls_x509_string_to_names(&tmp_san_dirname,
607 subtype_value)) != 0) {
608 mbedtls_strerror(ret, buf, sizeof(buf));
609 mbedtls_printf(
610 " failed\n ! mbedtls_x509_string_to_names "
611 "returned -0x%04x - %s\n\n",
612 (unsigned int) -ret, buf);
613 goto exit;
614 }
615 cur->node.san.directory_name = *tmp_san_dirname;
616 mbedtls_free(tmp_san_dirname);
617 tmp_san_dirname = NULL;
618 } else {
619 mbedtls_free(cur);
620 goto usage;
621 }
622
623 if (cur->node.type == MBEDTLS_X509_SAN_RFC822_NAME ||
624 cur->node.type == MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER ||
625 cur->node.type == MBEDTLS_X509_SAN_DNS_NAME) {
626 q = subtype_value;
627 cur->node.san.unstructured_name.p = (unsigned char *) q;
628 cur->node.san.unstructured_name.len = strlen(q);
629 }
630
631 if (prev == NULL) {
632 opt.san_list = cur;
633 } else {
634 prev->next = cur;
635 }
636
637 prev = cur;
638 q = r;
639 }
640 } else if (strcmp(p, "ns_cert_type") == 0) {
641 while (q != NULL) {
642 if ((r = strchr(q, ',')) != NULL) {
643 *r++ = '\0';
644 }
645
646 if (strcmp(q, "ssl_client") == 0) {
647 opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT;
648 } else if (strcmp(q, "ssl_server") == 0) {
649 opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER;
650 } else if (strcmp(q, "email") == 0) {
651 opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_EMAIL;
652 } else if (strcmp(q, "object_signing") == 0) {
653 opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING;
654 } else if (strcmp(q, "ssl_ca") == 0) {
655 opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_CA;
656 } else if (strcmp(q, "email_ca") == 0) {
657 opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA;
658 } else if (strcmp(q, "object_signing_ca") == 0) {
659 opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA;
660 } else {
661 mbedtls_printf("Invalid argument for option %s\n", p);
662 goto usage;
663 }
664
665 q = r;
666 }
667 } else if (strcmp(p, "format") == 0) {
668 if (strcmp(q, "der") == 0) {
669 opt.format = FORMAT_DER;
670 } else if (strcmp(q, "pem") == 0) {
671 opt.format = FORMAT_PEM;
672 } else {
673 mbedtls_printf("Invalid argument for option %s\n", p);
674 goto usage;
675 }
676 } else {
677 goto usage;
678 }
679 }
680
681 mbedtls_printf("\n");
682
683 /*
684 * 0. Seed the PRNG
685 */
686 mbedtls_printf(" . Seeding the random number generator...");
687 fflush(stdout);
688
689 if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
690 (const unsigned char *) pers,
691 strlen(pers))) != 0) {
692 mbedtls_strerror(ret, buf, sizeof(buf));
693 mbedtls_printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d - %s\n",
694 ret, buf);
695 goto exit;
696 }
697
698 mbedtls_printf(" ok\n");
699
700 // Parse serial to MPI
701 //
702 mbedtls_printf(" . Reading serial number...");
703 fflush(stdout);
704
705 if (serial_frmt == SERIAL_FRMT_HEX) {
706 ret = mbedtls_test_unhexify(serial, sizeof(serial),
707 opt.serial_hex, &serial_len);
708 } else { // SERIAL_FRMT_DEC || SERIAL_FRMT_UNSPEC
709 ret = parse_serial_decimal_format(serial, sizeof(serial),
710 opt.serial, &serial_len);
711 }
712
713 if (ret != 0) {
714 mbedtls_printf(" failed\n ! Unable to parse serial\n");
715 goto exit;
716 }
717
718 mbedtls_printf(" ok\n");
719
720 // Parse issuer certificate if present
721 //
722 if (!opt.selfsign && strlen(opt.issuer_crt)) {
723 /*
724 * 1.0.a. Load the certificates
725 */
726 mbedtls_printf(" . Loading the issuer certificate ...");
727 fflush(stdout);
728
729 if ((ret = mbedtls_x509_crt_parse_file(&issuer_crt, opt.issuer_crt)) != 0) {
730 mbedtls_strerror(ret, buf, sizeof(buf));
731 mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse_file "
732 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
733 goto exit;
734 }
735
736 ret = mbedtls_x509_dn_gets(issuer_name, sizeof(issuer_name),
737 &issuer_crt.subject);
738 if (ret < 0) {
739 mbedtls_strerror(ret, buf, sizeof(buf));
740 mbedtls_printf(" failed\n ! mbedtls_x509_dn_gets "
741 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
742 goto exit;
743 }
744
745 opt.issuer_name = issuer_name;
746
747 mbedtls_printf(" ok\n");
748 }
749
750 #if defined(MBEDTLS_X509_CSR_PARSE_C)
751 // Parse certificate request if present
752 //
753 if (!opt.selfsign && strlen(opt.request_file)) {
754 /*
755 * 1.0.b. Load the CSR
756 */
757 mbedtls_printf(" . Loading the certificate request ...");
758 fflush(stdout);
759
760 if ((ret = mbedtls_x509_csr_parse_file(&csr, opt.request_file)) != 0) {
761 mbedtls_strerror(ret, buf, sizeof(buf));
762 mbedtls_printf(" failed\n ! mbedtls_x509_csr_parse_file "
763 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
764 goto exit;
765 }
766
767 ret = mbedtls_x509_dn_gets(subject_name, sizeof(subject_name),
768 &csr.subject);
769 if (ret < 0) {
770 mbedtls_strerror(ret, buf, sizeof(buf));
771 mbedtls_printf(" failed\n ! mbedtls_x509_dn_gets "
772 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
773 goto exit;
774 }
775
776 opt.subject_name = subject_name;
777 subject_key = &csr.pk;
778
779 mbedtls_printf(" ok\n");
780 }
781 #endif /* MBEDTLS_X509_CSR_PARSE_C */
782
783 /*
784 * 1.1. Load the keys
785 */
786 if (!opt.selfsign && !strlen(opt.request_file)) {
787 mbedtls_printf(" . Loading the subject key ...");
788 fflush(stdout);
789
790 ret = mbedtls_pk_parse_keyfile(&loaded_subject_key, opt.subject_key,
791 opt.subject_pwd, mbedtls_ctr_drbg_random, &ctr_drbg);
792 if (ret != 0) {
793 mbedtls_strerror(ret, buf, sizeof(buf));
794 mbedtls_printf(" failed\n ! mbedtls_pk_parse_keyfile "
795 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
796 goto exit;
797 }
798
799 mbedtls_printf(" ok\n");
800 }
801
802 mbedtls_printf(" . Loading the issuer key ...");
803 fflush(stdout);
804
805 ret = mbedtls_pk_parse_keyfile(&loaded_issuer_key, opt.issuer_key,
806 opt.issuer_pwd, mbedtls_ctr_drbg_random, &ctr_drbg);
807 if (ret != 0) {
808 mbedtls_strerror(ret, buf, sizeof(buf));
809 mbedtls_printf(" failed\n ! mbedtls_pk_parse_keyfile "
810 "returned -x%02x - %s\n\n", (unsigned int) -ret, buf);
811 goto exit;
812 }
813
814 // Check if key and issuer certificate match
815 //
816 if (strlen(opt.issuer_crt)) {
817 if (mbedtls_pk_check_pair(&issuer_crt.pk, issuer_key,
818 mbedtls_ctr_drbg_random, &ctr_drbg) != 0) {
819 mbedtls_printf(" failed\n ! issuer_key does not match "
820 "issuer certificate\n\n");
821 goto exit;
822 }
823 }
824
825 mbedtls_printf(" ok\n");
826
827 if (opt.selfsign) {
828 opt.subject_name = opt.issuer_name;
829 subject_key = issuer_key;
830 }
831
832 mbedtls_x509write_crt_set_subject_key(&crt, subject_key);
833 mbedtls_x509write_crt_set_issuer_key(&crt, issuer_key);
834
835 /*
836 * 1.0. Check the names for validity
837 */
838 if ((ret = mbedtls_x509write_crt_set_subject_name(&crt, opt.subject_name)) != 0) {
839 mbedtls_strerror(ret, buf, sizeof(buf));
840 mbedtls_printf(" failed\n ! mbedtls_x509write_crt_set_subject_name "
841 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
842 goto exit;
843 }
844
845 if ((ret = mbedtls_x509write_crt_set_issuer_name(&crt, opt.issuer_name)) != 0) {
846 mbedtls_strerror(ret, buf, sizeof(buf));
847 mbedtls_printf(" failed\n ! mbedtls_x509write_crt_set_issuer_name "
848 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
849 goto exit;
850 }
851
852 mbedtls_printf(" . Setting certificate values ...");
853 fflush(stdout);
854
855 mbedtls_x509write_crt_set_version(&crt, opt.version);
856 mbedtls_x509write_crt_set_md_alg(&crt, opt.md);
857
858 ret = mbedtls_x509write_crt_set_serial_raw(&crt, serial, serial_len);
859 if (ret != 0) {
860 mbedtls_strerror(ret, buf, sizeof(buf));
861 mbedtls_printf(" failed\n ! mbedtls_x509write_crt_set_serial_raw "
862 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
863 goto exit;
864 }
865
866 ret = mbedtls_x509write_crt_set_validity(&crt, opt.not_before, opt.not_after);
867 if (ret != 0) {
868 mbedtls_strerror(ret, buf, sizeof(buf));
869 mbedtls_printf(" failed\n ! mbedtls_x509write_crt_set_validity "
870 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
871 goto exit;
872 }
873
874 mbedtls_printf(" ok\n");
875
876 if (opt.version == MBEDTLS_X509_CRT_VERSION_3 &&
877 opt.basic_constraints != 0) {
878 mbedtls_printf(" . Adding the Basic Constraints extension ...");
879 fflush(stdout);
880
881 ret = mbedtls_x509write_crt_set_basic_constraints(&crt, opt.is_ca,
882 opt.max_pathlen);
883 if (ret != 0) {
884 mbedtls_strerror(ret, buf, sizeof(buf));
885 mbedtls_printf(" failed\n ! x509write_crt_set_basic_constraints "
886 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
887 goto exit;
888 }
889
890 mbedtls_printf(" ok\n");
891 }
892
893 #if defined(MBEDTLS_MD_CAN_SHA1)
894 if (opt.version == MBEDTLS_X509_CRT_VERSION_3 &&
895 opt.subject_identifier != 0) {
896 mbedtls_printf(" . Adding the Subject Key Identifier ...");
897 fflush(stdout);
898
899 ret = mbedtls_x509write_crt_set_subject_key_identifier(&crt);
900 if (ret != 0) {
901 mbedtls_strerror(ret, buf, sizeof(buf));
902 mbedtls_printf(" failed\n ! mbedtls_x509write_crt_set_subject"
903 "_key_identifier returned -0x%04x - %s\n\n",
904 (unsigned int) -ret, buf);
905 goto exit;
906 }
907
908 mbedtls_printf(" ok\n");
909 }
910
911 if (opt.version == MBEDTLS_X509_CRT_VERSION_3 &&
912 opt.authority_identifier != 0) {
913 mbedtls_printf(" . Adding the Authority Key Identifier ...");
914 fflush(stdout);
915
916 ret = mbedtls_x509write_crt_set_authority_key_identifier(&crt);
917 if (ret != 0) {
918 mbedtls_strerror(ret, buf, sizeof(buf));
919 mbedtls_printf(" failed\n ! mbedtls_x509write_crt_set_authority_"
920 "key_identifier returned -0x%04x - %s\n\n",
921 (unsigned int) -ret, buf);
922 goto exit;
923 }
924
925 mbedtls_printf(" ok\n");
926 }
927 #endif /* MBEDTLS_MD_CAN_SHA1 */
928
929 if (opt.version == MBEDTLS_X509_CRT_VERSION_3 &&
930 opt.key_usage != 0) {
931 mbedtls_printf(" . Adding the Key Usage extension ...");
932 fflush(stdout);
933
934 ret = mbedtls_x509write_crt_set_key_usage(&crt, opt.key_usage);
935 if (ret != 0) {
936 mbedtls_strerror(ret, buf, sizeof(buf));
937 mbedtls_printf(" failed\n ! mbedtls_x509write_crt_set_key_usage "
938 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
939 goto exit;
940 }
941
942 mbedtls_printf(" ok\n");
943 }
944
945 if (opt.san_list != NULL) {
946 ret = mbedtls_x509write_crt_set_subject_alternative_name(&crt, opt.san_list);
947
948 if (ret != 0) {
949 mbedtls_printf(
950 " failed\n ! mbedtls_x509write_crt_set_subject_alternative_name returned %d",
951 ret);
952 goto exit;
953 }
954 }
955
956 if (opt.ext_key_usage) {
957 mbedtls_printf(" . Adding the Extended Key Usage extension ...");
958 fflush(stdout);
959
960 ret = mbedtls_x509write_crt_set_ext_key_usage(&crt, opt.ext_key_usage);
961 if (ret != 0) {
962 mbedtls_strerror(ret, buf, sizeof(buf));
963 mbedtls_printf(
964 " failed\n ! mbedtls_x509write_crt_set_ext_key_usage returned -0x%02x - %s\n\n",
965 (unsigned int) -ret,
966 buf);
967 goto exit;
968 }
969
970 mbedtls_printf(" ok\n");
971 }
972
973 if (opt.version == MBEDTLS_X509_CRT_VERSION_3 &&
974 opt.ns_cert_type != 0) {
975 mbedtls_printf(" . Adding the NS Cert Type extension ...");
976 fflush(stdout);
977
978 ret = mbedtls_x509write_crt_set_ns_cert_type(&crt, opt.ns_cert_type);
979 if (ret != 0) {
980 mbedtls_strerror(ret, buf, sizeof(buf));
981 mbedtls_printf(" failed\n ! mbedtls_x509write_crt_set_ns_cert_type "
982 "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf);
983 goto exit;
984 }
985
986 mbedtls_printf(" ok\n");
987 }
988
989 /*
990 * 1.2. Writing the certificate
991 */
992 mbedtls_printf(" . Writing the certificate...");
993 fflush(stdout);
994
995 if ((ret = write_certificate(&crt, opt.output_file,
996 mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
997 mbedtls_strerror(ret, buf, sizeof(buf));
998 mbedtls_printf(" failed\n ! write_certificate -0x%04x - %s\n\n",
999 (unsigned int) -ret, buf);
1000 goto exit;
1001 }
1002
1003 mbedtls_printf(" ok\n");
1004
1005 exit_code = MBEDTLS_EXIT_SUCCESS;
1006
1007 exit:
1008 cur = opt.san_list;
1009 while (cur != NULL) {
1010 mbedtls_x509_san_list *next = cur->next;
1011 /* Note: mbedtls_x509_free_subject_alt_name() is not what we want here.
1012 * It's the right thing for entries that were parsed from a certificate,
1013 * where pointers are to the raw certificate, but here all the
1014 * pointers were allocated while parsing from a user-provided string. */
1015 if (cur->node.type == MBEDTLS_X509_SAN_DIRECTORY_NAME) {
1016 mbedtls_x509_name *dn = &cur->node.san.directory_name;
1017 mbedtls_free(dn->oid.p);
1018 mbedtls_free(dn->val.p);
1019 mbedtls_asn1_free_named_data_list(&dn->next);
1020 }
1021 mbedtls_free(cur);
1022 cur = next;
1023 }
1024 #if defined(MBEDTLS_X509_CSR_PARSE_C)
1025 mbedtls_x509_csr_free(&csr);
1026 #endif /* MBEDTLS_X509_CSR_PARSE_C */
1027 mbedtls_x509_crt_free(&issuer_crt);
1028 mbedtls_x509write_crt_free(&crt);
1029 mbedtls_pk_free(&loaded_subject_key);
1030 mbedtls_pk_free(&loaded_issuer_key);
1031 mbedtls_ctr_drbg_free(&ctr_drbg);
1032 mbedtls_entropy_free(&entropy);
1033 #if defined(MBEDTLS_USE_PSA_CRYPTO)
1034 mbedtls_psa_crypto_free();
1035 #endif /* MBEDTLS_USE_PSA_CRYPTO */
1036
1037 mbedtls_exit(exit_code);
1038 }
1039 #endif /* MBEDTLS_X509_CRT_WRITE_C && MBEDTLS_X509_CRT_PARSE_C &&
1040 MBEDTLS_FS_IO && MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C &&
1041 MBEDTLS_ERROR_C && MBEDTLS_PEM_WRITE_C */
1042