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