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