blob: 32a3bb2e78ecf19a9d5fae830f972b2d052cc84f [file] [log] [blame]
Paul Bakker7c6b2c32013-09-16 13:49:26 +02001/*
2 * X.509 Certificate Signing Request (CSR) parsing
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Dave Rodgman16799db2023-11-02 19:47:20 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Paul Bakker7c6b2c32013-09-16 13:49:26 +02006 */
7/*
8 * The ITU-T X.509 standard defines a certificate format for PKI.
9 *
Manuel Pégourié-Gonnard1c082f32014-06-12 22:34:55 +020010 * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs)
11 * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs)
12 * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020013 *
14 * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
15 * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
16 */
17
Harry Ramsey0f6bc412024-10-04 10:36:54 +010018#include "x509_internal.h"
Paul Bakker7c6b2c32013-09-16 13:49:26 +020019
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020020#if defined(MBEDTLS_X509_CSR_PARSE_C)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020021
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000022#include "mbedtls/x509_csr.h"
Janos Follath73c616b2019-12-18 15:07:04 +000023#include "mbedtls/error.h"
Gilles Peskinecd4c0d72025-05-07 23:45:12 +020024#include "mbedtls/oid.h"
Gilles Peskine86a47f82025-05-07 20:20:12 +020025#include "x509_oid.h"
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -050026#include "mbedtls/platform_util.h"
Rich Evans00ab4702015-02-06 13:43:58 +000027
28#include <string.h>
29
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020030#if defined(MBEDTLS_PEM_PARSE_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000031#include "mbedtls/pem.h"
Paul Bakker7c6b2c32013-09-16 13:49:26 +020032#endif
Paul Bakker7c6b2c32013-09-16 13:49:26 +020033
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000034#include "mbedtls/platform.h"
Paul Bakker7c6b2c32013-09-16 13:49:26 +020035
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020036#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020037#include <stdio.h>
38#endif
39
40/*
41 * Version ::= INTEGER { v1(0) }
42 */
Gilles Peskine449bd832023-01-11 14:50:10 +010043static int x509_csr_get_version(unsigned char **p,
44 const unsigned char *end,
45 int *ver)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020046{
Janos Follath865b3eb2019-12-16 11:46:15 +000047 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker7c6b2c32013-09-16 13:49:26 +020048
Gilles Peskine449bd832023-01-11 14:50:10 +010049 if ((ret = mbedtls_asn1_get_int(p, end, ver)) != 0) {
50 if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
Paul Bakker7c6b2c32013-09-16 13:49:26 +020051 *ver = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +010052 return 0;
Paul Bakker7c6b2c32013-09-16 13:49:26 +020053 }
54
Gilles Peskine449bd832023-01-11 14:50:10 +010055 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION, ret);
Paul Bakker7c6b2c32013-09-16 13:49:26 +020056 }
57
Gilles Peskine449bd832023-01-11 14:50:10 +010058 return 0;
Paul Bakker7c6b2c32013-09-16 13:49:26 +020059}
60
61/*
Jens Alfke2d9e3592019-10-29 15:03:37 -070062 * Parse CSR extension requests in DER format
63 */
64static int x509_csr_parse_extensions(mbedtls_x509_csr *csr,
Matthias Schulzab408222023-10-18 13:20:59 +020065 unsigned char **p, const unsigned char *end,
66 mbedtls_x509_csr_ext_cb_t cb,
67 void *p_ctx)
Jens Alfke2d9e3592019-10-29 15:03:37 -070068{
Matthias Schulz873a2022023-10-17 16:02:20 +020069 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Alfke2d9e3592019-10-29 15:03:37 -070070 size_t len;
Matthias Schulzab408222023-10-18 13:20:59 +020071 unsigned char *end_ext_data, *end_ext_octet;
Matthias Schulzcc923f32023-10-17 12:36:23 +020072
Jens Alfke2d9e3592019-10-29 15:03:37 -070073 while (*p < end) {
74 mbedtls_x509_buf extn_oid = { 0, 0, NULL };
Matthias Schulz873a2022023-10-17 16:02:20 +020075 int is_critical = 0; /* DEFAULT FALSE */
Jens Alfke2d9e3592019-10-29 15:03:37 -070076 int ext_type = 0;
77
78 /* Read sequence tag */
79 if ((ret = mbedtls_asn1_get_tag(p, end, &len,
80 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
Przemek Stekiel86d19462023-01-24 09:45:19 +010081 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
Jens Alfke2d9e3592019-10-29 15:03:37 -070082 }
83
84 end_ext_data = *p + len;
85
86 /* Get extension ID */
87 if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &extn_oid.len,
88 MBEDTLS_ASN1_OID)) != 0) {
Przemek Stekiel86d19462023-01-24 09:45:19 +010089 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
Jens Alfke2d9e3592019-10-29 15:03:37 -070090 }
91
92 extn_oid.tag = MBEDTLS_ASN1_OID;
93 extn_oid.p = *p;
94 *p += extn_oid.len;
95
Matthias Schulz873a2022023-10-17 16:02:20 +020096 /* Get optional critical */
97 if ((ret = mbedtls_asn1_get_bool(p, end_ext_data, &is_critical)) != 0 &&
98 (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
99 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
100 }
Matthias Schulzadb3cc42023-10-17 11:50:50 +0200101
Jens Alfke2d9e3592019-10-29 15:03:37 -0700102 /* Data should be octet string type */
103 if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &len,
104 MBEDTLS_ASN1_OCTET_STRING)) != 0) {
Przemek Stekiel86d19462023-01-24 09:45:19 +0100105 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
Jens Alfke2d9e3592019-10-29 15:03:37 -0700106 }
Przemek Stekiel86d19462023-01-24 09:45:19 +0100107
Matthias Schulzab408222023-10-18 13:20:59 +0200108 end_ext_octet = *p + len;
109
110 if (end_ext_octet != end_ext_data) {
Przemek Stekiel86d19462023-01-24 09:45:19 +0100111 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
112 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
Jens Alfke2d9e3592019-10-29 15:03:37 -0700113 }
114
Przemek Stekielcbaf3162023-01-12 12:58:02 +0100115 /*
Przemek Stekiel94e21e12023-01-25 11:08:32 +0100116 * Detect supported extensions and skip unsupported extensions
Przemek Stekielcbaf3162023-01-12 12:58:02 +0100117 */
Gilles Peskine532e3ee2025-05-07 20:37:15 +0200118 ret = mbedtls_x509_oid_get_x509_ext_type(&extn_oid, &ext_type);
Przemek Stekielcbaf3162023-01-12 12:58:02 +0100119
Matthias Schulzab408222023-10-18 13:20:59 +0200120 if (ret != 0) {
121 /* Give the callback (if any) a chance to handle the extension */
122 if (cb != NULL) {
123 ret = cb(p_ctx, csr, &extn_oid, is_critical, *p, end_ext_octet);
124 if (ret != 0 && is_critical) {
125 return ret;
126 }
127 *p = end_ext_octet;
128 continue;
Przemek Stekiel94e21e12023-01-25 11:08:32 +0100129 }
130
Matthias Schulzab408222023-10-18 13:20:59 +0200131 /* No parser found, skip extension */
132 *p = end_ext_octet;
Przemek Stekiel94e21e12023-01-25 11:08:32 +0100133
Matthias Schulz873a2022023-10-17 16:02:20 +0200134 if (is_critical) {
135 /* Data is marked as critical: fail */
Przemek Stekiel94e21e12023-01-25 11:08:32 +0100136 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
Matthias Schulz873a2022023-10-17 16:02:20 +0200137 MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
Przemek Stekiel94e21e12023-01-25 11:08:32 +0100138 }
Matthias Schulzab408222023-10-18 13:20:59 +0200139 continue;
Przemek Stekiel86d19462023-01-24 09:45:19 +0100140 }
Matthias Schulzab408222023-10-18 13:20:59 +0200141
142 /* Forbid repeated extensions */
143 if ((csr->ext_types & ext_type) != 0) {
144 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
Matthias Schulzedc32ea2023-10-19 16:09:08 +0200145 MBEDTLS_ERR_ASN1_INVALID_DATA);
Matthias Schulzab408222023-10-18 13:20:59 +0200146 }
147
148 csr->ext_types |= ext_type;
149
150 switch (ext_type) {
151 case MBEDTLS_X509_EXT_KEY_USAGE:
152 /* Parse key usage */
153 if ((ret = mbedtls_x509_get_key_usage(p, end_ext_data,
Matthias Schulzedc32ea2023-10-19 16:09:08 +0200154 &csr->key_usage)) != 0) {
Matthias Schulzab408222023-10-18 13:20:59 +0200155 return ret;
156 }
157 break;
158
159 case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME:
160 /* Parse subject alt name */
161 if ((ret = mbedtls_x509_get_subject_alt_name(p, end_ext_data,
Matthias Schulzedc32ea2023-10-19 16:09:08 +0200162 &csr->subject_alt_names)) != 0) {
Matthias Schulzab408222023-10-18 13:20:59 +0200163 return ret;
164 }
165 break;
166
167 case MBEDTLS_X509_EXT_NS_CERT_TYPE:
168 /* Parse netscape certificate type */
169 if ((ret = mbedtls_x509_get_ns_cert_type(p, end_ext_data,
Matthias Schulzedc32ea2023-10-19 16:09:08 +0200170 &csr->ns_cert_type)) != 0) {
Matthias Schulzab408222023-10-18 13:20:59 +0200171 return ret;
172 }
173 break;
174 default:
175 /*
Matthias Schulzedc32ea2023-10-19 16:09:08 +0200176 * If this is a non-critical extension, which the oid layer
177 * supports, but there isn't an x509 parser for it,
178 * skip the extension.
179 */
Matthias Schulzab408222023-10-18 13:20:59 +0200180 if (is_critical) {
181 return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
182 } else {
183 *p = end_ext_octet;
184 }
185 }
Jens Alfke2d9e3592019-10-29 15:03:37 -0700186 }
187
188 if (*p != end) {
Przemek Stekiel86d19462023-01-24 09:45:19 +0100189 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
190 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
Jens Alfke2d9e3592019-10-29 15:03:37 -0700191 }
192
193 return 0;
194}
195
196/*
197 * Parse CSR attributes in DER format
198 */
199static int x509_csr_parse_attributes(mbedtls_x509_csr *csr,
Matthias Schulzab408222023-10-18 13:20:59 +0200200 const unsigned char *start, const unsigned char *end,
201 mbedtls_x509_csr_ext_cb_t cb,
202 void *p_ctx)
Jens Alfke2d9e3592019-10-29 15:03:37 -0700203{
204 int ret;
205 size_t len;
206 unsigned char *end_attr_data;
207 unsigned char **p = (unsigned char **) &start;
208
209 while (*p < end) {
210 mbedtls_x509_buf attr_oid = { 0, 0, NULL };
211
212 if ((ret = mbedtls_asn1_get_tag(p, end, &len,
213 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
Przemek Stekiel86d19462023-01-24 09:45:19 +0100214 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
Jens Alfke2d9e3592019-10-29 15:03:37 -0700215 }
216 end_attr_data = *p + len;
217
218 /* Get attribute ID */
219 if ((ret = mbedtls_asn1_get_tag(p, end_attr_data, &attr_oid.len,
220 MBEDTLS_ASN1_OID)) != 0) {
Przemek Stekiel86d19462023-01-24 09:45:19 +0100221 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
Jens Alfke2d9e3592019-10-29 15:03:37 -0700222 }
223
224 attr_oid.tag = MBEDTLS_ASN1_OID;
225 attr_oid.p = *p;
226 *p += attr_oid.len;
227
228 /* Check that this is an extension-request attribute */
229 if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS9_CSR_EXT_REQ, &attr_oid) == 0) {
230 if ((ret = mbedtls_asn1_get_tag(p, end, &len,
231 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET)) != 0) {
Przemek Stekiel86d19462023-01-24 09:45:19 +0100232 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
Jens Alfke2d9e3592019-10-29 15:03:37 -0700233 }
234
235 if ((ret = mbedtls_asn1_get_tag(p, end, &len,
236 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) !=
237 0) {
Przemek Stekiel86d19462023-01-24 09:45:19 +0100238 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
Jens Alfke2d9e3592019-10-29 15:03:37 -0700239 }
240
Matthias Schulzab408222023-10-18 13:20:59 +0200241 if ((ret = x509_csr_parse_extensions(csr, p, *p + len, cb, p_ctx)) != 0) {
Przemek Stekiel86d19462023-01-24 09:45:19 +0100242 return ret;
Jens Alfke2d9e3592019-10-29 15:03:37 -0700243 }
244
245 if (*p != end_attr_data) {
Przemek Stekiel86d19462023-01-24 09:45:19 +0100246 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
247 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
Jens Alfke2d9e3592019-10-29 15:03:37 -0700248 }
249 }
250
251 *p = end_attr_data;
252 }
253
254 if (*p != end) {
Przemek Stekiel86d19462023-01-24 09:45:19 +0100255 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
Przemek Stekiel36ad5e72023-01-26 22:30:45 +0100256 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
Jens Alfke2d9e3592019-10-29 15:03:37 -0700257 }
258
259 return 0;
260}
261
262/*
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200263 * Parse a CSR in DER format
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200264 */
Matthias Schulzab408222023-10-18 13:20:59 +0200265static int mbedtls_x509_csr_parse_der_internal(mbedtls_x509_csr *csr,
Matthias Schulzedc32ea2023-10-19 16:09:08 +0200266 const unsigned char *buf, size_t buflen,
267 mbedtls_x509_csr_ext_cb_t cb,
268 void *p_ctx)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200269{
Janos Follath865b3eb2019-12-16 11:46:15 +0000270 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200271 size_t len;
272 unsigned char *p, *end;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200273 mbedtls_x509_buf sig_params;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200274
Gilles Peskine449bd832023-01-11 14:50:10 +0100275 memset(&sig_params, 0, sizeof(mbedtls_x509_buf));
Manuel Pégourié-Gonnarddddbb1d2014-06-05 17:02:24 +0200276
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200277 /*
278 * Check for valid input
279 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100280 if (csr == NULL || buf == NULL || buflen == 0) {
281 return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
282 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200283
Gilles Peskine449bd832023-01-11 14:50:10 +0100284 mbedtls_x509_csr_init(csr);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200285
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200286 /*
287 * first copy the raw DER data
288 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100289 p = mbedtls_calloc(1, len = buflen);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200290
Gilles Peskine449bd832023-01-11 14:50:10 +0100291 if (p == NULL) {
292 return MBEDTLS_ERR_X509_ALLOC_FAILED;
293 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200294
Gilles Peskine449bd832023-01-11 14:50:10 +0100295 memcpy(p, buf, buflen);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200296
297 csr->raw.p = p;
298 csr->raw.len = len;
299 end = p + len;
300
301 /*
302 * CertificationRequest ::= SEQUENCE {
303 * certificationRequestInfo CertificationRequestInfo,
304 * signatureAlgorithm AlgorithmIdentifier,
305 * signature BIT STRING
306 * }
307 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100308 if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
309 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
310 mbedtls_x509_csr_free(csr);
311 return MBEDTLS_ERR_X509_INVALID_FORMAT;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200312 }
313
Gilles Peskine449bd832023-01-11 14:50:10 +0100314 if (len != (size_t) (end - p)) {
315 mbedtls_x509_csr_free(csr);
316 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT,
317 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200318 }
319
320 /*
321 * CertificationRequestInfo ::= SEQUENCE {
322 */
323 csr->cri.p = p;
324
Gilles Peskine449bd832023-01-11 14:50:10 +0100325 if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
326 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
327 mbedtls_x509_csr_free(csr);
328 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200329 }
330
331 end = p + len;
Dave Rodgmane4a6f5a2023-11-04 12:20:09 +0000332 csr->cri.len = (size_t) (end - csr->cri.p);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200333
334 /*
335 * Version ::= INTEGER { v1(0) }
336 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100337 if ((ret = x509_csr_get_version(&p, end, &csr->version)) != 0) {
338 mbedtls_x509_csr_free(csr);
339 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200340 }
341
Gilles Peskine449bd832023-01-11 14:50:10 +0100342 if (csr->version != 0) {
343 mbedtls_x509_csr_free(csr);
344 return MBEDTLS_ERR_X509_UNKNOWN_VERSION;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200345 }
346
Andres AG2e3ddfa2017-02-17 13:54:43 +0000347 csr->version++;
348
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200349 /*
350 * subject Name
351 */
352 csr->subject_raw.p = p;
353
Gilles Peskine449bd832023-01-11 14:50:10 +0100354 if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
355 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
356 mbedtls_x509_csr_free(csr);
357 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200358 }
359
Gilles Peskine449bd832023-01-11 14:50:10 +0100360 if ((ret = mbedtls_x509_get_name(&p, p + len, &csr->subject)) != 0) {
361 mbedtls_x509_csr_free(csr);
362 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200363 }
364
Dave Rodgmane4a6f5a2023-11-04 12:20:09 +0000365 csr->subject_raw.len = (size_t) (p - csr->subject_raw.p);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200366
367 /*
368 * subjectPKInfo SubjectPublicKeyInfo
369 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100370 if ((ret = mbedtls_pk_parse_subpubkey(&p, end, &csr->pk)) != 0) {
371 mbedtls_x509_csr_free(csr);
372 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200373 }
374
375 /*
376 * attributes [0] Attributes
Manuel Pégourié-Gonnard986bbf22016-02-24 14:36:05 +0000377 *
378 * The list of possible attributes is open-ended, though RFC 2985
379 * (PKCS#9) defines a few in section 5.4. We currently don't support any,
380 * so we just ignore them. This is a safe thing to do as the worst thing
381 * that could happen is that we issue a certificate that does not match
382 * the requester's expectations - this cannot cause a violation of our
383 * signature policies.
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200384 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100385 if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
386 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC)) !=
387 0) {
388 mbedtls_x509_csr_free(csr);
389 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200390 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200391
Matthias Schulzab408222023-10-18 13:20:59 +0200392 if ((ret = x509_csr_parse_attributes(csr, p, p + len, cb, p_ctx)) != 0) {
Jens Alfke2d9e3592019-10-29 15:03:37 -0700393 mbedtls_x509_csr_free(csr);
394 return ret;
395 }
396
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200397 p += len;
398
399 end = csr->raw.p + csr->raw.len;
400
401 /*
402 * signatureAlgorithm AlgorithmIdentifier,
403 * signature BIT STRING
404 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100405 if ((ret = mbedtls_x509_get_alg(&p, end, &csr->sig_oid, &sig_params)) != 0) {
406 mbedtls_x509_csr_free(csr);
407 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200408 }
409
Gilles Peskine449bd832023-01-11 14:50:10 +0100410 if ((ret = mbedtls_x509_get_sig_alg(&csr->sig_oid, &sig_params,
Valerio Setti68878cc2025-04-10 23:30:26 +0200411 &csr->sig_md, &csr->sig_pk)) != 0) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100412 mbedtls_x509_csr_free(csr);
413 return MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200414 }
415
Gilles Peskine449bd832023-01-11 14:50:10 +0100416 if ((ret = mbedtls_x509_get_sig(&p, end, &csr->sig)) != 0) {
417 mbedtls_x509_csr_free(csr);
418 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200419 }
420
Gilles Peskine449bd832023-01-11 14:50:10 +0100421 if (p != end) {
422 mbedtls_x509_csr_free(csr);
423 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT,
424 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200425 }
426
Gilles Peskine449bd832023-01-11 14:50:10 +0100427 return 0;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200428}
429
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200430/*
Matthias Schulzab408222023-10-18 13:20:59 +0200431 * Parse a CSR in DER format
432 */
433int mbedtls_x509_csr_parse_der(mbedtls_x509_csr *csr,
434 const unsigned char *buf, size_t buflen)
435{
436 return mbedtls_x509_csr_parse_der_internal(csr, buf, buflen, NULL, NULL);
437}
438
439/*
440 * Parse a CSR in DER format with callback for unknown extensions
441 */
442int mbedtls_x509_csr_parse_der_with_ext_cb(mbedtls_x509_csr *csr,
Matthias Schulzedc32ea2023-10-19 16:09:08 +0200443 const unsigned char *buf, size_t buflen,
444 mbedtls_x509_csr_ext_cb_t cb,
445 void *p_ctx)
Matthias Schulzab408222023-10-18 13:20:59 +0200446{
447 return mbedtls_x509_csr_parse_der_internal(csr, buf, buflen, cb, p_ctx);
448}
449
450/*
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200451 * Parse a CSR, allowing for PEM or raw DER encoding
452 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100453int mbedtls_x509_csr_parse(mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen)
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200454{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200455#if defined(MBEDTLS_PEM_PARSE_C)
Janos Follath865b3eb2019-12-16 11:46:15 +0000456 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200457 size_t use_len;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200458 mbedtls_pem_context pem;
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200459#endif
460
461 /*
462 * Check for valid input
463 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100464 if (csr == NULL || buf == NULL || buflen == 0) {
465 return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
466 }
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200467
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200468#if defined(MBEDTLS_PEM_PARSE_C)
Manuel Pégourié-Gonnard43b37cb2015-05-12 11:20:10 +0200469 /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
Gilles Peskine449bd832023-01-11 14:50:10 +0100470 if (buf[buflen - 1] == '\0') {
471 mbedtls_pem_init(&pem);
472 ret = mbedtls_pem_read_buffer(&pem,
473 "-----BEGIN CERTIFICATE REQUEST-----",
474 "-----END CERTIFICATE REQUEST-----",
475 buf, NULL, 0, &use_len);
476 if (ret == MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
477 ret = mbedtls_pem_read_buffer(&pem,
478 "-----BEGIN NEW CERTIFICATE REQUEST-----",
479 "-----END NEW CERTIFICATE REQUEST-----",
480 buf, NULL, 0, &use_len);
Simon Butcher0488ce62018-09-30 15:36:50 +0100481 }
Simon Butchere1660af2018-10-07 17:48:37 +0100482
Gilles Peskine449bd832023-01-11 14:50:10 +0100483 if (ret == 0) {
Philippe Antoinec03059d2018-06-14 07:35:11 +0200484 /*
485 * Was PEM encoded, parse the result
486 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100487 ret = mbedtls_x509_csr_parse_der(csr, pem.buf, pem.buflen);
Simon Butcher0488ce62018-09-30 15:36:50 +0100488 }
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200489
Gilles Peskine449bd832023-01-11 14:50:10 +0100490 mbedtls_pem_free(&pem);
491 if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
492 return ret;
493 }
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200494 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200495#endif /* MBEDTLS_PEM_PARSE_C */
Gilles Peskine449bd832023-01-11 14:50:10 +0100496 return mbedtls_x509_csr_parse_der(csr, buf, buflen);
Manuel Pégourié-Gonnardf3b47242014-06-16 18:06:48 +0200497}
498
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200499#if defined(MBEDTLS_FS_IO)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200500/*
501 * Load a CSR into the structure
502 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100503int mbedtls_x509_csr_parse_file(mbedtls_x509_csr *csr, const char *path)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200504{
Janos Follath865b3eb2019-12-16 11:46:15 +0000505 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200506 size_t n;
507 unsigned char *buf;
508
Gilles Peskine449bd832023-01-11 14:50:10 +0100509 if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
510 return ret;
511 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200512
Gilles Peskine449bd832023-01-11 14:50:10 +0100513 ret = mbedtls_x509_csr_parse(csr, buf, n);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200514
Tom Cosgroveca8c61b2023-07-17 15:17:40 +0100515 mbedtls_zeroize_and_free(buf, n);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200516
Gilles Peskine449bd832023-01-11 14:50:10 +0100517 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200518}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200519#endif /* MBEDTLS_FS_IO */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200520
Hanno Becker612a2f12020-10-09 09:19:39 +0100521#if !defined(MBEDTLS_X509_REMOVE_INFO)
Stefan Gloorb5c079b2025-02-21 10:33:51 +0100522#define MBEDTLS_BEFORE_COLON 14
523#define MBEDTLS_BEFORE_COLON_STR "14"
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200524/*
525 * Return an informational string about the CSR.
526 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100527int mbedtls_x509_csr_info(char *buf, size_t size, const char *prefix,
528 const mbedtls_x509_csr *csr)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200529{
Janos Follath865b3eb2019-12-16 11:46:15 +0000530 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200531 size_t n;
532 char *p;
Stefan Gloorb5c079b2025-02-21 10:33:51 +0100533 char key_size_str[MBEDTLS_BEFORE_COLON];
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200534
535 p = buf;
536 n = size;
537
Gilles Peskine449bd832023-01-11 14:50:10 +0100538 ret = mbedtls_snprintf(p, n, "%sCSR version : %d",
539 prefix, csr->version);
Manuel Pégourié-Gonnard16853682015-06-22 11:12:02 +0200540 MBEDTLS_X509_SAFE_SNPRINTF;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200541
Gilles Peskine449bd832023-01-11 14:50:10 +0100542 ret = mbedtls_snprintf(p, n, "\n%ssubject name : ", prefix);
Manuel Pégourié-Gonnard16853682015-06-22 11:12:02 +0200543 MBEDTLS_X509_SAFE_SNPRINTF;
Gilles Peskine449bd832023-01-11 14:50:10 +0100544 ret = mbedtls_x509_dn_gets(p, n, &csr->subject);
Manuel Pégourié-Gonnard16853682015-06-22 11:12:02 +0200545 MBEDTLS_X509_SAFE_SNPRINTF;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200546
Gilles Peskine449bd832023-01-11 14:50:10 +0100547 ret = mbedtls_snprintf(p, n, "\n%ssigned using : ", prefix);
Manuel Pégourié-Gonnard16853682015-06-22 11:12:02 +0200548 MBEDTLS_X509_SAFE_SNPRINTF;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200549
Valerio Settid24dfad2025-04-23 11:13:02 +0200550 ret = mbedtls_x509_sig_alg_gets(p, n, &csr->sig_oid, csr->sig_pk, csr->sig_md);
Manuel Pégourié-Gonnard16853682015-06-22 11:12:02 +0200551 MBEDTLS_X509_SAFE_SNPRINTF;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200552
Stefan Gloorb5c079b2025-02-21 10:33:51 +0100553 if ((ret = mbedtls_x509_key_size_helper(key_size_str, MBEDTLS_BEFORE_COLON,
Gilles Peskine449bd832023-01-11 14:50:10 +0100554 mbedtls_pk_get_name(&csr->pk))) != 0) {
555 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200556 }
557
Stefan Gloorb5c079b2025-02-21 10:33:51 +0100558 ret = mbedtls_snprintf(p, n, "\n%s%-" MBEDTLS_BEFORE_COLON_STR "s: %d bits\n",
559 prefix, key_size_str, (int) mbedtls_pk_get_bitlen(&csr->pk));
Manuel Pégourié-Gonnard16853682015-06-22 11:12:02 +0200560 MBEDTLS_X509_SAFE_SNPRINTF;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200561
Przemek Stekielcbaf3162023-01-12 12:58:02 +0100562 /*
563 * Optional extensions
564 */
565
566 if (csr->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) {
567 ret = mbedtls_snprintf(p, n, "\n%ssubject alt name :", prefix);
568 MBEDTLS_X509_SAFE_SNPRINTF;
569
Przemek Stekiel21c37282023-01-16 08:47:49 +0100570 if ((ret = mbedtls_x509_info_subject_alt_name(&p, &n,
571 &csr->subject_alt_names,
572 prefix)) != 0) {
Przemek Stekielcbaf3162023-01-12 12:58:02 +0100573 return ret;
574 }
575 }
576
577 if (csr->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) {
578 ret = mbedtls_snprintf(p, n, "\n%scert. type : ", prefix);
579 MBEDTLS_X509_SAFE_SNPRINTF;
580
Przemek Stekiel21c37282023-01-16 08:47:49 +0100581 if ((ret = mbedtls_x509_info_cert_type(&p, &n, csr->ns_cert_type)) != 0) {
Przemek Stekielcbaf3162023-01-12 12:58:02 +0100582 return ret;
583 }
584 }
585
586 if (csr->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) {
587 ret = mbedtls_snprintf(p, n, "\n%skey usage : ", prefix);
588 MBEDTLS_X509_SAFE_SNPRINTF;
589
Przemek Stekiel21c37282023-01-16 08:47:49 +0100590 if ((ret = mbedtls_x509_info_key_usage(&p, &n, csr->key_usage)) != 0) {
Przemek Stekielcbaf3162023-01-12 12:58:02 +0100591 return ret;
592 }
593 }
594
595 if (csr->ext_types != 0) {
596 ret = mbedtls_snprintf(p, n, "\n");
597 MBEDTLS_X509_SAFE_SNPRINTF;
598 }
599
Gilles Peskine449bd832023-01-11 14:50:10 +0100600 return (int) (size - n);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200601}
Hanno Becker612a2f12020-10-09 09:19:39 +0100602#endif /* MBEDTLS_X509_REMOVE_INFO */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200603
604/*
Paul Bakker369d2eb2013-09-18 11:58:25 +0200605 * Initialize a CSR
606 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100607void mbedtls_x509_csr_init(mbedtls_x509_csr *csr)
Paul Bakker369d2eb2013-09-18 11:58:25 +0200608{
Gilles Peskine449bd832023-01-11 14:50:10 +0100609 memset(csr, 0, sizeof(mbedtls_x509_csr));
Paul Bakker369d2eb2013-09-18 11:58:25 +0200610}
611
612/*
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200613 * Unallocate all CSR data
614 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100615void mbedtls_x509_csr_free(mbedtls_x509_csr *csr)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200616{
Gilles Peskine449bd832023-01-11 14:50:10 +0100617 if (csr == NULL) {
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200618 return;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200619 }
620
Gilles Peskine449bd832023-01-11 14:50:10 +0100621 mbedtls_pk_free(&csr->pk);
622
Gilles Peskine449bd832023-01-11 14:50:10 +0100623 mbedtls_asn1_free_named_data_list_shallow(csr->subject.next);
Przemek Stekiela4687682023-01-24 15:19:47 +0100624 mbedtls_asn1_sequence_free(csr->subject_alt_names.next);
Gilles Peskine449bd832023-01-11 14:50:10 +0100625
626 if (csr->raw.p != NULL) {
Tom Cosgroveca8c61b2023-07-17 15:17:40 +0100627 mbedtls_zeroize_and_free(csr->raw.p, csr->raw.len);
Gilles Peskine449bd832023-01-11 14:50:10 +0100628 }
629
630 mbedtls_platform_zeroize(csr, sizeof(mbedtls_x509_csr));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200631}
632
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200633#endif /* MBEDTLS_X509_CSR_PARSE_C */