blob: 0906a5a9d1397aad55a6c6d55794c81d390f15f5 [file] [log] [blame]
Andrzej Kurekc508dc22023-07-07 08:20:02 -04001/*
2 * X.509 internal, common functions for writing
3 *
4 * 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
Andrzej Kurekc508dc22023-07-07 08:20:02 -04006 */
Harry Ramsey0f6bc412024-10-04 10:36:54 +01007#include "x509_internal.h"
8
Andrzej Kurekc508dc22023-07-07 08:20:02 -04009#if defined(MBEDTLS_X509_CSR_WRITE_C) || defined(MBEDTLS_X509_CRT_WRITE_C)
10
11#include "mbedtls/x509_crt.h"
12#include "mbedtls/asn1write.h"
13#include "mbedtls/error.h"
14#include "mbedtls/oid.h"
15#include "mbedtls/platform.h"
16#include "mbedtls/platform_util.h"
Andrzej Kurekc508dc22023-07-07 08:20:02 -040017
18#include <string.h>
19#include <stdint.h>
20
21#if defined(MBEDTLS_PEM_WRITE_C)
22#include "mbedtls/pem.h"
23#endif /* MBEDTLS_PEM_WRITE_C */
24
Andrzej Kurekc508dc22023-07-07 08:20:02 -040025#include "psa/crypto.h"
26#include "mbedtls/psa_util.h"
27#include "md_psa.h"
Andrzej Kurekc508dc22023-07-07 08:20:02 -040028
29#define CHECK_OVERFLOW_ADD(a, b) \
30 do \
31 { \
32 if (a > SIZE_MAX - (b)) \
33 { \
34 return MBEDTLS_ERR_X509_BAD_INPUT_DATA; \
35 } \
36 a += b; \
37 } while (0)
38
39int mbedtls_x509_write_set_san_common(mbedtls_asn1_named_data **extensions,
40 const mbedtls_x509_san_list *san_list)
41{
42 int ret = 0;
43 const mbedtls_x509_san_list *cur;
44 unsigned char *buf;
45 unsigned char *p;
46 size_t len;
47 size_t buflen = 0;
48
49 /* Determine the maximum size of the SubjectAltName list */
50 for (cur = san_list; cur != NULL; cur = cur->next) {
51 /* Calculate size of the required buffer */
52 switch (cur->node.type) {
53 case MBEDTLS_X509_SAN_DNS_NAME:
54 case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
55 case MBEDTLS_X509_SAN_IP_ADDRESS:
56 case MBEDTLS_X509_SAN_RFC822_NAME:
57 /* length of value for each name entry,
58 * maximum 4 bytes for the length field,
59 * 1 byte for the tag/type.
60 */
61 CHECK_OVERFLOW_ADD(buflen, cur->node.san.unstructured_name.len);
62 CHECK_OVERFLOW_ADD(buflen, 4 + 1);
63 break;
64 case MBEDTLS_X509_SAN_DIRECTORY_NAME:
65 {
66 const mbedtls_asn1_named_data *chunk = &cur->node.san.directory_name;
67 while (chunk != NULL) {
68 // Max 4 bytes for length, +1 for tag,
69 // additional 4 max for length, +1 for tag.
70 // See x509_write_name for more information.
71 CHECK_OVERFLOW_ADD(buflen, 4 + 1 + 4 + 1);
72 CHECK_OVERFLOW_ADD(buflen, chunk->oid.len);
73 CHECK_OVERFLOW_ADD(buflen, chunk->val.len);
74 chunk = chunk->next;
75 }
76 CHECK_OVERFLOW_ADD(buflen, 4 + 1);
77 break;
78 }
79 default:
80 /* Not supported - return. */
81 return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
82 }
83 }
84
85 /* Add the extra length field and tag */
86 CHECK_OVERFLOW_ADD(buflen, 4 + 1);
87
88 /* Allocate buffer */
89 buf = mbedtls_calloc(1, buflen);
90 if (buf == NULL) {
91 return MBEDTLS_ERR_ASN1_ALLOC_FAILED;
92 }
93 p = buf + buflen;
94
95 /* Write ASN.1-based structure */
96 cur = san_list;
97 len = 0;
98 while (cur != NULL) {
99 size_t single_san_len = 0;
100 switch (cur->node.type) {
101 case MBEDTLS_X509_SAN_DNS_NAME:
102 case MBEDTLS_X509_SAN_RFC822_NAME:
103 case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
104 case MBEDTLS_X509_SAN_IP_ADDRESS:
105 {
106 const unsigned char *unstructured_name =
107 (const unsigned char *) cur->node.san.unstructured_name.p;
108 size_t unstructured_name_len = cur->node.san.unstructured_name.len;
109
110 MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
111 mbedtls_asn1_write_raw_buffer(
112 &p, buf,
113 unstructured_name, unstructured_name_len));
114 MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len, mbedtls_asn1_write_len(
115 &p, buf, unstructured_name_len));
116 MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
117 mbedtls_asn1_write_tag(
118 &p, buf,
119 MBEDTLS_ASN1_CONTEXT_SPECIFIC | cur->node.type));
120 }
121 break;
122 case MBEDTLS_X509_SAN_DIRECTORY_NAME:
123 MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
124 mbedtls_x509_write_names(&p, buf,
125 (mbedtls_asn1_named_data *) &
126 cur->node
127 .san.directory_name));
128 MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
129 mbedtls_asn1_write_len(&p, buf, single_san_len));
130 MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
131 mbedtls_asn1_write_tag(&p, buf,
132 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
133 MBEDTLS_ASN1_CONSTRUCTED |
134 MBEDTLS_X509_SAN_DIRECTORY_NAME));
135 break;
136 default:
137 /* Error out on an unsupported SAN */
138 ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
139 goto cleanup;
140 }
141 cur = cur->next;
142 /* check for overflow */
143 if (len > SIZE_MAX - single_san_len) {
144 ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA;
145 goto cleanup;
146 }
147 len += single_san_len;
148 }
149
150 MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&p, buf, len));
151 MBEDTLS_ASN1_CHK_CLEANUP_ADD(len,
152 mbedtls_asn1_write_tag(&p, buf,
153 MBEDTLS_ASN1_CONSTRUCTED |
154 MBEDTLS_ASN1_SEQUENCE));
155
156 ret = mbedtls_x509_set_extension(extensions,
157 MBEDTLS_OID_SUBJECT_ALT_NAME,
158 MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME),
159 0,
160 buf + buflen - len, len);
161
162 /* If we exceeded the allocated buffer it means that maximum size of the SubjectAltName list
163 * was incorrectly calculated and memory is corrupted. */
164 if (p < buf) {
165 ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
166 }
167cleanup:
168 mbedtls_free(buf);
169 return ret;
170}
171
172#endif /* MBEDTLS_X509_CSR_WRITE_C || MBEDTLS_X509_CRT_WRITE_C */