xref: /optee_os/lib/libmbedtls/mbedtls/library/x509write_csr.c (revision b0563631928755fe864b97785160fb3088e9efdc)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  X.509 Certificate Signing Request writing
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
5*b0563631STom 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 
17*b0563631STom 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"
26*b0563631STom 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 {
46817466cbSJens Wiklander     mbedtls_asn1_free_named_data_list(&ctx->subject);
47817466cbSJens Wiklander     mbedtls_asn1_free_named_data_list(&ctx->extensions);
48817466cbSJens Wiklander 
493d3b0591SJens Wiklander     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_x509write_csr));
50817466cbSJens Wiklander }
51817466cbSJens Wiklander 
52817466cbSJens Wiklander void mbedtls_x509write_csr_set_md_alg(mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg)
53817466cbSJens Wiklander {
54817466cbSJens Wiklander     ctx->md_alg = md_alg;
55817466cbSJens Wiklander }
56817466cbSJens Wiklander 
57817466cbSJens Wiklander void mbedtls_x509write_csr_set_key(mbedtls_x509write_csr *ctx, mbedtls_pk_context *key)
58817466cbSJens Wiklander {
59817466cbSJens Wiklander     ctx->key = key;
60817466cbSJens Wiklander }
61817466cbSJens Wiklander 
62817466cbSJens Wiklander int mbedtls_x509write_csr_set_subject_name(mbedtls_x509write_csr *ctx,
63817466cbSJens Wiklander                                            const char *subject_name)
64817466cbSJens Wiklander {
65817466cbSJens Wiklander     return mbedtls_x509_string_to_names(&ctx->subject, subject_name);
66817466cbSJens Wiklander }
67817466cbSJens Wiklander 
68817466cbSJens Wiklander int mbedtls_x509write_csr_set_extension(mbedtls_x509write_csr *ctx,
69817466cbSJens Wiklander                                         const char *oid, size_t oid_len,
7032b31808SJens Wiklander                                         int critical,
71817466cbSJens Wiklander                                         const unsigned char *val, size_t val_len)
72817466cbSJens Wiklander {
73817466cbSJens Wiklander     return mbedtls_x509_set_extension(&ctx->extensions, oid, oid_len,
7432b31808SJens Wiklander                                       critical, val, val_len);
7532b31808SJens Wiklander }
7632b31808SJens Wiklander 
7732b31808SJens Wiklander int mbedtls_x509write_csr_set_subject_alternative_name(mbedtls_x509write_csr *ctx,
7832b31808SJens Wiklander                                                        const mbedtls_x509_san_list *san_list)
7932b31808SJens Wiklander {
80*b0563631STom Van Eyck     return mbedtls_x509_write_set_san_common(&ctx->extensions, san_list);
81817466cbSJens Wiklander }
82817466cbSJens Wiklander 
83817466cbSJens Wiklander int mbedtls_x509write_csr_set_key_usage(mbedtls_x509write_csr *ctx, unsigned char key_usage)
84817466cbSJens Wiklander {
857901324dSJerome Forissier     unsigned char buf[4] = { 0 };
86817466cbSJens Wiklander     unsigned char *c;
8711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
88817466cbSJens Wiklander 
89817466cbSJens Wiklander     c = buf + 4;
90817466cbSJens Wiklander 
9111fa71b9SJerome Forissier     ret = mbedtls_asn1_write_named_bitstring(&c, buf, &key_usage, 8);
9232b31808SJens Wiklander     if (ret < 3 || ret > 4) {
9332b31808SJens Wiklander         return ret;
9432b31808SJens Wiklander     }
95817466cbSJens Wiklander 
96817466cbSJens Wiklander     ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_KEY_USAGE,
97817466cbSJens Wiklander                                               MBEDTLS_OID_SIZE(MBEDTLS_OID_KEY_USAGE),
9832b31808SJens Wiklander                                               0, c, (size_t) ret);
9932b31808SJens Wiklander     if (ret != 0) {
10032b31808SJens Wiklander         return ret;
10132b31808SJens Wiklander     }
102817466cbSJens Wiklander 
10332b31808SJens Wiklander     return 0;
104817466cbSJens Wiklander }
105817466cbSJens Wiklander 
106817466cbSJens Wiklander int mbedtls_x509write_csr_set_ns_cert_type(mbedtls_x509write_csr *ctx,
107817466cbSJens Wiklander                                            unsigned char ns_cert_type)
108817466cbSJens Wiklander {
1097901324dSJerome Forissier     unsigned char buf[4] = { 0 };
110817466cbSJens Wiklander     unsigned char *c;
11111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
112817466cbSJens Wiklander 
113817466cbSJens Wiklander     c = buf + 4;
114817466cbSJens Wiklander 
11511fa71b9SJerome Forissier     ret = mbedtls_asn1_write_named_bitstring(&c, buf, &ns_cert_type, 8);
11632b31808SJens Wiklander     if (ret < 3 || ret > 4) {
11732b31808SJens Wiklander         return ret;
11832b31808SJens Wiklander     }
119817466cbSJens Wiklander 
120817466cbSJens Wiklander     ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_NS_CERT_TYPE,
121817466cbSJens Wiklander                                               MBEDTLS_OID_SIZE(MBEDTLS_OID_NS_CERT_TYPE),
12232b31808SJens Wiklander                                               0, c, (size_t) ret);
12332b31808SJens Wiklander     if (ret != 0) {
12432b31808SJens Wiklander         return ret;
12532b31808SJens Wiklander     }
126817466cbSJens Wiklander 
12732b31808SJens Wiklander     return 0;
128817466cbSJens Wiklander }
129817466cbSJens Wiklander 
1307901324dSJerome Forissier static int x509write_csr_der_internal(mbedtls_x509write_csr *ctx,
1317901324dSJerome Forissier                                       unsigned char *buf,
1327901324dSJerome Forissier                                       size_t size,
13332b31808SJens Wiklander                                       unsigned char *sig, size_t sig_size,
134817466cbSJens Wiklander                                       int (*f_rng)(void *, unsigned char *, size_t),
135817466cbSJens Wiklander                                       void *p_rng)
136817466cbSJens Wiklander {
13711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
138817466cbSJens Wiklander     const char *sig_oid;
139817466cbSJens Wiklander     size_t sig_oid_len = 0;
140817466cbSJens Wiklander     unsigned char *c, *c2;
141*b0563631STom Van Eyck     unsigned char hash[MBEDTLS_MD_MAX_SIZE];
142817466cbSJens Wiklander     size_t pub_len = 0, sig_and_oid_len = 0, sig_len;
143817466cbSJens Wiklander     size_t len = 0;
144817466cbSJens Wiklander     mbedtls_pk_type_t pk_alg;
14511fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO)
14611fa71b9SJerome Forissier     size_t hash_len;
147*b0563631STom Van Eyck     psa_algorithm_t hash_alg = mbedtls_md_psa_alg_from_type(ctx->md_alg);
14811fa71b9SJerome Forissier #endif /* MBEDTLS_USE_PSA_CRYPTO */
149817466cbSJens Wiklander 
1507901324dSJerome Forissier     /* Write the CSR backwards starting from the end of buf */
1517901324dSJerome Forissier     c = buf + size;
1527901324dSJerome Forissier 
1537901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_extensions(&c, buf,
1547901324dSJerome Forissier                                                             ctx->extensions));
155817466cbSJens Wiklander 
15632b31808SJens Wiklander     if (len) {
1577901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
1587901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len,
1597901324dSJerome Forissier                              mbedtls_asn1_write_tag(
1607901324dSJerome Forissier                                  &c, buf,
1617901324dSJerome Forissier                                  MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
162817466cbSJens Wiklander 
1637901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
1647901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len,
1657901324dSJerome Forissier                              mbedtls_asn1_write_tag(
1667901324dSJerome Forissier                                  &c, buf,
1677901324dSJerome Forissier                                  MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET));
168817466cbSJens Wiklander 
1697901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len,
1707901324dSJerome Forissier                              mbedtls_asn1_write_oid(
1717901324dSJerome Forissier                                  &c, buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ,
172817466cbSJens Wiklander                                  MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS9_CSR_EXT_REQ)));
173817466cbSJens Wiklander 
1747901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
1757901324dSJerome Forissier         MBEDTLS_ASN1_CHK_ADD(len,
1767901324dSJerome Forissier                              mbedtls_asn1_write_tag(
1777901324dSJerome Forissier                                  &c, buf,
1787901324dSJerome Forissier                                  MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
179817466cbSJens Wiklander     }
180817466cbSJens Wiklander 
1817901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
1827901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len,
1837901324dSJerome Forissier                          mbedtls_asn1_write_tag(
1847901324dSJerome Forissier                              &c, buf,
1857901324dSJerome Forissier                              MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC));
186817466cbSJens Wiklander 
187817466cbSJens Wiklander     MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_pk_write_pubkey_der(ctx->key,
188*b0563631STom Van Eyck                                                               buf, (size_t) (c - buf)));
189817466cbSJens Wiklander     c -= pub_len;
190817466cbSJens Wiklander     len += pub_len;
191817466cbSJens Wiklander 
192817466cbSJens Wiklander     /*
193817466cbSJens Wiklander      *  Subject  ::=  Name
194817466cbSJens Wiklander      */
1957901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf,
1967901324dSJerome Forissier                                                        ctx->subject));
197817466cbSJens Wiklander 
198817466cbSJens Wiklander     /*
199817466cbSJens Wiklander      *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
200817466cbSJens Wiklander      */
2017901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(&c, buf, 0));
202817466cbSJens Wiklander 
2037901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
2047901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len,
2057901324dSJerome Forissier                          mbedtls_asn1_write_tag(
2067901324dSJerome Forissier                              &c, buf,
2077901324dSJerome Forissier                              MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
208817466cbSJens Wiklander 
209817466cbSJens Wiklander     /*
2107901324dSJerome Forissier      * Sign the written CSR data into the sig buffer
21111fa71b9SJerome Forissier      * Note: hash errors can happen only after an internal error
212817466cbSJens Wiklander      */
21311fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO)
21432b31808SJens Wiklander     if (psa_hash_compute(hash_alg,
21532b31808SJens Wiklander                          c,
21632b31808SJens Wiklander                          len,
21732b31808SJens Wiklander                          hash,
21832b31808SJens Wiklander                          sizeof(hash),
21932b31808SJens Wiklander                          &hash_len) != PSA_SUCCESS) {
22032b31808SJens Wiklander         return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED;
22111fa71b9SJerome Forissier     }
22211fa71b9SJerome Forissier #else /* MBEDTLS_USE_PSA_CRYPTO */
2235b25c76aSJerome Forissier     ret = mbedtls_md(mbedtls_md_info_from_type(ctx->md_alg), c, len, hash);
22432b31808SJens Wiklander     if (ret != 0) {
22532b31808SJens Wiklander         return ret;
22632b31808SJens Wiklander     }
22711fa71b9SJerome Forissier #endif
22832b31808SJens Wiklander     if ((ret = mbedtls_pk_sign(ctx->key, ctx->md_alg, hash, 0,
22932b31808SJens Wiklander                                sig, sig_size, &sig_len,
23032b31808SJens Wiklander                                f_rng, p_rng)) != 0) {
23132b31808SJens Wiklander         return ret;
2323d3b0591SJens Wiklander     }
2333d3b0591SJens Wiklander 
23432b31808SJens Wiklander     if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_RSA)) {
2353d3b0591SJens Wiklander         pk_alg = MBEDTLS_PK_RSA;
23632b31808SJens Wiklander     } else if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_ECDSA)) {
2373d3b0591SJens Wiklander         pk_alg = MBEDTLS_PK_ECDSA;
23832b31808SJens Wiklander     } else {
23932b31808SJens Wiklander         return MBEDTLS_ERR_X509_INVALID_ALG;
24032b31808SJens Wiklander     }
2413d3b0591SJens Wiklander 
2423d3b0591SJens Wiklander     if ((ret = mbedtls_oid_get_oid_by_sig_alg(pk_alg, ctx->md_alg,
24332b31808SJens Wiklander                                               &sig_oid, &sig_oid_len)) != 0) {
24432b31808SJens Wiklander         return ret;
245817466cbSJens Wiklander     }
246817466cbSJens Wiklander 
247817466cbSJens Wiklander     /*
2487901324dSJerome Forissier      * Move the written CSR data to the start of buf to create space for
2497901324dSJerome Forissier      * writing the signature into buf.
2507901324dSJerome Forissier      */
2517901324dSJerome Forissier     memmove(buf, c, len);
2527901324dSJerome Forissier 
2537901324dSJerome Forissier     /*
2547901324dSJerome Forissier      * Write sig and its OID into buf backwards from the end of buf.
2557901324dSJerome Forissier      * Note: mbedtls_x509_write_sig will check for c2 - ( buf + len ) < sig_len
2567901324dSJerome Forissier      * and return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL if needed.
257817466cbSJens Wiklander      */
258817466cbSJens Wiklander     c2 = buf + size;
2597901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(sig_and_oid_len,
2607901324dSJerome Forissier                          mbedtls_x509_write_sig(&c2, buf + len, sig_oid, sig_oid_len,
261*b0563631STom Van Eyck                                                 sig, sig_len, pk_alg));
262817466cbSJens Wiklander 
2637901324dSJerome Forissier     /*
2647901324dSJerome Forissier      * Compact the space between the CSR data and signature by moving the
2657901324dSJerome Forissier      * CSR data to the start of the signature.
2667901324dSJerome Forissier      */
267817466cbSJens Wiklander     c2 -= len;
2687901324dSJerome Forissier     memmove(c2, buf, len);
269817466cbSJens Wiklander 
2707901324dSJerome Forissier     /* ASN encode the total size and tag the CSR data with it. */
271817466cbSJens Wiklander     len += sig_and_oid_len;
272817466cbSJens Wiklander     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c2, buf, len));
2737901324dSJerome Forissier     MBEDTLS_ASN1_CHK_ADD(len,
2747901324dSJerome Forissier                          mbedtls_asn1_write_tag(
2757901324dSJerome Forissier                              &c2, buf,
2767901324dSJerome Forissier                              MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
2777901324dSJerome Forissier 
2787901324dSJerome Forissier     /* Zero the unused bytes at the start of buf */
279*b0563631STom Van Eyck     memset(buf, 0, (size_t) (c2 - buf));
280817466cbSJens Wiklander 
28132b31808SJens Wiklander     return (int) len;
282817466cbSJens Wiklander }
283817466cbSJens Wiklander 
2847901324dSJerome Forissier int mbedtls_x509write_csr_der(mbedtls_x509write_csr *ctx, unsigned char *buf,
2857901324dSJerome Forissier                               size_t size,
2867901324dSJerome Forissier                               int (*f_rng)(void *, unsigned char *, size_t),
2877901324dSJerome Forissier                               void *p_rng)
2887901324dSJerome Forissier {
2897901324dSJerome Forissier     int ret;
2907901324dSJerome Forissier     unsigned char *sig;
2917901324dSJerome Forissier 
29232b31808SJens Wiklander     if ((sig = mbedtls_calloc(1, MBEDTLS_PK_SIGNATURE_MAX_SIZE)) == NULL) {
29332b31808SJens Wiklander         return MBEDTLS_ERR_X509_ALLOC_FAILED;
2947901324dSJerome Forissier     }
2957901324dSJerome Forissier 
29632b31808SJens Wiklander     ret = x509write_csr_der_internal(ctx, buf, size,
29732b31808SJens Wiklander                                      sig, MBEDTLS_PK_SIGNATURE_MAX_SIZE,
29832b31808SJens Wiklander                                      f_rng, p_rng);
2997901324dSJerome Forissier 
3007901324dSJerome Forissier     mbedtls_free(sig);
3017901324dSJerome Forissier 
30232b31808SJens Wiklander     return ret;
3037901324dSJerome Forissier }
3047901324dSJerome Forissier 
305817466cbSJens Wiklander #define PEM_BEGIN_CSR           "-----BEGIN CERTIFICATE REQUEST-----\n"
306817466cbSJens Wiklander #define PEM_END_CSR             "-----END CERTIFICATE REQUEST-----\n"
307817466cbSJens Wiklander 
308817466cbSJens Wiklander #if defined(MBEDTLS_PEM_WRITE_C)
309817466cbSJens Wiklander int mbedtls_x509write_csr_pem(mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size,
310817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
311817466cbSJens Wiklander                               void *p_rng)
312817466cbSJens Wiklander {
31311fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
314817466cbSJens Wiklander     size_t olen = 0;
315817466cbSJens Wiklander 
31611fa71b9SJerome Forissier     if ((ret = mbedtls_x509write_csr_der(ctx, buf, size,
31732b31808SJens Wiklander                                          f_rng, p_rng)) < 0) {
31832b31808SJens Wiklander         return ret;
319817466cbSJens Wiklander     }
320817466cbSJens Wiklander 
321817466cbSJens Wiklander     if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_CSR, PEM_END_CSR,
32211fa71b9SJerome Forissier                                         buf + size - ret,
32332b31808SJens Wiklander                                         ret, buf, size, &olen)) != 0) {
32432b31808SJens Wiklander         return ret;
325817466cbSJens Wiklander     }
326817466cbSJens Wiklander 
32732b31808SJens Wiklander     return 0;
328817466cbSJens Wiklander }
329817466cbSJens Wiklander #endif /* MBEDTLS_PEM_WRITE_C */
330817466cbSJens Wiklander 
331817466cbSJens Wiklander #endif /* MBEDTLS_X509_CSR_WRITE_C */
332