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