2009-01-03 22:22:43 +01:00
|
|
|
/*
|
2014-06-12 22:34:55 +02:00
|
|
|
* X.509 certificate parsing and verification
|
2009-01-03 22:22:43 +01:00
|
|
|
*
|
2020-08-07 13:07:28 +02:00
|
|
|
* Copyright The Mbed TLS Contributors
|
2015-09-04 14:21:07 +02:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2010-07-18 22:36:00 +02:00
|
|
|
*
|
2015-09-04 14:21:07 +02:00
|
|
|
* 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
|
2010-07-18 22:36:00 +02:00
|
|
|
*
|
2015-09-04 14:21:07 +02:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2009-01-03 22:22:43 +01:00
|
|
|
*
|
2015-09-04 14:21:07 +02:00
|
|
|
* 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.
|
2009-01-03 22:22:43 +01:00
|
|
|
*/
|
|
|
|
/*
|
2012-02-16 16:28:14 +01:00
|
|
|
* The ITU-T X.509 standard defines a certificate format for PKI.
|
2009-01-03 22:22:43 +01:00
|
|
|
*
|
2014-06-12 22:34:55 +02:00
|
|
|
* http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs)
|
|
|
|
* http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs)
|
|
|
|
* http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10)
|
2009-01-03 22:22:43 +01:00
|
|
|
*
|
|
|
|
* http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
|
|
|
|
* http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
|
2017-07-03 18:30:43 +02:00
|
|
|
*
|
|
|
|
* [SIRO] https://cabforum.org/wp-content/uploads/Chunghwatelecom201503cabforumV4.pdf
|
2009-01-03 22:22:43 +01:00
|
|
|
*/
|
|
|
|
|
2020-06-03 01:43:33 +02:00
|
|
|
#include "common.h"
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_X509_CRT_PARSE_C)
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2015-03-09 18:05:11 +01:00
|
|
|
#include "mbedtls/x509_crt.h"
|
2019-12-18 16:07:04 +01:00
|
|
|
#include "mbedtls/error.h"
|
2015-03-09 18:05:11 +01:00
|
|
|
#include "mbedtls/oid.h"
|
2018-04-17 16:51:09 +02:00
|
|
|
#include "mbedtls/platform_util.h"
|
2015-02-06 14:43:58 +01:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_PEM_PARSE_C)
|
2015-03-09 18:05:11 +01:00
|
|
|
#include "mbedtls/pem.h"
|
2013-09-15 20:43:33 +02:00
|
|
|
#endif
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2018-10-31 11:18:39 +01:00
|
|
|
#if defined(MBEDTLS_USE_PSA_CRYPTO)
|
|
|
|
#include "psa/crypto.h"
|
|
|
|
#include "mbedtls/psa_util.h"
|
2022-02-07 14:40:55 +01:00
|
|
|
#endif /* MBEDTLS_USE_PSA_CRYPTO */
|
2022-09-06 13:08:28 +02:00
|
|
|
#include "hash_info.h"
|
2018-10-31 11:18:39 +01:00
|
|
|
|
2015-03-09 18:05:11 +01:00
|
|
|
#include "mbedtls/platform.h"
|
2013-07-03 13:37:05 +02:00
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_THREADING_C)
|
2015-03-09 18:05:11 +01:00
|
|
|
#include "mbedtls/threading.h"
|
2013-11-28 17:11:54 +01:00
|
|
|
#endif
|
|
|
|
|
2020-05-28 03:43:41 +02:00
|
|
|
#if defined(MBEDTLS_HAVE_TIME)
|
2013-10-28 18:48:30 +01:00
|
|
|
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
|
2011-11-18 15:26:47 +01:00
|
|
|
#include <windows.h>
|
|
|
|
#else
|
2009-01-03 22:22:43 +01:00
|
|
|
#include <time.h>
|
2011-11-18 15:26:47 +01:00
|
|
|
#endif
|
2020-05-28 03:43:41 +02:00
|
|
|
#endif
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_FS_IO)
|
2015-02-06 14:43:58 +01:00
|
|
|
#include <stdio.h>
|
2014-04-04 15:08:20 +02:00
|
|
|
#if !defined(_WIN32) || defined(EFIX64) || defined(EFI32)
|
2012-06-04 14:46:42 +02:00
|
|
|
#include <sys/types.h>
|
2013-06-24 19:22:42 +02:00
|
|
|
#include <sys/stat.h>
|
2021-05-04 11:47:36 +02:00
|
|
|
#if defined(__MBED__)
|
|
|
|
#include <platform/mbed_retarget.h>
|
|
|
|
#else
|
2012-06-04 14:46:42 +02:00
|
|
|
#include <dirent.h>
|
2021-05-04 11:47:36 +02:00
|
|
|
#endif /* __MBED__ */
|
2019-04-25 18:43:26 +02:00
|
|
|
#include <errno.h>
|
2015-02-06 14:43:58 +01:00
|
|
|
#endif /* !_WIN32 || EFIX64 || EFI32 */
|
2011-04-25 17:28:35 +02:00
|
|
|
#endif
|
|
|
|
|
2017-07-05 13:28:45 +02:00
|
|
|
/*
|
|
|
|
* Item in a verification chain: cert and flags for it
|
|
|
|
*/
|
|
|
|
typedef struct {
|
|
|
|
mbedtls_x509_crt *crt;
|
|
|
|
uint32_t flags;
|
|
|
|
} x509_crt_verify_chain_item;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Max size of verification chain: end-entity + intermediates + trusted root
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
#define X509_MAX_VERIFY_CHAIN_SIZE (MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2)
|
2014-06-13 17:20:13 +02:00
|
|
|
|
2021-06-02 00:03:26 +02:00
|
|
|
/* Default profile. Do not remove items unless there are serious security
|
|
|
|
* concerns. */
|
2015-06-15 14:34:59 +02:00
|
|
|
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default =
|
|
|
|
{
|
2021-06-02 00:05:29 +02:00
|
|
|
/* Hashes from SHA-256 and above. Note that this selection
|
|
|
|
* should be aligned with ssl_preset_default_hashes in ssl_tls.c. */
|
2023-01-11 14:50:10 +01:00
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
|
2015-06-15 15:33:19 +02:00
|
|
|
0xFFFFFFF, /* Any PK alg */
|
2015-06-15 14:34:59 +02:00
|
|
|
#if defined(MBEDTLS_ECP_C)
|
2021-06-02 00:05:29 +02:00
|
|
|
/* Curves at or above 128-bit security level. Note that this selection
|
|
|
|
* should be aligned with ssl_preset_default_curves in ssl_tls.c. */
|
2023-01-11 14:50:10 +01:00
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP521R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP256R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP384R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP512R1) |
|
2021-06-17 23:17:52 +02:00
|
|
|
0,
|
2015-06-15 14:34:59 +02:00
|
|
|
#else
|
2015-06-15 15:33:19 +02:00
|
|
|
0,
|
2015-06-15 14:34:59 +02:00
|
|
|
#endif
|
|
|
|
2048,
|
|
|
|
};
|
|
|
|
|
2021-06-02 00:03:26 +02:00
|
|
|
/* Next-generation profile. Currently identical to the default, but may
|
|
|
|
* be tightened at any time. */
|
|
|
|
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next =
|
2021-06-02 00:33:33 +02:00
|
|
|
{
|
|
|
|
/* Hashes from SHA-256 and above. */
|
2023-01-11 14:50:10 +01:00
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
|
2021-06-02 00:33:33 +02:00
|
|
|
0xFFFFFFF, /* Any PK alg */
|
|
|
|
#if defined(MBEDTLS_ECP_C)
|
|
|
|
/* Curves at or above 128-bit security level. */
|
2023-01-11 14:50:10 +01:00
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP521R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP256R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP384R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_BP512R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256K1),
|
2021-06-02 00:33:33 +02:00
|
|
|
#else
|
|
|
|
0,
|
|
|
|
#endif
|
|
|
|
2048,
|
|
|
|
};
|
2021-06-02 00:03:26 +02:00
|
|
|
|
2015-06-15 14:34:59 +02:00
|
|
|
/*
|
|
|
|
* NSA Suite B Profile
|
|
|
|
*/
|
2015-06-15 15:33:19 +02:00
|
|
|
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb =
|
2015-06-15 14:34:59 +02:00
|
|
|
{
|
2015-06-15 15:33:19 +02:00
|
|
|
/* Only SHA-256 and 384 */
|
2023-01-11 14:50:10 +01:00
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384),
|
2015-06-15 15:33:19 +02:00
|
|
|
/* Only ECDSA */
|
2023-01-11 14:50:10 +01:00
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECDSA) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECKEY),
|
2015-06-15 14:34:59 +02:00
|
|
|
#if defined(MBEDTLS_ECP_C)
|
2015-06-15 15:33:19 +02:00
|
|
|
/* Only NIST P-256 and P-384 */
|
2023-01-11 14:50:10 +01:00
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP256R1) |
|
|
|
|
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1),
|
2015-06-15 14:34:59 +02:00
|
|
|
#else
|
2015-06-15 15:33:19 +02:00
|
|
|
0,
|
2015-06-15 14:34:59 +02:00
|
|
|
#endif
|
2015-06-15 15:33:19 +02:00
|
|
|
0,
|
2015-06-15 14:34:59 +02:00
|
|
|
};
|
|
|
|
|
2021-06-18 09:48:27 +02:00
|
|
|
/*
|
|
|
|
* Empty / all-forbidden profile
|
|
|
|
*/
|
|
|
|
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_none =
|
|
|
|
{
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
(uint32_t) -1,
|
|
|
|
};
|
|
|
|
|
2015-06-15 16:17:55 +02:00
|
|
|
/*
|
|
|
|
* Check md_alg against profile
|
2017-10-26 10:24:16 +02:00
|
|
|
* Return 0 if md_alg is acceptable for this profile, -1 otherwise
|
2015-06-15 16:17:55 +02:00
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_profile_check_md_alg(const mbedtls_x509_crt_profile *profile,
|
|
|
|
mbedtls_md_type_t md_alg)
|
2015-06-15 16:17:55 +02:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
if (md_alg == MBEDTLS_MD_NONE) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-05-11 11:06:29 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((profile->allowed_mds & MBEDTLS_X509_ID_FLAG(md_alg)) != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-15 16:17:55 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2015-06-15 16:17:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check pk_alg against profile
|
2017-10-26 10:24:16 +02:00
|
|
|
* Return 0 if pk_alg is acceptable for this profile, -1 otherwise
|
2015-06-15 16:17:55 +02:00
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_profile_check_pk_alg(const mbedtls_x509_crt_profile *profile,
|
|
|
|
mbedtls_pk_type_t pk_alg)
|
2015-06-15 16:17:55 +02:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
if (pk_alg == MBEDTLS_PK_NONE) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-05-11 11:06:29 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((profile->allowed_pks & MBEDTLS_X509_ID_FLAG(pk_alg)) != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-15 16:17:55 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2015-06-15 16:17:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check key against profile
|
2017-10-26 10:24:16 +02:00
|
|
|
* Return 0 if pk is acceptable for this profile, -1 otherwise
|
2015-06-15 16:17:55 +02:00
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_profile_check_key(const mbedtls_x509_crt_profile *profile,
|
|
|
|
const mbedtls_pk_context *pk)
|
2015-06-15 16:17:55 +02:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type(pk);
|
2017-10-24 10:51:26 +02:00
|
|
|
|
2015-06-15 16:17:55 +02:00
|
|
|
#if defined(MBEDTLS_RSA_C)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS) {
|
|
|
|
if (mbedtls_pk_get_bitlen(pk) >= profile->rsa_min_bitlen) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-15 16:17:55 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2015-06-15 16:17:55 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-10-23 14:08:48 +02:00
|
|
|
#if defined(MBEDTLS_ECP_C)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (pk_alg == MBEDTLS_PK_ECDSA ||
|
2015-10-23 14:08:48 +02:00
|
|
|
pk_alg == MBEDTLS_PK_ECKEY ||
|
2023-01-11 14:50:10 +01:00
|
|
|
pk_alg == MBEDTLS_PK_ECKEY_DH) {
|
|
|
|
const mbedtls_ecp_group_id gid = mbedtls_pk_ec(*pk)->grp.id;
|
2015-06-15 16:17:55 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (gid == MBEDTLS_ECP_DP_NONE) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-05-11 11:06:29 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((profile->allowed_curves & MBEDTLS_X509_ID_FLAG(gid)) != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-15 16:17:55 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2015-06-15 16:17:55 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2015-06-15 16:17:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-02 10:19:16 +01:00
|
|
|
/*
|
|
|
|
* Like memcmp, but case-insensitive and always returns -1 if different
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_memcasecmp(const void *s1, const void *s2, size_t len)
|
2018-11-02 10:19:16 +01:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
unsigned char diff;
|
|
|
|
const unsigned char *n1 = s1, *n2 = s2;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
for (i = 0; i < len; i++) {
|
2018-11-02 10:19:16 +01:00
|
|
|
diff = n1[i] ^ n2[i];
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (diff == 0) {
|
2018-11-02 10:19:16 +01:00
|
|
|
continue;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2018-11-02 10:19:16 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (diff == 32 &&
|
|
|
|
((n1[i] >= 'a' && n1[i] <= 'z') ||
|
|
|
|
(n1[i] >= 'A' && n1[i] <= 'Z'))) {
|
2018-11-02 10:19:16 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2018-11-02 10:19:16 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2018-11-02 10:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return 0 if name matches wildcard, -1 otherwise
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_check_wildcard(const char *cn, const mbedtls_x509_buf *name)
|
2018-11-02 10:19:16 +01:00
|
|
|
{
|
|
|
|
size_t i;
|
2023-01-11 14:50:10 +01:00
|
|
|
size_t cn_idx = 0, cn_len = strlen(cn);
|
2018-11-02 10:19:16 +01:00
|
|
|
|
|
|
|
/* We can't have a match if there is no wildcard to match */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (name->len < 3 || name->p[0] != '*' || name->p[1] != '.') {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-11-02 10:19:16 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
for (i = 0; i < cn_len; ++i) {
|
|
|
|
if (cn[i] == '.') {
|
2018-11-02 10:19:16 +01:00
|
|
|
cn_idx = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (cn_idx == 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-11-02 10:19:16 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (cn_len - cn_idx == name->len - 1 &&
|
|
|
|
x509_memcasecmp(name->p + 1, cn + cn_idx, name->len - 1) == 0) {
|
|
|
|
return 0;
|
2018-11-02 10:19:16 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2018-11-02 10:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare two X.509 strings, case-insensitive, and allowing for some encoding
|
|
|
|
* variations (but not all).
|
|
|
|
*
|
|
|
|
* Return 0 if equal, -1 otherwise.
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_string_cmp(const mbedtls_x509_buf *a, const mbedtls_x509_buf *b)
|
2018-11-02 10:19:16 +01:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
if (a->tag == b->tag &&
|
2018-11-02 10:19:16 +01:00
|
|
|
a->len == b->len &&
|
2023-01-11 14:50:10 +01:00
|
|
|
memcmp(a->p, b->p, b->len) == 0) {
|
|
|
|
return 0;
|
2018-11-02 10:19:16 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING) &&
|
|
|
|
(b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING) &&
|
2018-11-02 10:19:16 +01:00
|
|
|
a->len == b->len &&
|
2023-01-11 14:50:10 +01:00
|
|
|
x509_memcasecmp(a->p, b->p, b->len) == 0) {
|
|
|
|
return 0;
|
2018-11-02 10:19:16 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2018-11-02 10:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare two X.509 Names (aka rdnSequence).
|
|
|
|
*
|
|
|
|
* See RFC 5280 section 7.1, though we don't implement the whole algorithm:
|
|
|
|
* we sometimes return unequal when the full algorithm would return equal,
|
|
|
|
* but never the other way. (In particular, we don't do Unicode normalisation
|
|
|
|
* or space folding.)
|
|
|
|
*
|
|
|
|
* Return 0 if equal, -1 otherwise.
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_name_cmp(const mbedtls_x509_name *a, const mbedtls_x509_name *b)
|
2018-11-02 10:19:16 +01:00
|
|
|
{
|
|
|
|
/* Avoid recursion, it might not be optimised by the compiler */
|
2023-01-11 14:50:10 +01:00
|
|
|
while (a != NULL || b != NULL) {
|
|
|
|
if (a == NULL || b == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-11-02 10:19:16 +01:00
|
|
|
|
|
|
|
/* type */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (a->oid.tag != b->oid.tag ||
|
2018-11-02 10:19:16 +01:00
|
|
|
a->oid.len != b->oid.len ||
|
2023-01-11 14:50:10 +01:00
|
|
|
memcmp(a->oid.p, b->oid.p, b->oid.len) != 0) {
|
|
|
|
return -1;
|
2018-11-02 10:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* value */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_string_cmp(&a->val, &b->val) != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-11-02 10:19:16 +01:00
|
|
|
|
|
|
|
/* structure of the list of sets */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (a->next_merged != b->next_merged) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-11-02 10:19:16 +01:00
|
|
|
|
|
|
|
a = a->next;
|
|
|
|
b = b->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* a == NULL == b */
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2018-11-02 10:19:16 +01:00
|
|
|
}
|
|
|
|
|
2017-08-23 10:55:41 +02:00
|
|
|
/*
|
|
|
|
* Reset (init or clear) a verify_chain
|
|
|
|
*/
|
|
|
|
static void x509_crt_verify_chain_reset(
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_x509_crt_verify_chain *ver_chain)
|
2017-08-23 10:55:41 +02:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
for (i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++) {
|
2017-08-23 10:55:41 +02:00
|
|
|
ver_chain->items[i].crt = NULL;
|
2019-01-10 10:19:26 +01:00
|
|
|
ver_chain->items[i].flags = (uint32_t) -1;
|
2017-08-23 10:55:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ver_chain->len = 0;
|
2019-03-28 14:45:55 +01:00
|
|
|
|
|
|
|
#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
|
|
|
|
ver_chain->trust_ca_cb_result = NULL;
|
|
|
|
#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
|
2017-08-23 10:55:41 +02:00
|
|
|
}
|
|
|
|
|
2009-01-03 22:22:43 +01:00
|
|
|
/*
|
|
|
|
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_get_version(unsigned char **p,
|
|
|
|
const unsigned char *end,
|
|
|
|
int *ver)
|
2009-01-03 22:22:43 +01:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2011-04-24 10:57:21 +02:00
|
|
|
size_t len;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
|
|
|
|
0)) != 0) {
|
|
|
|
if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
|
2011-10-19 16:15:17 +02:00
|
|
|
*ver = 0;
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2011-10-19 16:15:17 +02:00
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
end = *p + len;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_int(p, end, ver)) != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION, ret);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p != end) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
2009-05-02 17:13:40 +02:00
|
|
|
/*
|
|
|
|
* Validity ::= SEQUENCE {
|
|
|
|
* notBefore Time,
|
|
|
|
* notAfter Time }
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_get_dates(unsigned char **p,
|
|
|
|
const unsigned char *end,
|
|
|
|
mbedtls_x509_time *from,
|
|
|
|
mbedtls_x509_time *to)
|
2009-05-02 17:13:40 +02:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2011-04-24 10:57:21 +02:00
|
|
|
size_t len;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE, ret);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2009-05-02 17:13:40 +02:00
|
|
|
end = *p + len;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_x509_get_time(p, end, from)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2009-05-02 17:13:40 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_x509_get_time(p, end, to)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p != end) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* X.509 v2/v3 unique identifier (not parsed)
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_get_uid(unsigned char **p,
|
|
|
|
const unsigned char *end,
|
|
|
|
mbedtls_x509_buf *uid, int n)
|
2009-01-03 22:22:43 +01:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p == end) {
|
|
|
|
return 0;
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
|
|
|
uid->tag = **p;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &uid->len,
|
|
|
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
|
|
|
|
n)) != 0) {
|
|
|
|
if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
|
|
|
|
return 0;
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
uid->p = *p;
|
|
|
|
*p += uid->len;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_get_basic_constraints(unsigned char **p,
|
|
|
|
const unsigned char *end,
|
|
|
|
int *ca_istrue,
|
|
|
|
int *max_pathlen)
|
2009-01-03 22:22:43 +01:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2011-04-24 10:57:21 +02:00
|
|
|
size_t len;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
|
|
|
/*
|
2013-09-16 13:49:26 +02:00
|
|
|
* BasicConstraints ::= SEQUENCE {
|
|
|
|
* cA BOOLEAN DEFAULT FALSE,
|
|
|
|
* pathLenConstraint INTEGER (0..MAX) OPTIONAL }
|
2009-01-03 22:22:43 +01:00
|
|
|
*/
|
2013-09-16 13:49:26 +02:00
|
|
|
*ca_istrue = 0; /* DEFAULT FALSE */
|
|
|
|
*max_pathlen = 0; /* endless */
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p == end) {
|
|
|
|
return 0;
|
|
|
|
}
|
2009-05-02 17:13:40 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_bool(p, end, ca_istrue)) != 0) {
|
|
|
|
if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
|
|
|
|
ret = mbedtls_asn1_get_int(p, end, ca_istrue);
|
|
|
|
}
|
2009-05-02 17:13:40 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ret != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2009-05-02 17:13:40 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*ca_istrue != 0) {
|
2013-09-16 13:49:26 +02:00
|
|
|
*ca_istrue = 1;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p == end) {
|
|
|
|
return 0;
|
|
|
|
}
|
2013-09-16 13:49:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_int(p, end, max_pathlen)) != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2013-09-16 13:49:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p != end) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
|
|
|
}
|
2009-05-02 17:13:40 +02:00
|
|
|
|
2020-04-14 15:49:52 +02:00
|
|
|
/* Do not accept max_pathlen equal to INT_MAX to avoid a signed integer
|
|
|
|
* overflow, which is an undefined behavior. */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*max_pathlen == INT_MAX) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_INVALID_LENGTH);
|
|
|
|
}
|
2020-04-14 15:49:52 +02:00
|
|
|
|
2013-09-16 13:49:26 +02:00
|
|
|
(*max_pathlen)++;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2011-01-15 17:57:55 +01:00
|
|
|
* ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
|
|
|
|
*
|
|
|
|
* KeyPurposeId ::= OBJECT IDENTIFIER
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_get_ext_key_usage(unsigned char **p,
|
|
|
|
const unsigned char *end,
|
|
|
|
mbedtls_x509_sequence *ext_key_usage)
|
2011-01-15 17:57:55 +01:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2011-01-15 17:57:55 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_sequence_of(p, end, ext_key_usage, MBEDTLS_ASN1_OID)) != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2011-01-15 17:57:55 +01:00
|
|
|
|
|
|
|
/* Sequence length must be >= 1 */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ext_key_usage->buf.p == NULL) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_INVALID_LENGTH);
|
|
|
|
}
|
2011-01-15 17:57:55 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2011-01-15 17:57:55 +01:00
|
|
|
}
|
|
|
|
|
2021-02-12 16:11:17 +01:00
|
|
|
/*
|
|
|
|
* SubjectKeyIdentifier ::= KeyIdentifier
|
|
|
|
*
|
|
|
|
* KeyIdentifier ::= OCTET STRING
|
|
|
|
*/
|
|
|
|
static int x509_get_subject_key_id(unsigned char **p,
|
|
|
|
const unsigned char *end,
|
|
|
|
mbedtls_x509_buf *subject_key_id)
|
|
|
|
{
|
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
|
|
size_t len = 0u;
|
|
|
|
|
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
|
|
|
|
MBEDTLS_ASN1_OCTET_STRING)) != 0) {
|
2023-02-01 11:31:32 +01:00
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
2021-02-12 16:11:17 +01:00
|
|
|
} else {
|
|
|
|
subject_key_id->len = len;
|
|
|
|
subject_key_id->tag = MBEDTLS_ASN1_OCTET_STRING;
|
|
|
|
subject_key_id->p = *p;
|
|
|
|
*p += len;
|
|
|
|
}
|
|
|
|
|
2021-04-27 15:41:25 +02:00
|
|
|
if (*p != end) {
|
2023-01-30 14:38:18 +01:00
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
2021-04-27 15:41:25 +02:00
|
|
|
}
|
|
|
|
|
2021-02-12 16:11:17 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-05-10 15:16:33 +02:00
|
|
|
/*
|
|
|
|
* AuthorityKeyIdentifier ::= SEQUENCE {
|
|
|
|
* keyIdentifier [0] KeyIdentifier OPTIONAL,
|
|
|
|
* authorityCertIssuer [1] GeneralNames OPTIONAL,
|
|
|
|
* authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
|
|
|
|
*
|
|
|
|
* KeyIdentifier ::= OCTET STRING
|
|
|
|
*/
|
|
|
|
static int x509_get_authority_key_id(unsigned char **p,
|
|
|
|
unsigned char *end,
|
|
|
|
mbedtls_x509_authority *authority_key_id)
|
|
|
|
{
|
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
|
|
size_t len = 0u;
|
|
|
|
|
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
|
2023-01-30 14:38:18 +01:00
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
|
2023-02-01 11:31:32 +01:00
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
2021-05-10 15:16:33 +02:00
|
|
|
}
|
|
|
|
|
2023-02-01 11:06:08 +01:00
|
|
|
if (*p + len != end) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
|
|
|
}
|
|
|
|
|
2021-05-10 15:16:33 +02:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC)) != 0) {
|
|
|
|
/* KeyIdentifier is an OPTIONAL field */
|
|
|
|
} else {
|
|
|
|
authority_key_id->keyIdentifier.len = len;
|
|
|
|
authority_key_id->keyIdentifier.p = *p;
|
2021-05-11 12:55:58 +02:00
|
|
|
/* Setting tag of the keyIdentfier intentionally to 0x04.
|
|
|
|
* Although the .keyIdentfier field is CONTEXT_SPECIFIC ([0] OPTIONAL),
|
2023-04-17 16:06:57 +02:00
|
|
|
* its tag with the content is the payload of on OCTET STRING primitive */
|
2021-05-10 15:16:33 +02:00
|
|
|
authority_key_id->keyIdentifier.tag = MBEDTLS_ASN1_OCTET_STRING;
|
|
|
|
|
|
|
|
*p += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*p < end) {
|
2021-05-11 12:55:58 +02:00
|
|
|
/* Getting authorityCertIssuer using the required specific class tag [1] */
|
2021-05-10 15:16:33 +02:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
|
2023-02-03 15:03:59 +01:00
|
|
|
1)) != 0) {
|
2023-04-26 08:55:26 +02:00
|
|
|
/* authorityCertIssuer and authorityCertSerialNumber MUST both
|
|
|
|
be present or both be absent. At this point we expect to have both. */
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
2021-05-10 15:16:33 +02:00
|
|
|
} else {
|
2023-02-03 15:03:59 +01:00
|
|
|
/* "end" also includes the CertSerialNumber field so "len" shall be used */
|
2023-04-04 22:49:44 +02:00
|
|
|
ret = mbedtls_x509_get_subject_alt_name_ext(p,
|
|
|
|
(*p+len),
|
|
|
|
&authority_key_id->authorityCertIssuer);
|
2023-04-26 08:55:26 +02:00
|
|
|
if (ret != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2021-05-10 15:16:33 +02:00
|
|
|
|
2023-04-26 08:55:26 +02:00
|
|
|
/* Getting authorityCertSerialNumber using the required specific class tag [2] */
|
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
|
2023-05-03 16:19:16 +02:00
|
|
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2)) != 0) {
|
2023-04-26 08:55:26 +02:00
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
} else {
|
|
|
|
authority_key_id->authorityCertSerialNumber.len = len;
|
|
|
|
authority_key_id->authorityCertSerialNumber.p = *p;
|
2023-05-03 16:19:16 +02:00
|
|
|
authority_key_id->authorityCertSerialNumber.tag = MBEDTLS_ASN1_INTEGER;
|
2023-04-26 08:55:26 +02:00
|
|
|
*p += len;
|
|
|
|
}
|
2021-05-10 15:16:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*p != end) {
|
|
|
|
return MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-21 13:00:03 +01:00
|
|
|
/*
|
|
|
|
* id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 }
|
|
|
|
*
|
|
|
|
* anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 }
|
|
|
|
*
|
|
|
|
* certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
|
|
|
|
*
|
|
|
|
* PolicyInformation ::= SEQUENCE {
|
|
|
|
* policyIdentifier CertPolicyId,
|
|
|
|
* policyQualifiers SEQUENCE SIZE (1..MAX) OF
|
|
|
|
* PolicyQualifierInfo OPTIONAL }
|
|
|
|
*
|
|
|
|
* CertPolicyId ::= OBJECT IDENTIFIER
|
|
|
|
*
|
|
|
|
* PolicyQualifierInfo ::= SEQUENCE {
|
|
|
|
* policyQualifierId PolicyQualifierId,
|
|
|
|
* qualifier ANY DEFINED BY policyQualifierId }
|
|
|
|
*
|
|
|
|
* -- policyQualifierIds for Internet policy qualifiers
|
|
|
|
*
|
|
|
|
* id-qt OBJECT IDENTIFIER ::= { id-pkix 2 }
|
|
|
|
* id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 }
|
|
|
|
* id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 }
|
|
|
|
*
|
|
|
|
* PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
|
|
|
|
*
|
|
|
|
* Qualifier ::= CHOICE {
|
|
|
|
* cPSuri CPSuri,
|
|
|
|
* userNotice UserNotice }
|
|
|
|
*
|
|
|
|
* CPSuri ::= IA5String
|
|
|
|
*
|
|
|
|
* UserNotice ::= SEQUENCE {
|
|
|
|
* noticeRef NoticeReference OPTIONAL,
|
|
|
|
* explicitText DisplayText OPTIONAL }
|
|
|
|
*
|
|
|
|
* NoticeReference ::= SEQUENCE {
|
|
|
|
* organization DisplayText,
|
|
|
|
* noticeNumbers SEQUENCE OF INTEGER }
|
|
|
|
*
|
|
|
|
* DisplayText ::= CHOICE {
|
|
|
|
* ia5String IA5String (SIZE (1..200)),
|
|
|
|
* visibleString VisibleString (SIZE (1..200)),
|
|
|
|
* bmpString BMPString (SIZE (1..200)),
|
|
|
|
* utf8String UTF8String (SIZE (1..200)) }
|
|
|
|
*
|
|
|
|
* NOTE: we only parse and use anyPolicy without qualifiers at this point
|
|
|
|
* as defined in RFC 5280.
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_get_certificate_policies(unsigned char **p,
|
|
|
|
const unsigned char *end,
|
|
|
|
mbedtls_x509_sequence *certificate_policies)
|
2019-03-21 13:00:03 +01:00
|
|
|
{
|
2019-05-15 11:20:00 +02:00
|
|
|
int ret, parse_ret = 0;
|
2019-03-21 13:00:03 +01:00
|
|
|
size_t len;
|
|
|
|
mbedtls_asn1_buf *buf;
|
|
|
|
mbedtls_asn1_sequence *cur = certificate_policies;
|
|
|
|
|
|
|
|
/* Get main sequence tag */
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_asn1_get_tag(p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
|
|
|
|
if (ret != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p + len != end) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Cannot be an empty sequence.
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (len == 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while (*p < end) {
|
2019-03-21 13:00:03 +01:00
|
|
|
mbedtls_x509_buf policy_oid;
|
|
|
|
const unsigned char *policy_end;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the policy sequence
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
|
|
|
|
policy_end = *p + len;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, policy_end, &len,
|
|
|
|
MBEDTLS_ASN1_OID)) != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
|
|
|
|
policy_oid.tag = MBEDTLS_ASN1_OID;
|
|
|
|
policy_oid.len = len;
|
|
|
|
policy_oid.p = *p;
|
|
|
|
|
2019-05-15 11:20:00 +02:00
|
|
|
/*
|
|
|
|
* Only AnyPolicy is currently supported when enforcing policy.
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (MBEDTLS_OID_CMP(MBEDTLS_OID_ANY_POLICY, &policy_oid) != 0) {
|
2019-05-15 11:20:00 +02:00
|
|
|
/*
|
|
|
|
* Set the parsing return code but continue parsing, in case this
|
2021-05-11 18:22:05 +02:00
|
|
|
* extension is critical.
|
2019-05-15 11:20:00 +02:00
|
|
|
*/
|
|
|
|
parse_ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
|
|
|
|
}
|
|
|
|
|
2019-03-21 13:00:03 +01:00
|
|
|
/* Allocate and assign next pointer */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (cur->buf.p != NULL) {
|
|
|
|
if (cur->next != NULL) {
|
|
|
|
return MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
|
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
cur->next = mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
|
2019-03-21 13:00:03 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (cur->next == NULL) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_ALLOC_FAILED);
|
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
buf = &(cur->buf);
|
2019-03-21 13:00:03 +01:00
|
|
|
buf->tag = policy_oid.tag;
|
|
|
|
buf->p = policy_oid.p;
|
|
|
|
buf->len = policy_oid.len;
|
2019-05-13 15:38:39 +02:00
|
|
|
|
|
|
|
*p += len;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
/*
|
|
|
|
* If there is an optional qualifier, then *p < policy_end
|
|
|
|
* Check the Qualifier len to verify it doesn't exceed policy_end.
|
|
|
|
*/
|
|
|
|
if (*p < policy_end) {
|
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, policy_end, &len,
|
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) !=
|
|
|
|
0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2019-05-13 15:38:39 +02:00
|
|
|
/*
|
|
|
|
* Skip the optional policy qualifiers.
|
|
|
|
*/
|
|
|
|
*p += len;
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p != policy_end) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set final sequence entry's next pointer to NULL */
|
|
|
|
cur->next = NULL;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p != end) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return parse_ret;
|
2019-03-21 13:00:03 +01:00
|
|
|
}
|
|
|
|
|
2011-01-15 17:57:55 +01:00
|
|
|
/*
|
|
|
|
* X.509 v3 extensions
|
|
|
|
*
|
2009-05-02 17:13:40 +02:00
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_get_crt_ext(unsigned char **p,
|
|
|
|
const unsigned char *end,
|
|
|
|
mbedtls_x509_crt *crt,
|
|
|
|
mbedtls_x509_crt_ext_cb_t cb,
|
|
|
|
void *p_ctx)
|
2009-05-02 17:13:40 +02:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2011-04-24 10:57:21 +02:00
|
|
|
size_t len;
|
2020-06-13 11:08:16 +02:00
|
|
|
unsigned char *end_ext_data, *start_ext_octet, *end_ext_octet;
|
2009-05-02 17:13:40 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p == end) {
|
|
|
|
return 0;
|
|
|
|
}
|
Obey bounds of ASN.1 substructures
When parsing a substructure of an ASN.1 structure, no field within
the substructure must exceed the bounds of the substructure.
Concretely, the `end` pointer passed to the ASN.1 parsing routines
must be updated to point to the end of the substructure while parsing
the latter.
This was previously not the case for the routines
- x509_get_attr_type_and_value(),
- mbedtls_x509_get_crt_ext(),
- mbedtls_x509_get_crl_ext().
These functions kept using the end of the parent structure as the
`end` pointer and would hence allow substructure fields to cross
the substructure boundary. This could lead to successful parsing
of ill-formed X.509 CRTs.
This commit fixes this.
Care has to be taken when adapting `mbedtls_x509_get_crt_ext()`
and `mbedtls_x509_get_crl_ext()`, as the underlying function
`mbedtls_x509_get_ext()` returns `0` if no extensions are present
but doesn't set the variable which holds the bounds of the Extensions
structure in case the latter is present. This commit addresses
this by returning early from `mbedtls_x509_get_crt_ext()` and
`mbedtls_x509_get_crl_ext()` if parsing has reached the end of
the input buffer.
The following X.509 parsing tests need to be adapted:
- "TBSCertificate, issuer two inner set datas"
This test exercises the X.509 CRT parser with a Subject name
which has two empty `AttributeTypeAndValue` structures.
This is supposed to fail with `MBEDTLS_ERR_ASN1_OUT_OF_DATA`
because the parser should attempt to parse the first structure
and fail because of a lack of data. Previously, it failed to
obey the (0-length) bounds of the first AttributeTypeAndValue
structure and would try to interpret the beginning of the second
AttributeTypeAndValue structure as the first field of the first
AttributeTypeAndValue structure, returning an UNEXPECTED_TAG error.
- "TBSCertificate, issuer, no full following string"
This test exercises the parser's behaviour on an AttributeTypeAndValue
structure which contains more data than expected; it should therefore
fail with MBEDTLS_ERR_ASN1_LENGTH_MISMATCH. Because of the missing bounds
check, it previously failed with UNEXPECTED_TAG because it interpreted
the remaining byte in the first AttributeTypeAndValue structure as the
first byte in the second AttributeTypeAndValue structure.
- "SubjectAltName repeated"
This test should exercise two SubjectAltNames extensions in succession,
but a wrong length values makes the second SubjectAltNames extension appear
outside of the Extensions structure. With the new bounds in place, this
therefore fails with a LENGTH_MISMATCH error. This commit adapts the test
data to put the 2nd SubjectAltNames extension inside the Extensions
structure, too.
2019-02-12 18:22:36 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_x509_get_ext(p, end, &crt->v3_ext, 3)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2009-05-02 17:13:40 +02:00
|
|
|
|
Obey bounds of ASN.1 substructures
When parsing a substructure of an ASN.1 structure, no field within
the substructure must exceed the bounds of the substructure.
Concretely, the `end` pointer passed to the ASN.1 parsing routines
must be updated to point to the end of the substructure while parsing
the latter.
This was previously not the case for the routines
- x509_get_attr_type_and_value(),
- mbedtls_x509_get_crt_ext(),
- mbedtls_x509_get_crl_ext().
These functions kept using the end of the parent structure as the
`end` pointer and would hence allow substructure fields to cross
the substructure boundary. This could lead to successful parsing
of ill-formed X.509 CRTs.
This commit fixes this.
Care has to be taken when adapting `mbedtls_x509_get_crt_ext()`
and `mbedtls_x509_get_crl_ext()`, as the underlying function
`mbedtls_x509_get_ext()` returns `0` if no extensions are present
but doesn't set the variable which holds the bounds of the Extensions
structure in case the latter is present. This commit addresses
this by returning early from `mbedtls_x509_get_crt_ext()` and
`mbedtls_x509_get_crl_ext()` if parsing has reached the end of
the input buffer.
The following X.509 parsing tests need to be adapted:
- "TBSCertificate, issuer two inner set datas"
This test exercises the X.509 CRT parser with a Subject name
which has two empty `AttributeTypeAndValue` structures.
This is supposed to fail with `MBEDTLS_ERR_ASN1_OUT_OF_DATA`
because the parser should attempt to parse the first structure
and fail because of a lack of data. Previously, it failed to
obey the (0-length) bounds of the first AttributeTypeAndValue
structure and would try to interpret the beginning of the second
AttributeTypeAndValue structure as the first field of the first
AttributeTypeAndValue structure, returning an UNEXPECTED_TAG error.
- "TBSCertificate, issuer, no full following string"
This test exercises the parser's behaviour on an AttributeTypeAndValue
structure which contains more data than expected; it should therefore
fail with MBEDTLS_ERR_ASN1_LENGTH_MISMATCH. Because of the missing bounds
check, it previously failed with UNEXPECTED_TAG because it interpreted
the remaining byte in the first AttributeTypeAndValue structure as the
first byte in the second AttributeTypeAndValue structure.
- "SubjectAltName repeated"
This test should exercise two SubjectAltNames extensions in succession,
but a wrong length values makes the second SubjectAltNames extension appear
outside of the Extensions structure. With the new bounds in place, this
therefore fails with a LENGTH_MISMATCH error. This commit adapts the test
data to put the 2nd SubjectAltNames extension inside the Extensions
structure, too.
2019-02-12 18:22:36 +01:00
|
|
|
end = crt->v3_ext.p + crt->v3_ext.len;
|
2023-01-11 14:50:10 +01:00
|
|
|
while (*p < end) {
|
2011-01-15 17:57:55 +01:00
|
|
|
/*
|
|
|
|
* Extension ::= SEQUENCE {
|
|
|
|
* extnID OBJECT IDENTIFIER,
|
|
|
|
* critical BOOLEAN DEFAULT FALSE,
|
|
|
|
* extnValue OCTET STRING }
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_x509_buf extn_oid = { 0, 0, NULL };
|
2011-01-15 17:57:55 +01:00
|
|
|
int is_critical = 0; /* DEFAULT FALSE */
|
2013-04-07 22:00:46 +02:00
|
|
|
int ext_type = 0;
|
2011-01-15 17:57:55 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2009-07-27 23:34:45 +02:00
|
|
|
end_ext_data = *p + len;
|
|
|
|
|
2011-01-15 17:57:55 +01:00
|
|
|
/* Get extension ID */
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &extn_oid.len,
|
|
|
|
MBEDTLS_ASN1_OID)) != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2018-07-24 12:50:59 +02:00
|
|
|
extn_oid.tag = MBEDTLS_ASN1_OID;
|
2011-01-15 17:57:55 +01:00
|
|
|
extn_oid.p = *p;
|
|
|
|
*p += extn_oid.len;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2011-01-15 17:57:55 +01:00
|
|
|
/* Get optional critical */
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_bool(p, end_ext_data, &is_critical)) != 0 &&
|
|
|
|
(ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2011-01-15 17:57:55 +01:00
|
|
|
/* Data should be octet string type */
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &len,
|
|
|
|
MBEDTLS_ASN1_OCTET_STRING)) != 0) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2020-06-13 11:08:16 +02:00
|
|
|
start_ext_octet = *p;
|
2009-07-27 23:34:45 +02:00
|
|
|
end_ext_octet = *p + len;
|
2010-03-16 22:09:09 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (end_ext_octet != end_ext_data) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2011-01-15 17:57:55 +01:00
|
|
|
/*
|
|
|
|
* Detect supported extensions
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_oid_get_x509_ext_type(&extn_oid, &ext_type);
|
2013-04-07 22:00:46 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ret != 0) {
|
2020-04-25 14:41:25 +02:00
|
|
|
/* Give the callback (if any) a chance to handle the extension */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (cb != NULL) {
|
|
|
|
ret = cb(p_ctx, crt, &extn_oid, is_critical, *p, end_ext_octet);
|
|
|
|
if (ret != 0 && is_critical) {
|
|
|
|
return ret;
|
|
|
|
}
|
2020-05-28 08:55:08 +02:00
|
|
|
*p = end_ext_octet;
|
2020-04-25 14:41:25 +02:00
|
|
|
continue;
|
2020-05-28 08:55:08 +02:00
|
|
|
}
|
2020-04-25 14:41:25 +02:00
|
|
|
|
2013-04-07 22:00:46 +02:00
|
|
|
/* No parser found, skip extension */
|
|
|
|
*p = end_ext_octet;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (is_critical) {
|
2013-04-07 22:00:46 +02:00
|
|
|
/* Data is marked as critical: fail */
|
2023-01-11 14:50:10 +01:00
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
|
2013-04-07 22:00:46 +02:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-11-12 17:47:28 +01:00
|
|
|
/* Forbid repeated extensions */
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((crt->ext_types & ext_type) != 0) {
|
|
|
|
return MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
|
|
|
|
}
|
2014-11-12 17:47:28 +01:00
|
|
|
|
2013-04-07 22:00:46 +02:00
|
|
|
crt->ext_types |= ext_type;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
switch (ext_type) {
|
|
|
|
case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS:
|
|
|
|
/* Parse basic constraints */
|
|
|
|
if ((ret = x509_get_basic_constraints(p, end_ext_octet,
|
|
|
|
&crt->ca_istrue, &crt->max_pathlen)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
break;
|
2013-04-07 22:00:46 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
case MBEDTLS_X509_EXT_KEY_USAGE:
|
|
|
|
/* Parse key usage */
|
2023-01-16 08:47:49 +01:00
|
|
|
if ((ret = mbedtls_x509_get_key_usage(p, end_ext_octet,
|
|
|
|
&crt->key_usage)) != 0) {
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
break;
|
2013-04-07 22:00:46 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE:
|
|
|
|
/* Parse extended key usage */
|
|
|
|
if ((ret = x509_get_ext_key_usage(p, end_ext_octet,
|
|
|
|
&crt->ext_key_usage)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
break;
|
2021-05-10 15:16:33 +02:00
|
|
|
|
2021-02-12 16:11:17 +01:00
|
|
|
case MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER:
|
|
|
|
/* Parse subject key identifier */
|
|
|
|
if ((ret = x509_get_subject_key_id(p, end_ext_data,
|
|
|
|
&crt->subject_key_id)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
break;
|
2021-05-10 15:16:33 +02:00
|
|
|
|
2021-02-12 16:11:17 +01:00
|
|
|
case MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER:
|
|
|
|
/* Parse authority key identifier */
|
|
|
|
if ((ret = x509_get_authority_key_id(p, end_ext_octet,
|
|
|
|
&crt->authority_key_id)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
break;
|
2023-01-11 14:50:10 +01:00
|
|
|
case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME:
|
2021-05-10 15:16:33 +02:00
|
|
|
/* Parse subject alt name
|
|
|
|
* SubjectAltName ::= GeneralNames
|
|
|
|
*/
|
2023-02-21 08:32:37 +01:00
|
|
|
if ((ret = mbedtls_x509_get_subject_alt_name(p, end_ext_octet,
|
|
|
|
&crt->subject_alt_names)) != 0) {
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
break;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
case MBEDTLS_X509_EXT_NS_CERT_TYPE:
|
|
|
|
/* Parse netscape certificate type */
|
2023-01-16 08:47:49 +01:00
|
|
|
if ((ret = mbedtls_x509_get_ns_cert_type(p, end_ext_octet,
|
|
|
|
&crt->ns_cert_type)) != 0) {
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
break;
|
2013-04-07 22:00:46 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
case MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES:
|
|
|
|
/* Parse certificate policies type */
|
|
|
|
if ((ret = x509_get_certificate_policies(p, end_ext_octet,
|
|
|
|
&crt->certificate_policies)) != 0) {
|
|
|
|
/* Give the callback (if any) a chance to handle the extension
|
|
|
|
* if it contains unsupported policies */
|
|
|
|
if (ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE && cb != NULL &&
|
|
|
|
cb(p_ctx, crt, &extn_oid, is_critical,
|
|
|
|
start_ext_octet, end_ext_octet) == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_critical) {
|
|
|
|
return ret;
|
|
|
|
} else
|
|
|
|
/*
|
|
|
|
* If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, then we
|
|
|
|
* cannot interpret or enforce the policy. However, it is up to
|
|
|
|
* the user to choose how to enforce the policies,
|
|
|
|
* unless the extension is critical.
|
|
|
|
*/
|
|
|
|
if (ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2019-05-15 11:20:00 +02:00
|
|
|
/*
|
2023-01-11 14:50:10 +01:00
|
|
|
* If this is a non-critical extension, which the oid layer
|
|
|
|
* supports, but there isn't an x509 parser for it,
|
|
|
|
* skip the extension.
|
2019-05-15 11:20:00 +02:00
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (is_critical) {
|
|
|
|
return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
|
|
|
|
} else {
|
|
|
|
*p = end_ext_octet;
|
|
|
|
}
|
2011-01-15 17:57:55 +01:00
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*p != end) {
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2011-12-04 13:24:18 +01:00
|
|
|
* Parse and fill a single X.509 certificate in DER format
|
2009-01-03 22:22:43 +01:00
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_crt_parse_der_core(mbedtls_x509_crt *crt,
|
|
|
|
const unsigned char *buf,
|
|
|
|
size_t buflen,
|
|
|
|
int make_copy,
|
|
|
|
mbedtls_x509_crt_ext_cb_t cb,
|
|
|
|
void *p_ctx)
|
2009-01-03 22:22:43 +01:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2011-05-26 15:16:06 +02:00
|
|
|
size_t len;
|
2012-09-25 14:10:00 +02:00
|
|
|
unsigned char *p, *end, *crt_end;
|
2015-04-08 12:49:31 +02:00
|
|
|
mbedtls_x509_buf sig_params1, sig_params2, sig_oid2;
|
2014-01-22 10:12:57 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
memset(&sig_params1, 0, sizeof(mbedtls_x509_buf));
|
|
|
|
memset(&sig_params2, 0, sizeof(mbedtls_x509_buf));
|
|
|
|
memset(&sig_oid2, 0, sizeof(mbedtls_x509_buf));
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2009-03-28 19:52:39 +01:00
|
|
|
/*
|
|
|
|
* Check for valid input
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt == NULL || buf == NULL) {
|
|
|
|
return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
|
|
|
}
|
2009-03-28 19:52:39 +01:00
|
|
|
|
2019-01-31 09:57:44 +01:00
|
|
|
/* Use the original buffer until we figure out actual length. */
|
2023-01-11 14:50:10 +01:00
|
|
|
p = (unsigned char *) buf;
|
2016-02-17 15:34:12 +01:00
|
|
|
len = buflen;
|
2009-01-03 22:22:43 +01:00
|
|
|
end = p + len;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Certificate ::= SEQUENCE {
|
|
|
|
* tbsCertificate TBSCertificate,
|
|
|
|
* signatureAlgorithm AlgorithmIdentifier,
|
|
|
|
* signatureValue BIT STRING }
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return MBEDTLS_ERR_X509_INVALID_FORMAT;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
2019-01-31 09:57:44 +01:00
|
|
|
end = crt_end = p + len;
|
2016-02-17 15:34:12 +01:00
|
|
|
crt->raw.len = crt_end - buf;
|
2023-01-11 14:50:10 +01:00
|
|
|
if (make_copy != 0) {
|
2019-01-31 09:57:44 +01:00
|
|
|
/* Create and populate a new buffer for the raw field. */
|
2023-01-11 14:50:10 +01:00
|
|
|
crt->raw.p = p = mbedtls_calloc(1, crt->raw.len);
|
|
|
|
if (crt->raw.p == NULL) {
|
|
|
|
return MBEDTLS_ERR_X509_ALLOC_FAILED;
|
|
|
|
}
|
2016-02-17 15:34:12 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
memcpy(crt->raw.p, buf, crt->raw.len);
|
2019-01-31 09:57:44 +01:00
|
|
|
crt->own_buffer = 1;
|
2016-02-17 15:34:12 +01:00
|
|
|
|
2019-01-31 09:57:44 +01:00
|
|
|
p += crt->raw.len - len;
|
|
|
|
end = crt_end = p + len;
|
2023-01-11 14:50:10 +01:00
|
|
|
} else {
|
|
|
|
crt->raw.p = (unsigned char *) buf;
|
2019-01-31 09:57:44 +01:00
|
|
|
crt->own_buffer = 0;
|
|
|
|
}
|
2016-02-17 15:34:12 +01:00
|
|
|
|
2009-01-03 22:22:43 +01:00
|
|
|
/*
|
|
|
|
* TBSCertificate ::= SEQUENCE {
|
|
|
|
*/
|
|
|
|
crt->tbs.p = p;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
end = p + len;
|
|
|
|
crt->tbs.len = end - crt->tbs.p;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
|
|
|
|
*
|
|
|
|
* CertificateSerialNumber ::= INTEGER
|
|
|
|
*
|
|
|
|
* signature AlgorithmIdentifier
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = x509_get_version(&p, end, &crt->version)) != 0 ||
|
|
|
|
(ret = mbedtls_x509_get_serial(&p, end, &crt->serial)) != 0 ||
|
|
|
|
(ret = mbedtls_x509_get_alg(&p, end, &crt->sig_oid,
|
|
|
|
&sig_params1)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->version < 0 || crt->version > 2) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return MBEDTLS_ERR_X509_UNKNOWN_VERSION;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
2017-03-09 17:16:11 +01:00
|
|
|
crt->version++;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_x509_get_sig_alg(&crt->sig_oid, &sig_params1,
|
|
|
|
&crt->sig_md, &crt->sig_pk,
|
|
|
|
&crt->sig_opts)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* issuer Name
|
|
|
|
*/
|
|
|
|
crt->issuer_raw.p = p;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_x509_get_name(&p, p + len, &crt->issuer)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
crt->issuer_raw.len = p - crt->issuer_raw.p;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validity ::= SEQUENCE {
|
|
|
|
* notBefore Time,
|
|
|
|
* notAfter Time }
|
|
|
|
*
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = x509_get_dates(&p, end, &crt->valid_from,
|
|
|
|
&crt->valid_to)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* subject Name
|
|
|
|
*/
|
|
|
|
crt->subject_raw.p = p;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
|
|
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (len && (ret = mbedtls_x509_get_name(&p, p + len, &crt->subject)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
crt->subject_raw.len = p - crt->subject_raw.p;
|
|
|
|
|
|
|
|
/*
|
2013-07-09 12:13:24 +02:00
|
|
|
* SubjectPublicKeyInfo
|
2009-01-03 22:22:43 +01:00
|
|
|
*/
|
2019-02-06 17:13:41 +01:00
|
|
|
crt->pk_raw.p = p;
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_pk_parse_subpubkey(&p, end, &crt->pk)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
2019-02-06 17:13:41 +01:00
|
|
|
crt->pk_raw.len = p - crt->pk_raw.p;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
|
|
|
|
* -- If present, version shall be v2 or v3
|
|
|
|
* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
|
|
|
|
* -- If present, version shall be v2 or v3
|
|
|
|
* extensions [3] EXPLICIT Extensions OPTIONAL
|
|
|
|
* -- If present, version shall be v3
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->version == 2 || crt->version == 3) {
|
|
|
|
ret = x509_get_uid(&p, end, &crt->issuer_id, 1);
|
|
|
|
if (ret != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->version == 2 || crt->version == 3) {
|
|
|
|
ret = x509_get_uid(&p, end, &crt->subject_id, 2);
|
|
|
|
if (ret != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2013-09-16 13:49:26 +02:00
|
|
|
}
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->version == 3) {
|
|
|
|
ret = x509_get_crt_ext(&p, end, crt, cb, p_ctx);
|
|
|
|
if (ret != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (p != end) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
2013-09-16 13:49:26 +02:00
|
|
|
end = crt_end;
|
2009-05-02 17:13:40 +02:00
|
|
|
|
|
|
|
/*
|
2013-09-16 13:49:26 +02:00
|
|
|
* }
|
|
|
|
* -- end of TBSCertificate
|
|
|
|
*
|
2009-05-02 17:13:40 +02:00
|
|
|
* signatureAlgorithm AlgorithmIdentifier,
|
|
|
|
* signatureValue BIT STRING
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_x509_get_alg(&p, end, &sig_oid2, &sig_params2)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->sig_oid.len != sig_oid2.len ||
|
|
|
|
memcmp(crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len) != 0 ||
|
2020-11-24 18:30:18 +01:00
|
|
|
sig_params1.tag != sig_params2.tag ||
|
2014-06-05 17:02:24 +02:00
|
|
|
sig_params1.len != sig_params2.len ||
|
2023-01-11 14:50:10 +01:00
|
|
|
(sig_params1.len != 0 &&
|
|
|
|
memcmp(sig_params1.p, sig_params2.p, sig_params1.len) != 0)) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return MBEDTLS_ERR_X509_SIG_MISMATCH;
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_x509_get_sig(&p, end, &crt->sig)) != 0) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return ret;
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (p != end) {
|
|
|
|
mbedtls_x509_crt_free(crt);
|
|
|
|
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT,
|
|
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2013-09-16 13:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse one X.509 certificate in DER format from a buffer and add them to a
|
|
|
|
* chained list
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int mbedtls_x509_crt_parse_der_internal(mbedtls_x509_crt *chain,
|
|
|
|
const unsigned char *buf,
|
|
|
|
size_t buflen,
|
|
|
|
int make_copy,
|
|
|
|
mbedtls_x509_crt_ext_cb_t cb,
|
|
|
|
void *p_ctx)
|
2013-09-16 13:49:26 +02:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2015-04-08 12:49:31 +02:00
|
|
|
mbedtls_x509_crt *crt = chain, *prev = NULL;
|
2013-09-16 13:49:26 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for valid input
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt == NULL || buf == NULL) {
|
|
|
|
return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
|
|
|
}
|
2013-09-16 13:49:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while (crt->version != 0 && crt->next != NULL) {
|
2013-09-16 13:49:26 +02:00
|
|
|
prev = crt;
|
|
|
|
crt = crt->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add new certificate on the end of the chain if needed.
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->version != 0 && crt->next == NULL) {
|
|
|
|
crt->next = mbedtls_calloc(1, sizeof(mbedtls_x509_crt));
|
2009-05-02 17:13:40 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->next == NULL) {
|
|
|
|
return MBEDTLS_ERR_X509_ALLOC_FAILED;
|
|
|
|
}
|
2009-05-02 17:13:40 +02:00
|
|
|
|
2013-09-16 13:49:26 +02:00
|
|
|
prev = crt;
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_x509_crt_init(crt->next);
|
2013-09-16 13:49:26 +02:00
|
|
|
crt = crt->next;
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = x509_crt_parse_der_core(crt, buf, buflen, make_copy, cb, p_ctx);
|
|
|
|
if (ret != 0) {
|
|
|
|
if (prev) {
|
2013-09-16 13:49:26 +02:00
|
|
|
prev->next = NULL;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2013-09-16 13:49:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt != chain) {
|
|
|
|
mbedtls_free(crt);
|
|
|
|
}
|
2009-05-02 17:13:40 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_parse_der_nocopy(mbedtls_x509_crt *chain,
|
|
|
|
const unsigned char *buf,
|
|
|
|
size_t buflen)
|
2019-01-31 09:57:44 +01:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, 0, NULL, NULL);
|
2020-04-25 14:41:25 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_parse_der_with_ext_cb(mbedtls_x509_crt *chain,
|
|
|
|
const unsigned char *buf,
|
|
|
|
size_t buflen,
|
|
|
|
int make_copy,
|
|
|
|
mbedtls_x509_crt_ext_cb_t cb,
|
|
|
|
void *p_ctx)
|
2020-04-25 14:41:25 +02:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, make_copy, cb, p_ctx);
|
2019-01-31 09:57:44 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_parse_der(mbedtls_x509_crt *chain,
|
|
|
|
const unsigned char *buf,
|
|
|
|
size_t buflen)
|
2019-01-31 09:57:44 +01:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
return mbedtls_x509_crt_parse_der_internal(chain, buf, buflen, 1, NULL, NULL);
|
2019-01-31 09:57:44 +01:00
|
|
|
}
|
|
|
|
|
2009-04-19 20:44:26 +02:00
|
|
|
/*
|
2014-05-01 14:18:25 +02:00
|
|
|
* Parse one or more PEM certificates from a buffer and add them to the chained
|
|
|
|
* list
|
2009-04-19 20:44:26 +02:00
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_parse(mbedtls_x509_crt *chain,
|
|
|
|
const unsigned char *buf,
|
|
|
|
size_t buflen)
|
2009-04-19 20:44:26 +02:00
|
|
|
{
|
2016-05-31 15:03:54 +02:00
|
|
|
#if defined(MBEDTLS_PEM_PARSE_C)
|
2016-12-07 16:05:53 +01:00
|
|
|
int success = 0, first_error = 0, total_failed = 0;
|
2015-04-08 12:49:31 +02:00
|
|
|
int buf_format = MBEDTLS_X509_FORMAT_DER;
|
2016-05-31 15:03:54 +02:00
|
|
|
#endif
|
2009-04-19 20:44:26 +02:00
|
|
|
|
2013-09-16 13:49:26 +02:00
|
|
|
/*
|
|
|
|
* Check for valid input
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (chain == NULL || buf == NULL) {
|
|
|
|
return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
|
|
|
}
|
2009-04-19 20:44:26 +02:00
|
|
|
|
2013-09-16 13:49:26 +02:00
|
|
|
/*
|
|
|
|
* Determine buffer content. Buffer contains either one DER certificate or
|
|
|
|
* one or more PEM certificates.
|
|
|
|
*/
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_PEM_PARSE_C)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (buflen != 0 && buf[buflen - 1] == '\0' &&
|
|
|
|
strstr((const char *) buf, "-----BEGIN CERTIFICATE-----") != NULL) {
|
2015-04-08 12:49:31 +02:00
|
|
|
buf_format = MBEDTLS_X509_FORMAT_PEM;
|
2015-05-12 11:20:10 +02:00
|
|
|
}
|
2009-04-19 20:44:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (buf_format == MBEDTLS_X509_FORMAT_DER) {
|
|
|
|
return mbedtls_x509_crt_parse_der(chain, buf, buflen);
|
|
|
|
}
|
2016-05-31 15:03:54 +02:00
|
|
|
#else
|
2023-01-11 14:50:10 +01:00
|
|
|
return mbedtls_x509_crt_parse_der(chain, buf, buflen);
|
2016-05-31 15:03:54 +02:00
|
|
|
#endif
|
2013-08-19 14:29:31 +02:00
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_PEM_PARSE_C)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (buf_format == MBEDTLS_X509_FORMAT_PEM) {
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2015-04-08 12:49:31 +02:00
|
|
|
mbedtls_pem_context pem;
|
2009-04-19 20:44:26 +02:00
|
|
|
|
2015-05-12 11:20:10 +02:00
|
|
|
/* 1 rather than 0 since the terminating NULL byte is counted in */
|
2023-01-11 14:50:10 +01:00
|
|
|
while (buflen > 1) {
|
2013-09-16 13:49:26 +02:00
|
|
|
size_t use_len;
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_pem_init(&pem);
|
2013-09-16 13:49:26 +02:00
|
|
|
|
2015-05-12 11:20:10 +02:00
|
|
|
/* If we get there, we know the string is null-terminated */
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_pem_read_buffer(&pem,
|
|
|
|
"-----BEGIN CERTIFICATE-----",
|
|
|
|
"-----END CERTIFICATE-----",
|
|
|
|
buf, NULL, 0, &use_len);
|
2013-09-16 13:49:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ret == 0) {
|
2013-09-16 13:49:26 +02:00
|
|
|
/*
|
|
|
|
* Was PEM encoded
|
|
|
|
*/
|
|
|
|
buflen -= use_len;
|
|
|
|
buf += use_len;
|
2023-01-11 14:50:10 +01:00
|
|
|
} else if (ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA) {
|
|
|
|
return ret;
|
|
|
|
} else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
|
|
|
|
mbedtls_pem_free(&pem);
|
2009-04-19 20:44:26 +02:00
|
|
|
|
2013-09-16 13:49:26 +02:00
|
|
|
/*
|
|
|
|
* PEM header and footer were found
|
|
|
|
*/
|
|
|
|
buflen -= use_len;
|
|
|
|
buf += use_len;
|
2009-04-19 20:44:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (first_error == 0) {
|
2013-09-16 13:49:26 +02:00
|
|
|
first_error = ret;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2009-04-19 20:44:26 +02:00
|
|
|
|
2014-09-26 14:53:04 +02:00
|
|
|
total_failed++;
|
2013-09-16 13:49:26 +02:00
|
|
|
continue;
|
2023-01-11 14:50:10 +01:00
|
|
|
} else {
|
2013-09-16 13:49:26 +02:00
|
|
|
break;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2013-09-16 13:49:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_x509_crt_parse_der(chain, pem.buf, pem.buflen);
|
2013-09-16 13:49:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_pem_free(&pem);
|
2013-09-16 13:49:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ret != 0) {
|
2013-09-16 13:49:26 +02:00
|
|
|
/*
|
|
|
|
* Quit parsing on a memory error
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ret == MBEDTLS_ERR_X509_ALLOC_FAILED) {
|
|
|
|
return ret;
|
|
|
|
}
|
2013-09-16 13:49:26 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (first_error == 0) {
|
2013-09-16 13:49:26 +02:00
|
|
|
first_error = ret;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2013-09-16 13:49:26 +02:00
|
|
|
|
|
|
|
total_failed++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
success = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (success) {
|
|
|
|
return total_failed;
|
|
|
|
} else if (first_error) {
|
|
|
|
return first_error;
|
|
|
|
} else {
|
|
|
|
return MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT;
|
|
|
|
}
|
2016-05-31 15:03:54 +02:00
|
|
|
#endif /* MBEDTLS_PEM_PARSE_C */
|
2009-04-19 20:44:26 +02:00
|
|
|
}
|
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_FS_IO)
|
2009-01-03 22:22:43 +01:00
|
|
|
/*
|
|
|
|
* Load one or more certificates and add them to the chained list
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_parse_file(mbedtls_x509_crt *chain, const char *path)
|
2009-01-03 22:22:43 +01:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2009-01-03 22:22:43 +01:00
|
|
|
size_t n;
|
|
|
|
unsigned char *buf;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_x509_crt_parse(chain, buf, n);
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_platform_zeroize(buf, n);
|
|
|
|
mbedtls_free(buf);
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_parse_path(mbedtls_x509_crt *chain, const char *path)
|
2012-06-04 14:46:42 +02:00
|
|
|
{
|
|
|
|
int ret = 0;
|
2013-10-28 18:48:30 +01:00
|
|
|
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
|
2012-10-01 23:13:10 +02:00
|
|
|
int w_ret;
|
|
|
|
WCHAR szDir[MAX_PATH];
|
|
|
|
char filename[MAX_PATH];
|
2014-05-01 13:03:14 +02:00
|
|
|
char *p;
|
2023-01-11 14:50:10 +01:00
|
|
|
size_t len = strlen(path);
|
2012-10-01 23:13:10 +02:00
|
|
|
|
2014-05-01 13:03:14 +02:00
|
|
|
WIN32_FIND_DATAW file_data;
|
2012-06-04 14:46:42 +02:00
|
|
|
HANDLE hFind;
|
2012-11-02 12:06:08 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (len > MAX_PATH - 3) {
|
|
|
|
return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
|
|
|
}
|
2012-06-04 14:46:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
memset(szDir, 0, sizeof(szDir));
|
|
|
|
memset(filename, 0, MAX_PATH);
|
|
|
|
memcpy(filename, path, len);
|
2014-05-01 13:03:14 +02:00
|
|
|
filename[len++] = '\\';
|
|
|
|
p = filename + len;
|
2012-11-02 12:06:08 +01:00
|
|
|
filename[len++] = '*';
|
2012-10-01 23:13:10 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
w_ret = MultiByteToWideChar(CP_ACP, 0, filename, (int) len, szDir,
|
|
|
|
MAX_PATH - 3);
|
|
|
|
if (w_ret == 0) {
|
|
|
|
return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
|
|
|
}
|
2012-06-04 14:46:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
hFind = FindFirstFileW(szDir, &file_data);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE) {
|
|
|
|
return MBEDTLS_ERR_X509_FILE_IO_ERROR;
|
|
|
|
}
|
2012-06-04 14:46:42 +02:00
|
|
|
|
2012-11-02 12:06:08 +01:00
|
|
|
len = MAX_PATH - len;
|
2023-01-11 14:50:10 +01:00
|
|
|
do {
|
|
|
|
memset(p, 0, len);
|
2012-10-01 23:13:10 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
2012-06-04 14:46:42 +02:00
|
|
|
continue;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2012-06-04 14:46:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
w_ret = WideCharToMultiByte(CP_ACP, 0, file_data.cFileName,
|
2023-02-10 13:52:13 +01:00
|
|
|
-1,
|
|
|
|
p, (int) len,
|
2023-01-11 14:50:10 +01:00
|
|
|
NULL, NULL);
|
|
|
|
if (w_ret == 0) {
|
2017-01-09 14:09:16 +01:00
|
|
|
ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-06-04 14:46:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
w_ret = mbedtls_x509_crt_parse_file(chain, filename);
|
|
|
|
if (w_ret < 0) {
|
2013-06-24 19:22:42 +02:00
|
|
|
ret++;
|
2023-01-11 14:50:10 +01:00
|
|
|
} else {
|
2013-06-24 19:22:42 +02:00
|
|
|
ret += w_ret;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
|
|
|
} while (FindNextFileW(hFind, &file_data) != 0);
|
2012-06-04 14:46:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (GetLastError() != ERROR_NO_MORE_FILES) {
|
2015-04-08 12:49:31 +02:00
|
|
|
ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2012-06-04 14:46:42 +02:00
|
|
|
|
2017-01-09 14:09:16 +01:00
|
|
|
cleanup:
|
2023-01-11 14:50:10 +01:00
|
|
|
FindClose(hFind);
|
2013-10-14 15:51:50 +02:00
|
|
|
#else /* _WIN32 */
|
2013-11-26 16:47:11 +01:00
|
|
|
int t_ret;
|
2016-09-02 15:06:04 +02:00
|
|
|
int snp_ret;
|
2013-06-24 19:22:42 +02:00
|
|
|
struct stat sb;
|
2013-11-26 16:47:11 +01:00
|
|
|
struct dirent *entry;
|
2016-09-02 15:06:04 +02:00
|
|
|
char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN];
|
2023-01-11 14:50:10 +01:00
|
|
|
DIR *dir = opendir(path);
|
2012-06-04 14:46:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (dir == NULL) {
|
|
|
|
return MBEDTLS_ERR_X509_FILE_IO_ERROR;
|
|
|
|
}
|
2012-06-04 14:46:42 +02:00
|
|
|
|
2017-01-09 18:27:59 +01:00
|
|
|
#if defined(MBEDTLS_THREADING_C)
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_mutex_lock(&mbedtls_threading_readdir_mutex)) != 0) {
|
|
|
|
closedir(dir);
|
|
|
|
return ret;
|
2015-06-22 18:39:57 +02:00
|
|
|
}
|
2017-01-09 18:27:59 +01:00
|
|
|
#endif /* MBEDTLS_THREADING_C */
|
2013-11-28 17:11:54 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
memset(&sb, 0, sizeof(sb));
|
2021-03-05 15:17:51 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while ((entry = readdir(dir)) != NULL) {
|
2023-02-02 13:40:50 +01:00
|
|
|
snp_ret = mbedtls_snprintf(entry_name, sizeof(entry_name),
|
2023-01-11 14:50:10 +01:00
|
|
|
"%s/%s", path, entry->d_name);
|
2013-06-24 19:22:42 +02:00
|
|
|
|
2023-02-02 13:40:50 +01:00
|
|
|
if (snp_ret < 0 || (size_t) snp_ret >= sizeof(entry_name)) {
|
2016-09-02 15:06:04 +02:00
|
|
|
ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
|
|
|
|
goto cleanup;
|
2023-01-11 14:50:10 +01:00
|
|
|
} else if (stat(entry_name, &sb) == -1) {
|
|
|
|
if (errno == ENOENT) {
|
2022-07-20 17:08:00 +02:00
|
|
|
/* Broken symbolic link - ignore this entry.
|
|
|
|
stat(2) will return this error for either (a) a dangling
|
|
|
|
symlink or (b) a missing file.
|
|
|
|
Given that we have just obtained the filename from readdir,
|
|
|
|
assume that it does exist and therefore treat this as a
|
|
|
|
dangling symlink. */
|
|
|
|
continue;
|
2023-01-11 14:50:10 +01:00
|
|
|
} else {
|
2022-07-20 17:08:00 +02:00
|
|
|
/* Some other file error; report the error. */
|
|
|
|
ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
|
|
|
|
goto cleanup;
|
2019-04-25 18:43:26 +02:00
|
|
|
}
|
2013-09-09 17:26:14 +02:00
|
|
|
}
|
2013-06-24 19:22:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (!S_ISREG(sb.st_mode)) {
|
2012-06-04 14:46:42 +02:00
|
|
|
continue;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2012-06-04 14:46:42 +02:00
|
|
|
|
2013-06-24 19:22:42 +02:00
|
|
|
// Ignore parse errors
|
|
|
|
//
|
2023-01-11 14:50:10 +01:00
|
|
|
t_ret = mbedtls_x509_crt_parse_file(chain, entry_name);
|
|
|
|
if (t_ret < 0) {
|
2013-06-24 19:22:42 +02:00
|
|
|
ret++;
|
2023-01-11 14:50:10 +01:00
|
|
|
} else {
|
2013-09-16 13:49:26 +02:00
|
|
|
ret += t_ret;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2013-09-16 13:49:26 +02:00
|
|
|
}
|
2013-11-28 17:11:54 +01:00
|
|
|
|
|
|
|
cleanup:
|
2023-01-11 14:50:10 +01:00
|
|
|
closedir(dir);
|
2016-09-02 15:06:04 +02:00
|
|
|
|
2017-01-09 18:27:59 +01:00
|
|
|
#if defined(MBEDTLS_THREADING_C)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_mutex_unlock(&mbedtls_threading_readdir_mutex) != 0) {
|
2015-04-08 12:49:31 +02:00
|
|
|
ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-01-09 18:27:59 +01:00
|
|
|
#endif /* MBEDTLS_THREADING_C */
|
2013-11-28 17:11:54 +01:00
|
|
|
|
2013-10-14 15:51:50 +02:00
|
|
|
#endif /* _WIN32 */
|
2013-08-14 13:39:57 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
2013-07-11 16:17:23 +02:00
|
|
|
}
|
2015-04-08 12:49:31 +02:00
|
|
|
#endif /* MBEDTLS_FS_IO */
|
2013-07-11 16:17:23 +02:00
|
|
|
|
2018-12-11 20:55:56 +01:00
|
|
|
#if !defined(MBEDTLS_X509_REMOVE_INFO)
|
2023-04-24 09:52:17 +02:00
|
|
|
#define PRINT_ITEM(i) \
|
|
|
|
do { \
|
|
|
|
ret = mbedtls_snprintf(p, n, "%s" i, sep); \
|
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF; \
|
|
|
|
sep = ", "; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define CERT_TYPE(type, name) \
|
|
|
|
do { \
|
2023-04-26 08:55:26 +02:00
|
|
|
if (ns_cert_type & (type)) { \
|
|
|
|
PRINT_ITEM(name); \
|
|
|
|
} \
|
2023-04-24 09:52:17 +02:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define KEY_USAGE(code, name) \
|
|
|
|
do { \
|
2023-04-26 08:55:26 +02:00
|
|
|
if (key_usage & (code)) { \
|
|
|
|
PRINT_ITEM(name); \
|
|
|
|
} \
|
2023-04-24 09:52:17 +02:00
|
|
|
} while (0)
|
2021-05-10 15:16:33 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_info_ext_key_usage(char **buf, size_t *size,
|
|
|
|
const mbedtls_x509_sequence *extended_key_usage)
|
2014-04-01 17:32:44 +02:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2014-04-01 17:32:44 +02:00
|
|
|
const char *desc;
|
|
|
|
size_t n = *size;
|
|
|
|
char *p = *buf;
|
2015-04-08 12:49:31 +02:00
|
|
|
const mbedtls_x509_sequence *cur = extended_key_usage;
|
2014-04-01 18:00:07 +02:00
|
|
|
const char *sep = "";
|
2014-04-01 17:32:44 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while (cur != NULL) {
|
|
|
|
if (mbedtls_oid_get_extended_key_usage(&cur->buf, &desc) != 0) {
|
2014-04-01 17:32:44 +02:00
|
|
|
desc = "???";
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2014-04-01 17:32:44 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "%s%s", sep, desc);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2014-04-01 17:32:44 +02:00
|
|
|
|
2014-04-01 18:00:07 +02:00
|
|
|
sep = ", ";
|
|
|
|
|
2014-04-01 17:32:44 +02:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
*size = n;
|
|
|
|
*buf = p;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2014-04-01 17:32:44 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_info_cert_policies(char **buf, size_t *size,
|
|
|
|
const mbedtls_x509_sequence *certificate_policies)
|
2019-03-21 13:00:03 +01:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2019-03-21 13:00:03 +01:00
|
|
|
const char *desc;
|
|
|
|
size_t n = *size;
|
|
|
|
char *p = *buf;
|
|
|
|
const mbedtls_x509_sequence *cur = certificate_policies;
|
|
|
|
const char *sep = "";
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while (cur != NULL) {
|
|
|
|
if (mbedtls_oid_get_certificate_policies(&cur->buf, &desc) != 0) {
|
2019-03-21 13:00:03 +01:00
|
|
|
desc = "???";
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "%s%s", sep, desc);
|
2019-03-21 13:00:03 +01:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
|
|
|
|
|
|
|
sep = ", ";
|
|
|
|
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
*size = n;
|
|
|
|
*buf = p;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2019-03-21 13:00:03 +01:00
|
|
|
}
|
|
|
|
|
2009-01-03 22:22:43 +01:00
|
|
|
/*
|
2009-05-02 17:13:40 +02:00
|
|
|
* Return an informational string about the certificate.
|
2009-01-03 22:22:43 +01:00
|
|
|
*/
|
2014-04-01 12:19:09 +02:00
|
|
|
#define BEFORE_COLON 18
|
|
|
|
#define BC "18"
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_info(char *buf, size_t size, const char *prefix,
|
|
|
|
const mbedtls_x509_crt *crt)
|
2009-01-03 22:22:43 +01:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2011-04-24 10:57:21 +02:00
|
|
|
size_t n;
|
2009-05-02 17:13:40 +02:00
|
|
|
char *p;
|
2013-08-12 19:45:32 +02:00
|
|
|
char key_size_str[BEFORE_COLON];
|
2009-01-03 22:22:43 +01:00
|
|
|
|
|
|
|
p = buf;
|
2009-05-02 17:13:40 +02:00
|
|
|
n = size;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (NULL == crt) {
|
|
|
|
ret = mbedtls_snprintf(p, n, "\nCertificate is uninitialised!\n");
|
2016-05-31 15:03:54 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return (int) (size - n);
|
2016-05-31 15:03:54 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "%scert. version : %d\n",
|
|
|
|
prefix, crt->version);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "%sserial number : ",
|
|
|
|
prefix);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_x509_serial_gets(p, n, &crt->serial);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "\n%sissuer name : ", prefix);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_x509_dn_gets(p, n, &crt->issuer);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "\n%ssubject name : ", prefix);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_x509_dn_gets(p, n, &crt->subject);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "\n%sissued on : " \
|
|
|
|
"%04d-%02d-%02d %02d:%02d:%02d", prefix,
|
|
|
|
crt->valid_from.year, crt->valid_from.mon,
|
|
|
|
crt->valid_from.day, crt->valid_from.hour,
|
|
|
|
crt->valid_from.min, crt->valid_from.sec);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "\n%sexpires on : " \
|
|
|
|
"%04d-%02d-%02d %02d:%02d:%02d", prefix,
|
|
|
|
crt->valid_to.year, crt->valid_to.mon,
|
|
|
|
crt->valid_to.day, crt->valid_to.hour,
|
|
|
|
crt->valid_to.min, crt->valid_to.sec);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "\n%ssigned using : ", prefix);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_x509_sig_alg_gets(p, n, &crt->sig_oid, crt->sig_pk,
|
|
|
|
crt->sig_md, crt->sig_opts);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2014-04-01 12:19:09 +02:00
|
|
|
/* Key size */
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = mbedtls_x509_key_size_helper(key_size_str, BEFORE_COLON,
|
|
|
|
mbedtls_pk_get_name(&crt->pk))) != 0) {
|
|
|
|
return ret;
|
2013-08-12 19:45:32 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str,
|
|
|
|
(int) mbedtls_pk_get_bitlen(&crt->pk));
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2014-04-01 12:19:09 +02:00
|
|
|
/*
|
|
|
|
* Optional extensions
|
|
|
|
*/
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) {
|
|
|
|
ret = mbedtls_snprintf(p, n, "\n%sbasic constraints : CA=%s", prefix,
|
|
|
|
crt->ca_istrue ? "true" : "false");
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2014-04-01 12:19:09 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->max_pathlen > 0) {
|
|
|
|
ret = mbedtls_snprintf(p, n, ", max_pathlen=%d", crt->max_pathlen - 1);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2014-04-01 12:19:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) {
|
|
|
|
ret = mbedtls_snprintf(p, n, "\n%ssubject alt name :", prefix);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2014-04-01 13:43:28 +02:00
|
|
|
|
2023-01-16 08:47:49 +01:00
|
|
|
if ((ret = mbedtls_x509_info_subject_alt_name(&p, &n,
|
|
|
|
&crt->subject_alt_names,
|
|
|
|
prefix)) != 0) {
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
|
|
|
}
|
2014-04-01 12:19:09 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) {
|
|
|
|
ret = mbedtls_snprintf(p, n, "\n%scert. type : ", prefix);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2014-04-01 13:01:11 +02:00
|
|
|
|
2023-01-16 08:47:49 +01:00
|
|
|
if ((ret = mbedtls_x509_info_cert_type(&p, &n, crt->ns_cert_type)) != 0) {
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
|
|
|
}
|
2014-04-01 12:19:09 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) {
|
|
|
|
ret = mbedtls_snprintf(p, n, "\n%skey usage : ", prefix);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2014-04-01 14:12:11 +02:00
|
|
|
|
2023-01-16 08:47:49 +01:00
|
|
|
if ((ret = mbedtls_x509_info_key_usage(&p, &n, crt->key_usage)) != 0) {
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
|
|
|
}
|
2014-04-01 12:19:09 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE) {
|
|
|
|
ret = mbedtls_snprintf(p, n, "\n%sext key usage : ", prefix);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2014-04-01 17:32:44 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = x509_info_ext_key_usage(&p, &n,
|
|
|
|
&crt->ext_key_usage)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2014-04-01 12:19:09 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES) {
|
|
|
|
ret = mbedtls_snprintf(p, n, "\n%scertificate policies : ", prefix);
|
2019-03-21 13:00:03 +01:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((ret = x509_info_cert_policies(&p, &n,
|
|
|
|
&crt->certificate_policies)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2019-03-21 13:00:03 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "\n");
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2014-04-01 12:19:09 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return (int) (size - n);
|
2009-05-02 17:13:40 +02:00
|
|
|
}
|
|
|
|
|
2015-04-20 11:38:13 +02:00
|
|
|
struct x509_crt_verify_string {
|
|
|
|
int code;
|
|
|
|
const char *string;
|
|
|
|
};
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
#define X509_CRT_ERROR_INFO(err, err_str, info) { err, info },
|
2015-04-20 11:38:13 +02:00
|
|
|
static const struct x509_crt_verify_string x509_crt_verify_strings[] = {
|
2020-10-09 11:48:22 +02:00
|
|
|
MBEDTLS_X509_CRT_ERROR_INFO_LIST
|
2015-04-20 11:38:13 +02:00
|
|
|
{ 0, NULL }
|
|
|
|
};
|
2020-10-09 11:48:22 +02:00
|
|
|
#undef X509_CRT_ERROR_INFO
|
2015-04-20 11:38:13 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_verify_info(char *buf, size_t size, const char *prefix,
|
|
|
|
uint32_t flags)
|
2015-04-20 11:38:13 +02:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2015-04-20 11:38:13 +02:00
|
|
|
const struct x509_crt_verify_string *cur;
|
|
|
|
char *p = buf;
|
|
|
|
size_t n = size;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
for (cur = x509_crt_verify_strings; cur->string != NULL; cur++) {
|
|
|
|
if ((flags & cur->code) == 0) {
|
2015-04-20 11:38:13 +02:00
|
|
|
continue;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2015-04-20 11:38:13 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = mbedtls_snprintf(p, n, "%s%s\n", prefix, cur->string);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2015-04-20 11:38:13 +02:00
|
|
|
flags ^= cur->code;
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (flags != 0) {
|
|
|
|
ret = mbedtls_snprintf(p, n, "%sUnknown reason "
|
|
|
|
"(this should not happen)\n", prefix);
|
2015-06-22 11:12:02 +02:00
|
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
2015-04-20 11:38:13 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return (int) (size - n);
|
2015-04-20 11:38:13 +02:00
|
|
|
}
|
2020-10-09 10:19:39 +02:00
|
|
|
#endif /* MBEDTLS_X509_REMOVE_INFO */
|
2015-04-20 11:38:13 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_check_key_usage(const mbedtls_x509_crt *crt,
|
|
|
|
unsigned int usage)
|
2014-04-09 09:50:03 +02:00
|
|
|
{
|
2015-06-23 10:48:44 +02:00
|
|
|
unsigned int usage_must, usage_may;
|
|
|
|
unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY
|
2023-01-11 14:50:10 +01:00
|
|
|
| MBEDTLS_X509_KU_DECIPHER_ONLY;
|
2015-06-23 10:48:44 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-23 10:48:44 +02:00
|
|
|
|
|
|
|
usage_must = usage & ~may_mask;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (((crt->key_usage & ~may_mask) & usage_must) != usage_must) {
|
|
|
|
return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
|
|
|
}
|
2015-06-23 10:48:44 +02:00
|
|
|
|
|
|
|
usage_may = usage & may_mask;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (((crt->key_usage & may_mask) | usage_may) != usage_may) {
|
|
|
|
return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
|
|
|
}
|
2014-04-09 09:50:03 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2014-04-09 09:50:03 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_check_extended_key_usage(const mbedtls_x509_crt *crt,
|
|
|
|
const char *usage_oid,
|
|
|
|
size_t usage_len)
|
2014-04-10 17:53:56 +02:00
|
|
|
{
|
2015-04-08 12:49:31 +02:00
|
|
|
const mbedtls_x509_sequence *cur;
|
2014-04-10 17:53:56 +02:00
|
|
|
|
|
|
|
/* Extension is not mandatory, absent means no restriction */
|
2023-01-11 14:50:10 +01:00
|
|
|
if ((crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE) == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2014-04-10 17:53:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for the requested usage (or wildcard ANY) in our list
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
for (cur = &crt->ext_key_usage; cur != NULL; cur = cur->next) {
|
2015-04-08 12:49:31 +02:00
|
|
|
const mbedtls_x509_buf *cur_oid = &cur->buf;
|
2014-04-10 17:53:56 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (cur_oid->len == usage_len &&
|
|
|
|
memcmp(cur_oid->p, usage_oid, usage_len) == 0) {
|
|
|
|
return 0;
|
2014-04-10 17:53:56 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (MBEDTLS_OID_CMP(MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid) == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2014-04-10 17:53:56 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
2014-04-10 17:53:56 +02:00
|
|
|
}
|
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_X509_CRL_PARSE_C)
|
2009-05-03 12:18:48 +02:00
|
|
|
/*
|
|
|
|
* Return 1 if the certificate is revoked, or 0 otherwise.
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_is_revoked(const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl)
|
2009-05-03 12:18:48 +02:00
|
|
|
{
|
2015-04-08 12:49:31 +02:00
|
|
|
const mbedtls_x509_crl_entry *cur = &crl->entry;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while (cur != NULL && cur->serial.len != 0) {
|
|
|
|
if (crt->serial.len == cur->serial.len &&
|
|
|
|
memcmp(crt->serial.p, cur->serial.p, crt->serial.len) == 0) {
|
|
|
|
return 1;
|
2009-05-03 12:18:48 +02:00
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2009-05-03 12:18:48 +02:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
2011-01-16 22:12:10 +01:00
|
|
|
/*
|
2016-02-22 11:36:55 +01:00
|
|
|
* Check that the given certificate is not revoked according to the CRL.
|
2017-10-18 14:20:24 +02:00
|
|
|
* Skip validation if no CRL for the given CA is present.
|
2011-01-16 22:12:10 +01:00
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_crt_verifycrl(mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
|
|
|
|
mbedtls_x509_crl *crl_list,
|
|
|
|
const mbedtls_x509_crt_profile *profile)
|
2011-01-16 22:12:10 +01:00
|
|
|
{
|
|
|
|
int flags = 0;
|
2022-09-06 13:08:28 +02:00
|
|
|
unsigned char hash[MBEDTLS_HASH_MAX_SIZE];
|
2022-02-07 14:40:55 +01:00
|
|
|
#if defined(MBEDTLS_USE_PSA_CRYPTO)
|
|
|
|
psa_algorithm_t psa_algorithm;
|
|
|
|
#else
|
2015-04-08 12:49:31 +02:00
|
|
|
const mbedtls_md_info_t *md_info;
|
2022-02-07 14:40:55 +01:00
|
|
|
#endif /* MBEDTLS_USE_PSA_CRYPTO */
|
|
|
|
size_t hash_length;
|
2011-01-16 22:12:10 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ca == NULL) {
|
|
|
|
return flags;
|
|
|
|
}
|
2012-09-28 09:10:55 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while (crl_list != NULL) {
|
|
|
|
if (crl_list->version == 0 ||
|
|
|
|
x509_name_cmp(&crl_list->issuer, &ca->subject) != 0) {
|
2011-01-16 22:12:10 +01:00
|
|
|
crl_list = crl_list->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-04-08 15:10:07 +02:00
|
|
|
/*
|
|
|
|
* Check if the CA is configured to sign CRLs
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_x509_crt_check_key_usage(ca,
|
|
|
|
MBEDTLS_X509_KU_CRL_SIGN) != 0) {
|
2015-04-08 12:49:31 +02:00
|
|
|
flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED;
|
2014-04-08 15:10:07 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-01-16 22:12:10 +01:00
|
|
|
/*
|
|
|
|
* Check if CRL is correctly signed by the trusted CA
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_profile_check_md_alg(profile, crl_list->sig_md) != 0) {
|
2015-06-15 16:17:55 +02:00
|
|
|
flags |= MBEDTLS_X509_BADCRL_BAD_MD;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2015-06-15 16:17:55 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_profile_check_pk_alg(profile, crl_list->sig_pk) != 0) {
|
2015-06-15 16:17:55 +02:00
|
|
|
flags |= MBEDTLS_X509_BADCRL_BAD_PK;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2015-06-15 16:17:55 +02:00
|
|
|
|
2022-02-07 14:40:55 +01:00
|
|
|
#if defined(MBEDTLS_USE_PSA_CRYPTO)
|
2023-01-11 14:50:10 +01:00
|
|
|
psa_algorithm = mbedtls_hash_info_psa_from_md(crl_list->sig_md);
|
|
|
|
if (psa_hash_compute(psa_algorithm,
|
|
|
|
crl_list->tbs.p,
|
|
|
|
crl_list->tbs.len,
|
|
|
|
hash,
|
|
|
|
sizeof(hash),
|
|
|
|
&hash_length) != PSA_SUCCESS) {
|
2022-02-14 15:18:43 +01:00
|
|
|
/* Note: this can't happen except after an internal error */
|
|
|
|
flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED;
|
|
|
|
break;
|
|
|
|
}
|
2022-02-07 14:40:55 +01:00
|
|
|
#else
|
2023-01-11 14:50:10 +01:00
|
|
|
md_info = mbedtls_md_info_from_type(crl_list->sig_md);
|
|
|
|
hash_length = mbedtls_md_get_size(md_info);
|
|
|
|
if (mbedtls_md(md_info,
|
|
|
|
crl_list->tbs.p,
|
|
|
|
crl_list->tbs.len,
|
|
|
|
hash) != 0) {
|
2017-06-26 12:22:17 +02:00
|
|
|
/* Note: this can't happen except after an internal error */
|
2015-04-08 12:49:31 +02:00
|
|
|
flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED;
|
2013-04-07 22:00:46 +02:00
|
|
|
break;
|
|
|
|
}
|
2022-02-14 15:18:43 +01:00
|
|
|
#endif /* MBEDTLS_USE_PSA_CRYPTO */
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_profile_check_key(profile, &ca->pk) != 0) {
|
2015-06-15 16:17:55 +02:00
|
|
|
flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2015-06-15 10:39:46 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_pk_verify_ext(crl_list->sig_pk, crl_list->sig_opts, &ca->pk,
|
|
|
|
crl_list->sig_md, hash, hash_length,
|
|
|
|
crl_list->sig.p, crl_list->sig.len) != 0) {
|
2015-04-08 12:49:31 +02:00
|
|
|
flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED;
|
2013-08-12 18:41:18 +02:00
|
|
|
break;
|
2011-01-16 22:12:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for validity of CRL (Do not drop out)
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_x509_time_is_past(&crl_list->next_update)) {
|
2015-04-08 12:49:31 +02:00
|
|
|
flags |= MBEDTLS_X509_BADCRL_EXPIRED;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2011-01-16 22:12:10 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_x509_time_is_future(&crl_list->this_update)) {
|
2015-04-20 13:19:02 +02:00
|
|
|
flags |= MBEDTLS_X509_BADCRL_FUTURE;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2014-03-10 13:15:18 +01:00
|
|
|
|
2011-01-16 22:12:10 +01:00
|
|
|
/*
|
|
|
|
* Check if certificate is revoked
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_x509_crt_is_revoked(crt, crl_list)) {
|
2015-04-08 12:49:31 +02:00
|
|
|
flags |= MBEDTLS_X509_BADCERT_REVOKED;
|
2011-01-16 22:12:10 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
crl_list = crl_list->next;
|
|
|
|
}
|
2015-06-15 16:17:55 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return flags;
|
2011-01-16 22:12:10 +01:00
|
|
|
}
|
2015-04-08 12:49:31 +02:00
|
|
|
#endif /* MBEDTLS_X509_CRL_PARSE_C */
|
2011-01-16 22:12:10 +01:00
|
|
|
|
2017-07-03 19:26:25 +02:00
|
|
|
/*
|
|
|
|
* Check the signature of a certificate by its parent
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_crt_check_signature(const mbedtls_x509_crt *child,
|
|
|
|
mbedtls_x509_crt *parent,
|
|
|
|
mbedtls_x509_crt_restart_ctx *rs_ctx)
|
2017-07-03 19:26:25 +02:00
|
|
|
{
|
2018-10-31 11:18:39 +01:00
|
|
|
size_t hash_len;
|
2022-09-13 12:57:05 +02:00
|
|
|
unsigned char hash[MBEDTLS_HASH_MAX_SIZE];
|
2018-10-31 11:18:39 +01:00
|
|
|
#if !defined(MBEDTLS_USE_PSA_CRYPTO)
|
|
|
|
const mbedtls_md_info_t *md_info;
|
2023-01-11 14:50:10 +01:00
|
|
|
md_info = mbedtls_md_info_from_type(child->sig_md);
|
|
|
|
hash_len = mbedtls_md_get_size(md_info);
|
2018-11-20 09:20:09 +01:00
|
|
|
|
2018-10-31 11:18:39 +01:00
|
|
|
/* Note: hash errors can happen only after an internal error */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_md(md_info, child->tbs.p, child->tbs.len, hash) != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-10-31 11:18:39 +01:00
|
|
|
#else
|
2023-01-11 14:50:10 +01:00
|
|
|
psa_algorithm_t hash_alg = mbedtls_hash_info_psa_from_md(child->sig_md);
|
2022-02-07 14:40:55 +01:00
|
|
|
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
|
2018-10-31 11:18:39 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
status = psa_hash_compute(hash_alg,
|
|
|
|
child->tbs.p,
|
|
|
|
child->tbs.len,
|
|
|
|
hash,
|
|
|
|
sizeof(hash),
|
|
|
|
&hash_len);
|
|
|
|
if (status != PSA_SUCCESS) {
|
|
|
|
return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED;
|
2017-07-03 19:26:25 +02:00
|
|
|
}
|
|
|
|
|
2018-10-31 11:18:39 +01:00
|
|
|
#endif /* MBEDTLS_USE_PSA_CRYPTO */
|
2017-07-17 10:26:19 +02:00
|
|
|
/* Skip expensive computation on obvious mismatch */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (!mbedtls_pk_can_do(&parent->pk, child->sig_pk)) {
|
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 10:26:19 +02:00
|
|
|
|
2017-08-14 18:04:19 +02:00
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA) {
|
|
|
|
return mbedtls_pk_verify_restartable(&parent->pk,
|
|
|
|
child->sig_md, hash, hash_len,
|
|
|
|
child->sig.p, child->sig.len, &rs_ctx->pk);
|
2017-07-03 19:26:25 +02:00
|
|
|
}
|
2017-07-17 10:26:19 +02:00
|
|
|
#else
|
|
|
|
(void) rs_ctx;
|
|
|
|
#endif
|
2017-07-03 19:26:25 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return mbedtls_pk_verify_ext(child->sig_pk, child->sig_opts, &parent->pk,
|
|
|
|
child->sig_md, hash, hash_len,
|
|
|
|
child->sig.p, child->sig.len);
|
2017-07-03 19:26:25 +02:00
|
|
|
}
|
|
|
|
|
2014-04-08 13:18:01 +02:00
|
|
|
/*
|
2014-04-09 14:30:11 +02:00
|
|
|
* Check if 'parent' is a suitable parent (signing CA) for 'child'.
|
|
|
|
* Return 0 if yes, -1 if not.
|
2014-06-24 11:49:16 +02:00
|
|
|
*
|
|
|
|
* top means parent is a locally-trusted certificate
|
2014-04-08 13:18:01 +02:00
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_crt_check_parent(const mbedtls_x509_crt *child,
|
|
|
|
const mbedtls_x509_crt *parent,
|
|
|
|
int top)
|
2014-04-08 13:18:01 +02:00
|
|
|
{
|
2014-06-24 11:49:16 +02:00
|
|
|
int need_ca_bit;
|
|
|
|
|
2014-06-19 12:18:08 +02:00
|
|
|
/* Parent must be the issuer */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_name_cmp(&child->issuer, &parent->subject) != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2014-04-08 13:18:01 +02:00
|
|
|
|
2014-06-24 11:49:16 +02:00
|
|
|
/* Parent must have the basicConstraints CA bit set as a general rule */
|
|
|
|
need_ca_bit = 1;
|
|
|
|
|
|
|
|
/* Exception: v1/v2 certificates that are locally trusted. */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (top && parent->version < 3) {
|
2014-06-24 11:49:16 +02:00
|
|
|
need_ca_bit = 0;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2014-06-24 11:49:16 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (need_ca_bit && !parent->ca_istrue) {
|
|
|
|
return -1;
|
|
|
|
}
|
2014-06-24 11:49:16 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (need_ca_bit &&
|
|
|
|
mbedtls_x509_crt_check_key_usage(parent, MBEDTLS_X509_KU_KEY_CERT_SIGN) != 0) {
|
|
|
|
return -1;
|
2014-06-24 11:49:16 +02:00
|
|
|
}
|
2014-04-08 15:10:07 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2014-04-08 13:18:01 +02:00
|
|
|
}
|
|
|
|
|
2017-06-29 12:27:23 +02:00
|
|
|
/*
|
2017-06-29 12:55:27 +02:00
|
|
|
* Find a suitable parent for child in candidates, or return NULL.
|
|
|
|
*
|
|
|
|
* Here suitable is defined as:
|
2017-07-03 18:30:43 +02:00
|
|
|
* 1. subject name matches child's issuer
|
|
|
|
* 2. if necessary, the CA bit is set and key usage allows signing certs
|
|
|
|
* 3. for trusted roots, the signature is correct
|
2017-07-14 12:04:14 +02:00
|
|
|
* (for intermediates, the signature is checked and the result reported)
|
2017-07-03 18:30:43 +02:00
|
|
|
* 4. pathlen constraints are satisfied
|
2017-06-29 12:55:27 +02:00
|
|
|
*
|
2017-08-08 18:09:14 +02:00
|
|
|
* If there's a suitable candidate which is also time-valid, return the first
|
|
|
|
* such. Otherwise, return the first suitable candidate (or NULL if there is
|
|
|
|
* none).
|
2017-06-29 12:55:27 +02:00
|
|
|
*
|
|
|
|
* The rationale for this rule is that someone could have a list of trusted
|
|
|
|
* roots with two versions on the same root with different validity periods.
|
|
|
|
* (At least one user reported having such a list and wanted it to just work.)
|
|
|
|
* The reason we don't just require time-validity is that generally there is
|
|
|
|
* only one version, and if it's expired we want the flags to state that
|
|
|
|
* rather than NOT_TRUSTED, as would be the case if we required it here.
|
2017-07-03 18:30:43 +02:00
|
|
|
*
|
|
|
|
* The rationale for rule 3 (signature for trusted roots) is that users might
|
|
|
|
* have two versions of the same CA with different keys in their list, and the
|
2017-07-04 00:33:39 +02:00
|
|
|
* way we select the correct one is by checking the signature (as we don't
|
|
|
|
* rely on key identifier extensions). (This is one way users might choose to
|
|
|
|
* handle key rollover, another relies on self-issued certs, see [SIRO].)
|
2017-08-17 10:52:20 +02:00
|
|
|
*
|
|
|
|
* Arguments:
|
2018-03-07 10:00:57 +01:00
|
|
|
* - [in] child: certificate for which we're looking for a parent
|
|
|
|
* - [in] candidates: chained list of potential parents
|
2018-06-12 12:40:54 +02:00
|
|
|
* - [out] r_parent: parent found (or NULL)
|
|
|
|
* - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0
|
2018-03-07 10:00:57 +01:00
|
|
|
* - [in] top: 1 if candidates consists of trusted roots, ie we're at the top
|
|
|
|
* of the chain, 0 otherwise
|
|
|
|
* - [in] path_cnt: number of intermediates seen so far
|
|
|
|
* - [in] self_cnt: number of self-signed intermediates seen so far
|
|
|
|
* (will never be greater than path_cnt)
|
2018-06-12 12:40:54 +02:00
|
|
|
* - [in-out] rs_ctx: context for restarting operations
|
2018-03-07 10:00:57 +01:00
|
|
|
*
|
|
|
|
* Return value:
|
2018-06-12 12:40:54 +02:00
|
|
|
* - 0 on success
|
|
|
|
* - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise
|
2017-06-29 12:27:23 +02:00
|
|
|
*/
|
2017-07-17 10:26:19 +02:00
|
|
|
static int x509_crt_find_parent_in(
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_x509_crt *child,
|
|
|
|
mbedtls_x509_crt *candidates,
|
|
|
|
mbedtls_x509_crt **r_parent,
|
|
|
|
int *r_signature_is_good,
|
|
|
|
int top,
|
|
|
|
unsigned path_cnt,
|
|
|
|
unsigned self_cnt,
|
|
|
|
mbedtls_x509_crt_restart_ctx *rs_ctx)
|
2017-06-29 12:27:23 +02:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2017-08-14 18:04:19 +02:00
|
|
|
mbedtls_x509_crt *parent, *fallback_parent;
|
2019-05-30 20:49:17 +02:00
|
|
|
int signature_is_good = 0, fallback_signature_is_good;
|
2017-08-14 18:04:19 +02:00
|
|
|
|
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
2017-08-23 11:20:48 +02:00
|
|
|
/* did we have something in progress? */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (rs_ctx != NULL && rs_ctx->parent != NULL) {
|
2017-08-23 11:20:48 +02:00
|
|
|
/* restore saved state */
|
2017-08-14 18:04:19 +02:00
|
|
|
parent = rs_ctx->parent;
|
|
|
|
fallback_parent = rs_ctx->fallback_parent;
|
2018-07-02 12:33:14 +02:00
|
|
|
fallback_signature_is_good = rs_ctx->fallback_signature_is_good;
|
2017-08-14 18:04:19 +02:00
|
|
|
|
2017-08-23 11:20:48 +02:00
|
|
|
/* clear saved state */
|
|
|
|
rs_ctx->parent = NULL;
|
|
|
|
rs_ctx->fallback_parent = NULL;
|
2018-07-02 12:33:14 +02:00
|
|
|
rs_ctx->fallback_signature_is_good = 0;
|
2017-08-23 11:20:48 +02:00
|
|
|
|
|
|
|
/* resume where we left */
|
2017-08-14 18:04:19 +02:00
|
|
|
goto check_signature;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fallback_parent = NULL;
|
2018-07-02 12:33:14 +02:00
|
|
|
fallback_signature_is_good = 0;
|
2017-06-29 12:27:23 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
for (parent = candidates; parent != NULL; parent = parent->next) {
|
2017-07-03 18:30:43 +02:00
|
|
|
/* basic parenting skills (name, CA bit, key usage) */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_crt_check_parent(child, parent, top) != 0) {
|
2017-06-29 12:27:23 +02:00
|
|
|
continue;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-06-29 12:27:23 +02:00
|
|
|
|
2017-06-29 12:38:42 +02:00
|
|
|
/* +1 because stored max_pathlen is 1 higher that the actual value */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (parent->max_pathlen > 0 &&
|
|
|
|
(size_t) parent->max_pathlen < 1 + path_cnt - self_cnt) {
|
2017-06-29 12:38:42 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-07-03 18:30:43 +02:00
|
|
|
/* Signature */
|
2017-08-14 18:04:19 +02:00
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
|
|
|
check_signature:
|
|
|
|
#endif
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = x509_crt_check_signature(child, parent, rs_ctx);
|
2017-07-17 10:26:19 +02:00
|
|
|
|
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
|
2017-08-14 18:04:19 +02:00
|
|
|
/* save state */
|
|
|
|
rs_ctx->parent = parent;
|
|
|
|
rs_ctx->fallback_parent = fallback_parent;
|
2018-07-02 12:33:14 +02:00
|
|
|
rs_ctx->fallback_signature_is_good = fallback_signature_is_good;
|
2017-08-14 18:04:19 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
2017-07-17 10:26:19 +02:00
|
|
|
}
|
2017-08-14 18:04:19 +02:00
|
|
|
#else
|
|
|
|
(void) ret;
|
|
|
|
#endif
|
2017-07-17 10:26:19 +02:00
|
|
|
|
|
|
|
signature_is_good = ret == 0;
|
2023-01-11 14:50:10 +01:00
|
|
|
if (top && !signature_is_good) {
|
2017-07-03 19:26:25 +02:00
|
|
|
continue;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-07-03 18:30:43 +02:00
|
|
|
|
2017-08-08 18:09:14 +02:00
|
|
|
/* optional time check */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_x509_time_is_past(&parent->valid_to) ||
|
|
|
|
mbedtls_x509_time_is_future(&parent->valid_from)) {
|
|
|
|
if (fallback_parent == NULL) {
|
2017-07-14 12:04:14 +02:00
|
|
|
fallback_parent = parent;
|
2018-07-02 12:33:14 +02:00
|
|
|
fallback_signature_is_good = signature_is_good;
|
2017-07-14 12:04:14 +02:00
|
|
|
}
|
2017-06-29 12:55:27 +02:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-07-17 10:26:19 +02:00
|
|
|
*r_parent = parent;
|
|
|
|
*r_signature_is_good = signature_is_good;
|
2019-01-30 17:25:53 +01:00
|
|
|
|
|
|
|
break;
|
2017-07-17 10:26:19 +02:00
|
|
|
}
|
2019-01-30 17:25:53 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (parent == NULL) {
|
2017-07-17 10:26:19 +02:00
|
|
|
*r_parent = fallback_parent;
|
2018-07-02 12:33:14 +02:00
|
|
|
*r_signature_is_good = fallback_signature_is_good;
|
2017-07-14 12:04:14 +02:00
|
|
|
}
|
2017-06-29 12:55:27 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2017-06-29 12:27:23 +02:00
|
|
|
}
|
|
|
|
|
2017-07-04 01:01:39 +02:00
|
|
|
/*
|
|
|
|
* Find a parent in trusted CAs or the provided chain, or return NULL.
|
|
|
|
*
|
|
|
|
* Searches in trusted CAs first, and return the first suitable parent found
|
|
|
|
* (see find_parent_in() for definition of suitable).
|
2017-08-17 10:52:20 +02:00
|
|
|
*
|
|
|
|
* Arguments:
|
2018-03-07 10:00:57 +01:00
|
|
|
* - [in] child: certificate for which we're looking for a parent, followed
|
|
|
|
* by a chain of possible intermediates
|
2018-06-12 12:40:54 +02:00
|
|
|
* - [in] trust_ca: list of locally trusted certificates
|
|
|
|
* - [out] parent: parent found (or NULL)
|
|
|
|
* - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0
|
|
|
|
* - [out] signature_is_good: 1 if child signature by parent is valid, or 0
|
|
|
|
* - [in] path_cnt: number of links in the chain so far (EE -> ... -> child)
|
|
|
|
* - [in] self_cnt: number of self-signed certs in the chain so far
|
2018-03-07 10:00:57 +01:00
|
|
|
* (will always be no greater than path_cnt)
|
2018-06-12 12:40:54 +02:00
|
|
|
* - [in-out] rs_ctx: context for restarting operations
|
2018-03-07 10:00:57 +01:00
|
|
|
*
|
|
|
|
* Return value:
|
2018-06-12 12:40:54 +02:00
|
|
|
* - 0 on success
|
|
|
|
* - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise
|
2017-07-04 01:01:39 +02:00
|
|
|
*/
|
2017-07-17 10:26:19 +02:00
|
|
|
static int x509_crt_find_parent(
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_x509_crt *child,
|
|
|
|
mbedtls_x509_crt *trust_ca,
|
|
|
|
mbedtls_x509_crt **parent,
|
|
|
|
int *parent_is_trusted,
|
|
|
|
int *signature_is_good,
|
|
|
|
unsigned path_cnt,
|
|
|
|
unsigned self_cnt,
|
|
|
|
mbedtls_x509_crt_restart_ctx *rs_ctx)
|
2017-07-04 01:01:39 +02:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2017-08-14 16:11:43 +02:00
|
|
|
mbedtls_x509_crt *search_list;
|
2017-07-04 01:01:39 +02:00
|
|
|
|
|
|
|
*parent_is_trusted = 1;
|
2017-08-14 16:11:43 +02:00
|
|
|
|
2017-08-14 18:04:19 +02:00
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
2017-08-23 11:20:48 +02:00
|
|
|
/* restore then clear saved state if we have some stored */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (rs_ctx != NULL && rs_ctx->parent_is_trusted != -1) {
|
2017-08-14 18:04:19 +02:00
|
|
|
*parent_is_trusted = rs_ctx->parent_is_trusted;
|
2017-08-23 11:20:48 +02:00
|
|
|
rs_ctx->parent_is_trusted = -1;
|
|
|
|
}
|
2017-08-14 18:04:19 +02:00
|
|
|
#endif
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while (1) {
|
2017-08-14 16:11:43 +02:00
|
|
|
search_list = *parent_is_trusted ? trust_ca : child->next;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = x509_crt_find_parent_in(child, search_list,
|
|
|
|
parent, signature_is_good,
|
|
|
|
*parent_is_trusted,
|
|
|
|
path_cnt, self_cnt, rs_ctx);
|
2017-07-04 01:01:39 +02:00
|
|
|
|
2017-07-17 10:26:19 +02:00
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
|
2017-08-14 18:04:19 +02:00
|
|
|
/* save state */
|
|
|
|
rs_ctx->parent_is_trusted = *parent_is_trusted;
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
2017-08-14 16:11:43 +02:00
|
|
|
}
|
2017-08-14 18:04:19 +02:00
|
|
|
#else
|
|
|
|
(void) ret;
|
|
|
|
#endif
|
2017-07-17 10:26:19 +02:00
|
|
|
|
2017-08-14 16:11:43 +02:00
|
|
|
/* stop here if found or already in second iteration */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*parent != NULL || *parent_is_trusted == 0) {
|
2017-08-14 16:11:43 +02:00
|
|
|
break;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-07-04 01:01:39 +02:00
|
|
|
|
2017-08-14 16:11:43 +02:00
|
|
|
/* prepare second iteration */
|
|
|
|
*parent_is_trusted = 0;
|
|
|
|
}
|
2017-07-17 10:26:19 +02:00
|
|
|
|
2017-08-14 16:11:43 +02:00
|
|
|
/* extra precaution against mistakes in the caller */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*parent == NULL) {
|
2018-10-16 11:27:23 +02:00
|
|
|
*parent_is_trusted = 0;
|
|
|
|
*signature_is_good = 0;
|
2017-07-17 10:26:19 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2017-07-04 01:01:39 +02:00
|
|
|
}
|
|
|
|
|
2017-07-04 00:49:31 +02:00
|
|
|
/*
|
|
|
|
* Check if an end-entity certificate is locally trusted
|
|
|
|
*
|
|
|
|
* Currently we require such certificates to be self-signed (actually only
|
|
|
|
* check for self-issued as self-signatures are not checked)
|
|
|
|
*/
|
|
|
|
static int x509_crt_check_ee_locally_trusted(
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_x509_crt *crt,
|
|
|
|
mbedtls_x509_crt *trust_ca)
|
2017-07-04 00:49:31 +02:00
|
|
|
{
|
|
|
|
mbedtls_x509_crt *cur;
|
|
|
|
|
|
|
|
/* must be self-issued */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_name_cmp(&crt->issuer, &crt->subject) != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2017-07-04 00:49:31 +02:00
|
|
|
|
|
|
|
/* look for an exact match with trusted cert */
|
2023-01-11 14:50:10 +01:00
|
|
|
for (cur = trust_ca; cur != NULL; cur = cur->next) {
|
|
|
|
if (crt->raw.len == cur->raw.len &&
|
|
|
|
memcmp(crt->raw.p, cur->raw.p, crt->raw.len) == 0) {
|
|
|
|
return 0;
|
2017-07-04 00:49:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* too bad */
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2017-07-04 00:49:31 +02:00
|
|
|
}
|
|
|
|
|
2017-06-29 10:45:25 +02:00
|
|
|
/*
|
2017-07-05 16:43:44 +02:00
|
|
|
* Build and verify a certificate chain
|
2017-06-29 10:45:25 +02:00
|
|
|
*
|
2017-07-05 16:43:44 +02:00
|
|
|
* Given a peer-provided list of certificates EE, C1, ..., Cn and
|
|
|
|
* a list of trusted certs R1, ... Rp, try to build and verify a chain
|
2017-08-08 18:09:14 +02:00
|
|
|
* EE, Ci1, ... Ciq [, Rj]
|
2017-07-05 16:43:44 +02:00
|
|
|
* such that every cert in the chain is a child of the next one,
|
|
|
|
* jumping to a trusted root as early as possible.
|
2017-07-04 00:33:39 +02:00
|
|
|
*
|
2017-07-05 16:43:44 +02:00
|
|
|
* Verify that chain and return it with flags for all issues found.
|
|
|
|
*
|
|
|
|
* Special cases:
|
|
|
|
* - EE == Rj -> return a one-element list containing it
|
|
|
|
* - EE, Ci1, ..., Ciq cannot be continued with a trusted root
|
|
|
|
* -> return that chain with NOT_TRUSTED set on Ciq
|
2017-07-04 00:33:39 +02:00
|
|
|
*
|
2017-07-14 11:05:59 +02:00
|
|
|
* Tests for (aspects of) this function should include at least:
|
|
|
|
* - trusted EE
|
|
|
|
* - EE -> trusted root
|
2019-01-23 15:24:37 +01:00
|
|
|
* - EE -> intermediate CA -> trusted root
|
2017-07-14 11:05:59 +02:00
|
|
|
* - if relevant: EE untrusted
|
|
|
|
* - if relevant: EE -> intermediate, untrusted
|
|
|
|
* with the aspect under test checked at each relevant level (EE, int, root).
|
|
|
|
* For some aspects longer chains are required, but usually length 2 is
|
|
|
|
* enough (but length 1 is not in general).
|
|
|
|
*
|
2017-07-04 00:33:39 +02:00
|
|
|
* Arguments:
|
2017-07-05 17:05:03 +02:00
|
|
|
* - [in] crt: the cert list EE, C1, ..., Cn
|
|
|
|
* - [in] trust_ca: the trusted list R1, ..., Rp
|
|
|
|
* - [in] ca_crl, profile: as in verify_with_profile()
|
2017-08-14 17:17:14 +02:00
|
|
|
* - [out] ver_chain: the built and verified chain
|
2017-08-23 11:23:59 +02:00
|
|
|
* Only valid when return value is 0, may contain garbage otherwise!
|
|
|
|
* Restart note: need not be the same when calling again to resume.
|
2017-08-17 10:52:20 +02:00
|
|
|
* - [in-out] rs_ctx: context for restarting operations
|
2017-07-05 16:43:44 +02:00
|
|
|
*
|
|
|
|
* Return value:
|
|
|
|
* - non-zero if the chain could not be fully built and examined
|
|
|
|
* - 0 is the chain was successfully built and examined,
|
|
|
|
* even if it was found to be invalid
|
2017-06-29 10:45:25 +02:00
|
|
|
*/
|
2017-07-04 00:33:39 +02:00
|
|
|
static int x509_crt_verify_chain(
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_x509_crt *crt,
|
|
|
|
mbedtls_x509_crt *trust_ca,
|
|
|
|
mbedtls_x509_crl *ca_crl,
|
|
|
|
mbedtls_x509_crt_ca_cb_t f_ca_cb,
|
|
|
|
void *p_ca_cb,
|
|
|
|
const mbedtls_x509_crt_profile *profile,
|
|
|
|
mbedtls_x509_crt_verify_chain *ver_chain,
|
|
|
|
mbedtls_x509_crt_restart_ctx *rs_ctx)
|
2012-09-28 09:10:55 +02:00
|
|
|
{
|
2017-08-23 11:23:59 +02:00
|
|
|
/* Don't initialize any of those variables here, so that the compiler can
|
|
|
|
* catch potential issues with jumping ahead when restarting */
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2017-07-05 16:43:44 +02:00
|
|
|
uint32_t *flags;
|
2017-08-14 17:17:14 +02:00
|
|
|
mbedtls_x509_crt_verify_chain_item *cur;
|
2017-07-05 17:05:03 +02:00
|
|
|
mbedtls_x509_crt *child;
|
2017-07-03 21:35:04 +02:00
|
|
|
mbedtls_x509_crt *parent;
|
2017-08-14 18:04:19 +02:00
|
|
|
int parent_is_trusted;
|
|
|
|
int child_is_trusted;
|
|
|
|
int signature_is_good;
|
2017-08-28 13:25:55 +02:00
|
|
|
unsigned self_cnt;
|
2019-03-28 14:45:55 +01:00
|
|
|
mbedtls_x509_crt *cur_trust_ca = NULL;
|
2017-08-14 18:04:19 +02:00
|
|
|
|
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
|
|
|
/* resume if we had an operation in progress */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent) {
|
2017-08-23 11:20:48 +02:00
|
|
|
/* restore saved state */
|
2017-08-23 11:23:59 +02:00
|
|
|
*ver_chain = rs_ctx->ver_chain; /* struct copy */
|
2017-08-23 12:32:19 +02:00
|
|
|
self_cnt = rs_ctx->self_cnt;
|
2017-08-14 18:04:19 +02:00
|
|
|
|
2017-08-23 12:32:19 +02:00
|
|
|
/* restore derived state */
|
2017-08-14 18:04:19 +02:00
|
|
|
cur = &ver_chain->items[ver_chain->len - 1];
|
2017-08-23 12:32:19 +02:00
|
|
|
child = cur->crt;
|
2017-08-14 18:04:19 +02:00
|
|
|
flags = &cur->flags;
|
|
|
|
|
|
|
|
goto find_parent;
|
|
|
|
}
|
|
|
|
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
|
2017-07-03 21:25:10 +02:00
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
child = crt;
|
2017-08-14 18:04:19 +02:00
|
|
|
self_cnt = 0;
|
|
|
|
parent_is_trusted = 0;
|
|
|
|
child_is_trusted = 0;
|
2017-07-05 16:43:44 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while (1) {
|
2017-07-05 17:05:03 +02:00
|
|
|
/* Add certificate to the verification chain */
|
2017-08-14 17:17:14 +02:00
|
|
|
cur = &ver_chain->items[ver_chain->len];
|
|
|
|
cur->crt = child;
|
2017-08-23 10:55:41 +02:00
|
|
|
cur->flags = 0;
|
2017-08-14 17:17:14 +02:00
|
|
|
ver_chain->len++;
|
2017-08-23 10:55:41 +02:00
|
|
|
flags = &cur->flags;
|
2017-07-03 21:39:21 +02:00
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
/* Check time-validity (all certificates) */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_x509_time_is_past(&child->valid_to)) {
|
2017-07-05 17:05:03 +02:00
|
|
|
*flags |= MBEDTLS_X509_BADCERT_EXPIRED;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-07-03 21:39:21 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_x509_time_is_future(&child->valid_from)) {
|
2017-07-05 17:05:03 +02:00
|
|
|
*flags |= MBEDTLS_X509_BADCERT_FUTURE;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-07-04 00:00:24 +02:00
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
/* Stop here for trusted roots (but not for trusted EE certs) */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (child_is_trusted) {
|
|
|
|
return 0;
|
|
|
|
}
|
2017-07-03 21:39:21 +02:00
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
/* Check signature algorithm: MD & PK algs */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_profile_check_md_alg(profile, child->sig_md) != 0) {
|
2017-07-05 17:05:03 +02:00
|
|
|
*flags |= MBEDTLS_X509_BADCERT_BAD_MD;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-07-03 21:39:21 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_profile_check_pk_alg(profile, child->sig_pk) != 0) {
|
2017-07-05 17:05:03 +02:00
|
|
|
*flags |= MBEDTLS_X509_BADCERT_BAD_PK;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-07-04 00:49:31 +02:00
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
/* Special case: EE certs that are locally trusted */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ver_chain->len == 1 &&
|
|
|
|
x509_crt_check_ee_locally_trusted(child, trust_ca) == 0) {
|
|
|
|
return 0;
|
2017-07-05 17:05:03 +02:00
|
|
|
}
|
2017-07-03 21:25:10 +02:00
|
|
|
|
2017-08-14 18:04:19 +02:00
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
|
|
|
find_parent:
|
|
|
|
#endif
|
2019-03-28 14:45:55 +01:00
|
|
|
|
|
|
|
/* Obtain list of potential trusted signers from CA callback,
|
|
|
|
* or use statically provided list. */
|
|
|
|
#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (f_ca_cb != NULL) {
|
|
|
|
mbedtls_x509_crt_free(ver_chain->trust_ca_cb_result);
|
|
|
|
mbedtls_free(ver_chain->trust_ca_cb_result);
|
2019-03-28 14:45:55 +01:00
|
|
|
ver_chain->trust_ca_cb_result = NULL;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = f_ca_cb(p_ca_cb, child, &ver_chain->trust_ca_cb_result);
|
|
|
|
if (ret != 0) {
|
|
|
|
return MBEDTLS_ERR_X509_FATAL_ERROR;
|
|
|
|
}
|
2019-03-28 14:45:55 +01:00
|
|
|
|
|
|
|
cur_trust_ca = ver_chain->trust_ca_cb_result;
|
2023-01-11 14:50:10 +01:00
|
|
|
} else
|
2019-03-28 14:45:55 +01:00
|
|
|
#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
|
|
|
|
{
|
|
|
|
((void) f_ca_cb);
|
|
|
|
((void) p_ca_cb);
|
|
|
|
cur_trust_ca = trust_ca;
|
|
|
|
}
|
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
/* Look for a parent in trusted CAs or up the chain */
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = x509_crt_find_parent(child, cur_trust_ca, &parent,
|
|
|
|
&parent_is_trusted, &signature_is_good,
|
|
|
|
ver_chain->len - 1, self_cnt, rs_ctx);
|
2017-07-17 10:26:19 +02:00
|
|
|
|
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
|
2017-08-14 18:04:19 +02:00
|
|
|
/* save state */
|
2017-08-23 12:32:19 +02:00
|
|
|
rs_ctx->in_progress = x509_crt_rs_find_parent;
|
2017-08-14 18:04:19 +02:00
|
|
|
rs_ctx->self_cnt = self_cnt;
|
2017-08-23 11:23:59 +02:00
|
|
|
rs_ctx->ver_chain = *ver_chain; /* struct copy */
|
2017-08-14 18:04:19 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
2017-07-17 10:26:19 +02:00
|
|
|
}
|
2017-08-14 18:04:19 +02:00
|
|
|
#else
|
|
|
|
(void) ret;
|
|
|
|
#endif
|
2012-09-28 09:10:55 +02:00
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
/* No parent? We're done here */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (parent == NULL) {
|
2017-07-05 17:05:03 +02:00
|
|
|
*flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2017-07-05 17:05:03 +02:00
|
|
|
}
|
2012-09-28 09:10:55 +02:00
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
/* Count intermediate self-issued (not necessarily self-signed) certs.
|
|
|
|
* These can occur with some strategies for key rollover, see [SIRO],
|
|
|
|
* and should be excluded from max_pathlen checks. */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ver_chain->len != 1 &&
|
|
|
|
x509_name_cmp(&child->issuer, &child->subject) == 0) {
|
2017-07-05 17:05:03 +02:00
|
|
|
self_cnt++;
|
2017-08-09 10:28:07 +02:00
|
|
|
}
|
2014-11-20 16:34:20 +01:00
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
/* path_cnt is 0 for the first intermediate CA,
|
|
|
|
* and if parent is trusted it's not an intermediate CA */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (!parent_is_trusted &&
|
|
|
|
ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA) {
|
2017-07-05 17:05:03 +02:00
|
|
|
/* return immediately to avoid overflow the chain array */
|
2023-01-11 14:50:10 +01:00
|
|
|
return MBEDTLS_ERR_X509_FATAL_ERROR;
|
2017-07-05 17:05:03 +02:00
|
|
|
}
|
|
|
|
|
2017-08-17 10:52:20 +02:00
|
|
|
/* signature was checked while searching parent */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (!signature_is_good) {
|
2017-07-05 17:05:03 +02:00
|
|
|
*flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2012-09-28 09:10:55 +02:00
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
/* check size of signing key */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_profile_check_key(profile, &parent->pk) != 0) {
|
2017-07-05 17:05:03 +02:00
|
|
|
*flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2012-09-28 09:10:55 +02:00
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_X509_CRL_PARSE_C)
|
2017-07-05 17:05:03 +02:00
|
|
|
/* Check trusted CA's CRL for the given crt */
|
2023-01-11 14:50:10 +01:00
|
|
|
*flags |= x509_crt_verifycrl(child, parent, ca_crl, profile);
|
2017-07-05 17:05:03 +02:00
|
|
|
#else
|
|
|
|
(void) ca_crl;
|
2013-09-16 13:49:26 +02:00
|
|
|
#endif
|
2012-09-28 09:10:55 +02:00
|
|
|
|
2017-07-05 17:05:03 +02:00
|
|
|
/* prepare for next iteration */
|
|
|
|
child = parent;
|
|
|
|
parent = NULL;
|
|
|
|
child_is_trusted = parent_is_trusted;
|
2017-07-14 12:04:14 +02:00
|
|
|
signature_is_good = 0;
|
2017-07-05 17:05:03 +02:00
|
|
|
}
|
2012-09-28 09:10:55 +02:00
|
|
|
}
|
|
|
|
|
2017-07-04 01:31:59 +02:00
|
|
|
/*
|
|
|
|
* Check for CN match
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_crt_check_cn(const mbedtls_x509_buf *name,
|
|
|
|
const char *cn, size_t cn_len)
|
2017-07-04 01:31:59 +02:00
|
|
|
{
|
|
|
|
/* try exact match */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (name->len == cn_len &&
|
|
|
|
x509_memcasecmp(cn, name->p, cn_len) == 0) {
|
|
|
|
return 0;
|
2017-07-04 01:31:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* try wildcard match */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_check_wildcard(cn, name) == 0) {
|
|
|
|
return 0;
|
2017-07-04 01:31:59 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2017-07-04 01:31:59 +02:00
|
|
|
}
|
|
|
|
|
2020-07-21 13:22:41 +02:00
|
|
|
/*
|
|
|
|
* Check for SAN match, see RFC 5280 Section 4.2.1.6
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_crt_check_san(const mbedtls_x509_buf *name,
|
|
|
|
const char *cn, size_t cn_len)
|
2020-07-21 13:22:41 +02:00
|
|
|
{
|
|
|
|
const unsigned char san_type = (unsigned char) name->tag &
|
|
|
|
MBEDTLS_ASN1_TAG_VALUE_MASK;
|
|
|
|
|
|
|
|
/* dNSName */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (san_type == MBEDTLS_X509_SAN_DNS_NAME) {
|
|
|
|
return x509_crt_check_cn(name, cn, cn_len);
|
|
|
|
}
|
2020-07-21 13:22:41 +02:00
|
|
|
|
|
|
|
/* (We may handle other types here later.) */
|
|
|
|
|
|
|
|
/* Unrecognized type */
|
2023-01-11 14:50:10 +01:00
|
|
|
return -1;
|
2020-07-21 13:22:41 +02:00
|
|
|
}
|
|
|
|
|
2017-07-04 01:13:44 +02:00
|
|
|
/*
|
|
|
|
* Verify the requested CN - only call this if cn is not NULL!
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static void x509_crt_verify_name(const mbedtls_x509_crt *crt,
|
|
|
|
const char *cn,
|
|
|
|
uint32_t *flags)
|
2017-07-04 01:13:44 +02:00
|
|
|
{
|
2017-07-04 01:31:59 +02:00
|
|
|
const mbedtls_x509_name *name;
|
|
|
|
const mbedtls_x509_sequence *cur;
|
2023-01-11 14:50:10 +01:00
|
|
|
size_t cn_len = strlen(cn);
|
2017-07-04 01:13:44 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) {
|
|
|
|
for (cur = &crt->subject_alt_names; cur != NULL; cur = cur->next) {
|
|
|
|
if (x509_crt_check_san(&cur->buf, cn, cn_len) == 0) {
|
2017-07-04 01:13:44 +02:00
|
|
|
break;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-07-04 01:13:44 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (cur == NULL) {
|
2017-07-04 01:13:44 +02:00
|
|
|
*flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (name = &crt->subject; name != NULL; name = name->next) {
|
|
|
|
if (MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid) == 0 &&
|
|
|
|
x509_crt_check_cn(&name->val, cn, cn_len) == 0) {
|
2017-07-04 01:31:59 +02:00
|
|
|
break;
|
2017-07-04 01:13:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (name == NULL) {
|
2017-07-04 01:13:44 +02:00
|
|
|
*flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-07-04 01:13:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-05 17:18:42 +02:00
|
|
|
/*
|
|
|
|
* Merge the flags for all certs in the chain, after calling callback
|
|
|
|
*/
|
|
|
|
static int x509_crt_merge_flags_with_cb(
|
2023-01-11 14:50:10 +01:00
|
|
|
uint32_t *flags,
|
|
|
|
const mbedtls_x509_crt_verify_chain *ver_chain,
|
|
|
|
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
|
|
|
|
void *p_vrfy)
|
2017-07-05 17:18:42 +02:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2017-08-28 13:25:55 +02:00
|
|
|
unsigned i;
|
2017-07-05 17:18:42 +02:00
|
|
|
uint32_t cur_flags;
|
2017-08-14 17:17:14 +02:00
|
|
|
const mbedtls_x509_crt_verify_chain_item *cur;
|
2017-07-05 17:18:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
for (i = ver_chain->len; i != 0; --i) {
|
2017-08-14 17:17:14 +02:00
|
|
|
cur = &ver_chain->items[i-1];
|
|
|
|
cur_flags = cur->flags;
|
2017-07-05 17:18:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (NULL != f_vrfy) {
|
|
|
|
if ((ret = f_vrfy(p_vrfy, cur->crt, (int) i-1, &cur_flags)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2017-07-05 17:18:42 +02:00
|
|
|
|
|
|
|
*flags |= cur_flags;
|
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2017-07-05 17:18:42 +02:00
|
|
|
}
|
|
|
|
|
2017-07-11 11:02:20 +02:00
|
|
|
/*
|
|
|
|
* Verify the certificate validity, with profile, restartable version
|
2017-06-29 10:45:25 +02:00
|
|
|
*
|
2017-07-12 12:23:06 +02:00
|
|
|
* This function:
|
|
|
|
* - checks the requested CN (if any)
|
|
|
|
* - checks the type and size of the EE cert's key,
|
|
|
|
* as that isn't done as part of chain building/verification currently
|
|
|
|
* - builds and verifies the chain
|
|
|
|
* - then calls the callback and merges the flags
|
Add prototype for CRT verification with static and dynamic CA list
So far, there were the following CRT verification functions:
- `mbedtls_x509_crt_verify()` -- no profile, no restartable ECC
- `mbedtls_x509_crt_verify_with_profile()` -- profile, no restartable ECC
- `mbedtls_x509_crt_verify_restartable()` -- profile, restartable ECC
all publicly declared and offering increasing functionality.
On the implementation-side,
- `mbedtls_x509_crt_verify()` resolves to
a call to `mbedtls_x509_crt_verify_with_profile()` setting
the profile to `NULL`, and
- `mbedtls_x509_crt_verify_with_profile()`
resolves to a call to ``mbedtls_x509_crt_verify_restartable()`
setting the ECC restart context to NULL.
This commit adds two more functions to this zoo:
- `mbedtls_x509_crt_verify_with_cb()`
- `x509_crt_verify_restartable_cb()`
Here, `mbedtls_x509_crt_verify_with_cb()` is similar to
`mbedtls_x509_crt_verify_with_profile()` but uses a CA callback
instead of a static CA list, and no restart context.
`x509_crt_verify_restartable_cb()` is similar to
`mbedtls_x509_crt_verify_restartable()` but allows to either use
a static list of trusted CAs _or_ a trusted CA callback.
On the implementation-side,
- the body of `mbedtls_x509_crt_verify_restartable()` is moved to
`x509_crt_verify_restartable_cb()`, and the new version of
`mbedtls_x509_crt_verify_restartable()` just resolves to
`x509_crt_verify_restartable_cb()` with the trusted CA callback
set to NULL.
- The new function `mbedtls_x509_crt_verify_with_cb()`
forward to `x509_crt_verify_restartable_cb()` with the restart
context set to `NULL`.
There's no change to the implementation yet, and in particular,
`mbedtls_x509_crt_verify_with_cb()` isn't yet usable.
2019-03-28 14:34:42 +01:00
|
|
|
*
|
|
|
|
* The parameters pairs `trust_ca`, `ca_crl` and `f_ca_cb`, `p_ca_cb`
|
|
|
|
* are mutually exclusive: If `f_ca_cb != NULL`, it will be used by the
|
|
|
|
* verification routine to search for trusted signers, and CRLs will
|
|
|
|
* be disabled. Otherwise, `trust_ca` will be used as the static list
|
|
|
|
* of trusted signers, and `ca_crl` will be use as the static list
|
|
|
|
* of CRLs.
|
2015-06-15 10:39:46 +02:00
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
static int x509_crt_verify_restartable_ca_cb(mbedtls_x509_crt *crt,
|
|
|
|
mbedtls_x509_crt *trust_ca,
|
|
|
|
mbedtls_x509_crl *ca_crl,
|
|
|
|
mbedtls_x509_crt_ca_cb_t f_ca_cb,
|
|
|
|
void *p_ca_cb,
|
|
|
|
const mbedtls_x509_crt_profile *profile,
|
|
|
|
const char *cn, uint32_t *flags,
|
|
|
|
int (*f_vrfy)(void *,
|
|
|
|
mbedtls_x509_crt *,
|
|
|
|
int,
|
|
|
|
uint32_t *),
|
|
|
|
void *p_vrfy,
|
|
|
|
mbedtls_x509_crt_restart_ctx *rs_ctx)
|
2009-01-03 22:22:43 +01:00
|
|
|
{
|
2019-12-16 12:46:15 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2015-10-23 14:08:48 +02:00
|
|
|
mbedtls_pk_type_t pk_type;
|
2017-08-14 17:17:14 +02:00
|
|
|
mbedtls_x509_crt_verify_chain ver_chain;
|
2017-08-23 10:55:41 +02:00
|
|
|
uint32_t ee_flags;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2009-05-03 12:18:48 +02:00
|
|
|
*flags = 0;
|
2017-08-23 10:55:41 +02:00
|
|
|
ee_flags = 0;
|
2023-01-11 14:50:10 +01:00
|
|
|
x509_crt_verify_chain_reset(&ver_chain);
|
2009-05-03 12:18:48 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (profile == NULL) {
|
2017-06-22 12:19:27 +02:00
|
|
|
ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2017-07-04 01:13:44 +02:00
|
|
|
/* check name if requested */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (cn != NULL) {
|
|
|
|
x509_crt_verify_name(crt, cn, &ee_flags);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2015-10-23 14:08:48 +02:00
|
|
|
/* Check the type and size of the key */
|
2023-01-11 14:50:10 +01:00
|
|
|
pk_type = mbedtls_pk_get_type(&crt->pk);
|
2015-10-23 14:08:48 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_profile_check_pk_alg(profile, pk_type) != 0) {
|
2017-08-23 10:55:41 +02:00
|
|
|
ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2015-10-23 14:08:48 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (x509_profile_check_key(profile, &crt->pk) != 0) {
|
2017-08-23 10:55:41 +02:00
|
|
|
ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2015-10-23 14:08:48 +02:00
|
|
|
|
2017-07-04 00:33:39 +02:00
|
|
|
/* Check the chain */
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = x509_crt_verify_chain(crt, trust_ca, ca_crl,
|
|
|
|
f_ca_cb, p_ca_cb, profile,
|
|
|
|
&ver_chain, rs_ctx);
|
2017-07-17 10:26:19 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ret != 0) {
|
2017-07-05 13:28:45 +02:00
|
|
|
goto exit;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-07-05 13:28:45 +02:00
|
|
|
|
2017-08-23 10:55:41 +02:00
|
|
|
/* Merge end-entity flags */
|
|
|
|
ver_chain.items[0].flags |= ee_flags;
|
|
|
|
|
2017-07-05 17:18:42 +02:00
|
|
|
/* Build final flags, calling callback on the way if any */
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = x509_crt_merge_flags_with_cb(flags, &ver_chain, f_vrfy, p_vrfy);
|
2012-09-28 09:10:55 +02:00
|
|
|
|
2017-06-22 12:19:27 +02:00
|
|
|
exit:
|
2019-03-28 14:45:55 +01:00
|
|
|
|
|
|
|
#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_x509_crt_free(ver_chain.trust_ca_cb_result);
|
|
|
|
mbedtls_free(ver_chain.trust_ca_cb_result);
|
2019-03-28 14:45:55 +01:00
|
|
|
ver_chain.trust_ca_cb_result = NULL;
|
|
|
|
#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
|
|
|
|
|
2017-08-14 18:04:19 +02:00
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
2023-01-11 14:50:10 +01:00
|
|
|
if (rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS) {
|
|
|
|
mbedtls_x509_crt_restart_free(rs_ctx);
|
|
|
|
}
|
2017-08-14 18:04:19 +02:00
|
|
|
#endif
|
|
|
|
|
2017-07-06 12:16:25 +02:00
|
|
|
/* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by
|
|
|
|
* the SSL module for authmode optional, but non-zero return from the
|
|
|
|
* callback means a fatal error so it shouldn't be ignored */
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
|
2017-06-26 10:11:49 +02:00
|
|
|
ret = MBEDTLS_ERR_X509_FATAL_ERROR;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-06-26 10:11:49 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ret != 0) {
|
2017-06-22 12:19:27 +02:00
|
|
|
*flags = (uint32_t) -1;
|
2023-01-11 14:50:10 +01:00
|
|
|
return ret;
|
2017-06-22 12:19:27 +02:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (*flags != 0) {
|
|
|
|
return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED;
|
|
|
|
}
|
2011-01-13 18:54:59 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
Add prototype for CRT verification with static and dynamic CA list
So far, there were the following CRT verification functions:
- `mbedtls_x509_crt_verify()` -- no profile, no restartable ECC
- `mbedtls_x509_crt_verify_with_profile()` -- profile, no restartable ECC
- `mbedtls_x509_crt_verify_restartable()` -- profile, restartable ECC
all publicly declared and offering increasing functionality.
On the implementation-side,
- `mbedtls_x509_crt_verify()` resolves to
a call to `mbedtls_x509_crt_verify_with_profile()` setting
the profile to `NULL`, and
- `mbedtls_x509_crt_verify_with_profile()`
resolves to a call to ``mbedtls_x509_crt_verify_restartable()`
setting the ECC restart context to NULL.
This commit adds two more functions to this zoo:
- `mbedtls_x509_crt_verify_with_cb()`
- `x509_crt_verify_restartable_cb()`
Here, `mbedtls_x509_crt_verify_with_cb()` is similar to
`mbedtls_x509_crt_verify_with_profile()` but uses a CA callback
instead of a static CA list, and no restart context.
`x509_crt_verify_restartable_cb()` is similar to
`mbedtls_x509_crt_verify_restartable()` but allows to either use
a static list of trusted CAs _or_ a trusted CA callback.
On the implementation-side,
- the body of `mbedtls_x509_crt_verify_restartable()` is moved to
`x509_crt_verify_restartable_cb()`, and the new version of
`mbedtls_x509_crt_verify_restartable()` just resolves to
`x509_crt_verify_restartable_cb()` with the trusted CA callback
set to NULL.
- The new function `mbedtls_x509_crt_verify_with_cb()`
forward to `x509_crt_verify_restartable_cb()` with the restart
context set to `NULL`.
There's no change to the implementation yet, and in particular,
`mbedtls_x509_crt_verify_with_cb()` isn't yet usable.
2019-03-28 14:34:42 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify the certificate validity (default profile, not restartable)
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_verify(mbedtls_x509_crt *crt,
|
|
|
|
mbedtls_x509_crt *trust_ca,
|
|
|
|
mbedtls_x509_crl *ca_crl,
|
|
|
|
const char *cn, uint32_t *flags,
|
|
|
|
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
|
|
|
|
void *p_vrfy)
|
Add prototype for CRT verification with static and dynamic CA list
So far, there were the following CRT verification functions:
- `mbedtls_x509_crt_verify()` -- no profile, no restartable ECC
- `mbedtls_x509_crt_verify_with_profile()` -- profile, no restartable ECC
- `mbedtls_x509_crt_verify_restartable()` -- profile, restartable ECC
all publicly declared and offering increasing functionality.
On the implementation-side,
- `mbedtls_x509_crt_verify()` resolves to
a call to `mbedtls_x509_crt_verify_with_profile()` setting
the profile to `NULL`, and
- `mbedtls_x509_crt_verify_with_profile()`
resolves to a call to ``mbedtls_x509_crt_verify_restartable()`
setting the ECC restart context to NULL.
This commit adds two more functions to this zoo:
- `mbedtls_x509_crt_verify_with_cb()`
- `x509_crt_verify_restartable_cb()`
Here, `mbedtls_x509_crt_verify_with_cb()` is similar to
`mbedtls_x509_crt_verify_with_profile()` but uses a CA callback
instead of a static CA list, and no restart context.
`x509_crt_verify_restartable_cb()` is similar to
`mbedtls_x509_crt_verify_restartable()` but allows to either use
a static list of trusted CAs _or_ a trusted CA callback.
On the implementation-side,
- the body of `mbedtls_x509_crt_verify_restartable()` is moved to
`x509_crt_verify_restartable_cb()`, and the new version of
`mbedtls_x509_crt_verify_restartable()` just resolves to
`x509_crt_verify_restartable_cb()` with the trusted CA callback
set to NULL.
- The new function `mbedtls_x509_crt_verify_with_cb()`
forward to `x509_crt_verify_restartable_cb()` with the restart
context set to `NULL`.
There's no change to the implementation yet, and in particular,
`mbedtls_x509_crt_verify_with_cb()` isn't yet usable.
2019-03-28 14:34:42 +01:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl,
|
|
|
|
NULL, NULL,
|
|
|
|
&mbedtls_x509_crt_profile_default,
|
|
|
|
cn, flags,
|
|
|
|
f_vrfy, p_vrfy, NULL);
|
Add prototype for CRT verification with static and dynamic CA list
So far, there were the following CRT verification functions:
- `mbedtls_x509_crt_verify()` -- no profile, no restartable ECC
- `mbedtls_x509_crt_verify_with_profile()` -- profile, no restartable ECC
- `mbedtls_x509_crt_verify_restartable()` -- profile, restartable ECC
all publicly declared and offering increasing functionality.
On the implementation-side,
- `mbedtls_x509_crt_verify()` resolves to
a call to `mbedtls_x509_crt_verify_with_profile()` setting
the profile to `NULL`, and
- `mbedtls_x509_crt_verify_with_profile()`
resolves to a call to ``mbedtls_x509_crt_verify_restartable()`
setting the ECC restart context to NULL.
This commit adds two more functions to this zoo:
- `mbedtls_x509_crt_verify_with_cb()`
- `x509_crt_verify_restartable_cb()`
Here, `mbedtls_x509_crt_verify_with_cb()` is similar to
`mbedtls_x509_crt_verify_with_profile()` but uses a CA callback
instead of a static CA list, and no restart context.
`x509_crt_verify_restartable_cb()` is similar to
`mbedtls_x509_crt_verify_restartable()` but allows to either use
a static list of trusted CAs _or_ a trusted CA callback.
On the implementation-side,
- the body of `mbedtls_x509_crt_verify_restartable()` is moved to
`x509_crt_verify_restartable_cb()`, and the new version of
`mbedtls_x509_crt_verify_restartable()` just resolves to
`x509_crt_verify_restartable_cb()` with the trusted CA callback
set to NULL.
- The new function `mbedtls_x509_crt_verify_with_cb()`
forward to `x509_crt_verify_restartable_cb()` with the restart
context set to `NULL`.
There's no change to the implementation yet, and in particular,
`mbedtls_x509_crt_verify_with_cb()` isn't yet usable.
2019-03-28 14:34:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify the certificate validity (user-chosen profile, not restartable)
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_verify_with_profile(mbedtls_x509_crt *crt,
|
|
|
|
mbedtls_x509_crt *trust_ca,
|
|
|
|
mbedtls_x509_crl *ca_crl,
|
|
|
|
const mbedtls_x509_crt_profile *profile,
|
|
|
|
const char *cn, uint32_t *flags,
|
|
|
|
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
|
|
|
|
void *p_vrfy)
|
Add prototype for CRT verification with static and dynamic CA list
So far, there were the following CRT verification functions:
- `mbedtls_x509_crt_verify()` -- no profile, no restartable ECC
- `mbedtls_x509_crt_verify_with_profile()` -- profile, no restartable ECC
- `mbedtls_x509_crt_verify_restartable()` -- profile, restartable ECC
all publicly declared and offering increasing functionality.
On the implementation-side,
- `mbedtls_x509_crt_verify()` resolves to
a call to `mbedtls_x509_crt_verify_with_profile()` setting
the profile to `NULL`, and
- `mbedtls_x509_crt_verify_with_profile()`
resolves to a call to ``mbedtls_x509_crt_verify_restartable()`
setting the ECC restart context to NULL.
This commit adds two more functions to this zoo:
- `mbedtls_x509_crt_verify_with_cb()`
- `x509_crt_verify_restartable_cb()`
Here, `mbedtls_x509_crt_verify_with_cb()` is similar to
`mbedtls_x509_crt_verify_with_profile()` but uses a CA callback
instead of a static CA list, and no restart context.
`x509_crt_verify_restartable_cb()` is similar to
`mbedtls_x509_crt_verify_restartable()` but allows to either use
a static list of trusted CAs _or_ a trusted CA callback.
On the implementation-side,
- the body of `mbedtls_x509_crt_verify_restartable()` is moved to
`x509_crt_verify_restartable_cb()`, and the new version of
`mbedtls_x509_crt_verify_restartable()` just resolves to
`x509_crt_verify_restartable_cb()` with the trusted CA callback
set to NULL.
- The new function `mbedtls_x509_crt_verify_with_cb()`
forward to `x509_crt_verify_restartable_cb()` with the restart
context set to `NULL`.
There's no change to the implementation yet, and in particular,
`mbedtls_x509_crt_verify_with_cb()` isn't yet usable.
2019-03-28 14:34:42 +01:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl,
|
|
|
|
NULL, NULL,
|
|
|
|
profile, cn, flags,
|
|
|
|
f_vrfy, p_vrfy, NULL);
|
Add prototype for CRT verification with static and dynamic CA list
So far, there were the following CRT verification functions:
- `mbedtls_x509_crt_verify()` -- no profile, no restartable ECC
- `mbedtls_x509_crt_verify_with_profile()` -- profile, no restartable ECC
- `mbedtls_x509_crt_verify_restartable()` -- profile, restartable ECC
all publicly declared and offering increasing functionality.
On the implementation-side,
- `mbedtls_x509_crt_verify()` resolves to
a call to `mbedtls_x509_crt_verify_with_profile()` setting
the profile to `NULL`, and
- `mbedtls_x509_crt_verify_with_profile()`
resolves to a call to ``mbedtls_x509_crt_verify_restartable()`
setting the ECC restart context to NULL.
This commit adds two more functions to this zoo:
- `mbedtls_x509_crt_verify_with_cb()`
- `x509_crt_verify_restartable_cb()`
Here, `mbedtls_x509_crt_verify_with_cb()` is similar to
`mbedtls_x509_crt_verify_with_profile()` but uses a CA callback
instead of a static CA list, and no restart context.
`x509_crt_verify_restartable_cb()` is similar to
`mbedtls_x509_crt_verify_restartable()` but allows to either use
a static list of trusted CAs _or_ a trusted CA callback.
On the implementation-side,
- the body of `mbedtls_x509_crt_verify_restartable()` is moved to
`x509_crt_verify_restartable_cb()`, and the new version of
`mbedtls_x509_crt_verify_restartable()` just resolves to
`x509_crt_verify_restartable_cb()` with the trusted CA callback
set to NULL.
- The new function `mbedtls_x509_crt_verify_with_cb()`
forward to `x509_crt_verify_restartable_cb()` with the restart
context set to `NULL`.
There's no change to the implementation yet, and in particular,
`mbedtls_x509_crt_verify_with_cb()` isn't yet usable.
2019-03-28 14:34:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
|
|
|
|
/*
|
|
|
|
* Verify the certificate validity (user-chosen profile, CA callback,
|
|
|
|
* not restartable).
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_verify_with_ca_cb(mbedtls_x509_crt *crt,
|
|
|
|
mbedtls_x509_crt_ca_cb_t f_ca_cb,
|
|
|
|
void *p_ca_cb,
|
|
|
|
const mbedtls_x509_crt_profile *profile,
|
|
|
|
const char *cn, uint32_t *flags,
|
|
|
|
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
|
|
|
|
void *p_vrfy)
|
Add prototype for CRT verification with static and dynamic CA list
So far, there were the following CRT verification functions:
- `mbedtls_x509_crt_verify()` -- no profile, no restartable ECC
- `mbedtls_x509_crt_verify_with_profile()` -- profile, no restartable ECC
- `mbedtls_x509_crt_verify_restartable()` -- profile, restartable ECC
all publicly declared and offering increasing functionality.
On the implementation-side,
- `mbedtls_x509_crt_verify()` resolves to
a call to `mbedtls_x509_crt_verify_with_profile()` setting
the profile to `NULL`, and
- `mbedtls_x509_crt_verify_with_profile()`
resolves to a call to ``mbedtls_x509_crt_verify_restartable()`
setting the ECC restart context to NULL.
This commit adds two more functions to this zoo:
- `mbedtls_x509_crt_verify_with_cb()`
- `x509_crt_verify_restartable_cb()`
Here, `mbedtls_x509_crt_verify_with_cb()` is similar to
`mbedtls_x509_crt_verify_with_profile()` but uses a CA callback
instead of a static CA list, and no restart context.
`x509_crt_verify_restartable_cb()` is similar to
`mbedtls_x509_crt_verify_restartable()` but allows to either use
a static list of trusted CAs _or_ a trusted CA callback.
On the implementation-side,
- the body of `mbedtls_x509_crt_verify_restartable()` is moved to
`x509_crt_verify_restartable_cb()`, and the new version of
`mbedtls_x509_crt_verify_restartable()` just resolves to
`x509_crt_verify_restartable_cb()` with the trusted CA callback
set to NULL.
- The new function `mbedtls_x509_crt_verify_with_cb()`
forward to `x509_crt_verify_restartable_cb()` with the restart
context set to `NULL`.
There's no change to the implementation yet, and in particular,
`mbedtls_x509_crt_verify_with_cb()` isn't yet usable.
2019-03-28 14:34:42 +01:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
return x509_crt_verify_restartable_ca_cb(crt, NULL, NULL,
|
|
|
|
f_ca_cb, p_ca_cb,
|
|
|
|
profile, cn, flags,
|
|
|
|
f_vrfy, p_vrfy, NULL);
|
Add prototype for CRT verification with static and dynamic CA list
So far, there were the following CRT verification functions:
- `mbedtls_x509_crt_verify()` -- no profile, no restartable ECC
- `mbedtls_x509_crt_verify_with_profile()` -- profile, no restartable ECC
- `mbedtls_x509_crt_verify_restartable()` -- profile, restartable ECC
all publicly declared and offering increasing functionality.
On the implementation-side,
- `mbedtls_x509_crt_verify()` resolves to
a call to `mbedtls_x509_crt_verify_with_profile()` setting
the profile to `NULL`, and
- `mbedtls_x509_crt_verify_with_profile()`
resolves to a call to ``mbedtls_x509_crt_verify_restartable()`
setting the ECC restart context to NULL.
This commit adds two more functions to this zoo:
- `mbedtls_x509_crt_verify_with_cb()`
- `x509_crt_verify_restartable_cb()`
Here, `mbedtls_x509_crt_verify_with_cb()` is similar to
`mbedtls_x509_crt_verify_with_profile()` but uses a CA callback
instead of a static CA list, and no restart context.
`x509_crt_verify_restartable_cb()` is similar to
`mbedtls_x509_crt_verify_restartable()` but allows to either use
a static list of trusted CAs _or_ a trusted CA callback.
On the implementation-side,
- the body of `mbedtls_x509_crt_verify_restartable()` is moved to
`x509_crt_verify_restartable_cb()`, and the new version of
`mbedtls_x509_crt_verify_restartable()` just resolves to
`x509_crt_verify_restartable_cb()` with the trusted CA callback
set to NULL.
- The new function `mbedtls_x509_crt_verify_with_cb()`
forward to `x509_crt_verify_restartable_cb()` with the restart
context set to `NULL`.
There's no change to the implementation yet, and in particular,
`mbedtls_x509_crt_verify_with_cb()` isn't yet usable.
2019-03-28 14:34:42 +01:00
|
|
|
}
|
|
|
|
#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_x509_crt_verify_restartable(mbedtls_x509_crt *crt,
|
|
|
|
mbedtls_x509_crt *trust_ca,
|
|
|
|
mbedtls_x509_crl *ca_crl,
|
|
|
|
const mbedtls_x509_crt_profile *profile,
|
|
|
|
const char *cn, uint32_t *flags,
|
|
|
|
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
|
|
|
|
void *p_vrfy,
|
|
|
|
mbedtls_x509_crt_restart_ctx *rs_ctx)
|
Add prototype for CRT verification with static and dynamic CA list
So far, there were the following CRT verification functions:
- `mbedtls_x509_crt_verify()` -- no profile, no restartable ECC
- `mbedtls_x509_crt_verify_with_profile()` -- profile, no restartable ECC
- `mbedtls_x509_crt_verify_restartable()` -- profile, restartable ECC
all publicly declared and offering increasing functionality.
On the implementation-side,
- `mbedtls_x509_crt_verify()` resolves to
a call to `mbedtls_x509_crt_verify_with_profile()` setting
the profile to `NULL`, and
- `mbedtls_x509_crt_verify_with_profile()`
resolves to a call to ``mbedtls_x509_crt_verify_restartable()`
setting the ECC restart context to NULL.
This commit adds two more functions to this zoo:
- `mbedtls_x509_crt_verify_with_cb()`
- `x509_crt_verify_restartable_cb()`
Here, `mbedtls_x509_crt_verify_with_cb()` is similar to
`mbedtls_x509_crt_verify_with_profile()` but uses a CA callback
instead of a static CA list, and no restart context.
`x509_crt_verify_restartable_cb()` is similar to
`mbedtls_x509_crt_verify_restartable()` but allows to either use
a static list of trusted CAs _or_ a trusted CA callback.
On the implementation-side,
- the body of `mbedtls_x509_crt_verify_restartable()` is moved to
`x509_crt_verify_restartable_cb()`, and the new version of
`mbedtls_x509_crt_verify_restartable()` just resolves to
`x509_crt_verify_restartable_cb()` with the trusted CA callback
set to NULL.
- The new function `mbedtls_x509_crt_verify_with_cb()`
forward to `x509_crt_verify_restartable_cb()` with the restart
context set to `NULL`.
There's no change to the implementation yet, and in particular,
`mbedtls_x509_crt_verify_with_cb()` isn't yet usable.
2019-03-28 14:34:42 +01:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
return x509_crt_verify_restartable_ca_cb(crt, trust_ca, ca_crl,
|
|
|
|
NULL, NULL,
|
|
|
|
profile, cn, flags,
|
|
|
|
f_vrfy, p_vrfy, rs_ctx);
|
Add prototype for CRT verification with static and dynamic CA list
So far, there were the following CRT verification functions:
- `mbedtls_x509_crt_verify()` -- no profile, no restartable ECC
- `mbedtls_x509_crt_verify_with_profile()` -- profile, no restartable ECC
- `mbedtls_x509_crt_verify_restartable()` -- profile, restartable ECC
all publicly declared and offering increasing functionality.
On the implementation-side,
- `mbedtls_x509_crt_verify()` resolves to
a call to `mbedtls_x509_crt_verify_with_profile()` setting
the profile to `NULL`, and
- `mbedtls_x509_crt_verify_with_profile()`
resolves to a call to ``mbedtls_x509_crt_verify_restartable()`
setting the ECC restart context to NULL.
This commit adds two more functions to this zoo:
- `mbedtls_x509_crt_verify_with_cb()`
- `x509_crt_verify_restartable_cb()`
Here, `mbedtls_x509_crt_verify_with_cb()` is similar to
`mbedtls_x509_crt_verify_with_profile()` but uses a CA callback
instead of a static CA list, and no restart context.
`x509_crt_verify_restartable_cb()` is similar to
`mbedtls_x509_crt_verify_restartable()` but allows to either use
a static list of trusted CAs _or_ a trusted CA callback.
On the implementation-side,
- the body of `mbedtls_x509_crt_verify_restartable()` is moved to
`x509_crt_verify_restartable_cb()`, and the new version of
`mbedtls_x509_crt_verify_restartable()` just resolves to
`x509_crt_verify_restartable_cb()` with the trusted CA callback
set to NULL.
- The new function `mbedtls_x509_crt_verify_with_cb()`
forward to `x509_crt_verify_restartable_cb()` with the restart
context set to `NULL`.
There's no change to the implementation yet, and in particular,
`mbedtls_x509_crt_verify_with_cb()` isn't yet usable.
2019-03-28 14:34:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-18 11:58:25 +02:00
|
|
|
/*
|
|
|
|
* Initialize a certificate chain
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
void mbedtls_x509_crt_init(mbedtls_x509_crt *crt)
|
2013-09-18 11:58:25 +02:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
memset(crt, 0, sizeof(mbedtls_x509_crt));
|
2013-09-18 11:58:25 +02:00
|
|
|
}
|
|
|
|
|
2009-01-03 22:22:43 +01:00
|
|
|
/*
|
|
|
|
* Unallocate all certificate data
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
void mbedtls_x509_crt_free(mbedtls_x509_crt *crt)
|
2009-01-03 22:22:43 +01:00
|
|
|
{
|
2015-04-08 12:49:31 +02:00
|
|
|
mbedtls_x509_crt *cert_cur = crt;
|
|
|
|
mbedtls_x509_crt *cert_prv;
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while (cert_cur != NULL) {
|
|
|
|
mbedtls_pk_free(&cert_cur->pk);
|
2009-01-03 22:22:43 +01:00
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_free(cert_cur->sig_opts);
|
2014-06-05 15:14:28 +02:00
|
|
|
#endif
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_asn1_free_named_data_list_shallow(cert_cur->issuer.next);
|
|
|
|
mbedtls_asn1_free_named_data_list_shallow(cert_cur->subject.next);
|
|
|
|
mbedtls_asn1_sequence_free(cert_cur->ext_key_usage.next);
|
|
|
|
mbedtls_asn1_sequence_free(cert_cur->subject_alt_names.next);
|
|
|
|
mbedtls_asn1_sequence_free(cert_cur->certificate_policies.next);
|
2019-03-21 13:00:03 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (cert_cur->raw.p != NULL && cert_cur->own_buffer) {
|
|
|
|
mbedtls_platform_zeroize(cert_cur->raw.p, cert_cur->raw.len);
|
|
|
|
mbedtls_free(cert_cur->raw.p);
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
cert_prv = cert_cur;
|
|
|
|
cert_cur = cert_cur->next;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_platform_zeroize(cert_prv, sizeof(mbedtls_x509_crt));
|
|
|
|
if (cert_prv != crt) {
|
|
|
|
mbedtls_free(cert_prv);
|
|
|
|
}
|
2009-01-03 22:22:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-11 11:02:20 +02:00
|
|
|
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
|
|
|
/*
|
|
|
|
* Initialize a restart context
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
void mbedtls_x509_crt_restart_init(mbedtls_x509_crt_restart_ctx *ctx)
|
2017-07-11 11:02:20 +02:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_pk_restart_init(&ctx->pk);
|
2017-08-14 18:04:19 +02:00
|
|
|
|
|
|
|
ctx->parent = NULL;
|
|
|
|
ctx->fallback_parent = NULL;
|
2018-07-02 12:33:14 +02:00
|
|
|
ctx->fallback_signature_is_good = 0;
|
2017-08-14 18:04:19 +02:00
|
|
|
|
|
|
|
ctx->parent_is_trusted = -1;
|
|
|
|
|
2017-08-23 12:32:19 +02:00
|
|
|
ctx->in_progress = x509_crt_rs_none;
|
2017-08-14 18:04:19 +02:00
|
|
|
ctx->self_cnt = 0;
|
2023-01-11 14:50:10 +01:00
|
|
|
x509_crt_verify_chain_reset(&ctx->ver_chain);
|
2017-07-11 11:02:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free the components of a restart context
|
|
|
|
*/
|
2023-01-11 14:50:10 +01:00
|
|
|
void mbedtls_x509_crt_restart_free(mbedtls_x509_crt_restart_ctx *ctx)
|
2017-07-11 11:02:20 +02:00
|
|
|
{
|
2023-01-11 14:50:10 +01:00
|
|
|
if (ctx == NULL) {
|
2017-07-11 11:02:20 +02:00
|
|
|
return;
|
2023-01-11 14:50:10 +01:00
|
|
|
}
|
2017-07-11 11:02:20 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_pk_restart_free(&ctx->pk);
|
|
|
|
mbedtls_x509_crt_restart_init(ctx);
|
2017-07-11 11:02:20 +02:00
|
|
|
}
|
|
|
|
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
|
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|