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