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