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