From cd17ecfe85367963bd5585f0549f45f1f9aee551 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Mon, 5 Jun 2023 17:02:17 -0400 Subject: [PATCH] Use better IP parsing in x509 programs Remove unnecessary duplicated code. Signed-off-by: Andrzej Kurek --- include/mbedtls/x509.h | 17 ++++++++++++ library/x509_crt.c | 1 - library/x509_invasive.h | 53 -------------------------------------- programs/x509/cert_req.c | 29 +++++++-------------- programs/x509/cert_write.c | 25 +++++++----------- 5 files changed, 37 insertions(+), 88 deletions(-) delete mode 100644 library/x509_invasive.h diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index df6d7623a..d7777c90a 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -500,6 +500,23 @@ int mbedtls_x509_info_cert_type(char **buf, size_t *size, int mbedtls_x509_info_key_usage(char **buf, size_t *size, unsigned int key_usage); +/** + * \brief This function parses a CN string as an IP address. + * + * \param cn The CN string to parse. CN string MUST be NUL-terminated. + * \param dst The target buffer to populate with the binary IP address. + * The buffer MUST be 16 bytes to save IPv6, and should be + * 4-byte aligned if the result will be used as struct in_addr. + * e.g. uint32_t dst[4] + * + * \note \cn is parsed as an IPv6 address if string contains ':', + * else \cn is parsed as an IPv4 address. + * + * \return Length of binary IP address; num bytes written to target. + * \return \c 0 on failure to parse CN string as an IP address. + */ +size_t mbedtls_x509_crt_parse_cn_inet_pton(const char *cn, void *dst); + #define MBEDTLS_X509_SAFE_SNPRINTF \ do { \ if (ret < 0 || (size_t) ret >= n) \ diff --git a/library/x509_crt.c b/library/x509_crt.c index 9b3414a49..edd57828a 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2862,7 +2862,6 @@ static int x509_inet_pton_ipv4(const char *src, void *dst) #endif /* !AF_INET6 || MBEDTLS_TEST_SW_INET_PTON */ //no-check-names -MBEDTLS_STATIC_TESTABLE size_t mbedtls_x509_crt_parse_cn_inet_pton(const char *cn, void *dst) { return strchr(cn, ':') == NULL diff --git a/library/x509_invasive.h b/library/x509_invasive.h deleted file mode 100644 index d8fd74be4..000000000 --- a/library/x509_invasive.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * \file x509_invasive.h - * - * \brief x509 module: interfaces for invasive testing only. - * - * The interfaces in this file are intended for testing purposes only. - * They SHOULD NOT be made available in library integrations except when - * building the library for testing. - */ -/* - * Copyright The Mbed TLS Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MBEDTLS_X509_INVASIVE_H -#define MBEDTLS_X509_INVASIVE_H - -#include "common.h" - -#if defined(MBEDTLS_TEST_HOOKS) - -/** - * \brief This function parses a CN string as an IP address. - * - * \param cn The CN string to parse. CN string MUST be NUL-terminated. - * \param dst The target buffer to populate with the binary IP address. - * The buffer MUST be 16 bytes to save IPv6, and should be - * 4-byte aligned if the result will be used as struct in_addr. - * e.g. uint32_t dst[4] - * - * \note \cn is parsed as an IPv6 address if string contains ':', - * else \cn is parsed as an IPv4 address. - * - * \return Length of binary IP address; num bytes written to target. - * \return \c 0 on failure to parse CN string as an IP address. - */ -size_t mbedtls_x509_crt_parse_cn_inet_pton(const char *cn, void *dst); - -#endif /* MBEDTLS_TEST_HOOKS */ - -#endif /* MBEDTLS_X509_INVASIVE_H */ diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c index fe060f3d9..531871bc6 100644 --- a/programs/x509/cert_req.c +++ b/programs/x509/cert_req.c @@ -116,18 +116,6 @@ struct options { mbedtls_md_type_t md_alg; /* Hash algorithm used for signature. */ } opt; -static void ip_string_to_bytes(const char *str, uint8_t *bytes, int maxBytes) -{ - for (int i = 0; i < maxBytes; i++) { - bytes[i] = (uint8_t) strtoul(str, NULL, 10); - str = strchr(str, '.'); - if (str == NULL || *str == '\0') { - break; - } - str++; - } -} - int write_certificate_request(mbedtls_x509write_csr *req, const char *output_file, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) @@ -165,12 +153,13 @@ int main(int argc, char *argv[]) mbedtls_pk_context key; char buf[1024]; int i; - char *p, *q, *r, *r2; + char *p, *q, *r, *subtype_value; mbedtls_x509write_csr req; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; const char *pers = "csr example app"; mbedtls_x509_san_list *cur, *prev; + uint8_t ip[4] = { 0 }; /* * Set to sane values @@ -231,8 +220,6 @@ usage: prev = NULL; while (q != NULL) { - uint8_t ip[4] = { 0 }; - if ((r = strchr(q, ';')) != NULL) { *r++ = '\0'; } @@ -245,8 +232,8 @@ usage: cur->next = NULL; - if ((r2 = strchr(q, ':')) != NULL) { - *r2++ = '\0'; + if ((subtype_value = strchr(q, ':')) != NULL) { + *subtype_value++ = '\0'; } if (strcmp(q, "URI") == 0) { @@ -254,8 +241,12 @@ usage: } else if (strcmp(q, "DNS") == 0) { cur->node.type = MBEDTLS_X509_SAN_DNS_NAME; } else if (strcmp(q, "IP") == 0) { + size_t ip_len = 0; cur->node.type = MBEDTLS_X509_SAN_IP_ADDRESS; - ip_string_to_bytes(r2, ip, 4); + ip_len = mbedtls_x509_crt_parse_cn_inet_pton(subtype_value, ip); + if (ip_len == 0) { + goto exit; + } } else { mbedtls_free(cur); goto usage; @@ -265,7 +256,7 @@ usage: cur->node.san.unstructured_name.p = (unsigned char *) ip; cur->node.san.unstructured_name.len = sizeof(ip); } else { - q = r2; + q = subtype_value; cur->node.san.unstructured_name.p = (unsigned char *) q; cur->node.san.unstructured_name.len = strlen(q); } diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c index e4f8886fe..e58f52853 100644 --- a/programs/x509/cert_write.c +++ b/programs/x509/cert_write.c @@ -216,18 +216,6 @@ struct options { int format; /* format */ } opt; -static void ip_string_to_bytes(const char *str, uint8_t *bytes, int maxBytes) -{ - for (int i = 0; i < maxBytes; i++) { - bytes[i] = (uint8_t) strtoul(str, NULL, 10); - str = strchr(str, '.'); - if (str == NULL || *str == '\0') { - break; - } - str++; - } -} - int write_certificate(mbedtls_x509write_cert *crt, const char *output_file, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) @@ -601,8 +589,14 @@ usage: } else if (strcmp(q, "DNS") == 0) { cur->node.type = MBEDTLS_X509_SAN_DNS_NAME; } else if (strcmp(q, "IP") == 0) { + size_t ip_len = 0; cur->node.type = MBEDTLS_X509_SAN_IP_ADDRESS; - ip_string_to_bytes(subtype_value, ip, 4); + ip_len = mbedtls_x509_crt_parse_cn_inet_pton(subtype_value, ip); + if (ip_len == 0) { + mbedtls_printf("mbedtls_x509_crt_parse_cn_inet_pton failed to parse %s\n", + subtype_value); + goto exit; + } cur->node.san.unstructured_name.p = (unsigned char *) ip; cur->node.san.unstructured_name.len = sizeof(ip); } else if (strcmp(q, "DN") == 0) { @@ -625,8 +619,9 @@ usage: if (cur->node.type == MBEDTLS_X509_SAN_RFC822_NAME || cur->node.type == MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER || cur->node.type == MBEDTLS_X509_SAN_DNS_NAME) { - cur->node.san.unstructured_name.p = (unsigned char *) subtype_value; - cur->node.san.unstructured_name.len = strlen(subtype_value); + q = subtype_value; + cur->node.san.unstructured_name.p = (unsigned char *) q; + cur->node.san.unstructured_name.len = strlen(q); } if (prev == NULL) {