1/*
2 *  X.509 Certificate Signing Request writing
3 *
4 *  Copyright The Mbed TLS Contributors
5 *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 */
7/*
8 * References:
9 * - CSRs: PKCS#10 v1.7 aka RFC 2986
10 * - attributes: PKCS#9 v2.0 aka RFC 2985
11 */
12
13#include "common.h"
14
15#if defined(MBEDTLS_X509_CSR_WRITE_C)
16
17#include "x509_internal.h"
18#include "mbedtls/x509_csr.h"
19#include "mbedtls/asn1write.h"
20#include "mbedtls/error.h"
21#include "mbedtls/oid.h"
22#include "mbedtls/platform_util.h"
23
24#if defined(MBEDTLS_USE_PSA_CRYPTO)
25#include "psa/crypto.h"
26#include "psa_util_internal.h"
27#include "mbedtls/psa_util.h"
28#endif /* MBEDTLS_USE_PSA_CRYPTO */
29
30#include <string.h>
31#include <stdlib.h>
32
33#if defined(MBEDTLS_PEM_WRITE_C)
34#include "mbedtls/pem.h"
35#endif
36
37#include "mbedtls/platform.h"
38
39void mbedtls_x509write_csr_init(mbedtls_x509write_csr *ctx)
40{
41    memset(ctx, 0, sizeof(mbedtls_x509write_csr));
42}
43
44void mbedtls_x509write_csr_free(mbedtls_x509write_csr *ctx)
45{
46    mbedtls_asn1_free_named_data_list(&ctx->subject);
47    mbedtls_asn1_free_named_data_list(&ctx->extensions);
48
49    mbedtls_platform_zeroize(ctx, sizeof(mbedtls_x509write_csr));
50}
51
52void mbedtls_x509write_csr_set_md_alg(mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg)
53{
54    ctx->md_alg = md_alg;
55}
56
57void mbedtls_x509write_csr_set_key(mbedtls_x509write_csr *ctx, mbedtls_pk_context *key)
58{
59    ctx->key = key;
60}
61
62int mbedtls_x509write_csr_set_subject_name(mbedtls_x509write_csr *ctx,
63                                           const char *subject_name)
64{
65    return mbedtls_x509_string_to_names(&ctx->subject, subject_name);
66}
67
68int mbedtls_x509write_csr_set_extension(mbedtls_x509write_csr *ctx,
69                                        const char *oid, size_t oid_len,
70                                        int critical,
71                                        const unsigned char *val, size_t val_len)
72{
73    return mbedtls_x509_set_extension(&ctx->extensions, oid, oid_len,
74                                      critical, val, val_len);
75}
76
77int mbedtls_x509write_csr_set_subject_alternative_name(mbedtls_x509write_csr *ctx,
78                                                       const mbedtls_x509_san_list *san_list)
79{
80    return mbedtls_x509_write_set_san_common(&ctx->extensions, san_list);
81}
82
83int mbedtls_x509write_csr_set_key_usage(mbedtls_x509write_csr *ctx, unsigned char key_usage)
84{
85    unsigned char buf[4] = { 0 };
86    unsigned char *c;
87    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
88
89    c = buf + 4;
90
91    ret = mbedtls_asn1_write_named_bitstring(&c, buf, &key_usage, 8);
92    if (ret < 3 || ret > 4) {
93        return ret;
94    }
95
96    ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_KEY_USAGE,
97                                              MBEDTLS_OID_SIZE(MBEDTLS_OID_KEY_USAGE),
98                                              0, c, (size_t) ret);
99    if (ret != 0) {
100        return ret;
101    }
102
103    return 0;
104}
105
106int mbedtls_x509write_csr_set_ns_cert_type(mbedtls_x509write_csr *ctx,
107                                           unsigned char ns_cert_type)
108{
109    unsigned char buf[4] = { 0 };
110    unsigned char *c;
111    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
112
113    c = buf + 4;
114
115    ret = mbedtls_asn1_write_named_bitstring(&c, buf, &ns_cert_type, 8);
116    if (ret < 3 || ret > 4) {
117        return ret;
118    }
119
120    ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_NS_CERT_TYPE,
121                                              MBEDTLS_OID_SIZE(MBEDTLS_OID_NS_CERT_TYPE),
122                                              0, c, (size_t) ret);
123    if (ret != 0) {
124        return ret;
125    }
126
127    return 0;
128}
129
130static int x509write_csr_der_internal(mbedtls_x509write_csr *ctx,
131                                      unsigned char *buf,
132                                      size_t size,
133                                      unsigned char *sig, size_t sig_size,
134                                      int (*f_rng)(void *, unsigned char *, size_t),
135                                      void *p_rng)
136{
137    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
138    const char *sig_oid;
139    size_t sig_oid_len = 0;
140    unsigned char *c, *c2;
141    unsigned char hash[MBEDTLS_MD_MAX_SIZE];
142    size_t pub_len = 0, sig_and_oid_len = 0, sig_len;
143    size_t len = 0;
144    mbedtls_pk_type_t pk_alg;
145#if defined(MBEDTLS_USE_PSA_CRYPTO)
146    size_t hash_len;
147    psa_algorithm_t hash_alg = mbedtls_md_psa_alg_from_type(ctx->md_alg);
148#endif /* MBEDTLS_USE_PSA_CRYPTO */
149
150    /* Write the CSR backwards starting from the end of buf */
151    c = buf + size;
152
153    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_extensions(&c, buf,
154                                                            ctx->extensions));
155
156    if (len) {
157        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
158        MBEDTLS_ASN1_CHK_ADD(len,
159                             mbedtls_asn1_write_tag(
160                                 &c, buf,
161                                 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
162
163        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
164        MBEDTLS_ASN1_CHK_ADD(len,
165                             mbedtls_asn1_write_tag(
166                                 &c, buf,
167                                 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET));
168
169        MBEDTLS_ASN1_CHK_ADD(len,
170                             mbedtls_asn1_write_oid(
171                                 &c, buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ,
172                                 MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS9_CSR_EXT_REQ)));
173
174        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
175        MBEDTLS_ASN1_CHK_ADD(len,
176                             mbedtls_asn1_write_tag(
177                                 &c, buf,
178                                 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
179    }
180
181    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
182    MBEDTLS_ASN1_CHK_ADD(len,
183                         mbedtls_asn1_write_tag(
184                             &c, buf,
185                             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC));
186
187    MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_pk_write_pubkey_der(ctx->key,
188                                                              buf, (size_t) (c - buf)));
189    c -= pub_len;
190    len += pub_len;
191
192    /*
193     *  Subject  ::=  Name
194     */
195    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf,
196                                                       ctx->subject));
197
198    /*
199     *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
200     */
201    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(&c, buf, 0));
202
203    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
204    MBEDTLS_ASN1_CHK_ADD(len,
205                         mbedtls_asn1_write_tag(
206                             &c, buf,
207                             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
208
209    /*
210     * Sign the written CSR data into the sig buffer
211     * Note: hash errors can happen only after an internal error
212     */
213#if defined(MBEDTLS_USE_PSA_CRYPTO)
214    if (psa_hash_compute(hash_alg,
215                         c,
216                         len,
217                         hash,
218                         sizeof(hash),
219                         &hash_len) != PSA_SUCCESS) {
220        return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED;
221    }
222#else /* MBEDTLS_USE_PSA_CRYPTO */
223    ret = mbedtls_md(mbedtls_md_info_from_type(ctx->md_alg), c, len, hash);
224    if (ret != 0) {
225        return ret;
226    }
227#endif
228    if ((ret = mbedtls_pk_sign(ctx->key, ctx->md_alg, hash, 0,
229                               sig, sig_size, &sig_len,
230                               f_rng, p_rng)) != 0) {
231        return ret;
232    }
233
234    if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_RSA)) {
235        pk_alg = MBEDTLS_PK_RSA;
236    } else if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_ECDSA)) {
237        pk_alg = MBEDTLS_PK_ECDSA;
238    } else {
239        return MBEDTLS_ERR_X509_INVALID_ALG;
240    }
241
242    if ((ret = mbedtls_oid_get_oid_by_sig_alg(pk_alg, ctx->md_alg,
243                                              &sig_oid, &sig_oid_len)) != 0) {
244        return ret;
245    }
246
247    /*
248     * Move the written CSR data to the start of buf to create space for
249     * writing the signature into buf.
250     */
251    memmove(buf, c, len);
252
253    /*
254     * Write sig and its OID into buf backwards from the end of buf.
255     * Note: mbedtls_x509_write_sig will check for c2 - ( buf + len ) < sig_len
256     * and return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL if needed.
257     */
258    c2 = buf + size;
259    MBEDTLS_ASN1_CHK_ADD(sig_and_oid_len,
260                         mbedtls_x509_write_sig(&c2, buf + len, sig_oid, sig_oid_len,
261                                                sig, sig_len, pk_alg));
262
263    /*
264     * Compact the space between the CSR data and signature by moving the
265     * CSR data to the start of the signature.
266     */
267    c2 -= len;
268    memmove(c2, buf, len);
269
270    /* ASN encode the total size and tag the CSR data with it. */
271    len += sig_and_oid_len;
272    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c2, buf, len));
273    MBEDTLS_ASN1_CHK_ADD(len,
274                         mbedtls_asn1_write_tag(
275                             &c2, buf,
276                             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
277
278    /* Zero the unused bytes at the start of buf */
279    memset(buf, 0, (size_t) (c2 - buf));
280
281    return (int) len;
282}
283
284int mbedtls_x509write_csr_der(mbedtls_x509write_csr *ctx, unsigned char *buf,
285                              size_t size,
286                              int (*f_rng)(void *, unsigned char *, size_t),
287                              void *p_rng)
288{
289    int ret;
290    unsigned char *sig;
291
292    if ((sig = mbedtls_calloc(1, MBEDTLS_PK_SIGNATURE_MAX_SIZE)) == NULL) {
293        return MBEDTLS_ERR_X509_ALLOC_FAILED;
294    }
295
296    ret = x509write_csr_der_internal(ctx, buf, size,
297                                     sig, MBEDTLS_PK_SIGNATURE_MAX_SIZE,
298                                     f_rng, p_rng);
299
300    mbedtls_free(sig);
301
302    return ret;
303}
304
305#define PEM_BEGIN_CSR           "-----BEGIN CERTIFICATE REQUEST-----\n"
306#define PEM_END_CSR             "-----END CERTIFICATE REQUEST-----\n"
307
308#if defined(MBEDTLS_PEM_WRITE_C)
309int mbedtls_x509write_csr_pem(mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size,
310                              int (*f_rng)(void *, unsigned char *, size_t),
311                              void *p_rng)
312{
313    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
314    size_t olen = 0;
315
316    if ((ret = mbedtls_x509write_csr_der(ctx, buf, size,
317                                         f_rng, p_rng)) < 0) {
318        return ret;
319    }
320
321    if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_CSR, PEM_END_CSR,
322                                        buf + size - ret,
323                                        ret, buf, size, &olen)) != 0) {
324        return ret;
325    }
326
327    return 0;
328}
329#endif /* MBEDTLS_PEM_WRITE_C */
330
331#endif /* MBEDTLS_X509_CSR_WRITE_C */
332