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