xref: /optee_os/lib/libmbedtls/mbedtls/library/x509write_csr.c (revision cb03400251f98aed22a2664509e3ed9e183800b0)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  X.509 Certificate Signing Request writing
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
5b0563631STom Van Eyck  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6817466cbSJens Wiklander  */
7817466cbSJens Wiklander /*
8817466cbSJens Wiklander  * References:
9817466cbSJens Wiklander  * - CSRs: PKCS#10 v1.7 aka RFC 2986
10817466cbSJens Wiklander  * - attributes: PKCS#9 v2.0 aka RFC 2985
11817466cbSJens Wiklander  */
12817466cbSJens Wiklander 
137901324dSJerome Forissier #include "common.h"
14817466cbSJens Wiklander 
15817466cbSJens Wiklander #if defined(MBEDTLS_X509_CSR_WRITE_C)
16817466cbSJens Wiklander 
17b0563631STom Van Eyck #include "x509_internal.h"
18817466cbSJens Wiklander #include "mbedtls/x509_csr.h"
19817466cbSJens Wiklander #include "mbedtls/asn1write.h"
2011fa71b9SJerome Forissier #include "mbedtls/error.h"
2111fa71b9SJerome Forissier #include "mbedtls/oid.h"
223d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
23817466cbSJens Wiklander 
2411fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO)
2511fa71b9SJerome Forissier #include "psa/crypto.h"
26b0563631STom Van Eyck #include "psa_util_internal.h"
2711fa71b9SJerome Forissier #include "mbedtls/psa_util.h"
2832b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */
2911fa71b9SJerome Forissier 
30817466cbSJens Wiklander #include <string.h>
31817466cbSJens Wiklander #include <stdlib.h>
32817466cbSJens Wiklander 
33817466cbSJens Wiklander #if defined(MBEDTLS_PEM_WRITE_C)
34817466cbSJens Wiklander #include "mbedtls/pem.h"
35817466cbSJens Wiklander #endif
36817466cbSJens Wiklander 
377901324dSJerome Forissier #include "mbedtls/platform.h"
387901324dSJerome Forissier 
39817466cbSJens Wiklander void mbedtls_x509write_csr_init(mbedtls_x509write_csr *ctx)
40817466cbSJens Wiklander {
41817466cbSJens Wiklander     memset(ctx, 0, sizeof(mbedtls_x509write_csr));
42817466cbSJens Wiklander }
43817466cbSJens Wiklander 
44817466cbSJens Wiklander void mbedtls_x509write_csr_free(mbedtls_x509write_csr *ctx)
45817466cbSJens Wiklander {
46*cb034002SJerome Forissier     if (ctx == NULL) {
47*cb034002SJerome Forissier         return;
48*cb034002SJerome Forissier     }
49*cb034002SJerome Forissier 
50817466cbSJens Wiklander     mbedtls_asn1_free_named_data_list(&ctx->subject);
51817466cbSJens Wiklander     mbedtls_asn1_free_named_data_list(&ctx->extensions);
52817466cbSJens Wiklander 
533d3b0591SJens Wiklander     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_x509write_csr));
54817466cbSJens Wiklander }
55817466cbSJens Wiklander 
56817466cbSJens Wiklander void mbedtls_x509write_csr_set_md_alg(mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg)
57817466cbSJens Wiklander {
58817466cbSJens Wiklander     ctx->md_alg = md_alg;
59817466cbSJens Wiklander }
60817466cbSJens Wiklander 
61817466cbSJens Wiklander void mbedtls_x509write_csr_set_key(mbedtls_x509write_csr *ctx, mbedtls_pk_context *key)
62817466cbSJens Wiklander {
63817466cbSJens Wiklander     ctx->key = key;
64817466cbSJens Wiklander }
65817466cbSJens Wiklander 
66817466cbSJens Wiklander int mbedtls_x509write_csr_set_subject_name(mbedtls_x509write_csr *ctx,
67817466cbSJens Wiklander                                            const char *subject_name)
68817466cbSJens Wiklander {
69817466cbSJens Wiklander     return mbedtls_x509_string_to_names(&ctx->subject, subject_name);
70817466cbSJens Wiklander }
71817466cbSJens Wiklander 
72817466cbSJens Wiklander int mbedtls_x509write_csr_set_extension(mbedtls_x509write_csr *ctx,
73817466cbSJens Wiklander                                         const char *oid, size_t oid_len,
7432b31808SJens Wiklander                                         int critical,
75817466cbSJens Wiklander                                         const unsigned char *val, size_t val_len)
76817466cbSJens Wiklander {
77817466cbSJens Wiklander     return mbedtls_x509_set_extension(&ctx->extensions, oid, oid_len,
7832b31808SJens Wiklander                                       critical, val, val_len);
7932b31808SJens Wiklander }
8032b31808SJens Wiklander 
8132b31808SJens Wiklander int mbedtls_x509write_csr_set_subject_alternative_name(mbedtls_x509write_csr *ctx,
8232b31808SJens Wiklander                                                        const mbedtls_x509_san_list *san_list)
8332b31808SJens Wiklander {
84b0563631STom Van Eyck     return mbedtls_x509_write_set_san_common(&ctx->extensions, san_list);
85817466cbSJens Wiklander }
86817466cbSJens Wiklander 
87817466cbSJens Wiklander int mbedtls_x509write_csr_set_key_usage(mbedtls_x509write_csr *ctx, unsigned char key_usage)
88817466cbSJens Wiklander {
897901324dSJerome Forissier     unsigned char buf[4] = { 0 };
90817466cbSJens Wiklander     unsigned char *c;
9111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
92817466cbSJens Wiklander 
93817466cbSJens Wiklander     c = buf + 4;
94817466cbSJens Wiklander 
9511fa71b9SJerome Forissier     ret = mbedtls_asn1_write_named_bitstring(&c, buf, &key_usage, 8);
9632b31808SJens Wiklander     if (ret < 3 || ret > 4) {
9732b31808SJens Wiklander         return ret;
9832b31808SJens Wiklander     }
99817466cbSJens Wiklander 
100817466cbSJens Wiklander     ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_KEY_USAGE,
101817466cbSJens Wiklander                                               MBEDTLS_OID_SIZE(MBEDTLS_OID_KEY_USAGE),
10232b31808SJens Wiklander                                               0, c, (size_t) ret);
10332b31808SJens Wiklander     if (ret != 0) {
10432b31808SJens Wiklander         return ret;
10532b31808SJens Wiklander     }
106817466cbSJens Wiklander 
10732b31808SJens Wiklander     return 0;
108817466cbSJens Wiklander }
109817466cbSJens Wiklander 
110817466cbSJens Wiklander int mbedtls_x509write_csr_set_ns_cert_type(mbedtls_x509write_csr *ctx,
111817466cbSJens Wiklander                                            unsigned char ns_cert_type)
112817466cbSJens Wiklander {
1137901324dSJerome Forissier     unsigned char buf[4] = { 0 };
114817466cbSJens Wiklander     unsigned char *c;
11511fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
116817466cbSJens Wiklander 
117817466cbSJens Wiklander     c = buf + 4;
118817466cbSJens Wiklander 
11911fa71b9SJerome Forissier     ret = mbedtls_asn1_write_named_bitstring(&c, buf, &ns_cert_type, 8);
12032b31808SJens Wiklander     if (ret < 3 || ret > 4) {
12132b31808SJens Wiklander         return ret;
12232b31808SJens Wiklander     }
123817466cbSJens Wiklander 
124817466cbSJens Wiklander     ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_NS_CERT_TYPE,
125817466cbSJens Wiklander                                               MBEDTLS_OID_SIZE(MBEDTLS_OID_NS_CERT_TYPE),
12632b31808SJens Wiklander                                               0, c, (size_t) ret);
12732b31808SJens Wiklander     if (ret != 0) {
12832b31808SJens Wiklander         return ret;
12932b31808SJens Wiklander     }
130817466cbSJens Wiklander 
13132b31808SJens Wiklander     return 0;
132817466cbSJens Wiklander }
133817466cbSJens Wiklander 
1347901324dSJerome Forissier static int x509write_csr_der_internal(mbedtls_x509write_csr *ctx,
1357901324dSJerome Forissier                                       unsigned char *buf,
1367901324dSJerome Forissier                                       size_t size,
13732b31808SJens Wiklander                                       unsigned char *sig, size_t sig_size,
138817466cbSJens Wiklander                                       int (*f_rng)(void *, unsigned char *, size_t),
139817466cbSJens Wiklander                                       void *p_rng)
140817466cbSJens Wiklander {
14111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
142817466cbSJens Wiklander     const char *sig_oid;
143817466cbSJens Wiklander     size_t sig_oid_len = 0;
144817466cbSJens Wiklander     unsigned char *c, *c2;
145b0563631STom Van Eyck     unsigned char hash[MBEDTLS_MD_MAX_SIZE];
146817466cbSJens Wiklander     size_t pub_len = 0, sig_and_oid_len = 0, sig_len;
147817466cbSJens Wiklander     size_t len = 0;
148817466cbSJens Wiklander     mbedtls_pk_type_t pk_alg;
14911fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO)
15011fa71b9SJerome Forissier     size_t hash_len;
151b0563631STom Van Eyck     psa_algorithm_t hash_alg = mbedtls_md_psa_alg_from_type(ctx->md_alg);
15211fa71b9SJerome Forissier #endif /* MBEDTLS_USE_PSA_CRYPTO */
153817466cbSJens Wiklander 
1547901324dSJerome Forissier     /* Write the CSR backwards starting from the end of buf */
1557901324dSJerome Forissier     c = buf + size;
1567901324dSJerome Forissier 
1577901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_extensions(&c, buf,
1587901324dSJerome Forissier                                                             ctx->extensions));
159817466cbSJens Wiklander 
16032b31808SJens Wiklander     if (len) {
1617901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
1627901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len,
1637901324dSJerome Forissier                              mbedtls_asn1_write_tag(
1647901324dSJerome Forissier                                  &c, buf,
1657901324dSJerome Forissier                                  MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
166817466cbSJens Wiklander 
1677901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
1687901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len,
1697901324dSJerome Forissier                              mbedtls_asn1_write_tag(
1707901324dSJerome Forissier                                  &c, buf,
1717901324dSJerome Forissier                                  MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET));
172817466cbSJens Wiklander 
1737901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len,
1747901324dSJerome Forissier                              mbedtls_asn1_write_oid(
1757901324dSJerome Forissier                                  &c, buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ,
176817466cbSJens Wiklander                                  MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS9_CSR_EXT_REQ)));
177817466cbSJens Wiklander 
1787901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
1797901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len,
1807901324dSJerome Forissier                              mbedtls_asn1_write_tag(
1817901324dSJerome Forissier                                  &c, buf,
1827901324dSJerome Forissier                                  MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
183817466cbSJens Wiklander     }
184817466cbSJens Wiklander 
1857901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
1867901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len,
1877901324dSJerome Forissier                          mbedtls_asn1_write_tag(
1887901324dSJerome Forissier                              &c, buf,
1897901324dSJerome Forissier                              MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC));
190817466cbSJens Wiklander 
191817466cbSJens Wiklander     MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_pk_write_pubkey_der(ctx->key,
192b0563631STom Van Eyck                                                               buf, (size_t) (c - buf)));
193817466cbSJens Wiklander     c -= pub_len;
194817466cbSJens Wiklander     len += pub_len;
195817466cbSJens Wiklander 
196817466cbSJens Wiklander     /*
197817466cbSJens Wiklander      *  Subject  ::=  Name
198817466cbSJens Wiklander      */
1997901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf,
2007901324dSJerome Forissier                                                        ctx->subject));
201817466cbSJens Wiklander 
202817466cbSJens Wiklander     /*
203817466cbSJens Wiklander      *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
204817466cbSJens Wiklander      */
2057901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(&c, buf, 0));
206817466cbSJens Wiklander 
2077901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
2087901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len,
2097901324dSJerome Forissier                          mbedtls_asn1_write_tag(
2107901324dSJerome Forissier                              &c, buf,
2117901324dSJerome Forissier                              MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
212817466cbSJens Wiklander 
213817466cbSJens Wiklander     /*
2147901324dSJerome Forissier      * Sign the written CSR data into the sig buffer
21511fa71b9SJerome Forissier      * Note: hash errors can happen only after an internal error
216817466cbSJens Wiklander      */
21711fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO)
21832b31808SJens Wiklander     if (psa_hash_compute(hash_alg,
21932b31808SJens Wiklander                          c,
22032b31808SJens Wiklander                          len,
22132b31808SJens Wiklander                          hash,
22232b31808SJens Wiklander                          sizeof(hash),
22332b31808SJens Wiklander                          &hash_len) != PSA_SUCCESS) {
22432b31808SJens Wiklander         return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED;
22511fa71b9SJerome Forissier     }
22611fa71b9SJerome Forissier #else /* MBEDTLS_USE_PSA_CRYPTO */
2275b25c76aSJerome Forissier     ret = mbedtls_md(mbedtls_md_info_from_type(ctx->md_alg), c, len, hash);
22832b31808SJens Wiklander     if (ret != 0) {
22932b31808SJens Wiklander         return ret;
23032b31808SJens Wiklander     }
23111fa71b9SJerome Forissier #endif
23232b31808SJens Wiklander     if ((ret = mbedtls_pk_sign(ctx->key, ctx->md_alg, hash, 0,
23332b31808SJens Wiklander                                sig, sig_size, &sig_len,
23432b31808SJens Wiklander                                f_rng, p_rng)) != 0) {
23532b31808SJens Wiklander         return ret;
2363d3b0591SJens Wiklander     }
2373d3b0591SJens Wiklander 
23832b31808SJens Wiklander     if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_RSA)) {
2393d3b0591SJens Wiklander         pk_alg = MBEDTLS_PK_RSA;
24032b31808SJens Wiklander     } else if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_ECDSA)) {
2413d3b0591SJens Wiklander         pk_alg = MBEDTLS_PK_ECDSA;
24232b31808SJens Wiklander     } else {
24332b31808SJens Wiklander         return MBEDTLS_ERR_X509_INVALID_ALG;
24432b31808SJens Wiklander     }
2453d3b0591SJens Wiklander 
2463d3b0591SJens Wiklander     if ((ret = mbedtls_oid_get_oid_by_sig_alg(pk_alg, ctx->md_alg,
24732b31808SJens Wiklander                                               &sig_oid, &sig_oid_len)) != 0) {
24832b31808SJens Wiklander         return ret;
249817466cbSJens Wiklander     }
250817466cbSJens Wiklander 
251817466cbSJens Wiklander     /*
2527901324dSJerome Forissier      * Move the written CSR data to the start of buf to create space for
2537901324dSJerome Forissier      * writing the signature into buf.
2547901324dSJerome Forissier      */
2557901324dSJerome Forissier     memmove(buf, c, len);
2567901324dSJerome Forissier 
2577901324dSJerome Forissier     /*
2587901324dSJerome Forissier      * Write sig and its OID into buf backwards from the end of buf.
2597901324dSJerome Forissier      * Note: mbedtls_x509_write_sig will check for c2 - ( buf + len ) < sig_len
2607901324dSJerome Forissier      * and return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL if needed.
261817466cbSJens Wiklander      */
262817466cbSJens Wiklander     c2 = buf + size;
2637901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(sig_and_oid_len,
2647901324dSJerome Forissier                          mbedtls_x509_write_sig(&c2, buf + len, sig_oid, sig_oid_len,
265b0563631STom Van Eyck                                                 sig, sig_len, pk_alg));
266817466cbSJens Wiklander 
2677901324dSJerome Forissier     /*
2687901324dSJerome Forissier      * Compact the space between the CSR data and signature by moving the
2697901324dSJerome Forissier      * CSR data to the start of the signature.
2707901324dSJerome Forissier      */
271817466cbSJens Wiklander     c2 -= len;
2727901324dSJerome Forissier     memmove(c2, buf, len);
273817466cbSJens Wiklander 
2747901324dSJerome Forissier     /* ASN encode the total size and tag the CSR data with it. */
275817466cbSJens Wiklander     len += sig_and_oid_len;
276817466cbSJens Wiklander     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c2, buf, len));
2777901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len,
2787901324dSJerome Forissier                          mbedtls_asn1_write_tag(
2797901324dSJerome Forissier                              &c2, buf,
2807901324dSJerome Forissier                              MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
2817901324dSJerome Forissier 
2827901324dSJerome Forissier     /* Zero the unused bytes at the start of buf */
283b0563631STom Van Eyck     memset(buf, 0, (size_t) (c2 - buf));
284817466cbSJens Wiklander 
28532b31808SJens Wiklander     return (int) len;
286817466cbSJens Wiklander }
287817466cbSJens Wiklander 
2887901324dSJerome Forissier int mbedtls_x509write_csr_der(mbedtls_x509write_csr *ctx, unsigned char *buf,
2897901324dSJerome Forissier                               size_t size,
2907901324dSJerome Forissier                               int (*f_rng)(void *, unsigned char *, size_t),
2917901324dSJerome Forissier                               void *p_rng)
2927901324dSJerome Forissier {
2937901324dSJerome Forissier     int ret;
2947901324dSJerome Forissier     unsigned char *sig;
2957901324dSJerome Forissier 
29632b31808SJens Wiklander     if ((sig = mbedtls_calloc(1, MBEDTLS_PK_SIGNATURE_MAX_SIZE)) == NULL) {
29732b31808SJens Wiklander         return MBEDTLS_ERR_X509_ALLOC_FAILED;
2987901324dSJerome Forissier     }
2997901324dSJerome Forissier 
30032b31808SJens Wiklander     ret = x509write_csr_der_internal(ctx, buf, size,
30132b31808SJens Wiklander                                      sig, MBEDTLS_PK_SIGNATURE_MAX_SIZE,
30232b31808SJens Wiklander                                      f_rng, p_rng);
3037901324dSJerome Forissier 
3047901324dSJerome Forissier     mbedtls_free(sig);
3057901324dSJerome Forissier 
30632b31808SJens Wiklander     return ret;
3077901324dSJerome Forissier }
3087901324dSJerome Forissier 
309817466cbSJens Wiklander #define PEM_BEGIN_CSR           "-----BEGIN CERTIFICATE REQUEST-----\n"
310817466cbSJens Wiklander #define PEM_END_CSR             "-----END CERTIFICATE REQUEST-----\n"
311817466cbSJens Wiklander 
312817466cbSJens Wiklander #if defined(MBEDTLS_PEM_WRITE_C)
313817466cbSJens Wiklander int mbedtls_x509write_csr_pem(mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size,
314817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
315817466cbSJens Wiklander                               void *p_rng)
316817466cbSJens Wiklander {
31711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
318817466cbSJens Wiklander     size_t olen = 0;
319817466cbSJens Wiklander 
32011fa71b9SJerome Forissier     if ((ret = mbedtls_x509write_csr_der(ctx, buf, size,
32132b31808SJens Wiklander                                          f_rng, p_rng)) < 0) {
32232b31808SJens Wiklander         return ret;
323817466cbSJens Wiklander     }
324817466cbSJens Wiklander 
325817466cbSJens Wiklander     if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_CSR, PEM_END_CSR,
32611fa71b9SJerome Forissier                                         buf + size - ret,
32732b31808SJens Wiklander                                         ret, buf, size, &olen)) != 0) {
32832b31808SJens Wiklander         return ret;
329817466cbSJens Wiklander     }
330817466cbSJens Wiklander 
33132b31808SJens Wiklander     return 0;
332817466cbSJens Wiklander }
333817466cbSJens Wiklander #endif /* MBEDTLS_PEM_WRITE_C */
334817466cbSJens Wiklander 
335817466cbSJens Wiklander #endif /* MBEDTLS_X509_CSR_WRITE_C */
336