1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /* 3817466cbSJens Wiklander * X.509 certificate parsing and verification 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander * 19817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 20817466cbSJens Wiklander */ 21817466cbSJens Wiklander /* 22817466cbSJens Wiklander * The ITU-T X.509 standard defines a certificate format for PKI. 23817466cbSJens Wiklander * 24817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) 25817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) 26817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) 27817466cbSJens Wiklander * 28817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf 29817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf 303d3b0591SJens Wiklander * 313d3b0591SJens Wiklander * [SIRO] https://cabforum.org/wp-content/uploads/Chunghwatelecom201503cabforumV4.pdf 32817466cbSJens Wiklander */ 33817466cbSJens Wiklander 34817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 35817466cbSJens Wiklander #include "mbedtls/config.h" 36817466cbSJens Wiklander #else 37817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 38817466cbSJens Wiklander #endif 39817466cbSJens Wiklander 40817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRT_PARSE_C) 41817466cbSJens Wiklander 42817466cbSJens Wiklander #include "mbedtls/x509_crt.h" 43*11fa71b9SJerome Forissier #include "mbedtls/error.h" 44817466cbSJens Wiklander #include "mbedtls/oid.h" 453d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 46817466cbSJens Wiklander 47817466cbSJens Wiklander #include <string.h> 48817466cbSJens Wiklander 49817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 50817466cbSJens Wiklander #include "mbedtls/pem.h" 51817466cbSJens Wiklander #endif 52817466cbSJens Wiklander 53*11fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 54*11fa71b9SJerome Forissier #include "psa/crypto.h" 55*11fa71b9SJerome Forissier #include "mbedtls/psa_util.h" 56*11fa71b9SJerome Forissier #endif 57*11fa71b9SJerome Forissier 58817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 59817466cbSJens Wiklander #include "mbedtls/platform.h" 60817466cbSJens Wiklander #else 613d3b0591SJens Wiklander #include <stdio.h> 62817466cbSJens Wiklander #include <stdlib.h> 63817466cbSJens Wiklander #define mbedtls_free free 64817466cbSJens Wiklander #define mbedtls_calloc calloc 65817466cbSJens Wiklander #define mbedtls_snprintf snprintf 66817466cbSJens Wiklander #endif 67817466cbSJens Wiklander 68817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 69817466cbSJens Wiklander #include "mbedtls/threading.h" 70817466cbSJens Wiklander #endif 71817466cbSJens Wiklander 72817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 73817466cbSJens Wiklander #include <windows.h> 74817466cbSJens Wiklander #else 75817466cbSJens Wiklander #include <time.h> 76817466cbSJens Wiklander #endif 77817466cbSJens Wiklander 78817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 79817466cbSJens Wiklander #include <stdio.h> 80817466cbSJens Wiklander #if !defined(_WIN32) || defined(EFIX64) || defined(EFI32) 81817466cbSJens Wiklander #include <sys/types.h> 82817466cbSJens Wiklander #include <sys/stat.h> 83817466cbSJens Wiklander #include <dirent.h> 84817466cbSJens Wiklander #endif /* !_WIN32 || EFIX64 || EFI32 */ 85817466cbSJens Wiklander #endif 86817466cbSJens Wiklander 873d3b0591SJens Wiklander /* 883d3b0591SJens Wiklander * Item in a verification chain: cert and flags for it 893d3b0591SJens Wiklander */ 903d3b0591SJens Wiklander typedef struct { 913d3b0591SJens Wiklander mbedtls_x509_crt *crt; 923d3b0591SJens Wiklander uint32_t flags; 933d3b0591SJens Wiklander } x509_crt_verify_chain_item; 943d3b0591SJens Wiklander 953d3b0591SJens Wiklander /* 963d3b0591SJens Wiklander * Max size of verification chain: end-entity + intermediates + trusted root 973d3b0591SJens Wiklander */ 983d3b0591SJens Wiklander #define X509_MAX_VERIFY_CHAIN_SIZE ( MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2 ) 99817466cbSJens Wiklander 100817466cbSJens Wiklander /* 101817466cbSJens Wiklander * Default profile 102817466cbSJens Wiklander */ 103817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default = 104817466cbSJens Wiklander { 105817466cbSJens Wiklander #if defined(MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES) 106817466cbSJens Wiklander /* Allow SHA-1 (weak, but still safe in controlled environments) */ 107817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | 108817466cbSJens Wiklander #endif 109817466cbSJens Wiklander /* Only SHA-2 hashes */ 110817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | 111817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | 112817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | 113817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), 114817466cbSJens Wiklander 0xFFFFFFF, /* Any PK alg */ 115817466cbSJens Wiklander 0xFFFFFFF, /* Any curve */ 116817466cbSJens Wiklander 2048, 117817466cbSJens Wiklander }; 118817466cbSJens Wiklander 119817466cbSJens Wiklander /* 120817466cbSJens Wiklander * Next-default profile 121817466cbSJens Wiklander */ 122817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next = 123817466cbSJens Wiklander { 124817466cbSJens Wiklander /* Hashes from SHA-256 and above */ 125817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | 126817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | 127817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), 128817466cbSJens Wiklander 0xFFFFFFF, /* Any PK alg */ 129817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 130817466cbSJens Wiklander /* Curves at or above 128-bit security level */ 131817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | 132817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ) | 133817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP521R1 ) | 134817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP256R1 ) | 135817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP384R1 ) | 136817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP512R1 ) | 137817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256K1 ), 138817466cbSJens Wiklander #else 139817466cbSJens Wiklander 0, 140817466cbSJens Wiklander #endif 141817466cbSJens Wiklander 2048, 142817466cbSJens Wiklander }; 143817466cbSJens Wiklander 144817466cbSJens Wiklander /* 145817466cbSJens Wiklander * NSA Suite B Profile 146817466cbSJens Wiklander */ 147817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb = 148817466cbSJens Wiklander { 149817466cbSJens Wiklander /* Only SHA-256 and 384 */ 150817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | 151817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), 152817466cbSJens Wiklander /* Only ECDSA */ 1533d3b0591SJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ) | 1543d3b0591SJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECKEY ), 155817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 156817466cbSJens Wiklander /* Only NIST P-256 and P-384 */ 157817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | 158817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ), 159817466cbSJens Wiklander #else 160817466cbSJens Wiklander 0, 161817466cbSJens Wiklander #endif 162817466cbSJens Wiklander 0, 163817466cbSJens Wiklander }; 164817466cbSJens Wiklander 165817466cbSJens Wiklander /* 166817466cbSJens Wiklander * Check md_alg against profile 1673d3b0591SJens Wiklander * Return 0 if md_alg is acceptable for this profile, -1 otherwise 168817466cbSJens Wiklander */ 169817466cbSJens Wiklander static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile, 170817466cbSJens Wiklander mbedtls_md_type_t md_alg ) 171817466cbSJens Wiklander { 1723d3b0591SJens Wiklander if( md_alg == MBEDTLS_MD_NONE ) 1733d3b0591SJens Wiklander return( -1 ); 1743d3b0591SJens Wiklander 175817466cbSJens Wiklander if( ( profile->allowed_mds & MBEDTLS_X509_ID_FLAG( md_alg ) ) != 0 ) 176817466cbSJens Wiklander return( 0 ); 177817466cbSJens Wiklander 178817466cbSJens Wiklander return( -1 ); 179817466cbSJens Wiklander } 180817466cbSJens Wiklander 181817466cbSJens Wiklander /* 182817466cbSJens Wiklander * Check pk_alg against profile 1833d3b0591SJens Wiklander * Return 0 if pk_alg is acceptable for this profile, -1 otherwise 184817466cbSJens Wiklander */ 185817466cbSJens Wiklander static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile, 186817466cbSJens Wiklander mbedtls_pk_type_t pk_alg ) 187817466cbSJens Wiklander { 1883d3b0591SJens Wiklander if( pk_alg == MBEDTLS_PK_NONE ) 1893d3b0591SJens Wiklander return( -1 ); 1903d3b0591SJens Wiklander 191817466cbSJens Wiklander if( ( profile->allowed_pks & MBEDTLS_X509_ID_FLAG( pk_alg ) ) != 0 ) 192817466cbSJens Wiklander return( 0 ); 193817466cbSJens Wiklander 194817466cbSJens Wiklander return( -1 ); 195817466cbSJens Wiklander } 196817466cbSJens Wiklander 197817466cbSJens Wiklander /* 198817466cbSJens Wiklander * Check key against profile 1993d3b0591SJens Wiklander * Return 0 if pk is acceptable for this profile, -1 otherwise 200817466cbSJens Wiklander */ 201817466cbSJens Wiklander static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, 202817466cbSJens Wiklander const mbedtls_pk_context *pk ) 203817466cbSJens Wiklander { 2043d3b0591SJens Wiklander const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type( pk ); 2053d3b0591SJens Wiklander 206817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 207817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS ) 208817466cbSJens Wiklander { 209817466cbSJens Wiklander if( mbedtls_pk_get_bitlen( pk ) >= profile->rsa_min_bitlen ) 210817466cbSJens Wiklander return( 0 ); 211817466cbSJens Wiklander 212817466cbSJens Wiklander return( -1 ); 213817466cbSJens Wiklander } 214817466cbSJens Wiklander #endif 215817466cbSJens Wiklander 216817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 217817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_ECDSA || 218817466cbSJens Wiklander pk_alg == MBEDTLS_PK_ECKEY || 219817466cbSJens Wiklander pk_alg == MBEDTLS_PK_ECKEY_DH ) 220817466cbSJens Wiklander { 2213d3b0591SJens Wiklander const mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id; 2223d3b0591SJens Wiklander 2233d3b0591SJens Wiklander if( gid == MBEDTLS_ECP_DP_NONE ) 2243d3b0591SJens Wiklander return( -1 ); 225817466cbSJens Wiklander 226817466cbSJens Wiklander if( ( profile->allowed_curves & MBEDTLS_X509_ID_FLAG( gid ) ) != 0 ) 227817466cbSJens Wiklander return( 0 ); 228817466cbSJens Wiklander 229817466cbSJens Wiklander return( -1 ); 230817466cbSJens Wiklander } 231817466cbSJens Wiklander #endif 232817466cbSJens Wiklander 233817466cbSJens Wiklander return( -1 ); 234817466cbSJens Wiklander } 235817466cbSJens Wiklander 236817466cbSJens Wiklander /* 2373d3b0591SJens Wiklander * Like memcmp, but case-insensitive and always returns -1 if different 2383d3b0591SJens Wiklander */ 2393d3b0591SJens Wiklander static int x509_memcasecmp( const void *s1, const void *s2, size_t len ) 2403d3b0591SJens Wiklander { 2413d3b0591SJens Wiklander size_t i; 2423d3b0591SJens Wiklander unsigned char diff; 2433d3b0591SJens Wiklander const unsigned char *n1 = s1, *n2 = s2; 2443d3b0591SJens Wiklander 2453d3b0591SJens Wiklander for( i = 0; i < len; i++ ) 2463d3b0591SJens Wiklander { 2473d3b0591SJens Wiklander diff = n1[i] ^ n2[i]; 2483d3b0591SJens Wiklander 2493d3b0591SJens Wiklander if( diff == 0 ) 2503d3b0591SJens Wiklander continue; 2513d3b0591SJens Wiklander 2523d3b0591SJens Wiklander if( diff == 32 && 2533d3b0591SJens Wiklander ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || 2543d3b0591SJens Wiklander ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) 2553d3b0591SJens Wiklander { 2563d3b0591SJens Wiklander continue; 2573d3b0591SJens Wiklander } 2583d3b0591SJens Wiklander 2593d3b0591SJens Wiklander return( -1 ); 2603d3b0591SJens Wiklander } 2613d3b0591SJens Wiklander 2623d3b0591SJens Wiklander return( 0 ); 2633d3b0591SJens Wiklander } 2643d3b0591SJens Wiklander 2653d3b0591SJens Wiklander /* 2663d3b0591SJens Wiklander * Return 0 if name matches wildcard, -1 otherwise 2673d3b0591SJens Wiklander */ 2683d3b0591SJens Wiklander static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name ) 2693d3b0591SJens Wiklander { 2703d3b0591SJens Wiklander size_t i; 2713d3b0591SJens Wiklander size_t cn_idx = 0, cn_len = strlen( cn ); 2723d3b0591SJens Wiklander 2733d3b0591SJens Wiklander /* We can't have a match if there is no wildcard to match */ 2743d3b0591SJens Wiklander if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) 2753d3b0591SJens Wiklander return( -1 ); 2763d3b0591SJens Wiklander 2773d3b0591SJens Wiklander for( i = 0; i < cn_len; ++i ) 2783d3b0591SJens Wiklander { 2793d3b0591SJens Wiklander if( cn[i] == '.' ) 2803d3b0591SJens Wiklander { 2813d3b0591SJens Wiklander cn_idx = i; 2823d3b0591SJens Wiklander break; 2833d3b0591SJens Wiklander } 2843d3b0591SJens Wiklander } 2853d3b0591SJens Wiklander 2863d3b0591SJens Wiklander if( cn_idx == 0 ) 2873d3b0591SJens Wiklander return( -1 ); 2883d3b0591SJens Wiklander 2893d3b0591SJens Wiklander if( cn_len - cn_idx == name->len - 1 && 2903d3b0591SJens Wiklander x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) 2913d3b0591SJens Wiklander { 2923d3b0591SJens Wiklander return( 0 ); 2933d3b0591SJens Wiklander } 2943d3b0591SJens Wiklander 2953d3b0591SJens Wiklander return( -1 ); 2963d3b0591SJens Wiklander } 2973d3b0591SJens Wiklander 2983d3b0591SJens Wiklander /* 2993d3b0591SJens Wiklander * Compare two X.509 strings, case-insensitive, and allowing for some encoding 3003d3b0591SJens Wiklander * variations (but not all). 3013d3b0591SJens Wiklander * 3023d3b0591SJens Wiklander * Return 0 if equal, -1 otherwise. 3033d3b0591SJens Wiklander */ 3043d3b0591SJens Wiklander static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ) 3053d3b0591SJens Wiklander { 3063d3b0591SJens Wiklander if( a->tag == b->tag && 3073d3b0591SJens Wiklander a->len == b->len && 3083d3b0591SJens Wiklander memcmp( a->p, b->p, b->len ) == 0 ) 3093d3b0591SJens Wiklander { 3103d3b0591SJens Wiklander return( 0 ); 3113d3b0591SJens Wiklander } 3123d3b0591SJens Wiklander 3133d3b0591SJens Wiklander if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && 3143d3b0591SJens Wiklander ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && 3153d3b0591SJens Wiklander a->len == b->len && 3163d3b0591SJens Wiklander x509_memcasecmp( a->p, b->p, b->len ) == 0 ) 3173d3b0591SJens Wiklander { 3183d3b0591SJens Wiklander return( 0 ); 3193d3b0591SJens Wiklander } 3203d3b0591SJens Wiklander 3213d3b0591SJens Wiklander return( -1 ); 3223d3b0591SJens Wiklander } 3233d3b0591SJens Wiklander 3243d3b0591SJens Wiklander /* 3253d3b0591SJens Wiklander * Compare two X.509 Names (aka rdnSequence). 3263d3b0591SJens Wiklander * 3273d3b0591SJens Wiklander * See RFC 5280 section 7.1, though we don't implement the whole algorithm: 3283d3b0591SJens Wiklander * we sometimes return unequal when the full algorithm would return equal, 3293d3b0591SJens Wiklander * but never the other way. (In particular, we don't do Unicode normalisation 3303d3b0591SJens Wiklander * or space folding.) 3313d3b0591SJens Wiklander * 3323d3b0591SJens Wiklander * Return 0 if equal, -1 otherwise. 3333d3b0591SJens Wiklander */ 3343d3b0591SJens Wiklander static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ) 3353d3b0591SJens Wiklander { 3363d3b0591SJens Wiklander /* Avoid recursion, it might not be optimised by the compiler */ 3373d3b0591SJens Wiklander while( a != NULL || b != NULL ) 3383d3b0591SJens Wiklander { 3393d3b0591SJens Wiklander if( a == NULL || b == NULL ) 3403d3b0591SJens Wiklander return( -1 ); 3413d3b0591SJens Wiklander 3423d3b0591SJens Wiklander /* type */ 3433d3b0591SJens Wiklander if( a->oid.tag != b->oid.tag || 3443d3b0591SJens Wiklander a->oid.len != b->oid.len || 3453d3b0591SJens Wiklander memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) 3463d3b0591SJens Wiklander { 3473d3b0591SJens Wiklander return( -1 ); 3483d3b0591SJens Wiklander } 3493d3b0591SJens Wiklander 3503d3b0591SJens Wiklander /* value */ 3513d3b0591SJens Wiklander if( x509_string_cmp( &a->val, &b->val ) != 0 ) 3523d3b0591SJens Wiklander return( -1 ); 3533d3b0591SJens Wiklander 3543d3b0591SJens Wiklander /* structure of the list of sets */ 3553d3b0591SJens Wiklander if( a->next_merged != b->next_merged ) 3563d3b0591SJens Wiklander return( -1 ); 3573d3b0591SJens Wiklander 3583d3b0591SJens Wiklander a = a->next; 3593d3b0591SJens Wiklander b = b->next; 3603d3b0591SJens Wiklander } 3613d3b0591SJens Wiklander 3623d3b0591SJens Wiklander /* a == NULL == b */ 3633d3b0591SJens Wiklander return( 0 ); 3643d3b0591SJens Wiklander } 3653d3b0591SJens Wiklander 3663d3b0591SJens Wiklander /* 3673d3b0591SJens Wiklander * Reset (init or clear) a verify_chain 3683d3b0591SJens Wiklander */ 3693d3b0591SJens Wiklander static void x509_crt_verify_chain_reset( 3703d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain *ver_chain ) 3713d3b0591SJens Wiklander { 3723d3b0591SJens Wiklander size_t i; 3733d3b0591SJens Wiklander 3743d3b0591SJens Wiklander for( i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++ ) 3753d3b0591SJens Wiklander { 3763d3b0591SJens Wiklander ver_chain->items[i].crt = NULL; 3775b25c76aSJerome Forissier ver_chain->items[i].flags = (uint32_t) -1; 3783d3b0591SJens Wiklander } 3793d3b0591SJens Wiklander 3803d3b0591SJens Wiklander ver_chain->len = 0; 381*11fa71b9SJerome Forissier 382*11fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 383*11fa71b9SJerome Forissier ver_chain->trust_ca_cb_result = NULL; 384*11fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 3853d3b0591SJens Wiklander } 3863d3b0591SJens Wiklander 3873d3b0591SJens Wiklander /* 388817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 389817466cbSJens Wiklander */ 390817466cbSJens Wiklander static int x509_get_version( unsigned char **p, 391817466cbSJens Wiklander const unsigned char *end, 392817466cbSJens Wiklander int *ver ) 393817466cbSJens Wiklander { 394*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 395817466cbSJens Wiklander size_t len; 396817466cbSJens Wiklander 397817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 398817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) != 0 ) 399817466cbSJens Wiklander { 400817466cbSJens Wiklander if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 401817466cbSJens Wiklander { 402817466cbSJens Wiklander *ver = 0; 403817466cbSJens Wiklander return( 0 ); 404817466cbSJens Wiklander } 405817466cbSJens Wiklander 4065b25c76aSJerome Forissier return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); 407817466cbSJens Wiklander } 408817466cbSJens Wiklander 409817466cbSJens Wiklander end = *p + len; 410817466cbSJens Wiklander 411817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) 412817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); 413817466cbSJens Wiklander 414817466cbSJens Wiklander if( *p != end ) 415817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_VERSION + 416817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 417817466cbSJens Wiklander 418817466cbSJens Wiklander return( 0 ); 419817466cbSJens Wiklander } 420817466cbSJens Wiklander 421817466cbSJens Wiklander /* 422817466cbSJens Wiklander * Validity ::= SEQUENCE { 423817466cbSJens Wiklander * notBefore Time, 424817466cbSJens Wiklander * notAfter Time } 425817466cbSJens Wiklander */ 426817466cbSJens Wiklander static int x509_get_dates( unsigned char **p, 427817466cbSJens Wiklander const unsigned char *end, 428817466cbSJens Wiklander mbedtls_x509_time *from, 429817466cbSJens Wiklander mbedtls_x509_time *to ) 430817466cbSJens Wiklander { 431*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 432817466cbSJens Wiklander size_t len; 433817466cbSJens Wiklander 434817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 435817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 436817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); 437817466cbSJens Wiklander 438817466cbSJens Wiklander end = *p + len; 439817466cbSJens Wiklander 440817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_time( p, end, from ) ) != 0 ) 441817466cbSJens Wiklander return( ret ); 442817466cbSJens Wiklander 443817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_time( p, end, to ) ) != 0 ) 444817466cbSJens Wiklander return( ret ); 445817466cbSJens Wiklander 446817466cbSJens Wiklander if( *p != end ) 447817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_DATE + 448817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 449817466cbSJens Wiklander 450817466cbSJens Wiklander return( 0 ); 451817466cbSJens Wiklander } 452817466cbSJens Wiklander 453817466cbSJens Wiklander /* 454817466cbSJens Wiklander * X.509 v2/v3 unique identifier (not parsed) 455817466cbSJens Wiklander */ 456817466cbSJens Wiklander static int x509_get_uid( unsigned char **p, 457817466cbSJens Wiklander const unsigned char *end, 458817466cbSJens Wiklander mbedtls_x509_buf *uid, int n ) 459817466cbSJens Wiklander { 460*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 461817466cbSJens Wiklander 462817466cbSJens Wiklander if( *p == end ) 463817466cbSJens Wiklander return( 0 ); 464817466cbSJens Wiklander 465817466cbSJens Wiklander uid->tag = **p; 466817466cbSJens Wiklander 467817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &uid->len, 468817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | n ) ) != 0 ) 469817466cbSJens Wiklander { 470817466cbSJens Wiklander if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 471817466cbSJens Wiklander return( 0 ); 472817466cbSJens Wiklander 4735b25c76aSJerome Forissier return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); 474817466cbSJens Wiklander } 475817466cbSJens Wiklander 476817466cbSJens Wiklander uid->p = *p; 477817466cbSJens Wiklander *p += uid->len; 478817466cbSJens Wiklander 479817466cbSJens Wiklander return( 0 ); 480817466cbSJens Wiklander } 481817466cbSJens Wiklander 482817466cbSJens Wiklander static int x509_get_basic_constraints( unsigned char **p, 483817466cbSJens Wiklander const unsigned char *end, 484817466cbSJens Wiklander int *ca_istrue, 485817466cbSJens Wiklander int *max_pathlen ) 486817466cbSJens Wiklander { 487*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 488817466cbSJens Wiklander size_t len; 489817466cbSJens Wiklander 490817466cbSJens Wiklander /* 491817466cbSJens Wiklander * BasicConstraints ::= SEQUENCE { 492817466cbSJens Wiklander * cA BOOLEAN DEFAULT FALSE, 493817466cbSJens Wiklander * pathLenConstraint INTEGER (0..MAX) OPTIONAL } 494817466cbSJens Wiklander */ 495817466cbSJens Wiklander *ca_istrue = 0; /* DEFAULT FALSE */ 496817466cbSJens Wiklander *max_pathlen = 0; /* endless */ 497817466cbSJens Wiklander 498817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 499817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 500817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 501817466cbSJens Wiklander 502817466cbSJens Wiklander if( *p == end ) 503817466cbSJens Wiklander return( 0 ); 504817466cbSJens Wiklander 505817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bool( p, end, ca_istrue ) ) != 0 ) 506817466cbSJens Wiklander { 507817466cbSJens Wiklander if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 508817466cbSJens Wiklander ret = mbedtls_asn1_get_int( p, end, ca_istrue ); 509817466cbSJens Wiklander 510817466cbSJens Wiklander if( ret != 0 ) 511817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 512817466cbSJens Wiklander 513817466cbSJens Wiklander if( *ca_istrue != 0 ) 514817466cbSJens Wiklander *ca_istrue = 1; 515817466cbSJens Wiklander } 516817466cbSJens Wiklander 517817466cbSJens Wiklander if( *p == end ) 518817466cbSJens Wiklander return( 0 ); 519817466cbSJens Wiklander 520817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 ) 521817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 522817466cbSJens Wiklander 523817466cbSJens Wiklander if( *p != end ) 524817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 525817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 526817466cbSJens Wiklander 527817466cbSJens Wiklander (*max_pathlen)++; 528817466cbSJens Wiklander 529817466cbSJens Wiklander return( 0 ); 530817466cbSJens Wiklander } 531817466cbSJens Wiklander 532817466cbSJens Wiklander static int x509_get_ns_cert_type( unsigned char **p, 533817466cbSJens Wiklander const unsigned char *end, 534817466cbSJens Wiklander unsigned char *ns_cert_type) 535817466cbSJens Wiklander { 536*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 537817466cbSJens Wiklander mbedtls_x509_bitstring bs = { 0, 0, NULL }; 538817466cbSJens Wiklander 539817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) 540817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 541817466cbSJens Wiklander 542817466cbSJens Wiklander if( bs.len != 1 ) 543817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 544817466cbSJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH ); 545817466cbSJens Wiklander 546817466cbSJens Wiklander /* Get actual bitstring */ 547817466cbSJens Wiklander *ns_cert_type = *bs.p; 548817466cbSJens Wiklander return( 0 ); 549817466cbSJens Wiklander } 550817466cbSJens Wiklander 551817466cbSJens Wiklander static int x509_get_key_usage( unsigned char **p, 552817466cbSJens Wiklander const unsigned char *end, 553817466cbSJens Wiklander unsigned int *key_usage) 554817466cbSJens Wiklander { 555*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 556817466cbSJens Wiklander size_t i; 557817466cbSJens Wiklander mbedtls_x509_bitstring bs = { 0, 0, NULL }; 558817466cbSJens Wiklander 559817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) 560817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 561817466cbSJens Wiklander 562817466cbSJens Wiklander if( bs.len < 1 ) 563817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 564817466cbSJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH ); 565817466cbSJens Wiklander 566817466cbSJens Wiklander /* Get actual bitstring */ 567817466cbSJens Wiklander *key_usage = 0; 568817466cbSJens Wiklander for( i = 0; i < bs.len && i < sizeof( unsigned int ); i++ ) 569817466cbSJens Wiklander { 570817466cbSJens Wiklander *key_usage |= (unsigned int) bs.p[i] << (8*i); 571817466cbSJens Wiklander } 572817466cbSJens Wiklander 573817466cbSJens Wiklander return( 0 ); 574817466cbSJens Wiklander } 575817466cbSJens Wiklander 576817466cbSJens Wiklander /* 577817466cbSJens Wiklander * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId 578817466cbSJens Wiklander * 579817466cbSJens Wiklander * KeyPurposeId ::= OBJECT IDENTIFIER 580817466cbSJens Wiklander */ 581817466cbSJens Wiklander static int x509_get_ext_key_usage( unsigned char **p, 582817466cbSJens Wiklander const unsigned char *end, 583817466cbSJens Wiklander mbedtls_x509_sequence *ext_key_usage) 584817466cbSJens Wiklander { 585*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 586817466cbSJens Wiklander 587817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, MBEDTLS_ASN1_OID ) ) != 0 ) 588817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 589817466cbSJens Wiklander 590817466cbSJens Wiklander /* Sequence length must be >= 1 */ 591817466cbSJens Wiklander if( ext_key_usage->buf.p == NULL ) 592817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 593817466cbSJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH ); 594817466cbSJens Wiklander 595817466cbSJens Wiklander return( 0 ); 596817466cbSJens Wiklander } 597817466cbSJens Wiklander 598817466cbSJens Wiklander /* 599817466cbSJens Wiklander * SubjectAltName ::= GeneralNames 600817466cbSJens Wiklander * 601817466cbSJens Wiklander * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 602817466cbSJens Wiklander * 603817466cbSJens Wiklander * GeneralName ::= CHOICE { 604817466cbSJens Wiklander * otherName [0] OtherName, 605817466cbSJens Wiklander * rfc822Name [1] IA5String, 606817466cbSJens Wiklander * dNSName [2] IA5String, 607817466cbSJens Wiklander * x400Address [3] ORAddress, 608817466cbSJens Wiklander * directoryName [4] Name, 609817466cbSJens Wiklander * ediPartyName [5] EDIPartyName, 610817466cbSJens Wiklander * uniformResourceIdentifier [6] IA5String, 611817466cbSJens Wiklander * iPAddress [7] OCTET STRING, 612817466cbSJens Wiklander * registeredID [8] OBJECT IDENTIFIER } 613817466cbSJens Wiklander * 614817466cbSJens Wiklander * OtherName ::= SEQUENCE { 615817466cbSJens Wiklander * type-id OBJECT IDENTIFIER, 616817466cbSJens Wiklander * value [0] EXPLICIT ANY DEFINED BY type-id } 617817466cbSJens Wiklander * 618817466cbSJens Wiklander * EDIPartyName ::= SEQUENCE { 619817466cbSJens Wiklander * nameAssigner [0] DirectoryString OPTIONAL, 620817466cbSJens Wiklander * partyName [1] DirectoryString } 621817466cbSJens Wiklander * 622*11fa71b9SJerome Forissier * NOTE: we list all types, but only use dNSName and otherName 623*11fa71b9SJerome Forissier * of type HwModuleName, as defined in RFC 4108, at this point. 624817466cbSJens Wiklander */ 625817466cbSJens Wiklander static int x509_get_subject_alt_name( unsigned char **p, 626817466cbSJens Wiklander const unsigned char *end, 627817466cbSJens Wiklander mbedtls_x509_sequence *subject_alt_name ) 628817466cbSJens Wiklander { 629*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 630817466cbSJens Wiklander size_t len, tag_len; 631817466cbSJens Wiklander mbedtls_asn1_buf *buf; 632817466cbSJens Wiklander unsigned char tag; 633817466cbSJens Wiklander mbedtls_asn1_sequence *cur = subject_alt_name; 634817466cbSJens Wiklander 635817466cbSJens Wiklander /* Get main sequence tag */ 636817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 637817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 638817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 639817466cbSJens Wiklander 640817466cbSJens Wiklander if( *p + len != end ) 641817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 642817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 643817466cbSJens Wiklander 644817466cbSJens Wiklander while( *p < end ) 645817466cbSJens Wiklander { 646*11fa71b9SJerome Forissier mbedtls_x509_subject_alternative_name dummy_san_buf; 647*11fa71b9SJerome Forissier memset( &dummy_san_buf, 0, sizeof( dummy_san_buf ) ); 648*11fa71b9SJerome Forissier 649817466cbSJens Wiklander if( ( end - *p ) < 1 ) 650817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 651817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 652817466cbSJens Wiklander 653817466cbSJens Wiklander tag = **p; 654817466cbSJens Wiklander (*p)++; 655817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_len( p, end, &tag_len ) ) != 0 ) 656817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 657817466cbSJens Wiklander 6583d3b0591SJens Wiklander if( ( tag & MBEDTLS_ASN1_TAG_CLASS_MASK ) != 6593d3b0591SJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC ) 6603d3b0591SJens Wiklander { 661817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 662817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 6633d3b0591SJens Wiklander } 664817466cbSJens Wiklander 665*11fa71b9SJerome Forissier /* 666*11fa71b9SJerome Forissier * Check that the SAN are structured correct. 667*11fa71b9SJerome Forissier */ 668*11fa71b9SJerome Forissier ret = mbedtls_x509_parse_subject_alt_name( &(cur->buf), &dummy_san_buf ); 669*11fa71b9SJerome Forissier /* 670*11fa71b9SJerome Forissier * In case the extension is malformed, return an error, 671*11fa71b9SJerome Forissier * and clear the allocated sequences. 672*11fa71b9SJerome Forissier */ 673*11fa71b9SJerome Forissier if( ret != 0 && ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) 674817466cbSJens Wiklander { 675*11fa71b9SJerome Forissier mbedtls_x509_sequence *seq_cur = subject_alt_name->next; 676*11fa71b9SJerome Forissier mbedtls_x509_sequence *seq_prv; 677*11fa71b9SJerome Forissier while( seq_cur != NULL ) 678*11fa71b9SJerome Forissier { 679*11fa71b9SJerome Forissier seq_prv = seq_cur; 680*11fa71b9SJerome Forissier seq_cur = seq_cur->next; 681*11fa71b9SJerome Forissier mbedtls_platform_zeroize( seq_prv, 682*11fa71b9SJerome Forissier sizeof( mbedtls_x509_sequence ) ); 683*11fa71b9SJerome Forissier mbedtls_free( seq_prv ); 684*11fa71b9SJerome Forissier } 685*11fa71b9SJerome Forissier subject_alt_name->next = NULL; 686*11fa71b9SJerome Forissier return( ret ); 687817466cbSJens Wiklander } 688817466cbSJens Wiklander 689817466cbSJens Wiklander /* Allocate and assign next pointer */ 690817466cbSJens Wiklander if( cur->buf.p != NULL ) 691817466cbSJens Wiklander { 692817466cbSJens Wiklander if( cur->next != NULL ) 693817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); 694817466cbSJens Wiklander 695817466cbSJens Wiklander cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); 696817466cbSJens Wiklander 697817466cbSJens Wiklander if( cur->next == NULL ) 698817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 699817466cbSJens Wiklander MBEDTLS_ERR_ASN1_ALLOC_FAILED ); 700817466cbSJens Wiklander 701817466cbSJens Wiklander cur = cur->next; 702817466cbSJens Wiklander } 703817466cbSJens Wiklander 704817466cbSJens Wiklander buf = &(cur->buf); 705817466cbSJens Wiklander buf->tag = tag; 706817466cbSJens Wiklander buf->p = *p; 707817466cbSJens Wiklander buf->len = tag_len; 708817466cbSJens Wiklander *p += buf->len; 709817466cbSJens Wiklander } 710817466cbSJens Wiklander 711817466cbSJens Wiklander /* Set final sequence entry's next pointer to NULL */ 712817466cbSJens Wiklander cur->next = NULL; 713817466cbSJens Wiklander 714817466cbSJens Wiklander if( *p != end ) 715817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 716817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 717817466cbSJens Wiklander 718817466cbSJens Wiklander return( 0 ); 719817466cbSJens Wiklander } 720817466cbSJens Wiklander 721817466cbSJens Wiklander /* 722*11fa71b9SJerome Forissier * id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } 723*11fa71b9SJerome Forissier * 724*11fa71b9SJerome Forissier * anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 } 725*11fa71b9SJerome Forissier * 726*11fa71b9SJerome Forissier * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation 727*11fa71b9SJerome Forissier * 728*11fa71b9SJerome Forissier * PolicyInformation ::= SEQUENCE { 729*11fa71b9SJerome Forissier * policyIdentifier CertPolicyId, 730*11fa71b9SJerome Forissier * policyQualifiers SEQUENCE SIZE (1..MAX) OF 731*11fa71b9SJerome Forissier * PolicyQualifierInfo OPTIONAL } 732*11fa71b9SJerome Forissier * 733*11fa71b9SJerome Forissier * CertPolicyId ::= OBJECT IDENTIFIER 734*11fa71b9SJerome Forissier * 735*11fa71b9SJerome Forissier * PolicyQualifierInfo ::= SEQUENCE { 736*11fa71b9SJerome Forissier * policyQualifierId PolicyQualifierId, 737*11fa71b9SJerome Forissier * qualifier ANY DEFINED BY policyQualifierId } 738*11fa71b9SJerome Forissier * 739*11fa71b9SJerome Forissier * -- policyQualifierIds for Internet policy qualifiers 740*11fa71b9SJerome Forissier * 741*11fa71b9SJerome Forissier * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } 742*11fa71b9SJerome Forissier * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } 743*11fa71b9SJerome Forissier * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } 744*11fa71b9SJerome Forissier * 745*11fa71b9SJerome Forissier * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) 746*11fa71b9SJerome Forissier * 747*11fa71b9SJerome Forissier * Qualifier ::= CHOICE { 748*11fa71b9SJerome Forissier * cPSuri CPSuri, 749*11fa71b9SJerome Forissier * userNotice UserNotice } 750*11fa71b9SJerome Forissier * 751*11fa71b9SJerome Forissier * CPSuri ::= IA5String 752*11fa71b9SJerome Forissier * 753*11fa71b9SJerome Forissier * UserNotice ::= SEQUENCE { 754*11fa71b9SJerome Forissier * noticeRef NoticeReference OPTIONAL, 755*11fa71b9SJerome Forissier * explicitText DisplayText OPTIONAL } 756*11fa71b9SJerome Forissier * 757*11fa71b9SJerome Forissier * NoticeReference ::= SEQUENCE { 758*11fa71b9SJerome Forissier * organization DisplayText, 759*11fa71b9SJerome Forissier * noticeNumbers SEQUENCE OF INTEGER } 760*11fa71b9SJerome Forissier * 761*11fa71b9SJerome Forissier * DisplayText ::= CHOICE { 762*11fa71b9SJerome Forissier * ia5String IA5String (SIZE (1..200)), 763*11fa71b9SJerome Forissier * visibleString VisibleString (SIZE (1..200)), 764*11fa71b9SJerome Forissier * bmpString BMPString (SIZE (1..200)), 765*11fa71b9SJerome Forissier * utf8String UTF8String (SIZE (1..200)) } 766*11fa71b9SJerome Forissier * 767*11fa71b9SJerome Forissier * NOTE: we only parse and use anyPolicy without qualifiers at this point 768*11fa71b9SJerome Forissier * as defined in RFC 5280. 769*11fa71b9SJerome Forissier */ 770*11fa71b9SJerome Forissier static int x509_get_certificate_policies( unsigned char **p, 771*11fa71b9SJerome Forissier const unsigned char *end, 772*11fa71b9SJerome Forissier mbedtls_x509_sequence *certificate_policies ) 773*11fa71b9SJerome Forissier { 774*11fa71b9SJerome Forissier int ret, parse_ret = 0; 775*11fa71b9SJerome Forissier size_t len; 776*11fa71b9SJerome Forissier mbedtls_asn1_buf *buf; 777*11fa71b9SJerome Forissier mbedtls_asn1_sequence *cur = certificate_policies; 778*11fa71b9SJerome Forissier 779*11fa71b9SJerome Forissier /* Get main sequence tag */ 780*11fa71b9SJerome Forissier ret = mbedtls_asn1_get_tag( p, end, &len, 781*11fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ); 782*11fa71b9SJerome Forissier if( ret != 0 ) 783*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 784*11fa71b9SJerome Forissier 785*11fa71b9SJerome Forissier if( *p + len != end ) 786*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 787*11fa71b9SJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 788*11fa71b9SJerome Forissier 789*11fa71b9SJerome Forissier /* 790*11fa71b9SJerome Forissier * Cannot be an empty sequence. 791*11fa71b9SJerome Forissier */ 792*11fa71b9SJerome Forissier if( len == 0 ) 793*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 794*11fa71b9SJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 795*11fa71b9SJerome Forissier 796*11fa71b9SJerome Forissier while( *p < end ) 797*11fa71b9SJerome Forissier { 798*11fa71b9SJerome Forissier mbedtls_x509_buf policy_oid; 799*11fa71b9SJerome Forissier const unsigned char *policy_end; 800*11fa71b9SJerome Forissier 801*11fa71b9SJerome Forissier /* 802*11fa71b9SJerome Forissier * Get the policy sequence 803*11fa71b9SJerome Forissier */ 804*11fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 805*11fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 806*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 807*11fa71b9SJerome Forissier 808*11fa71b9SJerome Forissier policy_end = *p + len; 809*11fa71b9SJerome Forissier 810*11fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len, 811*11fa71b9SJerome Forissier MBEDTLS_ASN1_OID ) ) != 0 ) 812*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 813*11fa71b9SJerome Forissier 814*11fa71b9SJerome Forissier policy_oid.tag = MBEDTLS_ASN1_OID; 815*11fa71b9SJerome Forissier policy_oid.len = len; 816*11fa71b9SJerome Forissier policy_oid.p = *p; 817*11fa71b9SJerome Forissier 818*11fa71b9SJerome Forissier /* 819*11fa71b9SJerome Forissier * Only AnyPolicy is currently supported when enforcing policy. 820*11fa71b9SJerome Forissier */ 821*11fa71b9SJerome Forissier if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_POLICY, &policy_oid ) != 0 ) 822*11fa71b9SJerome Forissier { 823*11fa71b9SJerome Forissier /* 824*11fa71b9SJerome Forissier * Set the parsing return code but continue parsing, in case this 825*11fa71b9SJerome Forissier * extension is critical and MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION 826*11fa71b9SJerome Forissier * is configured. 827*11fa71b9SJerome Forissier */ 828*11fa71b9SJerome Forissier parse_ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; 829*11fa71b9SJerome Forissier } 830*11fa71b9SJerome Forissier 831*11fa71b9SJerome Forissier /* Allocate and assign next pointer */ 832*11fa71b9SJerome Forissier if( cur->buf.p != NULL ) 833*11fa71b9SJerome Forissier { 834*11fa71b9SJerome Forissier if( cur->next != NULL ) 835*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); 836*11fa71b9SJerome Forissier 837*11fa71b9SJerome Forissier cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); 838*11fa71b9SJerome Forissier 839*11fa71b9SJerome Forissier if( cur->next == NULL ) 840*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 841*11fa71b9SJerome Forissier MBEDTLS_ERR_ASN1_ALLOC_FAILED ); 842*11fa71b9SJerome Forissier 843*11fa71b9SJerome Forissier cur = cur->next; 844*11fa71b9SJerome Forissier } 845*11fa71b9SJerome Forissier 846*11fa71b9SJerome Forissier buf = &( cur->buf ); 847*11fa71b9SJerome Forissier buf->tag = policy_oid.tag; 848*11fa71b9SJerome Forissier buf->p = policy_oid.p; 849*11fa71b9SJerome Forissier buf->len = policy_oid.len; 850*11fa71b9SJerome Forissier 851*11fa71b9SJerome Forissier *p += len; 852*11fa71b9SJerome Forissier 853*11fa71b9SJerome Forissier /* 854*11fa71b9SJerome Forissier * If there is an optional qualifier, then *p < policy_end 855*11fa71b9SJerome Forissier * Check the Qualifier len to verify it doesn't exceed policy_end. 856*11fa71b9SJerome Forissier */ 857*11fa71b9SJerome Forissier if( *p < policy_end ) 858*11fa71b9SJerome Forissier { 859*11fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len, 860*11fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 861*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 862*11fa71b9SJerome Forissier /* 863*11fa71b9SJerome Forissier * Skip the optional policy qualifiers. 864*11fa71b9SJerome Forissier */ 865*11fa71b9SJerome Forissier *p += len; 866*11fa71b9SJerome Forissier } 867*11fa71b9SJerome Forissier 868*11fa71b9SJerome Forissier if( *p != policy_end ) 869*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 870*11fa71b9SJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 871*11fa71b9SJerome Forissier } 872*11fa71b9SJerome Forissier 873*11fa71b9SJerome Forissier /* Set final sequence entry's next pointer to NULL */ 874*11fa71b9SJerome Forissier cur->next = NULL; 875*11fa71b9SJerome Forissier 876*11fa71b9SJerome Forissier if( *p != end ) 877*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 878*11fa71b9SJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 879*11fa71b9SJerome Forissier 880*11fa71b9SJerome Forissier return( parse_ret ); 881*11fa71b9SJerome Forissier } 882*11fa71b9SJerome Forissier 883*11fa71b9SJerome Forissier /* 884817466cbSJens Wiklander * X.509 v3 extensions 885817466cbSJens Wiklander * 886817466cbSJens Wiklander */ 887817466cbSJens Wiklander static int x509_get_crt_ext( unsigned char **p, 888817466cbSJens Wiklander const unsigned char *end, 889817466cbSJens Wiklander mbedtls_x509_crt *crt ) 890817466cbSJens Wiklander { 891*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 892817466cbSJens Wiklander size_t len; 893817466cbSJens Wiklander unsigned char *end_ext_data, *end_ext_octet; 894817466cbSJens Wiklander 8955b25c76aSJerome Forissier if( *p == end ) 896817466cbSJens Wiklander return( 0 ); 897817466cbSJens Wiklander 8985b25c76aSJerome Forissier if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) 899817466cbSJens Wiklander return( ret ); 900817466cbSJens Wiklander 9015b25c76aSJerome Forissier end = crt->v3_ext.p + crt->v3_ext.len; 902817466cbSJens Wiklander while( *p < end ) 903817466cbSJens Wiklander { 904817466cbSJens Wiklander /* 905817466cbSJens Wiklander * Extension ::= SEQUENCE { 906817466cbSJens Wiklander * extnID OBJECT IDENTIFIER, 907817466cbSJens Wiklander * critical BOOLEAN DEFAULT FALSE, 908817466cbSJens Wiklander * extnValue OCTET STRING } 909817466cbSJens Wiklander */ 910817466cbSJens Wiklander mbedtls_x509_buf extn_oid = {0, 0, NULL}; 911817466cbSJens Wiklander int is_critical = 0; /* DEFAULT FALSE */ 912817466cbSJens Wiklander int ext_type = 0; 913817466cbSJens Wiklander 914817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 915817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 916817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 917817466cbSJens Wiklander 918817466cbSJens Wiklander end_ext_data = *p + len; 919817466cbSJens Wiklander 920817466cbSJens Wiklander /* Get extension ID */ 9213d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &extn_oid.len, 9223d3b0591SJens Wiklander MBEDTLS_ASN1_OID ) ) != 0 ) 923817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 924817466cbSJens Wiklander 9253d3b0591SJens Wiklander extn_oid.tag = MBEDTLS_ASN1_OID; 926817466cbSJens Wiklander extn_oid.p = *p; 927817466cbSJens Wiklander *p += extn_oid.len; 928817466cbSJens Wiklander 929817466cbSJens Wiklander /* Get optional critical */ 930817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 && 931817466cbSJens Wiklander ( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) 932817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 933817466cbSJens Wiklander 934817466cbSJens Wiklander /* Data should be octet string type */ 935817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, 936817466cbSJens Wiklander MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 937817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 938817466cbSJens Wiklander 939817466cbSJens Wiklander end_ext_octet = *p + len; 940817466cbSJens Wiklander 941817466cbSJens Wiklander if( end_ext_octet != end_ext_data ) 942817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 943817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 944817466cbSJens Wiklander 945817466cbSJens Wiklander /* 946817466cbSJens Wiklander * Detect supported extensions 947817466cbSJens Wiklander */ 948817466cbSJens Wiklander ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type ); 949817466cbSJens Wiklander 950817466cbSJens Wiklander if( ret != 0 ) 951817466cbSJens Wiklander { 952817466cbSJens Wiklander /* No parser found, skip extension */ 953817466cbSJens Wiklander *p = end_ext_octet; 954817466cbSJens Wiklander 955817466cbSJens Wiklander #if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) 956817466cbSJens Wiklander if( is_critical ) 957817466cbSJens Wiklander { 958817466cbSJens Wiklander /* Data is marked as critical: fail */ 959817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 960817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 961817466cbSJens Wiklander } 962817466cbSJens Wiklander #endif 963817466cbSJens Wiklander continue; 964817466cbSJens Wiklander } 965817466cbSJens Wiklander 966817466cbSJens Wiklander /* Forbid repeated extensions */ 967817466cbSJens Wiklander if( ( crt->ext_types & ext_type ) != 0 ) 968817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); 969817466cbSJens Wiklander 970817466cbSJens Wiklander crt->ext_types |= ext_type; 971817466cbSJens Wiklander 972817466cbSJens Wiklander switch( ext_type ) 973817466cbSJens Wiklander { 974817466cbSJens Wiklander case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS: 975817466cbSJens Wiklander /* Parse basic constraints */ 976817466cbSJens Wiklander if( ( ret = x509_get_basic_constraints( p, end_ext_octet, 977817466cbSJens Wiklander &crt->ca_istrue, &crt->max_pathlen ) ) != 0 ) 978817466cbSJens Wiklander return( ret ); 979817466cbSJens Wiklander break; 980817466cbSJens Wiklander 981817466cbSJens Wiklander case MBEDTLS_X509_EXT_KEY_USAGE: 982817466cbSJens Wiklander /* Parse key usage */ 983817466cbSJens Wiklander if( ( ret = x509_get_key_usage( p, end_ext_octet, 984817466cbSJens Wiklander &crt->key_usage ) ) != 0 ) 985817466cbSJens Wiklander return( ret ); 986817466cbSJens Wiklander break; 987817466cbSJens Wiklander 988817466cbSJens Wiklander case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: 989817466cbSJens Wiklander /* Parse extended key usage */ 990817466cbSJens Wiklander if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, 991817466cbSJens Wiklander &crt->ext_key_usage ) ) != 0 ) 992817466cbSJens Wiklander return( ret ); 993817466cbSJens Wiklander break; 994817466cbSJens Wiklander 995817466cbSJens Wiklander case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: 996817466cbSJens Wiklander /* Parse subject alt name */ 997817466cbSJens Wiklander if( ( ret = x509_get_subject_alt_name( p, end_ext_octet, 998817466cbSJens Wiklander &crt->subject_alt_names ) ) != 0 ) 999817466cbSJens Wiklander return( ret ); 1000817466cbSJens Wiklander break; 1001817466cbSJens Wiklander 1002817466cbSJens Wiklander case MBEDTLS_X509_EXT_NS_CERT_TYPE: 1003817466cbSJens Wiklander /* Parse netscape certificate type */ 1004817466cbSJens Wiklander if( ( ret = x509_get_ns_cert_type( p, end_ext_octet, 1005817466cbSJens Wiklander &crt->ns_cert_type ) ) != 0 ) 1006817466cbSJens Wiklander return( ret ); 1007817466cbSJens Wiklander break; 1008817466cbSJens Wiklander 1009*11fa71b9SJerome Forissier case MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES: 1010*11fa71b9SJerome Forissier /* Parse certificate policies type */ 1011*11fa71b9SJerome Forissier if( ( ret = x509_get_certificate_policies( p, end_ext_octet, 1012*11fa71b9SJerome Forissier &crt->certificate_policies ) ) != 0 ) 1013*11fa71b9SJerome Forissier { 1014*11fa71b9SJerome Forissier #if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) 1015*11fa71b9SJerome Forissier if( is_critical ) 1016*11fa71b9SJerome Forissier return( ret ); 1017*11fa71b9SJerome Forissier else 1018*11fa71b9SJerome Forissier #endif 1019*11fa71b9SJerome Forissier /* 1020*11fa71b9SJerome Forissier * If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, then we 1021*11fa71b9SJerome Forissier * cannot interpret or enforce the policy. However, it is up to 1022*11fa71b9SJerome Forissier * the user to choose how to enforce the policies, 1023*11fa71b9SJerome Forissier * unless the extension is critical. 1024*11fa71b9SJerome Forissier */ 1025*11fa71b9SJerome Forissier if( ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) 1026*11fa71b9SJerome Forissier return( ret ); 1027*11fa71b9SJerome Forissier } 1028*11fa71b9SJerome Forissier break; 1029*11fa71b9SJerome Forissier 1030817466cbSJens Wiklander default: 1031*11fa71b9SJerome Forissier /* 1032*11fa71b9SJerome Forissier * If this is a non-critical extension, which the oid layer 1033*11fa71b9SJerome Forissier * supports, but there isn't an x509 parser for it, 1034*11fa71b9SJerome Forissier * skip the extension. 1035*11fa71b9SJerome Forissier */ 1036*11fa71b9SJerome Forissier #if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) 1037*11fa71b9SJerome Forissier if( is_critical ) 1038817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); 1039*11fa71b9SJerome Forissier else 1040*11fa71b9SJerome Forissier #endif 1041*11fa71b9SJerome Forissier *p = end_ext_octet; 1042817466cbSJens Wiklander } 1043817466cbSJens Wiklander } 1044817466cbSJens Wiklander 1045817466cbSJens Wiklander if( *p != end ) 1046817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 1047817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 1048817466cbSJens Wiklander 1049817466cbSJens Wiklander return( 0 ); 1050817466cbSJens Wiklander } 1051817466cbSJens Wiklander 1052817466cbSJens Wiklander /* 1053817466cbSJens Wiklander * Parse and fill a single X.509 certificate in DER format 1054817466cbSJens Wiklander */ 1055*11fa71b9SJerome Forissier static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, 1056*11fa71b9SJerome Forissier const unsigned char *buf, 1057*11fa71b9SJerome Forissier size_t buflen, 1058*11fa71b9SJerome Forissier int make_copy ) 1059817466cbSJens Wiklander { 1060*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1061817466cbSJens Wiklander size_t len; 1062817466cbSJens Wiklander unsigned char *p, *end, *crt_end; 1063817466cbSJens Wiklander mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; 1064817466cbSJens Wiklander 1065817466cbSJens Wiklander memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); 1066817466cbSJens Wiklander memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); 1067817466cbSJens Wiklander memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); 1068817466cbSJens Wiklander 1069817466cbSJens Wiklander /* 1070817466cbSJens Wiklander * Check for valid input 1071817466cbSJens Wiklander */ 1072817466cbSJens Wiklander if( crt == NULL || buf == NULL ) 1073817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1074817466cbSJens Wiklander 1075*11fa71b9SJerome Forissier /* Use the original buffer until we figure out actual length. */ 1076817466cbSJens Wiklander p = (unsigned char*) buf; 1077817466cbSJens Wiklander len = buflen; 1078817466cbSJens Wiklander end = p + len; 1079817466cbSJens Wiklander 1080817466cbSJens Wiklander /* 1081817466cbSJens Wiklander * Certificate ::= SEQUENCE { 1082817466cbSJens Wiklander * tbsCertificate TBSCertificate, 1083817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 1084817466cbSJens Wiklander * signatureValue BIT STRING } 1085817466cbSJens Wiklander */ 1086817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1087817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1088817466cbSJens Wiklander { 1089817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1090817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT ); 1091817466cbSJens Wiklander } 1092817466cbSJens Wiklander 1093*11fa71b9SJerome Forissier end = crt_end = p + len; 1094817466cbSJens Wiklander crt->raw.len = crt_end - buf; 1095*11fa71b9SJerome Forissier if( make_copy != 0 ) 1096*11fa71b9SJerome Forissier { 1097*11fa71b9SJerome Forissier /* Create and populate a new buffer for the raw field. */ 1098817466cbSJens Wiklander crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len ); 1099*11fa71b9SJerome Forissier if( crt->raw.p == NULL ) 1100817466cbSJens Wiklander return( MBEDTLS_ERR_X509_ALLOC_FAILED ); 1101817466cbSJens Wiklander 1102*11fa71b9SJerome Forissier memcpy( crt->raw.p, buf, crt->raw.len ); 1103*11fa71b9SJerome Forissier crt->own_buffer = 1; 1104817466cbSJens Wiklander 1105817466cbSJens Wiklander p += crt->raw.len - len; 1106817466cbSJens Wiklander end = crt_end = p + len; 1107*11fa71b9SJerome Forissier } 1108*11fa71b9SJerome Forissier else 1109*11fa71b9SJerome Forissier { 1110*11fa71b9SJerome Forissier crt->raw.p = (unsigned char*) buf; 1111*11fa71b9SJerome Forissier crt->own_buffer = 0; 1112*11fa71b9SJerome Forissier } 1113817466cbSJens Wiklander 1114817466cbSJens Wiklander /* 1115817466cbSJens Wiklander * TBSCertificate ::= SEQUENCE { 1116817466cbSJens Wiklander */ 1117817466cbSJens Wiklander crt->tbs.p = p; 1118817466cbSJens Wiklander 1119817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1120817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1121817466cbSJens Wiklander { 1122817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1123817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); 1124817466cbSJens Wiklander } 1125817466cbSJens Wiklander 1126817466cbSJens Wiklander end = p + len; 1127817466cbSJens Wiklander crt->tbs.len = end - crt->tbs.p; 1128817466cbSJens Wiklander 1129817466cbSJens Wiklander /* 1130817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 1131817466cbSJens Wiklander * 1132817466cbSJens Wiklander * CertificateSerialNumber ::= INTEGER 1133817466cbSJens Wiklander * 1134817466cbSJens Wiklander * signature AlgorithmIdentifier 1135817466cbSJens Wiklander */ 1136817466cbSJens Wiklander if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 || 1137817466cbSJens Wiklander ( ret = mbedtls_x509_get_serial( &p, end, &crt->serial ) ) != 0 || 1138817466cbSJens Wiklander ( ret = mbedtls_x509_get_alg( &p, end, &crt->sig_oid, 1139817466cbSJens Wiklander &sig_params1 ) ) != 0 ) 1140817466cbSJens Wiklander { 1141817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1142817466cbSJens Wiklander return( ret ); 1143817466cbSJens Wiklander } 1144817466cbSJens Wiklander 1145817466cbSJens Wiklander if( crt->version < 0 || crt->version > 2 ) 1146817466cbSJens Wiklander { 1147817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1148817466cbSJens Wiklander return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); 1149817466cbSJens Wiklander } 1150817466cbSJens Wiklander 1151817466cbSJens Wiklander crt->version++; 1152817466cbSJens Wiklander 1153817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1, 1154817466cbSJens Wiklander &crt->sig_md, &crt->sig_pk, 1155817466cbSJens Wiklander &crt->sig_opts ) ) != 0 ) 1156817466cbSJens Wiklander { 1157817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1158817466cbSJens Wiklander return( ret ); 1159817466cbSJens Wiklander } 1160817466cbSJens Wiklander 1161817466cbSJens Wiklander /* 1162817466cbSJens Wiklander * issuer Name 1163817466cbSJens Wiklander */ 1164817466cbSJens Wiklander crt->issuer_raw.p = p; 1165817466cbSJens Wiklander 1166817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1167817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1168817466cbSJens Wiklander { 1169817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1170817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); 1171817466cbSJens Wiklander } 1172817466cbSJens Wiklander 1173817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) 1174817466cbSJens Wiklander { 1175817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1176817466cbSJens Wiklander return( ret ); 1177817466cbSJens Wiklander } 1178817466cbSJens Wiklander 1179817466cbSJens Wiklander crt->issuer_raw.len = p - crt->issuer_raw.p; 1180817466cbSJens Wiklander 1181817466cbSJens Wiklander /* 1182817466cbSJens Wiklander * Validity ::= SEQUENCE { 1183817466cbSJens Wiklander * notBefore Time, 1184817466cbSJens Wiklander * notAfter Time } 1185817466cbSJens Wiklander * 1186817466cbSJens Wiklander */ 1187817466cbSJens Wiklander if( ( ret = x509_get_dates( &p, end, &crt->valid_from, 1188817466cbSJens Wiklander &crt->valid_to ) ) != 0 ) 1189817466cbSJens Wiklander { 1190817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1191817466cbSJens Wiklander return( ret ); 1192817466cbSJens Wiklander } 1193817466cbSJens Wiklander 1194817466cbSJens Wiklander /* 1195817466cbSJens Wiklander * subject Name 1196817466cbSJens Wiklander */ 1197817466cbSJens Wiklander crt->subject_raw.p = p; 1198817466cbSJens Wiklander 1199817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1200817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1201817466cbSJens Wiklander { 1202817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1203817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); 1204817466cbSJens Wiklander } 1205817466cbSJens Wiklander 1206817466cbSJens Wiklander if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) 1207817466cbSJens Wiklander { 1208817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1209817466cbSJens Wiklander return( ret ); 1210817466cbSJens Wiklander } 1211817466cbSJens Wiklander 1212817466cbSJens Wiklander crt->subject_raw.len = p - crt->subject_raw.p; 1213817466cbSJens Wiklander 1214817466cbSJens Wiklander /* 1215817466cbSJens Wiklander * SubjectPublicKeyInfo 1216817466cbSJens Wiklander */ 1217*11fa71b9SJerome Forissier crt->pk_raw.p = p; 1218817466cbSJens Wiklander if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 ) 1219817466cbSJens Wiklander { 1220817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1221817466cbSJens Wiklander return( ret ); 1222817466cbSJens Wiklander } 1223*11fa71b9SJerome Forissier crt->pk_raw.len = p - crt->pk_raw.p; 1224817466cbSJens Wiklander 1225817466cbSJens Wiklander /* 1226817466cbSJens Wiklander * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 1227817466cbSJens Wiklander * -- If present, version shall be v2 or v3 1228817466cbSJens Wiklander * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 1229817466cbSJens Wiklander * -- If present, version shall be v2 or v3 1230817466cbSJens Wiklander * extensions [3] EXPLICIT Extensions OPTIONAL 1231817466cbSJens Wiklander * -- If present, version shall be v3 1232817466cbSJens Wiklander */ 1233817466cbSJens Wiklander if( crt->version == 2 || crt->version == 3 ) 1234817466cbSJens Wiklander { 1235817466cbSJens Wiklander ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); 1236817466cbSJens Wiklander if( ret != 0 ) 1237817466cbSJens Wiklander { 1238817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1239817466cbSJens Wiklander return( ret ); 1240817466cbSJens Wiklander } 1241817466cbSJens Wiklander } 1242817466cbSJens Wiklander 1243817466cbSJens Wiklander if( crt->version == 2 || crt->version == 3 ) 1244817466cbSJens Wiklander { 1245817466cbSJens Wiklander ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); 1246817466cbSJens Wiklander if( ret != 0 ) 1247817466cbSJens Wiklander { 1248817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1249817466cbSJens Wiklander return( ret ); 1250817466cbSJens Wiklander } 1251817466cbSJens Wiklander } 1252817466cbSJens Wiklander 1253817466cbSJens Wiklander #if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) 1254817466cbSJens Wiklander if( crt->version == 3 ) 1255817466cbSJens Wiklander #endif 1256817466cbSJens Wiklander { 1257817466cbSJens Wiklander ret = x509_get_crt_ext( &p, end, crt ); 1258817466cbSJens Wiklander if( ret != 0 ) 1259817466cbSJens Wiklander { 1260817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1261817466cbSJens Wiklander return( ret ); 1262817466cbSJens Wiklander } 1263817466cbSJens Wiklander } 1264817466cbSJens Wiklander 1265817466cbSJens Wiklander if( p != end ) 1266817466cbSJens Wiklander { 1267817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1268817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + 1269817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 1270817466cbSJens Wiklander } 1271817466cbSJens Wiklander 1272817466cbSJens Wiklander end = crt_end; 1273817466cbSJens Wiklander 1274817466cbSJens Wiklander /* 1275817466cbSJens Wiklander * } 1276817466cbSJens Wiklander * -- end of TBSCertificate 1277817466cbSJens Wiklander * 1278817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 1279817466cbSJens Wiklander * signatureValue BIT STRING 1280817466cbSJens Wiklander */ 1281817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) 1282817466cbSJens Wiklander { 1283817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1284817466cbSJens Wiklander return( ret ); 1285817466cbSJens Wiklander } 1286817466cbSJens Wiklander 1287817466cbSJens Wiklander if( crt->sig_oid.len != sig_oid2.len || 1288817466cbSJens Wiklander memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 || 1289817466cbSJens Wiklander sig_params1.len != sig_params2.len || 1290817466cbSJens Wiklander ( sig_params1.len != 0 && 1291817466cbSJens Wiklander memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) 1292817466cbSJens Wiklander { 1293817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1294817466cbSJens Wiklander return( MBEDTLS_ERR_X509_SIG_MISMATCH ); 1295817466cbSJens Wiklander } 1296817466cbSJens Wiklander 1297817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_sig( &p, end, &crt->sig ) ) != 0 ) 1298817466cbSJens Wiklander { 1299817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1300817466cbSJens Wiklander return( ret ); 1301817466cbSJens Wiklander } 1302817466cbSJens Wiklander 1303817466cbSJens Wiklander if( p != end ) 1304817466cbSJens Wiklander { 1305817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1306817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + 1307817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 1308817466cbSJens Wiklander } 1309817466cbSJens Wiklander 1310817466cbSJens Wiklander return( 0 ); 1311817466cbSJens Wiklander } 1312817466cbSJens Wiklander 1313817466cbSJens Wiklander /* 1314817466cbSJens Wiklander * Parse one X.509 certificate in DER format from a buffer and add them to a 1315817466cbSJens Wiklander * chained list 1316817466cbSJens Wiklander */ 1317*11fa71b9SJerome Forissier static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain, 1318*11fa71b9SJerome Forissier const unsigned char *buf, 1319*11fa71b9SJerome Forissier size_t buflen, 1320*11fa71b9SJerome Forissier int make_copy ) 1321817466cbSJens Wiklander { 1322*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1323817466cbSJens Wiklander mbedtls_x509_crt *crt = chain, *prev = NULL; 1324817466cbSJens Wiklander 1325817466cbSJens Wiklander /* 1326817466cbSJens Wiklander * Check for valid input 1327817466cbSJens Wiklander */ 1328817466cbSJens Wiklander if( crt == NULL || buf == NULL ) 1329817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1330817466cbSJens Wiklander 1331817466cbSJens Wiklander while( crt->version != 0 && crt->next != NULL ) 1332817466cbSJens Wiklander { 1333817466cbSJens Wiklander prev = crt; 1334817466cbSJens Wiklander crt = crt->next; 1335817466cbSJens Wiklander } 1336817466cbSJens Wiklander 1337817466cbSJens Wiklander /* 1338817466cbSJens Wiklander * Add new certificate on the end of the chain if needed. 1339817466cbSJens Wiklander */ 1340817466cbSJens Wiklander if( crt->version != 0 && crt->next == NULL ) 1341817466cbSJens Wiklander { 1342817466cbSJens Wiklander crt->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); 1343817466cbSJens Wiklander 1344817466cbSJens Wiklander if( crt->next == NULL ) 1345817466cbSJens Wiklander return( MBEDTLS_ERR_X509_ALLOC_FAILED ); 1346817466cbSJens Wiklander 1347817466cbSJens Wiklander prev = crt; 1348817466cbSJens Wiklander mbedtls_x509_crt_init( crt->next ); 1349817466cbSJens Wiklander crt = crt->next; 1350817466cbSJens Wiklander } 1351817466cbSJens Wiklander 1352*11fa71b9SJerome Forissier if( ( ret = x509_crt_parse_der_core( crt, buf, buflen, make_copy ) ) != 0 ) 1353817466cbSJens Wiklander { 1354817466cbSJens Wiklander if( prev ) 1355817466cbSJens Wiklander prev->next = NULL; 1356817466cbSJens Wiklander 1357817466cbSJens Wiklander if( crt != chain ) 1358817466cbSJens Wiklander mbedtls_free( crt ); 1359817466cbSJens Wiklander 1360817466cbSJens Wiklander return( ret ); 1361817466cbSJens Wiklander } 1362817466cbSJens Wiklander 1363817466cbSJens Wiklander return( 0 ); 1364817466cbSJens Wiklander } 1365817466cbSJens Wiklander 1366*11fa71b9SJerome Forissier int mbedtls_x509_crt_parse_der_nocopy( mbedtls_x509_crt *chain, 1367*11fa71b9SJerome Forissier const unsigned char *buf, 1368*11fa71b9SJerome Forissier size_t buflen ) 1369*11fa71b9SJerome Forissier { 1370*11fa71b9SJerome Forissier return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 0 ) ); 1371*11fa71b9SJerome Forissier } 1372*11fa71b9SJerome Forissier 1373*11fa71b9SJerome Forissier int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, 1374*11fa71b9SJerome Forissier const unsigned char *buf, 1375*11fa71b9SJerome Forissier size_t buflen ) 1376*11fa71b9SJerome Forissier { 1377*11fa71b9SJerome Forissier return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1 ) ); 1378*11fa71b9SJerome Forissier } 1379*11fa71b9SJerome Forissier 1380817466cbSJens Wiklander /* 1381817466cbSJens Wiklander * Parse one or more PEM certificates from a buffer and add them to the chained 1382817466cbSJens Wiklander * list 1383817466cbSJens Wiklander */ 1384*11fa71b9SJerome Forissier int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, 1385*11fa71b9SJerome Forissier const unsigned char *buf, 1386*11fa71b9SJerome Forissier size_t buflen ) 1387817466cbSJens Wiklander { 1388817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1389817466cbSJens Wiklander int success = 0, first_error = 0, total_failed = 0; 1390817466cbSJens Wiklander int buf_format = MBEDTLS_X509_FORMAT_DER; 1391817466cbSJens Wiklander #endif 1392817466cbSJens Wiklander 1393817466cbSJens Wiklander /* 1394817466cbSJens Wiklander * Check for valid input 1395817466cbSJens Wiklander */ 1396817466cbSJens Wiklander if( chain == NULL || buf == NULL ) 1397817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1398817466cbSJens Wiklander 1399817466cbSJens Wiklander /* 1400817466cbSJens Wiklander * Determine buffer content. Buffer contains either one DER certificate or 1401817466cbSJens Wiklander * one or more PEM certificates. 1402817466cbSJens Wiklander */ 1403817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1404817466cbSJens Wiklander if( buflen != 0 && buf[buflen - 1] == '\0' && 1405817466cbSJens Wiklander strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL ) 1406817466cbSJens Wiklander { 1407817466cbSJens Wiklander buf_format = MBEDTLS_X509_FORMAT_PEM; 1408817466cbSJens Wiklander } 1409817466cbSJens Wiklander 1410817466cbSJens Wiklander if( buf_format == MBEDTLS_X509_FORMAT_DER ) 1411817466cbSJens Wiklander return mbedtls_x509_crt_parse_der( chain, buf, buflen ); 1412817466cbSJens Wiklander #else 1413817466cbSJens Wiklander return mbedtls_x509_crt_parse_der( chain, buf, buflen ); 1414817466cbSJens Wiklander #endif 1415817466cbSJens Wiklander 1416817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1417817466cbSJens Wiklander if( buf_format == MBEDTLS_X509_FORMAT_PEM ) 1418817466cbSJens Wiklander { 1419*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1420817466cbSJens Wiklander mbedtls_pem_context pem; 1421817466cbSJens Wiklander 1422817466cbSJens Wiklander /* 1 rather than 0 since the terminating NULL byte is counted in */ 1423817466cbSJens Wiklander while( buflen > 1 ) 1424817466cbSJens Wiklander { 1425817466cbSJens Wiklander size_t use_len; 1426817466cbSJens Wiklander mbedtls_pem_init( &pem ); 1427817466cbSJens Wiklander 1428817466cbSJens Wiklander /* If we get there, we know the string is null-terminated */ 1429817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1430817466cbSJens Wiklander "-----BEGIN CERTIFICATE-----", 1431817466cbSJens Wiklander "-----END CERTIFICATE-----", 1432817466cbSJens Wiklander buf, NULL, 0, &use_len ); 1433817466cbSJens Wiklander 1434817466cbSJens Wiklander if( ret == 0 ) 1435817466cbSJens Wiklander { 1436817466cbSJens Wiklander /* 1437817466cbSJens Wiklander * Was PEM encoded 1438817466cbSJens Wiklander */ 1439817466cbSJens Wiklander buflen -= use_len; 1440817466cbSJens Wiklander buf += use_len; 1441817466cbSJens Wiklander } 1442817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA ) 1443817466cbSJens Wiklander { 1444817466cbSJens Wiklander return( ret ); 1445817466cbSJens Wiklander } 1446817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1447817466cbSJens Wiklander { 1448817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1449817466cbSJens Wiklander 1450817466cbSJens Wiklander /* 1451817466cbSJens Wiklander * PEM header and footer were found 1452817466cbSJens Wiklander */ 1453817466cbSJens Wiklander buflen -= use_len; 1454817466cbSJens Wiklander buf += use_len; 1455817466cbSJens Wiklander 1456817466cbSJens Wiklander if( first_error == 0 ) 1457817466cbSJens Wiklander first_error = ret; 1458817466cbSJens Wiklander 1459817466cbSJens Wiklander total_failed++; 1460817466cbSJens Wiklander continue; 1461817466cbSJens Wiklander } 1462817466cbSJens Wiklander else 1463817466cbSJens Wiklander break; 1464817466cbSJens Wiklander 1465817466cbSJens Wiklander ret = mbedtls_x509_crt_parse_der( chain, pem.buf, pem.buflen ); 1466817466cbSJens Wiklander 1467817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1468817466cbSJens Wiklander 1469817466cbSJens Wiklander if( ret != 0 ) 1470817466cbSJens Wiklander { 1471817466cbSJens Wiklander /* 1472817466cbSJens Wiklander * Quit parsing on a memory error 1473817466cbSJens Wiklander */ 1474817466cbSJens Wiklander if( ret == MBEDTLS_ERR_X509_ALLOC_FAILED ) 1475817466cbSJens Wiklander return( ret ); 1476817466cbSJens Wiklander 1477817466cbSJens Wiklander if( first_error == 0 ) 1478817466cbSJens Wiklander first_error = ret; 1479817466cbSJens Wiklander 1480817466cbSJens Wiklander total_failed++; 1481817466cbSJens Wiklander continue; 1482817466cbSJens Wiklander } 1483817466cbSJens Wiklander 1484817466cbSJens Wiklander success = 1; 1485817466cbSJens Wiklander } 1486817466cbSJens Wiklander } 1487817466cbSJens Wiklander 1488817466cbSJens Wiklander if( success ) 1489817466cbSJens Wiklander return( total_failed ); 1490817466cbSJens Wiklander else if( first_error ) 1491817466cbSJens Wiklander return( first_error ); 1492817466cbSJens Wiklander else 1493817466cbSJens Wiklander return( MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT ); 1494817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1495817466cbSJens Wiklander } 1496817466cbSJens Wiklander 1497817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 1498817466cbSJens Wiklander /* 1499817466cbSJens Wiklander * Load one or more certificates and add them to the chained list 1500817466cbSJens Wiklander */ 1501817466cbSJens Wiklander int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ) 1502817466cbSJens Wiklander { 1503*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1504817466cbSJens Wiklander size_t n; 1505817466cbSJens Wiklander unsigned char *buf; 1506817466cbSJens Wiklander 1507817466cbSJens Wiklander if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) 1508817466cbSJens Wiklander return( ret ); 1509817466cbSJens Wiklander 1510817466cbSJens Wiklander ret = mbedtls_x509_crt_parse( chain, buf, n ); 1511817466cbSJens Wiklander 15123d3b0591SJens Wiklander mbedtls_platform_zeroize( buf, n ); 1513817466cbSJens Wiklander mbedtls_free( buf ); 1514817466cbSJens Wiklander 1515817466cbSJens Wiklander return( ret ); 1516817466cbSJens Wiklander } 1517817466cbSJens Wiklander 1518817466cbSJens Wiklander int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) 1519817466cbSJens Wiklander { 1520817466cbSJens Wiklander int ret = 0; 1521817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 1522817466cbSJens Wiklander int w_ret; 1523817466cbSJens Wiklander WCHAR szDir[MAX_PATH]; 1524817466cbSJens Wiklander char filename[MAX_PATH]; 1525817466cbSJens Wiklander char *p; 1526817466cbSJens Wiklander size_t len = strlen( path ); 1527817466cbSJens Wiklander 1528817466cbSJens Wiklander WIN32_FIND_DATAW file_data; 1529817466cbSJens Wiklander HANDLE hFind; 1530817466cbSJens Wiklander 1531817466cbSJens Wiklander if( len > MAX_PATH - 3 ) 1532817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1533817466cbSJens Wiklander 1534817466cbSJens Wiklander memset( szDir, 0, sizeof(szDir) ); 1535817466cbSJens Wiklander memset( filename, 0, MAX_PATH ); 1536817466cbSJens Wiklander memcpy( filename, path, len ); 1537817466cbSJens Wiklander filename[len++] = '\\'; 1538817466cbSJens Wiklander p = filename + len; 1539817466cbSJens Wiklander filename[len++] = '*'; 1540817466cbSJens Wiklander 1541817466cbSJens Wiklander w_ret = MultiByteToWideChar( CP_ACP, 0, filename, (int)len, szDir, 1542817466cbSJens Wiklander MAX_PATH - 3 ); 1543817466cbSJens Wiklander if( w_ret == 0 ) 1544817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1545817466cbSJens Wiklander 1546817466cbSJens Wiklander hFind = FindFirstFileW( szDir, &file_data ); 1547817466cbSJens Wiklander if( hFind == INVALID_HANDLE_VALUE ) 1548817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); 1549817466cbSJens Wiklander 1550817466cbSJens Wiklander len = MAX_PATH - len; 1551817466cbSJens Wiklander do 1552817466cbSJens Wiklander { 1553817466cbSJens Wiklander memset( p, 0, len ); 1554817466cbSJens Wiklander 1555817466cbSJens Wiklander if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) 1556817466cbSJens Wiklander continue; 1557817466cbSJens Wiklander 1558817466cbSJens Wiklander w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName, 1559817466cbSJens Wiklander lstrlenW( file_data.cFileName ), 1560817466cbSJens Wiklander p, (int) len - 1, 1561817466cbSJens Wiklander NULL, NULL ); 1562817466cbSJens Wiklander if( w_ret == 0 ) 1563817466cbSJens Wiklander { 1564817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1565817466cbSJens Wiklander goto cleanup; 1566817466cbSJens Wiklander } 1567817466cbSJens Wiklander 1568817466cbSJens Wiklander w_ret = mbedtls_x509_crt_parse_file( chain, filename ); 1569817466cbSJens Wiklander if( w_ret < 0 ) 1570817466cbSJens Wiklander ret++; 1571817466cbSJens Wiklander else 1572817466cbSJens Wiklander ret += w_ret; 1573817466cbSJens Wiklander } 1574817466cbSJens Wiklander while( FindNextFileW( hFind, &file_data ) != 0 ); 1575817466cbSJens Wiklander 1576817466cbSJens Wiklander if( GetLastError() != ERROR_NO_MORE_FILES ) 1577817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1578817466cbSJens Wiklander 1579817466cbSJens Wiklander cleanup: 1580817466cbSJens Wiklander FindClose( hFind ); 1581817466cbSJens Wiklander #else /* _WIN32 */ 1582817466cbSJens Wiklander int t_ret; 1583817466cbSJens Wiklander int snp_ret; 1584817466cbSJens Wiklander struct stat sb; 1585817466cbSJens Wiklander struct dirent *entry; 1586817466cbSJens Wiklander char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN]; 1587817466cbSJens Wiklander DIR *dir = opendir( path ); 1588817466cbSJens Wiklander 1589817466cbSJens Wiklander if( dir == NULL ) 1590817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); 1591817466cbSJens Wiklander 1592817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 1593817466cbSJens Wiklander if( ( ret = mbedtls_mutex_lock( &mbedtls_threading_readdir_mutex ) ) != 0 ) 1594817466cbSJens Wiklander { 1595817466cbSJens Wiklander closedir( dir ); 1596817466cbSJens Wiklander return( ret ); 1597817466cbSJens Wiklander } 1598817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */ 1599817466cbSJens Wiklander 1600817466cbSJens Wiklander while( ( entry = readdir( dir ) ) != NULL ) 1601817466cbSJens Wiklander { 1602817466cbSJens Wiklander snp_ret = mbedtls_snprintf( entry_name, sizeof entry_name, 1603817466cbSJens Wiklander "%s/%s", path, entry->d_name ); 1604817466cbSJens Wiklander 1605817466cbSJens Wiklander if( snp_ret < 0 || (size_t)snp_ret >= sizeof entry_name ) 1606817466cbSJens Wiklander { 1607817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; 1608817466cbSJens Wiklander goto cleanup; 1609817466cbSJens Wiklander } 1610817466cbSJens Wiklander else if( stat( entry_name, &sb ) == -1 ) 1611817466cbSJens Wiklander { 1612817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1613817466cbSJens Wiklander goto cleanup; 1614817466cbSJens Wiklander } 1615817466cbSJens Wiklander 1616817466cbSJens Wiklander if( !S_ISREG( sb.st_mode ) ) 1617817466cbSJens Wiklander continue; 1618817466cbSJens Wiklander 1619817466cbSJens Wiklander // Ignore parse errors 1620817466cbSJens Wiklander // 1621817466cbSJens Wiklander t_ret = mbedtls_x509_crt_parse_file( chain, entry_name ); 1622817466cbSJens Wiklander if( t_ret < 0 ) 1623817466cbSJens Wiklander ret++; 1624817466cbSJens Wiklander else 1625817466cbSJens Wiklander ret += t_ret; 1626817466cbSJens Wiklander } 1627817466cbSJens Wiklander 1628817466cbSJens Wiklander cleanup: 1629817466cbSJens Wiklander closedir( dir ); 1630817466cbSJens Wiklander 1631817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 1632817466cbSJens Wiklander if( mbedtls_mutex_unlock( &mbedtls_threading_readdir_mutex ) != 0 ) 1633817466cbSJens Wiklander ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR; 1634817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */ 1635817466cbSJens Wiklander 1636817466cbSJens Wiklander #endif /* _WIN32 */ 1637817466cbSJens Wiklander 1638817466cbSJens Wiklander return( ret ); 1639817466cbSJens Wiklander } 1640817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 1641817466cbSJens Wiklander 1642*11fa71b9SJerome Forissier /* 1643*11fa71b9SJerome Forissier * OtherName ::= SEQUENCE { 1644*11fa71b9SJerome Forissier * type-id OBJECT IDENTIFIER, 1645*11fa71b9SJerome Forissier * value [0] EXPLICIT ANY DEFINED BY type-id } 1646*11fa71b9SJerome Forissier * 1647*11fa71b9SJerome Forissier * HardwareModuleName ::= SEQUENCE { 1648*11fa71b9SJerome Forissier * hwType OBJECT IDENTIFIER, 1649*11fa71b9SJerome Forissier * hwSerialNum OCTET STRING } 1650*11fa71b9SJerome Forissier * 1651*11fa71b9SJerome Forissier * NOTE: we currently only parse and use otherName of type HwModuleName, 1652*11fa71b9SJerome Forissier * as defined in RFC 4108. 1653*11fa71b9SJerome Forissier */ 1654*11fa71b9SJerome Forissier static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name, 1655*11fa71b9SJerome Forissier mbedtls_x509_san_other_name *other_name ) 1656817466cbSJens Wiklander { 1657*11fa71b9SJerome Forissier int ret = 0; 1658*11fa71b9SJerome Forissier size_t len; 1659*11fa71b9SJerome Forissier unsigned char *p = subject_alt_name->p; 1660*11fa71b9SJerome Forissier const unsigned char *end = p + subject_alt_name->len; 1661*11fa71b9SJerome Forissier mbedtls_x509_buf cur_oid; 1662*11fa71b9SJerome Forissier 1663*11fa71b9SJerome Forissier if( ( subject_alt_name->tag & 1664*11fa71b9SJerome Forissier ( MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK ) ) != 1665*11fa71b9SJerome Forissier ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ) ) 1666*11fa71b9SJerome Forissier { 1667*11fa71b9SJerome Forissier /* 1668*11fa71b9SJerome Forissier * The given subject alternative name is not of type "othername". 1669*11fa71b9SJerome Forissier */ 1670*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1671*11fa71b9SJerome Forissier } 1672*11fa71b9SJerome Forissier 1673*11fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1674*11fa71b9SJerome Forissier MBEDTLS_ASN1_OID ) ) != 0 ) 1675*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 1676*11fa71b9SJerome Forissier 1677*11fa71b9SJerome Forissier cur_oid.tag = MBEDTLS_ASN1_OID; 1678*11fa71b9SJerome Forissier cur_oid.p = p; 1679*11fa71b9SJerome Forissier cur_oid.len = len; 1680*11fa71b9SJerome Forissier 1681*11fa71b9SJerome Forissier /* 1682*11fa71b9SJerome Forissier * Only HwModuleName is currently supported. 1683*11fa71b9SJerome Forissier */ 1684*11fa71b9SJerome Forissier if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME, &cur_oid ) != 0 ) 1685*11fa71b9SJerome Forissier { 1686*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); 1687*11fa71b9SJerome Forissier } 1688*11fa71b9SJerome Forissier 1689*11fa71b9SJerome Forissier if( p + len >= end ) 1690*11fa71b9SJerome Forissier { 1691*11fa71b9SJerome Forissier mbedtls_platform_zeroize( other_name, sizeof( *other_name ) ); 1692*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 1693*11fa71b9SJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 1694*11fa71b9SJerome Forissier } 1695*11fa71b9SJerome Forissier p += len; 1696*11fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1697*11fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) 1698*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 1699*11fa71b9SJerome Forissier 1700*11fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1701*11fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1702*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 1703*11fa71b9SJerome Forissier 1704*11fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OID ) ) != 0 ) 1705*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 1706*11fa71b9SJerome Forissier 1707*11fa71b9SJerome Forissier other_name->value.hardware_module_name.oid.tag = MBEDTLS_ASN1_OID; 1708*11fa71b9SJerome Forissier other_name->value.hardware_module_name.oid.p = p; 1709*11fa71b9SJerome Forissier other_name->value.hardware_module_name.oid.len = len; 1710*11fa71b9SJerome Forissier 1711*11fa71b9SJerome Forissier if( p + len >= end ) 1712*11fa71b9SJerome Forissier { 1713*11fa71b9SJerome Forissier mbedtls_platform_zeroize( other_name, sizeof( *other_name ) ); 1714*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 1715*11fa71b9SJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 1716*11fa71b9SJerome Forissier } 1717*11fa71b9SJerome Forissier p += len; 1718*11fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1719*11fa71b9SJerome Forissier MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 1720*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 1721*11fa71b9SJerome Forissier 1722*11fa71b9SJerome Forissier other_name->value.hardware_module_name.val.tag = MBEDTLS_ASN1_OCTET_STRING; 1723*11fa71b9SJerome Forissier other_name->value.hardware_module_name.val.p = p; 1724*11fa71b9SJerome Forissier other_name->value.hardware_module_name.val.len = len; 1725*11fa71b9SJerome Forissier p += len; 1726*11fa71b9SJerome Forissier if( p != end ) 1727*11fa71b9SJerome Forissier { 1728*11fa71b9SJerome Forissier mbedtls_platform_zeroize( other_name, 1729*11fa71b9SJerome Forissier sizeof( *other_name ) ); 1730*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 1731*11fa71b9SJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 1732*11fa71b9SJerome Forissier } 1733*11fa71b9SJerome Forissier return( 0 ); 1734*11fa71b9SJerome Forissier } 1735*11fa71b9SJerome Forissier 1736*11fa71b9SJerome Forissier static int x509_info_subject_alt_name( char **buf, size_t *size, 1737*11fa71b9SJerome Forissier const mbedtls_x509_sequence 1738*11fa71b9SJerome Forissier *subject_alt_name, 1739*11fa71b9SJerome Forissier const char *prefix ) 1740*11fa71b9SJerome Forissier { 1741*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1742817466cbSJens Wiklander size_t n = *size; 1743817466cbSJens Wiklander char *p = *buf; 1744817466cbSJens Wiklander const mbedtls_x509_sequence *cur = subject_alt_name; 1745*11fa71b9SJerome Forissier mbedtls_x509_subject_alternative_name san; 1746*11fa71b9SJerome Forissier int parse_ret; 1747817466cbSJens Wiklander 1748817466cbSJens Wiklander while( cur != NULL ) 1749817466cbSJens Wiklander { 1750*11fa71b9SJerome Forissier memset( &san, 0, sizeof( san ) ); 1751*11fa71b9SJerome Forissier parse_ret = mbedtls_x509_parse_subject_alt_name( &cur->buf, &san ); 1752*11fa71b9SJerome Forissier if( parse_ret != 0 ) 1753*11fa71b9SJerome Forissier { 1754*11fa71b9SJerome Forissier if( parse_ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) 1755*11fa71b9SJerome Forissier { 1756*11fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s <unsupported>", prefix ); 1757*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 1758*11fa71b9SJerome Forissier } 1759*11fa71b9SJerome Forissier else 1760*11fa71b9SJerome Forissier { 1761*11fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s <malformed>", prefix ); 1762*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 1763*11fa71b9SJerome Forissier } 1764*11fa71b9SJerome Forissier cur = cur->next; 1765*11fa71b9SJerome Forissier continue; 1766*11fa71b9SJerome Forissier } 1767*11fa71b9SJerome Forissier 1768*11fa71b9SJerome Forissier switch( san.type ) 1769*11fa71b9SJerome Forissier { 1770*11fa71b9SJerome Forissier /* 1771*11fa71b9SJerome Forissier * otherName 1772*11fa71b9SJerome Forissier */ 1773*11fa71b9SJerome Forissier case MBEDTLS_X509_SAN_OTHER_NAME: 1774*11fa71b9SJerome Forissier { 1775*11fa71b9SJerome Forissier mbedtls_x509_san_other_name *other_name = &san.san.other_name; 1776*11fa71b9SJerome Forissier 1777*11fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s otherName :", prefix ); 1778*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 1779*11fa71b9SJerome Forissier 1780*11fa71b9SJerome Forissier if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME, 1781*11fa71b9SJerome Forissier &other_name->value.hardware_module_name.oid ) != 0 ) 1782*11fa71b9SJerome Forissier { 1783*11fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s hardware module name :", prefix ); 1784*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 1785*11fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s hardware type : ", prefix ); 1786*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 1787*11fa71b9SJerome Forissier 1788*11fa71b9SJerome Forissier ret = mbedtls_oid_get_numeric_string( p, n, &other_name->value.hardware_module_name.oid ); 1789*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 1790*11fa71b9SJerome Forissier 1791*11fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s hardware serial number : ", prefix ); 1792*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 1793*11fa71b9SJerome Forissier 1794*11fa71b9SJerome Forissier if( other_name->value.hardware_module_name.val.len >= n ) 1795817466cbSJens Wiklander { 1796817466cbSJens Wiklander *p = '\0'; 1797817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); 1798817466cbSJens Wiklander } 1799817466cbSJens Wiklander 1800*11fa71b9SJerome Forissier memcpy( p, other_name->value.hardware_module_name.val.p, 1801*11fa71b9SJerome Forissier other_name->value.hardware_module_name.val.len ); 1802*11fa71b9SJerome Forissier p += other_name->value.hardware_module_name.val.len; 1803817466cbSJens Wiklander 1804*11fa71b9SJerome Forissier n -= other_name->value.hardware_module_name.val.len; 1805*11fa71b9SJerome Forissier 1806*11fa71b9SJerome Forissier }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ 1807*11fa71b9SJerome Forissier } 1808*11fa71b9SJerome Forissier break; 1809*11fa71b9SJerome Forissier 1810*11fa71b9SJerome Forissier /* 1811*11fa71b9SJerome Forissier * dNSName 1812*11fa71b9SJerome Forissier */ 1813*11fa71b9SJerome Forissier case MBEDTLS_X509_SAN_DNS_NAME: 1814*11fa71b9SJerome Forissier { 1815*11fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s dNSName : ", prefix ); 1816*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 1817*11fa71b9SJerome Forissier if( san.san.unstructured_name.len >= n ) 1818*11fa71b9SJerome Forissier { 1819*11fa71b9SJerome Forissier *p = '\0'; 1820*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); 1821*11fa71b9SJerome Forissier } 1822*11fa71b9SJerome Forissier 1823*11fa71b9SJerome Forissier memcpy( p, san.san.unstructured_name.p, san.san.unstructured_name.len ); 1824*11fa71b9SJerome Forissier p += san.san.unstructured_name.len; 1825*11fa71b9SJerome Forissier n -= san.san.unstructured_name.len; 1826*11fa71b9SJerome Forissier } 1827*11fa71b9SJerome Forissier break; 1828*11fa71b9SJerome Forissier 1829*11fa71b9SJerome Forissier /* 1830*11fa71b9SJerome Forissier * Type not supported, skip item. 1831*11fa71b9SJerome Forissier */ 1832*11fa71b9SJerome Forissier default: 1833*11fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s <unsupported>", prefix ); 1834*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 1835*11fa71b9SJerome Forissier break; 1836*11fa71b9SJerome Forissier } 1837817466cbSJens Wiklander 1838817466cbSJens Wiklander cur = cur->next; 1839817466cbSJens Wiklander } 1840817466cbSJens Wiklander 1841817466cbSJens Wiklander *p = '\0'; 1842817466cbSJens Wiklander 1843817466cbSJens Wiklander *size = n; 1844817466cbSJens Wiklander *buf = p; 1845817466cbSJens Wiklander 1846817466cbSJens Wiklander return( 0 ); 1847817466cbSJens Wiklander } 1848817466cbSJens Wiklander 1849*11fa71b9SJerome Forissier int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf, 1850*11fa71b9SJerome Forissier mbedtls_x509_subject_alternative_name *san ) 1851*11fa71b9SJerome Forissier { 1852*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1853*11fa71b9SJerome Forissier switch( san_buf->tag & 1854*11fa71b9SJerome Forissier ( MBEDTLS_ASN1_TAG_CLASS_MASK | 1855*11fa71b9SJerome Forissier MBEDTLS_ASN1_TAG_VALUE_MASK ) ) 1856*11fa71b9SJerome Forissier { 1857*11fa71b9SJerome Forissier /* 1858*11fa71b9SJerome Forissier * otherName 1859*11fa71b9SJerome Forissier */ 1860*11fa71b9SJerome Forissier case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ): 1861*11fa71b9SJerome Forissier { 1862*11fa71b9SJerome Forissier mbedtls_x509_san_other_name other_name; 1863*11fa71b9SJerome Forissier 1864*11fa71b9SJerome Forissier ret = x509_get_other_name( san_buf, &other_name ); 1865*11fa71b9SJerome Forissier if( ret != 0 ) 1866*11fa71b9SJerome Forissier return( ret ); 1867*11fa71b9SJerome Forissier 1868*11fa71b9SJerome Forissier memset( san, 0, sizeof( mbedtls_x509_subject_alternative_name ) ); 1869*11fa71b9SJerome Forissier san->type = MBEDTLS_X509_SAN_OTHER_NAME; 1870*11fa71b9SJerome Forissier memcpy( &san->san.other_name, 1871*11fa71b9SJerome Forissier &other_name, sizeof( other_name ) ); 1872*11fa71b9SJerome Forissier 1873*11fa71b9SJerome Forissier } 1874*11fa71b9SJerome Forissier break; 1875*11fa71b9SJerome Forissier 1876*11fa71b9SJerome Forissier /* 1877*11fa71b9SJerome Forissier * dNSName 1878*11fa71b9SJerome Forissier */ 1879*11fa71b9SJerome Forissier case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ): 1880*11fa71b9SJerome Forissier { 1881*11fa71b9SJerome Forissier memset( san, 0, sizeof( mbedtls_x509_subject_alternative_name ) ); 1882*11fa71b9SJerome Forissier san->type = MBEDTLS_X509_SAN_DNS_NAME; 1883*11fa71b9SJerome Forissier 1884*11fa71b9SJerome Forissier memcpy( &san->san.unstructured_name, 1885*11fa71b9SJerome Forissier san_buf, sizeof( *san_buf ) ); 1886*11fa71b9SJerome Forissier 1887*11fa71b9SJerome Forissier } 1888*11fa71b9SJerome Forissier break; 1889*11fa71b9SJerome Forissier 1890*11fa71b9SJerome Forissier /* 1891*11fa71b9SJerome Forissier * Type not supported 1892*11fa71b9SJerome Forissier */ 1893*11fa71b9SJerome Forissier default: 1894*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); 1895*11fa71b9SJerome Forissier } 1896*11fa71b9SJerome Forissier return( 0 ); 1897*11fa71b9SJerome Forissier } 1898*11fa71b9SJerome Forissier 1899817466cbSJens Wiklander #define PRINT_ITEM(i) \ 1900817466cbSJens Wiklander { \ 1901817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s" i, sep ); \ 1902817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; \ 1903817466cbSJens Wiklander sep = ", "; \ 1904817466cbSJens Wiklander } 1905817466cbSJens Wiklander 1906817466cbSJens Wiklander #define CERT_TYPE(type,name) \ 19075b25c76aSJerome Forissier if( ns_cert_type & (type) ) \ 1908817466cbSJens Wiklander PRINT_ITEM( name ); 1909817466cbSJens Wiklander 1910817466cbSJens Wiklander static int x509_info_cert_type( char **buf, size_t *size, 1911817466cbSJens Wiklander unsigned char ns_cert_type ) 1912817466cbSJens Wiklander { 1913*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1914817466cbSJens Wiklander size_t n = *size; 1915817466cbSJens Wiklander char *p = *buf; 1916817466cbSJens Wiklander const char *sep = ""; 1917817466cbSJens Wiklander 1918817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT, "SSL Client" ); 1919817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER, "SSL Server" ); 1920817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL, "Email" ); 1921817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING, "Object Signing" ); 1922817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_RESERVED, "Reserved" ); 1923817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CA, "SSL CA" ); 1924817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA, "Email CA" ); 1925817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA, "Object Signing CA" ); 1926817466cbSJens Wiklander 1927817466cbSJens Wiklander *size = n; 1928817466cbSJens Wiklander *buf = p; 1929817466cbSJens Wiklander 1930817466cbSJens Wiklander return( 0 ); 1931817466cbSJens Wiklander } 1932817466cbSJens Wiklander 1933817466cbSJens Wiklander #define KEY_USAGE(code,name) \ 19345b25c76aSJerome Forissier if( key_usage & (code) ) \ 1935817466cbSJens Wiklander PRINT_ITEM( name ); 1936817466cbSJens Wiklander 1937817466cbSJens Wiklander static int x509_info_key_usage( char **buf, size_t *size, 1938817466cbSJens Wiklander unsigned int key_usage ) 1939817466cbSJens Wiklander { 1940*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1941817466cbSJens Wiklander size_t n = *size; 1942817466cbSJens Wiklander char *p = *buf; 1943817466cbSJens Wiklander const char *sep = ""; 1944817466cbSJens Wiklander 1945817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_DIGITAL_SIGNATURE, "Digital Signature" ); 1946817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_NON_REPUDIATION, "Non Repudiation" ); 1947817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_KEY_ENCIPHERMENT, "Key Encipherment" ); 1948817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_DATA_ENCIPHERMENT, "Data Encipherment" ); 1949817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_KEY_AGREEMENT, "Key Agreement" ); 1950817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_KEY_CERT_SIGN, "Key Cert Sign" ); 1951817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_CRL_SIGN, "CRL Sign" ); 1952817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_ENCIPHER_ONLY, "Encipher Only" ); 1953817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_DECIPHER_ONLY, "Decipher Only" ); 1954817466cbSJens Wiklander 1955817466cbSJens Wiklander *size = n; 1956817466cbSJens Wiklander *buf = p; 1957817466cbSJens Wiklander 1958817466cbSJens Wiklander return( 0 ); 1959817466cbSJens Wiklander } 1960817466cbSJens Wiklander 1961817466cbSJens Wiklander static int x509_info_ext_key_usage( char **buf, size_t *size, 1962817466cbSJens Wiklander const mbedtls_x509_sequence *extended_key_usage ) 1963817466cbSJens Wiklander { 1964*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1965817466cbSJens Wiklander const char *desc; 1966817466cbSJens Wiklander size_t n = *size; 1967817466cbSJens Wiklander char *p = *buf; 1968817466cbSJens Wiklander const mbedtls_x509_sequence *cur = extended_key_usage; 1969817466cbSJens Wiklander const char *sep = ""; 1970817466cbSJens Wiklander 1971817466cbSJens Wiklander while( cur != NULL ) 1972817466cbSJens Wiklander { 1973817466cbSJens Wiklander if( mbedtls_oid_get_extended_key_usage( &cur->buf, &desc ) != 0 ) 1974817466cbSJens Wiklander desc = "???"; 1975817466cbSJens Wiklander 1976817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); 1977817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1978817466cbSJens Wiklander 1979817466cbSJens Wiklander sep = ", "; 1980817466cbSJens Wiklander 1981817466cbSJens Wiklander cur = cur->next; 1982817466cbSJens Wiklander } 1983817466cbSJens Wiklander 1984817466cbSJens Wiklander *size = n; 1985817466cbSJens Wiklander *buf = p; 1986817466cbSJens Wiklander 1987817466cbSJens Wiklander return( 0 ); 1988817466cbSJens Wiklander } 1989817466cbSJens Wiklander 1990*11fa71b9SJerome Forissier static int x509_info_cert_policies( char **buf, size_t *size, 1991*11fa71b9SJerome Forissier const mbedtls_x509_sequence *certificate_policies ) 1992*11fa71b9SJerome Forissier { 1993*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1994*11fa71b9SJerome Forissier const char *desc; 1995*11fa71b9SJerome Forissier size_t n = *size; 1996*11fa71b9SJerome Forissier char *p = *buf; 1997*11fa71b9SJerome Forissier const mbedtls_x509_sequence *cur = certificate_policies; 1998*11fa71b9SJerome Forissier const char *sep = ""; 1999*11fa71b9SJerome Forissier 2000*11fa71b9SJerome Forissier while( cur != NULL ) 2001*11fa71b9SJerome Forissier { 2002*11fa71b9SJerome Forissier if( mbedtls_oid_get_certificate_policies( &cur->buf, &desc ) != 0 ) 2003*11fa71b9SJerome Forissier desc = "???"; 2004*11fa71b9SJerome Forissier 2005*11fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); 2006*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 2007*11fa71b9SJerome Forissier 2008*11fa71b9SJerome Forissier sep = ", "; 2009*11fa71b9SJerome Forissier 2010*11fa71b9SJerome Forissier cur = cur->next; 2011*11fa71b9SJerome Forissier } 2012*11fa71b9SJerome Forissier 2013*11fa71b9SJerome Forissier *size = n; 2014*11fa71b9SJerome Forissier *buf = p; 2015*11fa71b9SJerome Forissier 2016*11fa71b9SJerome Forissier return( 0 ); 2017*11fa71b9SJerome Forissier } 2018*11fa71b9SJerome Forissier 2019817466cbSJens Wiklander /* 2020817466cbSJens Wiklander * Return an informational string about the certificate. 2021817466cbSJens Wiklander */ 2022817466cbSJens Wiklander #define BEFORE_COLON 18 2023817466cbSJens Wiklander #define BC "18" 2024817466cbSJens Wiklander int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, 2025817466cbSJens Wiklander const mbedtls_x509_crt *crt ) 2026817466cbSJens Wiklander { 2027*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2028817466cbSJens Wiklander size_t n; 2029817466cbSJens Wiklander char *p; 2030817466cbSJens Wiklander char key_size_str[BEFORE_COLON]; 2031817466cbSJens Wiklander 2032817466cbSJens Wiklander p = buf; 2033817466cbSJens Wiklander n = size; 2034817466cbSJens Wiklander 2035817466cbSJens Wiklander if( NULL == crt ) 2036817466cbSJens Wiklander { 2037817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); 2038817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2039817466cbSJens Wiklander 2040817466cbSJens Wiklander return( (int) ( size - n ) ); 2041817466cbSJens Wiklander } 2042817466cbSJens Wiklander 2043817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", 2044817466cbSJens Wiklander prefix, crt->version ); 2045817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2046817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%sserial number : ", 2047817466cbSJens Wiklander prefix ); 2048817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2049817466cbSJens Wiklander 2050817466cbSJens Wiklander ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); 2051817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2052817466cbSJens Wiklander 2053817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); 2054817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2055817466cbSJens Wiklander ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); 2056817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2057817466cbSJens Wiklander 2058817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); 2059817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2060817466cbSJens Wiklander ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); 2061817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2062817466cbSJens Wiklander 2063817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ 2064817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix, 2065817466cbSJens Wiklander crt->valid_from.year, crt->valid_from.mon, 2066817466cbSJens Wiklander crt->valid_from.day, crt->valid_from.hour, 2067817466cbSJens Wiklander crt->valid_from.min, crt->valid_from.sec ); 2068817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2069817466cbSJens Wiklander 2070817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ 2071817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix, 2072817466cbSJens Wiklander crt->valid_to.year, crt->valid_to.mon, 2073817466cbSJens Wiklander crt->valid_to.day, crt->valid_to.hour, 2074817466cbSJens Wiklander crt->valid_to.min, crt->valid_to.sec ); 2075817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2076817466cbSJens Wiklander 2077817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); 2078817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2079817466cbSJens Wiklander 2080817466cbSJens Wiklander ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, 2081817466cbSJens Wiklander crt->sig_md, crt->sig_opts ); 2082817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2083817466cbSJens Wiklander 2084817466cbSJens Wiklander /* Key size */ 2085817466cbSJens Wiklander if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, 2086817466cbSJens Wiklander mbedtls_pk_get_name( &crt->pk ) ) ) != 0 ) 2087817466cbSJens Wiklander { 2088817466cbSJens Wiklander return( ret ); 2089817466cbSJens Wiklander } 2090817466cbSJens Wiklander 2091817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, 2092817466cbSJens Wiklander (int) mbedtls_pk_get_bitlen( &crt->pk ) ); 2093817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2094817466cbSJens Wiklander 2095817466cbSJens Wiklander /* 2096817466cbSJens Wiklander * Optional extensions 2097817466cbSJens Wiklander */ 2098817466cbSJens Wiklander 2099817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS ) 2100817466cbSJens Wiklander { 2101817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, 2102817466cbSJens Wiklander crt->ca_istrue ? "true" : "false" ); 2103817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2104817466cbSJens Wiklander 2105817466cbSJens Wiklander if( crt->max_pathlen > 0 ) 2106817466cbSJens Wiklander { 2107817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", crt->max_pathlen - 1 ); 2108817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2109817466cbSJens Wiklander } 2110817466cbSJens Wiklander } 2111817466cbSJens Wiklander 2112817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) 2113817466cbSJens Wiklander { 2114817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%ssubject alt name :", prefix ); 2115817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2116817466cbSJens Wiklander 2117817466cbSJens Wiklander if( ( ret = x509_info_subject_alt_name( &p, &n, 2118*11fa71b9SJerome Forissier &crt->subject_alt_names, 2119*11fa71b9SJerome Forissier prefix ) ) != 0 ) 2120817466cbSJens Wiklander return( ret ); 2121817466cbSJens Wiklander } 2122817466cbSJens Wiklander 2123817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) 2124817466cbSJens Wiklander { 2125817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); 2126817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2127817466cbSJens Wiklander 2128817466cbSJens Wiklander if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 ) 2129817466cbSJens Wiklander return( ret ); 2130817466cbSJens Wiklander } 2131817466cbSJens Wiklander 2132817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) 2133817466cbSJens Wiklander { 2134817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%skey usage : ", prefix ); 2135817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2136817466cbSJens Wiklander 2137817466cbSJens Wiklander if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 ) 2138817466cbSJens Wiklander return( ret ); 2139817466cbSJens Wiklander } 2140817466cbSJens Wiklander 2141817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) 2142817466cbSJens Wiklander { 2143817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sext key usage : ", prefix ); 2144817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2145817466cbSJens Wiklander 2146817466cbSJens Wiklander if( ( ret = x509_info_ext_key_usage( &p, &n, 2147817466cbSJens Wiklander &crt->ext_key_usage ) ) != 0 ) 2148817466cbSJens Wiklander return( ret ); 2149817466cbSJens Wiklander } 2150817466cbSJens Wiklander 2151*11fa71b9SJerome Forissier if( crt->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES ) 2152*11fa71b9SJerome Forissier { 2153*11fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%scertificate policies : ", prefix ); 2154*11fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 2155*11fa71b9SJerome Forissier 2156*11fa71b9SJerome Forissier if( ( ret = x509_info_cert_policies( &p, &n, 2157*11fa71b9SJerome Forissier &crt->certificate_policies ) ) != 0 ) 2158*11fa71b9SJerome Forissier return( ret ); 2159*11fa71b9SJerome Forissier } 2160*11fa71b9SJerome Forissier 2161817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n" ); 2162817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2163817466cbSJens Wiklander 2164817466cbSJens Wiklander return( (int) ( size - n ) ); 2165817466cbSJens Wiklander } 2166817466cbSJens Wiklander 2167817466cbSJens Wiklander struct x509_crt_verify_string { 2168817466cbSJens Wiklander int code; 2169817466cbSJens Wiklander const char *string; 2170817466cbSJens Wiklander }; 2171817466cbSJens Wiklander 2172817466cbSJens Wiklander static const struct x509_crt_verify_string x509_crt_verify_strings[] = { 2173817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_EXPIRED, "The certificate validity has expired" }, 2174817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_REVOKED, "The certificate has been revoked (is on a CRL)" }, 2175817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_CN_MISMATCH, "The certificate Common Name (CN) does not match with the expected CN" }, 2176817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_NOT_TRUSTED, "The certificate is not correctly signed by the trusted CA" }, 2177817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_NOT_TRUSTED, "The CRL is not correctly signed by the trusted CA" }, 2178817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_EXPIRED, "The CRL is expired" }, 2179817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_MISSING, "Certificate was missing" }, 2180817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_SKIP_VERIFY, "Certificate verification was skipped" }, 2181817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_OTHER, "Other reason (can be used by verify callback)" }, 2182817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_FUTURE, "The certificate validity starts in the future" }, 2183817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_FUTURE, "The CRL is from the future" }, 2184817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_KEY_USAGE, "Usage does not match the keyUsage extension" }, 2185817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_EXT_KEY_USAGE, "Usage does not match the extendedKeyUsage extension" }, 2186817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_NS_CERT_TYPE, "Usage does not match the nsCertType extension" }, 2187817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_BAD_MD, "The certificate is signed with an unacceptable hash." }, 2188817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_BAD_PK, "The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, 2189817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_BAD_KEY, "The certificate is signed with an unacceptable key (eg bad curve, RSA too short)." }, 2190817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_BAD_MD, "The CRL is signed with an unacceptable hash." }, 2191817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_BAD_PK, "The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, 2192817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_BAD_KEY, "The CRL is signed with an unacceptable key (eg bad curve, RSA too short)." }, 2193817466cbSJens Wiklander { 0, NULL } 2194817466cbSJens Wiklander }; 2195817466cbSJens Wiklander 2196817466cbSJens Wiklander int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, 2197817466cbSJens Wiklander uint32_t flags ) 2198817466cbSJens Wiklander { 2199*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2200817466cbSJens Wiklander const struct x509_crt_verify_string *cur; 2201817466cbSJens Wiklander char *p = buf; 2202817466cbSJens Wiklander size_t n = size; 2203817466cbSJens Wiklander 2204817466cbSJens Wiklander for( cur = x509_crt_verify_strings; cur->string != NULL ; cur++ ) 2205817466cbSJens Wiklander { 2206817466cbSJens Wiklander if( ( flags & cur->code ) == 0 ) 2207817466cbSJens Wiklander continue; 2208817466cbSJens Wiklander 2209817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s%s\n", prefix, cur->string ); 2210817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2211817466cbSJens Wiklander flags ^= cur->code; 2212817466cbSJens Wiklander } 2213817466cbSJens Wiklander 2214817466cbSJens Wiklander if( flags != 0 ) 2215817466cbSJens Wiklander { 2216817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%sUnknown reason " 2217817466cbSJens Wiklander "(this should not happen)\n", prefix ); 2218817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2219817466cbSJens Wiklander } 2220817466cbSJens Wiklander 2221817466cbSJens Wiklander return( (int) ( size - n ) ); 2222817466cbSJens Wiklander } 2223817466cbSJens Wiklander 2224817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) 2225817466cbSJens Wiklander int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, 2226817466cbSJens Wiklander unsigned int usage ) 2227817466cbSJens Wiklander { 2228817466cbSJens Wiklander unsigned int usage_must, usage_may; 2229817466cbSJens Wiklander unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY 2230817466cbSJens Wiklander | MBEDTLS_X509_KU_DECIPHER_ONLY; 2231817466cbSJens Wiklander 2232817466cbSJens Wiklander if( ( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) == 0 ) 2233817466cbSJens Wiklander return( 0 ); 2234817466cbSJens Wiklander 2235817466cbSJens Wiklander usage_must = usage & ~may_mask; 2236817466cbSJens Wiklander 2237817466cbSJens Wiklander if( ( ( crt->key_usage & ~may_mask ) & usage_must ) != usage_must ) 2238817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 2239817466cbSJens Wiklander 2240817466cbSJens Wiklander usage_may = usage & may_mask; 2241817466cbSJens Wiklander 2242817466cbSJens Wiklander if( ( ( crt->key_usage & may_mask ) | usage_may ) != usage_may ) 2243817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 2244817466cbSJens Wiklander 2245817466cbSJens Wiklander return( 0 ); 2246817466cbSJens Wiklander } 2247817466cbSJens Wiklander #endif 2248817466cbSJens Wiklander 2249817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) 2250817466cbSJens Wiklander int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, 2251817466cbSJens Wiklander const char *usage_oid, 2252817466cbSJens Wiklander size_t usage_len ) 2253817466cbSJens Wiklander { 2254817466cbSJens Wiklander const mbedtls_x509_sequence *cur; 2255817466cbSJens Wiklander 2256817466cbSJens Wiklander /* Extension is not mandatory, absent means no restriction */ 2257817466cbSJens Wiklander if( ( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) 2258817466cbSJens Wiklander return( 0 ); 2259817466cbSJens Wiklander 2260817466cbSJens Wiklander /* 2261817466cbSJens Wiklander * Look for the requested usage (or wildcard ANY) in our list 2262817466cbSJens Wiklander */ 2263817466cbSJens Wiklander for( cur = &crt->ext_key_usage; cur != NULL; cur = cur->next ) 2264817466cbSJens Wiklander { 2265817466cbSJens Wiklander const mbedtls_x509_buf *cur_oid = &cur->buf; 2266817466cbSJens Wiklander 2267817466cbSJens Wiklander if( cur_oid->len == usage_len && 2268817466cbSJens Wiklander memcmp( cur_oid->p, usage_oid, usage_len ) == 0 ) 2269817466cbSJens Wiklander { 2270817466cbSJens Wiklander return( 0 ); 2271817466cbSJens Wiklander } 2272817466cbSJens Wiklander 2273817466cbSJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid ) == 0 ) 2274817466cbSJens Wiklander return( 0 ); 2275817466cbSJens Wiklander } 2276817466cbSJens Wiklander 2277817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 2278817466cbSJens Wiklander } 2279817466cbSJens Wiklander #endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ 2280817466cbSJens Wiklander 2281817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 2282817466cbSJens Wiklander /* 2283817466cbSJens Wiklander * Return 1 if the certificate is revoked, or 0 otherwise. 2284817466cbSJens Wiklander */ 2285817466cbSJens Wiklander int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ) 2286817466cbSJens Wiklander { 2287817466cbSJens Wiklander const mbedtls_x509_crl_entry *cur = &crl->entry; 2288817466cbSJens Wiklander 2289817466cbSJens Wiklander while( cur != NULL && cur->serial.len != 0 ) 2290817466cbSJens Wiklander { 2291817466cbSJens Wiklander if( crt->serial.len == cur->serial.len && 2292817466cbSJens Wiklander memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 ) 2293817466cbSJens Wiklander { 2294817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &cur->revocation_date ) ) 2295817466cbSJens Wiklander return( 1 ); 2296817466cbSJens Wiklander } 2297817466cbSJens Wiklander 2298817466cbSJens Wiklander cur = cur->next; 2299817466cbSJens Wiklander } 2300817466cbSJens Wiklander 2301817466cbSJens Wiklander return( 0 ); 2302817466cbSJens Wiklander } 2303817466cbSJens Wiklander 2304817466cbSJens Wiklander /* 2305817466cbSJens Wiklander * Check that the given certificate is not revoked according to the CRL. 23063d3b0591SJens Wiklander * Skip validation if no CRL for the given CA is present. 2307817466cbSJens Wiklander */ 2308817466cbSJens Wiklander static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, 2309817466cbSJens Wiklander mbedtls_x509_crl *crl_list, 2310817466cbSJens Wiklander const mbedtls_x509_crt_profile *profile ) 2311817466cbSJens Wiklander { 2312817466cbSJens Wiklander int flags = 0; 2313817466cbSJens Wiklander unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 2314817466cbSJens Wiklander const mbedtls_md_info_t *md_info; 2315817466cbSJens Wiklander 2316817466cbSJens Wiklander if( ca == NULL ) 2317817466cbSJens Wiklander return( flags ); 2318817466cbSJens Wiklander 2319817466cbSJens Wiklander while( crl_list != NULL ) 2320817466cbSJens Wiklander { 2321817466cbSJens Wiklander if( crl_list->version == 0 || 23223d3b0591SJens Wiklander x509_name_cmp( &crl_list->issuer, &ca->subject ) != 0 ) 2323817466cbSJens Wiklander { 2324817466cbSJens Wiklander crl_list = crl_list->next; 2325817466cbSJens Wiklander continue; 2326817466cbSJens Wiklander } 2327817466cbSJens Wiklander 2328817466cbSJens Wiklander /* 2329817466cbSJens Wiklander * Check if the CA is configured to sign CRLs 2330817466cbSJens Wiklander */ 2331817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) 23323d3b0591SJens Wiklander if( mbedtls_x509_crt_check_key_usage( ca, 23333d3b0591SJens Wiklander MBEDTLS_X509_KU_CRL_SIGN ) != 0 ) 2334817466cbSJens Wiklander { 2335817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 2336817466cbSJens Wiklander break; 2337817466cbSJens Wiklander } 2338817466cbSJens Wiklander #endif 2339817466cbSJens Wiklander 2340817466cbSJens Wiklander /* 2341817466cbSJens Wiklander * Check if CRL is correctly signed by the trusted CA 2342817466cbSJens Wiklander */ 2343817466cbSJens Wiklander if( x509_profile_check_md_alg( profile, crl_list->sig_md ) != 0 ) 2344817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_MD; 2345817466cbSJens Wiklander 2346817466cbSJens Wiklander if( x509_profile_check_pk_alg( profile, crl_list->sig_pk ) != 0 ) 2347817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_PK; 2348817466cbSJens Wiklander 2349817466cbSJens Wiklander md_info = mbedtls_md_info_from_type( crl_list->sig_md ); 23503d3b0591SJens Wiklander if( mbedtls_md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash ) != 0 ) 2351817466cbSJens Wiklander { 23523d3b0591SJens Wiklander /* Note: this can't happen except after an internal error */ 2353817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 2354817466cbSJens Wiklander break; 2355817466cbSJens Wiklander } 2356817466cbSJens Wiklander 23573d3b0591SJens Wiklander if( x509_profile_check_key( profile, &ca->pk ) != 0 ) 2358817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 2359817466cbSJens Wiklander 2360817466cbSJens Wiklander if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, &ca->pk, 2361817466cbSJens Wiklander crl_list->sig_md, hash, mbedtls_md_get_size( md_info ), 2362817466cbSJens Wiklander crl_list->sig.p, crl_list->sig.len ) != 0 ) 2363817466cbSJens Wiklander { 2364817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 2365817466cbSJens Wiklander break; 2366817466cbSJens Wiklander } 2367817466cbSJens Wiklander 2368817466cbSJens Wiklander /* 2369817466cbSJens Wiklander * Check for validity of CRL (Do not drop out) 2370817466cbSJens Wiklander */ 2371817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &crl_list->next_update ) ) 2372817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_EXPIRED; 2373817466cbSJens Wiklander 2374817466cbSJens Wiklander if( mbedtls_x509_time_is_future( &crl_list->this_update ) ) 2375817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_FUTURE; 2376817466cbSJens Wiklander 2377817466cbSJens Wiklander /* 2378817466cbSJens Wiklander * Check if certificate is revoked 2379817466cbSJens Wiklander */ 2380817466cbSJens Wiklander if( mbedtls_x509_crt_is_revoked( crt, crl_list ) ) 2381817466cbSJens Wiklander { 2382817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_REVOKED; 2383817466cbSJens Wiklander break; 2384817466cbSJens Wiklander } 2385817466cbSJens Wiklander 2386817466cbSJens Wiklander crl_list = crl_list->next; 2387817466cbSJens Wiklander } 2388817466cbSJens Wiklander 2389817466cbSJens Wiklander return( flags ); 2390817466cbSJens Wiklander } 2391817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRL_PARSE_C */ 2392817466cbSJens Wiklander 2393817466cbSJens Wiklander /* 23943d3b0591SJens Wiklander * Check the signature of a certificate by its parent 2395817466cbSJens Wiklander */ 23963d3b0591SJens Wiklander static int x509_crt_check_signature( const mbedtls_x509_crt *child, 23973d3b0591SJens Wiklander mbedtls_x509_crt *parent, 23983d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx ) 2399817466cbSJens Wiklander { 24003d3b0591SJens Wiklander unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 2401*11fa71b9SJerome Forissier size_t hash_len; 2402*11fa71b9SJerome Forissier #if !defined(MBEDTLS_USE_PSA_CRYPTO) 2403*11fa71b9SJerome Forissier const mbedtls_md_info_t *md_info; 24043d3b0591SJens Wiklander md_info = mbedtls_md_info_from_type( child->sig_md ); 2405*11fa71b9SJerome Forissier hash_len = mbedtls_md_get_size( md_info ); 2406*11fa71b9SJerome Forissier 2407*11fa71b9SJerome Forissier /* Note: hash errors can happen only after an internal error */ 24083d3b0591SJens Wiklander if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) 2409*11fa71b9SJerome Forissier return( -1 ); 2410*11fa71b9SJerome Forissier #else 2411*11fa71b9SJerome Forissier psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT; 2412*11fa71b9SJerome Forissier psa_algorithm_t hash_alg = mbedtls_psa_translate_md( child->sig_md ); 2413*11fa71b9SJerome Forissier 2414*11fa71b9SJerome Forissier if( psa_hash_setup( &hash_operation, hash_alg ) != PSA_SUCCESS ) 2415*11fa71b9SJerome Forissier return( -1 ); 2416*11fa71b9SJerome Forissier 2417*11fa71b9SJerome Forissier if( psa_hash_update( &hash_operation, child->tbs.p, child->tbs.len ) 2418*11fa71b9SJerome Forissier != PSA_SUCCESS ) 2419817466cbSJens Wiklander { 2420817466cbSJens Wiklander return( -1 ); 2421817466cbSJens Wiklander } 2422817466cbSJens Wiklander 2423*11fa71b9SJerome Forissier if( psa_hash_finish( &hash_operation, hash, sizeof( hash ), &hash_len ) 2424*11fa71b9SJerome Forissier != PSA_SUCCESS ) 2425*11fa71b9SJerome Forissier { 2426*11fa71b9SJerome Forissier return( -1 ); 2427*11fa71b9SJerome Forissier } 2428*11fa71b9SJerome Forissier #endif /* MBEDTLS_USE_PSA_CRYPTO */ 24293d3b0591SJens Wiklander /* Skip expensive computation on obvious mismatch */ 24303d3b0591SJens Wiklander if( ! mbedtls_pk_can_do( &parent->pk, child->sig_pk ) ) 2431817466cbSJens Wiklander return( -1 ); 2432817466cbSJens Wiklander 24333d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 24343d3b0591SJens Wiklander if( rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA ) 2435817466cbSJens Wiklander { 24363d3b0591SJens Wiklander return( mbedtls_pk_verify_restartable( &parent->pk, 2437*11fa71b9SJerome Forissier child->sig_md, hash, hash_len, 24383d3b0591SJens Wiklander child->sig.p, child->sig.len, &rs_ctx->pk ) ); 2439817466cbSJens Wiklander } 24403d3b0591SJens Wiklander #else 24413d3b0591SJens Wiklander (void) rs_ctx; 24423d3b0591SJens Wiklander #endif 2443817466cbSJens Wiklander 24443d3b0591SJens Wiklander return( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, 2445*11fa71b9SJerome Forissier child->sig_md, hash, hash_len, 24463d3b0591SJens Wiklander child->sig.p, child->sig.len ) ); 2447817466cbSJens Wiklander } 2448817466cbSJens Wiklander 2449817466cbSJens Wiklander /* 2450817466cbSJens Wiklander * Check if 'parent' is a suitable parent (signing CA) for 'child'. 2451817466cbSJens Wiklander * Return 0 if yes, -1 if not. 2452817466cbSJens Wiklander * 2453817466cbSJens Wiklander * top means parent is a locally-trusted certificate 2454817466cbSJens Wiklander */ 2455817466cbSJens Wiklander static int x509_crt_check_parent( const mbedtls_x509_crt *child, 2456817466cbSJens Wiklander const mbedtls_x509_crt *parent, 24573d3b0591SJens Wiklander int top ) 2458817466cbSJens Wiklander { 2459817466cbSJens Wiklander int need_ca_bit; 2460817466cbSJens Wiklander 2461817466cbSJens Wiklander /* Parent must be the issuer */ 2462817466cbSJens Wiklander if( x509_name_cmp( &child->issuer, &parent->subject ) != 0 ) 2463817466cbSJens Wiklander return( -1 ); 2464817466cbSJens Wiklander 2465817466cbSJens Wiklander /* Parent must have the basicConstraints CA bit set as a general rule */ 2466817466cbSJens Wiklander need_ca_bit = 1; 2467817466cbSJens Wiklander 2468817466cbSJens Wiklander /* Exception: v1/v2 certificates that are locally trusted. */ 2469817466cbSJens Wiklander if( top && parent->version < 3 ) 2470817466cbSJens Wiklander need_ca_bit = 0; 2471817466cbSJens Wiklander 2472817466cbSJens Wiklander if( need_ca_bit && ! parent->ca_istrue ) 2473817466cbSJens Wiklander return( -1 ); 2474817466cbSJens Wiklander 2475817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) 2476817466cbSJens Wiklander if( need_ca_bit && 2477817466cbSJens Wiklander mbedtls_x509_crt_check_key_usage( parent, MBEDTLS_X509_KU_KEY_CERT_SIGN ) != 0 ) 2478817466cbSJens Wiklander { 2479817466cbSJens Wiklander return( -1 ); 2480817466cbSJens Wiklander } 2481817466cbSJens Wiklander #endif 2482817466cbSJens Wiklander 2483817466cbSJens Wiklander return( 0 ); 2484817466cbSJens Wiklander } 2485817466cbSJens Wiklander 24863d3b0591SJens Wiklander /* 24873d3b0591SJens Wiklander * Find a suitable parent for child in candidates, or return NULL. 24883d3b0591SJens Wiklander * 24893d3b0591SJens Wiklander * Here suitable is defined as: 24903d3b0591SJens Wiklander * 1. subject name matches child's issuer 24913d3b0591SJens Wiklander * 2. if necessary, the CA bit is set and key usage allows signing certs 24923d3b0591SJens Wiklander * 3. for trusted roots, the signature is correct 24933d3b0591SJens Wiklander * (for intermediates, the signature is checked and the result reported) 24943d3b0591SJens Wiklander * 4. pathlen constraints are satisfied 24953d3b0591SJens Wiklander * 24963d3b0591SJens Wiklander * If there's a suitable candidate which is also time-valid, return the first 24973d3b0591SJens Wiklander * such. Otherwise, return the first suitable candidate (or NULL if there is 24983d3b0591SJens Wiklander * none). 24993d3b0591SJens Wiklander * 25003d3b0591SJens Wiklander * The rationale for this rule is that someone could have a list of trusted 25013d3b0591SJens Wiklander * roots with two versions on the same root with different validity periods. 25023d3b0591SJens Wiklander * (At least one user reported having such a list and wanted it to just work.) 25033d3b0591SJens Wiklander * The reason we don't just require time-validity is that generally there is 25043d3b0591SJens Wiklander * only one version, and if it's expired we want the flags to state that 25053d3b0591SJens Wiklander * rather than NOT_TRUSTED, as would be the case if we required it here. 25063d3b0591SJens Wiklander * 25073d3b0591SJens Wiklander * The rationale for rule 3 (signature for trusted roots) is that users might 25083d3b0591SJens Wiklander * have two versions of the same CA with different keys in their list, and the 25093d3b0591SJens Wiklander * way we select the correct one is by checking the signature (as we don't 25103d3b0591SJens Wiklander * rely on key identifier extensions). (This is one way users might choose to 25113d3b0591SJens Wiklander * handle key rollover, another relies on self-issued certs, see [SIRO].) 25123d3b0591SJens Wiklander * 25133d3b0591SJens Wiklander * Arguments: 25143d3b0591SJens Wiklander * - [in] child: certificate for which we're looking for a parent 25153d3b0591SJens Wiklander * - [in] candidates: chained list of potential parents 25163d3b0591SJens Wiklander * - [out] r_parent: parent found (or NULL) 25173d3b0591SJens Wiklander * - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0 25183d3b0591SJens Wiklander * - [in] top: 1 if candidates consists of trusted roots, ie we're at the top 25193d3b0591SJens Wiklander * of the chain, 0 otherwise 25203d3b0591SJens Wiklander * - [in] path_cnt: number of intermediates seen so far 25213d3b0591SJens Wiklander * - [in] self_cnt: number of self-signed intermediates seen so far 25223d3b0591SJens Wiklander * (will never be greater than path_cnt) 25233d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 25243d3b0591SJens Wiklander * 25253d3b0591SJens Wiklander * Return value: 25263d3b0591SJens Wiklander * - 0 on success 25273d3b0591SJens Wiklander * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise 25283d3b0591SJens Wiklander */ 25293d3b0591SJens Wiklander static int x509_crt_find_parent_in( 25303d3b0591SJens Wiklander mbedtls_x509_crt *child, 25313d3b0591SJens Wiklander mbedtls_x509_crt *candidates, 25323d3b0591SJens Wiklander mbedtls_x509_crt **r_parent, 25333d3b0591SJens Wiklander int *r_signature_is_good, 25343d3b0591SJens Wiklander int top, 25353d3b0591SJens Wiklander unsigned path_cnt, 25363d3b0591SJens Wiklander unsigned self_cnt, 25373d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx ) 2538817466cbSJens Wiklander { 2539*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 25403d3b0591SJens Wiklander mbedtls_x509_crt *parent, *fallback_parent; 2541*11fa71b9SJerome Forissier int signature_is_good = 0, fallback_signature_is_good; 2542817466cbSJens Wiklander 25433d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 25443d3b0591SJens Wiklander /* did we have something in progress? */ 25453d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->parent != NULL ) 2546817466cbSJens Wiklander { 25473d3b0591SJens Wiklander /* restore saved state */ 25483d3b0591SJens Wiklander parent = rs_ctx->parent; 25493d3b0591SJens Wiklander fallback_parent = rs_ctx->fallback_parent; 25503d3b0591SJens Wiklander fallback_signature_is_good = rs_ctx->fallback_signature_is_good; 25513d3b0591SJens Wiklander 25523d3b0591SJens Wiklander /* clear saved state */ 25533d3b0591SJens Wiklander rs_ctx->parent = NULL; 25543d3b0591SJens Wiklander rs_ctx->fallback_parent = NULL; 25553d3b0591SJens Wiklander rs_ctx->fallback_signature_is_good = 0; 25563d3b0591SJens Wiklander 25573d3b0591SJens Wiklander /* resume where we left */ 25583d3b0591SJens Wiklander goto check_signature; 2559817466cbSJens Wiklander } 25603d3b0591SJens Wiklander #endif 2561817466cbSJens Wiklander 25623d3b0591SJens Wiklander fallback_parent = NULL; 25633d3b0591SJens Wiklander fallback_signature_is_good = 0; 25643d3b0591SJens Wiklander 25653d3b0591SJens Wiklander for( parent = candidates; parent != NULL; parent = parent->next ) 2566817466cbSJens Wiklander { 25673d3b0591SJens Wiklander /* basic parenting skills (name, CA bit, key usage) */ 25683d3b0591SJens Wiklander if( x509_crt_check_parent( child, parent, top ) != 0 ) 2569817466cbSJens Wiklander continue; 2570817466cbSJens Wiklander 25713d3b0591SJens Wiklander /* +1 because stored max_pathlen is 1 higher that the actual value */ 25723d3b0591SJens Wiklander if( parent->max_pathlen > 0 && 25733d3b0591SJens Wiklander (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt ) 2574817466cbSJens Wiklander { 2575817466cbSJens Wiklander continue; 2576817466cbSJens Wiklander } 2577817466cbSJens Wiklander 25783d3b0591SJens Wiklander /* Signature */ 25793d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 25803d3b0591SJens Wiklander check_signature: 25813d3b0591SJens Wiklander #endif 25823d3b0591SJens Wiklander ret = x509_crt_check_signature( child, parent, rs_ctx ); 2583817466cbSJens Wiklander 25843d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 25853d3b0591SJens Wiklander if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) 2586817466cbSJens Wiklander { 25873d3b0591SJens Wiklander /* save state */ 25883d3b0591SJens Wiklander rs_ctx->parent = parent; 25893d3b0591SJens Wiklander rs_ctx->fallback_parent = fallback_parent; 25903d3b0591SJens Wiklander rs_ctx->fallback_signature_is_good = fallback_signature_is_good; 25913d3b0591SJens Wiklander 25923d3b0591SJens Wiklander return( ret ); 25933d3b0591SJens Wiklander } 25943d3b0591SJens Wiklander #else 25953d3b0591SJens Wiklander (void) ret; 25963d3b0591SJens Wiklander #endif 25973d3b0591SJens Wiklander 25983d3b0591SJens Wiklander signature_is_good = ret == 0; 25993d3b0591SJens Wiklander if( top && ! signature_is_good ) 26003d3b0591SJens Wiklander continue; 26013d3b0591SJens Wiklander 26023d3b0591SJens Wiklander /* optional time check */ 26033d3b0591SJens Wiklander if( mbedtls_x509_time_is_past( &parent->valid_to ) || 26043d3b0591SJens Wiklander mbedtls_x509_time_is_future( &parent->valid_from ) ) 26053d3b0591SJens Wiklander { 26063d3b0591SJens Wiklander if( fallback_parent == NULL ) 26073d3b0591SJens Wiklander { 26083d3b0591SJens Wiklander fallback_parent = parent; 26093d3b0591SJens Wiklander fallback_signature_is_good = signature_is_good; 26103d3b0591SJens Wiklander } 2611817466cbSJens Wiklander 2612817466cbSJens Wiklander continue; 2613817466cbSJens Wiklander } 2614817466cbSJens Wiklander 26155b25c76aSJerome Forissier *r_parent = parent; 26165b25c76aSJerome Forissier *r_signature_is_good = signature_is_good; 26175b25c76aSJerome Forissier 2618817466cbSJens Wiklander break; 2619817466cbSJens Wiklander } 2620817466cbSJens Wiklander 26215b25c76aSJerome Forissier if( parent == NULL ) 2622817466cbSJens Wiklander { 26233d3b0591SJens Wiklander *r_parent = fallback_parent; 26243d3b0591SJens Wiklander *r_signature_is_good = fallback_signature_is_good; 2625817466cbSJens Wiklander } 2626817466cbSJens Wiklander 2627817466cbSJens Wiklander return( 0 ); 2628817466cbSJens Wiklander } 2629817466cbSJens Wiklander 26303d3b0591SJens Wiklander /* 26313d3b0591SJens Wiklander * Find a parent in trusted CAs or the provided chain, or return NULL. 26323d3b0591SJens Wiklander * 26333d3b0591SJens Wiklander * Searches in trusted CAs first, and return the first suitable parent found 26343d3b0591SJens Wiklander * (see find_parent_in() for definition of suitable). 26353d3b0591SJens Wiklander * 26363d3b0591SJens Wiklander * Arguments: 26373d3b0591SJens Wiklander * - [in] child: certificate for which we're looking for a parent, followed 26383d3b0591SJens Wiklander * by a chain of possible intermediates 26393d3b0591SJens Wiklander * - [in] trust_ca: list of locally trusted certificates 26403d3b0591SJens Wiklander * - [out] parent: parent found (or NULL) 26413d3b0591SJens Wiklander * - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0 26423d3b0591SJens Wiklander * - [out] signature_is_good: 1 if child signature by parent is valid, or 0 26433d3b0591SJens Wiklander * - [in] path_cnt: number of links in the chain so far (EE -> ... -> child) 26443d3b0591SJens Wiklander * - [in] self_cnt: number of self-signed certs in the chain so far 26453d3b0591SJens Wiklander * (will always be no greater than path_cnt) 26463d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 26473d3b0591SJens Wiklander * 26483d3b0591SJens Wiklander * Return value: 26493d3b0591SJens Wiklander * - 0 on success 26503d3b0591SJens Wiklander * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise 26513d3b0591SJens Wiklander */ 26523d3b0591SJens Wiklander static int x509_crt_find_parent( 26533d3b0591SJens Wiklander mbedtls_x509_crt *child, 26543d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 26553d3b0591SJens Wiklander mbedtls_x509_crt **parent, 26563d3b0591SJens Wiklander int *parent_is_trusted, 26573d3b0591SJens Wiklander int *signature_is_good, 26583d3b0591SJens Wiklander unsigned path_cnt, 26593d3b0591SJens Wiklander unsigned self_cnt, 26603d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx ) 2661817466cbSJens Wiklander { 2662*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 26633d3b0591SJens Wiklander mbedtls_x509_crt *search_list; 2664817466cbSJens Wiklander 26653d3b0591SJens Wiklander *parent_is_trusted = 1; 2666817466cbSJens Wiklander 26673d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 26683d3b0591SJens Wiklander /* restore then clear saved state if we have some stored */ 26693d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->parent_is_trusted != -1 ) 2670817466cbSJens Wiklander { 26713d3b0591SJens Wiklander *parent_is_trusted = rs_ctx->parent_is_trusted; 26723d3b0591SJens Wiklander rs_ctx->parent_is_trusted = -1; 26733d3b0591SJens Wiklander } 26743d3b0591SJens Wiklander #endif 26753d3b0591SJens Wiklander 26763d3b0591SJens Wiklander while( 1 ) { 26773d3b0591SJens Wiklander search_list = *parent_is_trusted ? trust_ca : child->next; 26783d3b0591SJens Wiklander 26793d3b0591SJens Wiklander ret = x509_crt_find_parent_in( child, search_list, 26803d3b0591SJens Wiklander parent, signature_is_good, 26813d3b0591SJens Wiklander *parent_is_trusted, 26823d3b0591SJens Wiklander path_cnt, self_cnt, rs_ctx ); 26833d3b0591SJens Wiklander 26843d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 26853d3b0591SJens Wiklander if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) 26863d3b0591SJens Wiklander { 26873d3b0591SJens Wiklander /* save state */ 26883d3b0591SJens Wiklander rs_ctx->parent_is_trusted = *parent_is_trusted; 26893d3b0591SJens Wiklander return( ret ); 26903d3b0591SJens Wiklander } 26913d3b0591SJens Wiklander #else 26923d3b0591SJens Wiklander (void) ret; 26933d3b0591SJens Wiklander #endif 26943d3b0591SJens Wiklander 26953d3b0591SJens Wiklander /* stop here if found or already in second iteration */ 26963d3b0591SJens Wiklander if( *parent != NULL || *parent_is_trusted == 0 ) 26973d3b0591SJens Wiklander break; 26983d3b0591SJens Wiklander 26993d3b0591SJens Wiklander /* prepare second iteration */ 27003d3b0591SJens Wiklander *parent_is_trusted = 0; 2701817466cbSJens Wiklander } 2702817466cbSJens Wiklander 27033d3b0591SJens Wiklander /* extra precaution against mistakes in the caller */ 27043d3b0591SJens Wiklander if( *parent == NULL ) 27053d3b0591SJens Wiklander { 27063d3b0591SJens Wiklander *parent_is_trusted = 0; 27073d3b0591SJens Wiklander *signature_is_good = 0; 27083d3b0591SJens Wiklander } 27093d3b0591SJens Wiklander 27103d3b0591SJens Wiklander return( 0 ); 27113d3b0591SJens Wiklander } 27123d3b0591SJens Wiklander 27133d3b0591SJens Wiklander /* 27143d3b0591SJens Wiklander * Check if an end-entity certificate is locally trusted 27153d3b0591SJens Wiklander * 27163d3b0591SJens Wiklander * Currently we require such certificates to be self-signed (actually only 27173d3b0591SJens Wiklander * check for self-issued as self-signatures are not checked) 27183d3b0591SJens Wiklander */ 27193d3b0591SJens Wiklander static int x509_crt_check_ee_locally_trusted( 27203d3b0591SJens Wiklander mbedtls_x509_crt *crt, 27213d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca ) 27223d3b0591SJens Wiklander { 27233d3b0591SJens Wiklander mbedtls_x509_crt *cur; 27243d3b0591SJens Wiklander 27253d3b0591SJens Wiklander /* must be self-issued */ 27263d3b0591SJens Wiklander if( x509_name_cmp( &crt->issuer, &crt->subject ) != 0 ) 27273d3b0591SJens Wiklander return( -1 ); 27283d3b0591SJens Wiklander 27293d3b0591SJens Wiklander /* look for an exact match with trusted cert */ 27303d3b0591SJens Wiklander for( cur = trust_ca; cur != NULL; cur = cur->next ) 27313d3b0591SJens Wiklander { 27323d3b0591SJens Wiklander if( crt->raw.len == cur->raw.len && 27333d3b0591SJens Wiklander memcmp( crt->raw.p, cur->raw.p, crt->raw.len ) == 0 ) 27343d3b0591SJens Wiklander { 27353d3b0591SJens Wiklander return( 0 ); 27363d3b0591SJens Wiklander } 27373d3b0591SJens Wiklander } 27383d3b0591SJens Wiklander 27393d3b0591SJens Wiklander /* too bad */ 27403d3b0591SJens Wiklander return( -1 ); 27413d3b0591SJens Wiklander } 27423d3b0591SJens Wiklander 27433d3b0591SJens Wiklander /* 27443d3b0591SJens Wiklander * Build and verify a certificate chain 27453d3b0591SJens Wiklander * 27463d3b0591SJens Wiklander * Given a peer-provided list of certificates EE, C1, ..., Cn and 27473d3b0591SJens Wiklander * a list of trusted certs R1, ... Rp, try to build and verify a chain 27483d3b0591SJens Wiklander * EE, Ci1, ... Ciq [, Rj] 27493d3b0591SJens Wiklander * such that every cert in the chain is a child of the next one, 27503d3b0591SJens Wiklander * jumping to a trusted root as early as possible. 27513d3b0591SJens Wiklander * 27523d3b0591SJens Wiklander * Verify that chain and return it with flags for all issues found. 27533d3b0591SJens Wiklander * 27543d3b0591SJens Wiklander * Special cases: 27553d3b0591SJens Wiklander * - EE == Rj -> return a one-element list containing it 27563d3b0591SJens Wiklander * - EE, Ci1, ..., Ciq cannot be continued with a trusted root 27573d3b0591SJens Wiklander * -> return that chain with NOT_TRUSTED set on Ciq 27583d3b0591SJens Wiklander * 27593d3b0591SJens Wiklander * Tests for (aspects of) this function should include at least: 27603d3b0591SJens Wiklander * - trusted EE 27613d3b0591SJens Wiklander * - EE -> trusted root 27625b25c76aSJerome Forissier * - EE -> intermediate CA -> trusted root 27633d3b0591SJens Wiklander * - if relevant: EE untrusted 27643d3b0591SJens Wiklander * - if relevant: EE -> intermediate, untrusted 27653d3b0591SJens Wiklander * with the aspect under test checked at each relevant level (EE, int, root). 27663d3b0591SJens Wiklander * For some aspects longer chains are required, but usually length 2 is 27673d3b0591SJens Wiklander * enough (but length 1 is not in general). 27683d3b0591SJens Wiklander * 27693d3b0591SJens Wiklander * Arguments: 27703d3b0591SJens Wiklander * - [in] crt: the cert list EE, C1, ..., Cn 27713d3b0591SJens Wiklander * - [in] trust_ca: the trusted list R1, ..., Rp 27723d3b0591SJens Wiklander * - [in] ca_crl, profile: as in verify_with_profile() 27733d3b0591SJens Wiklander * - [out] ver_chain: the built and verified chain 27743d3b0591SJens Wiklander * Only valid when return value is 0, may contain garbage otherwise! 27753d3b0591SJens Wiklander * Restart note: need not be the same when calling again to resume. 27763d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 27773d3b0591SJens Wiklander * 27783d3b0591SJens Wiklander * Return value: 27793d3b0591SJens Wiklander * - non-zero if the chain could not be fully built and examined 27803d3b0591SJens Wiklander * - 0 is the chain was successfully built and examined, 27813d3b0591SJens Wiklander * even if it was found to be invalid 27823d3b0591SJens Wiklander */ 27833d3b0591SJens Wiklander static int x509_crt_verify_chain( 27843d3b0591SJens Wiklander mbedtls_x509_crt *crt, 27853d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 27863d3b0591SJens Wiklander mbedtls_x509_crl *ca_crl, 2787*11fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 2788*11fa71b9SJerome Forissier void *p_ca_cb, 27893d3b0591SJens Wiklander const mbedtls_x509_crt_profile *profile, 27903d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain *ver_chain, 27913d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx ) 27923d3b0591SJens Wiklander { 27933d3b0591SJens Wiklander /* Don't initialize any of those variables here, so that the compiler can 27943d3b0591SJens Wiklander * catch potential issues with jumping ahead when restarting */ 2795*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 27963d3b0591SJens Wiklander uint32_t *flags; 27973d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain_item *cur; 27983d3b0591SJens Wiklander mbedtls_x509_crt *child; 27993d3b0591SJens Wiklander mbedtls_x509_crt *parent; 28003d3b0591SJens Wiklander int parent_is_trusted; 28013d3b0591SJens Wiklander int child_is_trusted; 28023d3b0591SJens Wiklander int signature_is_good; 28033d3b0591SJens Wiklander unsigned self_cnt; 2804*11fa71b9SJerome Forissier mbedtls_x509_crt *cur_trust_ca = NULL; 28053d3b0591SJens Wiklander 28063d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 28073d3b0591SJens Wiklander /* resume if we had an operation in progress */ 28083d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent ) 28093d3b0591SJens Wiklander { 28103d3b0591SJens Wiklander /* restore saved state */ 28113d3b0591SJens Wiklander *ver_chain = rs_ctx->ver_chain; /* struct copy */ 28123d3b0591SJens Wiklander self_cnt = rs_ctx->self_cnt; 28133d3b0591SJens Wiklander 28143d3b0591SJens Wiklander /* restore derived state */ 28153d3b0591SJens Wiklander cur = &ver_chain->items[ver_chain->len - 1]; 28163d3b0591SJens Wiklander child = cur->crt; 28173d3b0591SJens Wiklander flags = &cur->flags; 28183d3b0591SJens Wiklander 28193d3b0591SJens Wiklander goto find_parent; 28203d3b0591SJens Wiklander } 28213d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ 28223d3b0591SJens Wiklander 28233d3b0591SJens Wiklander child = crt; 28243d3b0591SJens Wiklander self_cnt = 0; 28253d3b0591SJens Wiklander parent_is_trusted = 0; 28263d3b0591SJens Wiklander child_is_trusted = 0; 28273d3b0591SJens Wiklander 28283d3b0591SJens Wiklander while( 1 ) { 28293d3b0591SJens Wiklander /* Add certificate to the verification chain */ 28303d3b0591SJens Wiklander cur = &ver_chain->items[ver_chain->len]; 28313d3b0591SJens Wiklander cur->crt = child; 28323d3b0591SJens Wiklander cur->flags = 0; 28333d3b0591SJens Wiklander ver_chain->len++; 28343d3b0591SJens Wiklander flags = &cur->flags; 28353d3b0591SJens Wiklander 28363d3b0591SJens Wiklander /* Check time-validity (all certificates) */ 2837817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &child->valid_to ) ) 2838817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_EXPIRED; 2839817466cbSJens Wiklander 2840817466cbSJens Wiklander if( mbedtls_x509_time_is_future( &child->valid_from ) ) 2841817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_FUTURE; 2842817466cbSJens Wiklander 28433d3b0591SJens Wiklander /* Stop here for trusted roots (but not for trusted EE certs) */ 28443d3b0591SJens Wiklander if( child_is_trusted ) 28453d3b0591SJens Wiklander return( 0 ); 28463d3b0591SJens Wiklander 28473d3b0591SJens Wiklander /* Check signature algorithm: MD & PK algs */ 2848817466cbSJens Wiklander if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) 2849817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_MD; 2850817466cbSJens Wiklander 2851817466cbSJens Wiklander if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) 2852817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_PK; 2853817466cbSJens Wiklander 28543d3b0591SJens Wiklander /* Special case: EE certs that are locally trusted */ 28553d3b0591SJens Wiklander if( ver_chain->len == 1 && 28563d3b0591SJens Wiklander x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 ) 2857817466cbSJens Wiklander { 28583d3b0591SJens Wiklander return( 0 ); 2859817466cbSJens Wiklander } 2860817466cbSJens Wiklander 28613d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 28623d3b0591SJens Wiklander find_parent: 28633d3b0591SJens Wiklander #endif 2864*11fa71b9SJerome Forissier 2865*11fa71b9SJerome Forissier /* Obtain list of potential trusted signers from CA callback, 2866*11fa71b9SJerome Forissier * or use statically provided list. */ 2867*11fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 2868*11fa71b9SJerome Forissier if( f_ca_cb != NULL ) 2869*11fa71b9SJerome Forissier { 2870*11fa71b9SJerome Forissier mbedtls_x509_crt_free( ver_chain->trust_ca_cb_result ); 2871*11fa71b9SJerome Forissier mbedtls_free( ver_chain->trust_ca_cb_result ); 2872*11fa71b9SJerome Forissier ver_chain->trust_ca_cb_result = NULL; 2873*11fa71b9SJerome Forissier 2874*11fa71b9SJerome Forissier ret = f_ca_cb( p_ca_cb, child, &ver_chain->trust_ca_cb_result ); 2875*11fa71b9SJerome Forissier if( ret != 0 ) 2876*11fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_FATAL_ERROR ); 2877*11fa71b9SJerome Forissier 2878*11fa71b9SJerome Forissier cur_trust_ca = ver_chain->trust_ca_cb_result; 2879*11fa71b9SJerome Forissier } 2880*11fa71b9SJerome Forissier else 2881*11fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 2882*11fa71b9SJerome Forissier { 2883*11fa71b9SJerome Forissier ((void) f_ca_cb); 2884*11fa71b9SJerome Forissier ((void) p_ca_cb); 2885*11fa71b9SJerome Forissier cur_trust_ca = trust_ca; 2886*11fa71b9SJerome Forissier } 2887*11fa71b9SJerome Forissier 28883d3b0591SJens Wiklander /* Look for a parent in trusted CAs or up the chain */ 2889*11fa71b9SJerome Forissier ret = x509_crt_find_parent( child, cur_trust_ca, &parent, 28903d3b0591SJens Wiklander &parent_is_trusted, &signature_is_good, 28913d3b0591SJens Wiklander ver_chain->len - 1, self_cnt, rs_ctx ); 28923d3b0591SJens Wiklander 28933d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 28943d3b0591SJens Wiklander if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) 28953d3b0591SJens Wiklander { 28963d3b0591SJens Wiklander /* save state */ 28973d3b0591SJens Wiklander rs_ctx->in_progress = x509_crt_rs_find_parent; 28983d3b0591SJens Wiklander rs_ctx->self_cnt = self_cnt; 28993d3b0591SJens Wiklander rs_ctx->ver_chain = *ver_chain; /* struct copy */ 29003d3b0591SJens Wiklander 29013d3b0591SJens Wiklander return( ret ); 29023d3b0591SJens Wiklander } 29033d3b0591SJens Wiklander #else 29043d3b0591SJens Wiklander (void) ret; 29053d3b0591SJens Wiklander #endif 29063d3b0591SJens Wiklander 29073d3b0591SJens Wiklander /* No parent? We're done here */ 29083d3b0591SJens Wiklander if( parent == NULL ) 29093d3b0591SJens Wiklander { 29103d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 29113d3b0591SJens Wiklander return( 0 ); 29123d3b0591SJens Wiklander } 29133d3b0591SJens Wiklander 29143d3b0591SJens Wiklander /* Count intermediate self-issued (not necessarily self-signed) certs. 29153d3b0591SJens Wiklander * These can occur with some strategies for key rollover, see [SIRO], 29163d3b0591SJens Wiklander * and should be excluded from max_pathlen checks. */ 29173d3b0591SJens Wiklander if( ver_chain->len != 1 && 29183d3b0591SJens Wiklander x509_name_cmp( &child->issuer, &child->subject ) == 0 ) 29193d3b0591SJens Wiklander { 29203d3b0591SJens Wiklander self_cnt++; 29213d3b0591SJens Wiklander } 29223d3b0591SJens Wiklander 29233d3b0591SJens Wiklander /* path_cnt is 0 for the first intermediate CA, 29243d3b0591SJens Wiklander * and if parent is trusted it's not an intermediate CA */ 29253d3b0591SJens Wiklander if( ! parent_is_trusted && 29263d3b0591SJens Wiklander ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) 29273d3b0591SJens Wiklander { 29283d3b0591SJens Wiklander /* return immediately to avoid overflow the chain array */ 29293d3b0591SJens Wiklander return( MBEDTLS_ERR_X509_FATAL_ERROR ); 29303d3b0591SJens Wiklander } 29313d3b0591SJens Wiklander 29323d3b0591SJens Wiklander /* signature was checked while searching parent */ 29333d3b0591SJens Wiklander if( ! signature_is_good ) 29343d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 29353d3b0591SJens Wiklander 29363d3b0591SJens Wiklander /* check size of signing key */ 29373d3b0591SJens Wiklander if( x509_profile_check_key( profile, &parent->pk ) != 0 ) 2938817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 2939817466cbSJens Wiklander 2940817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 2941817466cbSJens Wiklander /* Check trusted CA's CRL for the given crt */ 2942817466cbSJens Wiklander *flags |= x509_crt_verifycrl( child, parent, ca_crl, profile ); 29433d3b0591SJens Wiklander #else 29443d3b0591SJens Wiklander (void) ca_crl; 2945817466cbSJens Wiklander #endif 2946817466cbSJens Wiklander 29473d3b0591SJens Wiklander /* prepare for next iteration */ 29483d3b0591SJens Wiklander child = parent; 29493d3b0591SJens Wiklander parent = NULL; 29503d3b0591SJens Wiklander child_is_trusted = parent_is_trusted; 29513d3b0591SJens Wiklander signature_is_good = 0; 29523d3b0591SJens Wiklander } 29533d3b0591SJens Wiklander } 29543d3b0591SJens Wiklander 29553d3b0591SJens Wiklander /* 29563d3b0591SJens Wiklander * Check for CN match 29573d3b0591SJens Wiklander */ 29583d3b0591SJens Wiklander static int x509_crt_check_cn( const mbedtls_x509_buf *name, 29593d3b0591SJens Wiklander const char *cn, size_t cn_len ) 2960817466cbSJens Wiklander { 29613d3b0591SJens Wiklander /* try exact match */ 29623d3b0591SJens Wiklander if( name->len == cn_len && 29633d3b0591SJens Wiklander x509_memcasecmp( cn, name->p, cn_len ) == 0 ) 29643d3b0591SJens Wiklander { 29653d3b0591SJens Wiklander return( 0 ); 29663d3b0591SJens Wiklander } 29673d3b0591SJens Wiklander 29683d3b0591SJens Wiklander /* try wildcard match */ 29693d3b0591SJens Wiklander if( x509_check_wildcard( cn, name ) == 0 ) 29703d3b0591SJens Wiklander { 29713d3b0591SJens Wiklander return( 0 ); 29723d3b0591SJens Wiklander } 29733d3b0591SJens Wiklander 29743d3b0591SJens Wiklander return( -1 ); 29753d3b0591SJens Wiklander } 29763d3b0591SJens Wiklander 29773d3b0591SJens Wiklander /* 29783d3b0591SJens Wiklander * Verify the requested CN - only call this if cn is not NULL! 29793d3b0591SJens Wiklander */ 29803d3b0591SJens Wiklander static void x509_crt_verify_name( const mbedtls_x509_crt *crt, 29813d3b0591SJens Wiklander const char *cn, 29823d3b0591SJens Wiklander uint32_t *flags ) 29833d3b0591SJens Wiklander { 29843d3b0591SJens Wiklander const mbedtls_x509_name *name; 29853d3b0591SJens Wiklander const mbedtls_x509_sequence *cur; 29863d3b0591SJens Wiklander size_t cn_len = strlen( cn ); 29873d3b0591SJens Wiklander 29883d3b0591SJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) 29893d3b0591SJens Wiklander { 29903d3b0591SJens Wiklander for( cur = &crt->subject_alt_names; cur != NULL; cur = cur->next ) 29913d3b0591SJens Wiklander { 29923d3b0591SJens Wiklander if( x509_crt_check_cn( &cur->buf, cn, cn_len ) == 0 ) 2993817466cbSJens Wiklander break; 2994817466cbSJens Wiklander } 2995817466cbSJens Wiklander 29963d3b0591SJens Wiklander if( cur == NULL ) 29973d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; 2998817466cbSJens Wiklander } 2999817466cbSJens Wiklander else 3000817466cbSJens Wiklander { 30013d3b0591SJens Wiklander for( name = &crt->subject; name != NULL; name = name->next ) 3002817466cbSJens Wiklander { 30033d3b0591SJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 && 30043d3b0591SJens Wiklander x509_crt_check_cn( &name->val, cn, cn_len ) == 0 ) 3005817466cbSJens Wiklander { 3006817466cbSJens Wiklander break; 3007817466cbSJens Wiklander } 3008817466cbSJens Wiklander } 30093d3b0591SJens Wiklander 30103d3b0591SJens Wiklander if( name == NULL ) 30113d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; 3012817466cbSJens Wiklander } 3013817466cbSJens Wiklander } 3014817466cbSJens Wiklander 30153d3b0591SJens Wiklander /* 30163d3b0591SJens Wiklander * Merge the flags for all certs in the chain, after calling callback 30173d3b0591SJens Wiklander */ 30183d3b0591SJens Wiklander static int x509_crt_merge_flags_with_cb( 30193d3b0591SJens Wiklander uint32_t *flags, 30203d3b0591SJens Wiklander const mbedtls_x509_crt_verify_chain *ver_chain, 30213d3b0591SJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 30223d3b0591SJens Wiklander void *p_vrfy ) 30233d3b0591SJens Wiklander { 3024*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 30253d3b0591SJens Wiklander unsigned i; 30263d3b0591SJens Wiklander uint32_t cur_flags; 30273d3b0591SJens Wiklander const mbedtls_x509_crt_verify_chain_item *cur; 30283d3b0591SJens Wiklander 30293d3b0591SJens Wiklander for( i = ver_chain->len; i != 0; --i ) 30303d3b0591SJens Wiklander { 30313d3b0591SJens Wiklander cur = &ver_chain->items[i-1]; 30323d3b0591SJens Wiklander cur_flags = cur->flags; 30333d3b0591SJens Wiklander 3034817466cbSJens Wiklander if( NULL != f_vrfy ) 30353d3b0591SJens Wiklander if( ( ret = f_vrfy( p_vrfy, cur->crt, (int) i-1, &cur_flags ) ) != 0 ) 3036817466cbSJens Wiklander return( ret ); 3037817466cbSJens Wiklander 30383d3b0591SJens Wiklander *flags |= cur_flags; 30393d3b0591SJens Wiklander } 3040817466cbSJens Wiklander 3041817466cbSJens Wiklander return( 0 ); 3042817466cbSJens Wiklander } 3043817466cbSJens Wiklander 3044817466cbSJens Wiklander /* 30453d3b0591SJens Wiklander * Verify the certificate validity, with profile, restartable version 30463d3b0591SJens Wiklander * 30473d3b0591SJens Wiklander * This function: 30483d3b0591SJens Wiklander * - checks the requested CN (if any) 30493d3b0591SJens Wiklander * - checks the type and size of the EE cert's key, 30503d3b0591SJens Wiklander * as that isn't done as part of chain building/verification currently 30513d3b0591SJens Wiklander * - builds and verifies the chain 30523d3b0591SJens Wiklander * - then calls the callback and merges the flags 3053*11fa71b9SJerome Forissier * 3054*11fa71b9SJerome Forissier * The parameters pairs `trust_ca`, `ca_crl` and `f_ca_cb`, `p_ca_cb` 3055*11fa71b9SJerome Forissier * are mutually exclusive: If `f_ca_cb != NULL`, it will be used by the 3056*11fa71b9SJerome Forissier * verification routine to search for trusted signers, and CRLs will 3057*11fa71b9SJerome Forissier * be disabled. Otherwise, `trust_ca` will be used as the static list 3058*11fa71b9SJerome Forissier * of trusted signers, and `ca_crl` will be use as the static list 3059*11fa71b9SJerome Forissier * of CRLs. 30603d3b0591SJens Wiklander */ 3061*11fa71b9SJerome Forissier static int x509_crt_verify_restartable_ca_cb( mbedtls_x509_crt *crt, 30623d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 30633d3b0591SJens Wiklander mbedtls_x509_crl *ca_crl, 3064*11fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 3065*11fa71b9SJerome Forissier void *p_ca_cb, 30663d3b0591SJens Wiklander const mbedtls_x509_crt_profile *profile, 30673d3b0591SJens Wiklander const char *cn, uint32_t *flags, 30683d3b0591SJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 30693d3b0591SJens Wiklander void *p_vrfy, 30703d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx ) 30713d3b0591SJens Wiklander { 3072*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3073817466cbSJens Wiklander mbedtls_pk_type_t pk_type; 30743d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain ver_chain; 30753d3b0591SJens Wiklander uint32_t ee_flags; 3076817466cbSJens Wiklander 3077817466cbSJens Wiklander *flags = 0; 30783d3b0591SJens Wiklander ee_flags = 0; 30793d3b0591SJens Wiklander x509_crt_verify_chain_reset( &ver_chain ); 3080817466cbSJens Wiklander 3081817466cbSJens Wiklander if( profile == NULL ) 3082817466cbSJens Wiklander { 3083817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; 3084817466cbSJens Wiklander goto exit; 3085817466cbSJens Wiklander } 3086817466cbSJens Wiklander 30873d3b0591SJens Wiklander /* check name if requested */ 3088817466cbSJens Wiklander if( cn != NULL ) 30893d3b0591SJens Wiklander x509_crt_verify_name( crt, cn, &ee_flags ); 3090817466cbSJens Wiklander 3091817466cbSJens Wiklander /* Check the type and size of the key */ 3092817466cbSJens Wiklander pk_type = mbedtls_pk_get_type( &crt->pk ); 3093817466cbSJens Wiklander 3094817466cbSJens Wiklander if( x509_profile_check_pk_alg( profile, pk_type ) != 0 ) 30953d3b0591SJens Wiklander ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK; 3096817466cbSJens Wiklander 30973d3b0591SJens Wiklander if( x509_profile_check_key( profile, &crt->pk ) != 0 ) 30983d3b0591SJens Wiklander ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 3099817466cbSJens Wiklander 31003d3b0591SJens Wiklander /* Check the chain */ 3101*11fa71b9SJerome Forissier ret = x509_crt_verify_chain( crt, trust_ca, ca_crl, 3102*11fa71b9SJerome Forissier f_ca_cb, p_ca_cb, profile, 31033d3b0591SJens Wiklander &ver_chain, rs_ctx ); 3104817466cbSJens Wiklander 3105817466cbSJens Wiklander if( ret != 0 ) 3106817466cbSJens Wiklander goto exit; 3107817466cbSJens Wiklander 31083d3b0591SJens Wiklander /* Merge end-entity flags */ 31093d3b0591SJens Wiklander ver_chain.items[0].flags |= ee_flags; 31103d3b0591SJens Wiklander 31113d3b0591SJens Wiklander /* Build final flags, calling callback on the way if any */ 31123d3b0591SJens Wiklander ret = x509_crt_merge_flags_with_cb( flags, &ver_chain, f_vrfy, p_vrfy ); 3113817466cbSJens Wiklander 3114817466cbSJens Wiklander exit: 3115*11fa71b9SJerome Forissier 3116*11fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 3117*11fa71b9SJerome Forissier mbedtls_x509_crt_free( ver_chain.trust_ca_cb_result ); 3118*11fa71b9SJerome Forissier mbedtls_free( ver_chain.trust_ca_cb_result ); 3119*11fa71b9SJerome Forissier ver_chain.trust_ca_cb_result = NULL; 3120*11fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 3121*11fa71b9SJerome Forissier 31223d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 31233d3b0591SJens Wiklander if( rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) 31243d3b0591SJens Wiklander mbedtls_x509_crt_restart_free( rs_ctx ); 31253d3b0591SJens Wiklander #endif 31263d3b0591SJens Wiklander 3127817466cbSJens Wiklander /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by 3128817466cbSJens Wiklander * the SSL module for authmode optional, but non-zero return from the 3129817466cbSJens Wiklander * callback means a fatal error so it shouldn't be ignored */ 3130817466cbSJens Wiklander if( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ) 3131817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FATAL_ERROR; 3132817466cbSJens Wiklander 3133817466cbSJens Wiklander if( ret != 0 ) 3134817466cbSJens Wiklander { 3135817466cbSJens Wiklander *flags = (uint32_t) -1; 3136817466cbSJens Wiklander return( ret ); 3137817466cbSJens Wiklander } 3138817466cbSJens Wiklander 3139817466cbSJens Wiklander if( *flags != 0 ) 3140817466cbSJens Wiklander return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); 3141817466cbSJens Wiklander 3142817466cbSJens Wiklander return( 0 ); 3143817466cbSJens Wiklander } 3144817466cbSJens Wiklander 3145*11fa71b9SJerome Forissier 3146*11fa71b9SJerome Forissier /* 3147*11fa71b9SJerome Forissier * Verify the certificate validity (default profile, not restartable) 3148*11fa71b9SJerome Forissier */ 3149*11fa71b9SJerome Forissier int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, 3150*11fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 3151*11fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 3152*11fa71b9SJerome Forissier const char *cn, uint32_t *flags, 3153*11fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 3154*11fa71b9SJerome Forissier void *p_vrfy ) 3155*11fa71b9SJerome Forissier { 3156*11fa71b9SJerome Forissier return( x509_crt_verify_restartable_ca_cb( crt, trust_ca, ca_crl, 3157*11fa71b9SJerome Forissier NULL, NULL, 3158*11fa71b9SJerome Forissier &mbedtls_x509_crt_profile_default, 3159*11fa71b9SJerome Forissier cn, flags, 3160*11fa71b9SJerome Forissier f_vrfy, p_vrfy, NULL ) ); 3161*11fa71b9SJerome Forissier } 3162*11fa71b9SJerome Forissier 3163*11fa71b9SJerome Forissier /* 3164*11fa71b9SJerome Forissier * Verify the certificate validity (user-chosen profile, not restartable) 3165*11fa71b9SJerome Forissier */ 3166*11fa71b9SJerome Forissier int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, 3167*11fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 3168*11fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 3169*11fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 3170*11fa71b9SJerome Forissier const char *cn, uint32_t *flags, 3171*11fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 3172*11fa71b9SJerome Forissier void *p_vrfy ) 3173*11fa71b9SJerome Forissier { 3174*11fa71b9SJerome Forissier return( x509_crt_verify_restartable_ca_cb( crt, trust_ca, ca_crl, 3175*11fa71b9SJerome Forissier NULL, NULL, 3176*11fa71b9SJerome Forissier profile, cn, flags, 3177*11fa71b9SJerome Forissier f_vrfy, p_vrfy, NULL ) ); 3178*11fa71b9SJerome Forissier } 3179*11fa71b9SJerome Forissier 3180*11fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 3181*11fa71b9SJerome Forissier /* 3182*11fa71b9SJerome Forissier * Verify the certificate validity (user-chosen profile, CA callback, 3183*11fa71b9SJerome Forissier * not restartable). 3184*11fa71b9SJerome Forissier */ 3185*11fa71b9SJerome Forissier int mbedtls_x509_crt_verify_with_ca_cb( mbedtls_x509_crt *crt, 3186*11fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 3187*11fa71b9SJerome Forissier void *p_ca_cb, 3188*11fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 3189*11fa71b9SJerome Forissier const char *cn, uint32_t *flags, 3190*11fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 3191*11fa71b9SJerome Forissier void *p_vrfy ) 3192*11fa71b9SJerome Forissier { 3193*11fa71b9SJerome Forissier return( x509_crt_verify_restartable_ca_cb( crt, NULL, NULL, 3194*11fa71b9SJerome Forissier f_ca_cb, p_ca_cb, 3195*11fa71b9SJerome Forissier profile, cn, flags, 3196*11fa71b9SJerome Forissier f_vrfy, p_vrfy, NULL ) ); 3197*11fa71b9SJerome Forissier } 3198*11fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 3199*11fa71b9SJerome Forissier 3200*11fa71b9SJerome Forissier int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, 3201*11fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 3202*11fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 3203*11fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 3204*11fa71b9SJerome Forissier const char *cn, uint32_t *flags, 3205*11fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 3206*11fa71b9SJerome Forissier void *p_vrfy, 3207*11fa71b9SJerome Forissier mbedtls_x509_crt_restart_ctx *rs_ctx ) 3208*11fa71b9SJerome Forissier { 3209*11fa71b9SJerome Forissier return( x509_crt_verify_restartable_ca_cb( crt, trust_ca, ca_crl, 3210*11fa71b9SJerome Forissier NULL, NULL, 3211*11fa71b9SJerome Forissier profile, cn, flags, 3212*11fa71b9SJerome Forissier f_vrfy, p_vrfy, rs_ctx ) ); 3213*11fa71b9SJerome Forissier } 3214*11fa71b9SJerome Forissier 3215*11fa71b9SJerome Forissier 3216817466cbSJens Wiklander /* 3217817466cbSJens Wiklander * Initialize a certificate chain 3218817466cbSJens Wiklander */ 3219817466cbSJens Wiklander void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ) 3220817466cbSJens Wiklander { 3221817466cbSJens Wiklander memset( crt, 0, sizeof(mbedtls_x509_crt) ); 3222817466cbSJens Wiklander } 3223817466cbSJens Wiklander 3224817466cbSJens Wiklander /* 3225817466cbSJens Wiklander * Unallocate all certificate data 3226817466cbSJens Wiklander */ 3227817466cbSJens Wiklander void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) 3228817466cbSJens Wiklander { 3229817466cbSJens Wiklander mbedtls_x509_crt *cert_cur = crt; 3230817466cbSJens Wiklander mbedtls_x509_crt *cert_prv; 3231817466cbSJens Wiklander mbedtls_x509_name *name_cur; 3232817466cbSJens Wiklander mbedtls_x509_name *name_prv; 3233817466cbSJens Wiklander mbedtls_x509_sequence *seq_cur; 3234817466cbSJens Wiklander mbedtls_x509_sequence *seq_prv; 3235817466cbSJens Wiklander 3236817466cbSJens Wiklander if( crt == NULL ) 3237817466cbSJens Wiklander return; 3238817466cbSJens Wiklander 3239817466cbSJens Wiklander do 3240817466cbSJens Wiklander { 3241817466cbSJens Wiklander mbedtls_pk_free( &cert_cur->pk ); 3242817466cbSJens Wiklander 3243817466cbSJens Wiklander #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) 3244817466cbSJens Wiklander mbedtls_free( cert_cur->sig_opts ); 3245817466cbSJens Wiklander #endif 3246817466cbSJens Wiklander 3247817466cbSJens Wiklander name_cur = cert_cur->issuer.next; 3248817466cbSJens Wiklander while( name_cur != NULL ) 3249817466cbSJens Wiklander { 3250817466cbSJens Wiklander name_prv = name_cur; 3251817466cbSJens Wiklander name_cur = name_cur->next; 32523d3b0591SJens Wiklander mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); 3253817466cbSJens Wiklander mbedtls_free( name_prv ); 3254817466cbSJens Wiklander } 3255817466cbSJens Wiklander 3256817466cbSJens Wiklander name_cur = cert_cur->subject.next; 3257817466cbSJens Wiklander while( name_cur != NULL ) 3258817466cbSJens Wiklander { 3259817466cbSJens Wiklander name_prv = name_cur; 3260817466cbSJens Wiklander name_cur = name_cur->next; 32613d3b0591SJens Wiklander mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); 3262817466cbSJens Wiklander mbedtls_free( name_prv ); 3263817466cbSJens Wiklander } 3264817466cbSJens Wiklander 3265817466cbSJens Wiklander seq_cur = cert_cur->ext_key_usage.next; 3266817466cbSJens Wiklander while( seq_cur != NULL ) 3267817466cbSJens Wiklander { 3268817466cbSJens Wiklander seq_prv = seq_cur; 3269817466cbSJens Wiklander seq_cur = seq_cur->next; 32703d3b0591SJens Wiklander mbedtls_platform_zeroize( seq_prv, 32713d3b0591SJens Wiklander sizeof( mbedtls_x509_sequence ) ); 3272817466cbSJens Wiklander mbedtls_free( seq_prv ); 3273817466cbSJens Wiklander } 3274817466cbSJens Wiklander 3275817466cbSJens Wiklander seq_cur = cert_cur->subject_alt_names.next; 3276817466cbSJens Wiklander while( seq_cur != NULL ) 3277817466cbSJens Wiklander { 3278817466cbSJens Wiklander seq_prv = seq_cur; 3279817466cbSJens Wiklander seq_cur = seq_cur->next; 32803d3b0591SJens Wiklander mbedtls_platform_zeroize( seq_prv, 32813d3b0591SJens Wiklander sizeof( mbedtls_x509_sequence ) ); 3282817466cbSJens Wiklander mbedtls_free( seq_prv ); 3283817466cbSJens Wiklander } 3284817466cbSJens Wiklander 3285*11fa71b9SJerome Forissier seq_cur = cert_cur->certificate_policies.next; 3286*11fa71b9SJerome Forissier while( seq_cur != NULL ) 3287*11fa71b9SJerome Forissier { 3288*11fa71b9SJerome Forissier seq_prv = seq_cur; 3289*11fa71b9SJerome Forissier seq_cur = seq_cur->next; 3290*11fa71b9SJerome Forissier mbedtls_platform_zeroize( seq_prv, 3291*11fa71b9SJerome Forissier sizeof( mbedtls_x509_sequence ) ); 3292*11fa71b9SJerome Forissier mbedtls_free( seq_prv ); 3293*11fa71b9SJerome Forissier } 3294*11fa71b9SJerome Forissier 3295*11fa71b9SJerome Forissier if( cert_cur->raw.p != NULL && cert_cur->own_buffer ) 3296817466cbSJens Wiklander { 32973d3b0591SJens Wiklander mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len ); 3298817466cbSJens Wiklander mbedtls_free( cert_cur->raw.p ); 3299817466cbSJens Wiklander } 3300817466cbSJens Wiklander 3301817466cbSJens Wiklander cert_cur = cert_cur->next; 3302817466cbSJens Wiklander } 3303817466cbSJens Wiklander while( cert_cur != NULL ); 3304817466cbSJens Wiklander 3305817466cbSJens Wiklander cert_cur = crt; 3306817466cbSJens Wiklander do 3307817466cbSJens Wiklander { 3308817466cbSJens Wiklander cert_prv = cert_cur; 3309817466cbSJens Wiklander cert_cur = cert_cur->next; 3310817466cbSJens Wiklander 33113d3b0591SJens Wiklander mbedtls_platform_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) ); 3312817466cbSJens Wiklander if( cert_prv != crt ) 3313817466cbSJens Wiklander mbedtls_free( cert_prv ); 3314817466cbSJens Wiklander } 3315817466cbSJens Wiklander while( cert_cur != NULL ); 3316817466cbSJens Wiklander } 3317817466cbSJens Wiklander 33183d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 33193d3b0591SJens Wiklander /* 33203d3b0591SJens Wiklander * Initialize a restart context 33213d3b0591SJens Wiklander */ 33223d3b0591SJens Wiklander void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx ) 33233d3b0591SJens Wiklander { 33243d3b0591SJens Wiklander mbedtls_pk_restart_init( &ctx->pk ); 33253d3b0591SJens Wiklander 33263d3b0591SJens Wiklander ctx->parent = NULL; 33273d3b0591SJens Wiklander ctx->fallback_parent = NULL; 33283d3b0591SJens Wiklander ctx->fallback_signature_is_good = 0; 33293d3b0591SJens Wiklander 33303d3b0591SJens Wiklander ctx->parent_is_trusted = -1; 33313d3b0591SJens Wiklander 33323d3b0591SJens Wiklander ctx->in_progress = x509_crt_rs_none; 33333d3b0591SJens Wiklander ctx->self_cnt = 0; 33343d3b0591SJens Wiklander x509_crt_verify_chain_reset( &ctx->ver_chain ); 33353d3b0591SJens Wiklander } 33363d3b0591SJens Wiklander 33373d3b0591SJens Wiklander /* 33383d3b0591SJens Wiklander * Free the components of a restart context 33393d3b0591SJens Wiklander */ 33403d3b0591SJens Wiklander void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx ) 33413d3b0591SJens Wiklander { 33423d3b0591SJens Wiklander if( ctx == NULL ) 33433d3b0591SJens Wiklander return; 33443d3b0591SJens Wiklander 33453d3b0591SJens Wiklander mbedtls_pk_restart_free( &ctx->pk ); 33463d3b0591SJens Wiklander mbedtls_x509_crt_restart_init( ctx ); 33473d3b0591SJens Wiklander } 33483d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ 33493d3b0591SJens Wiklander 3350817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRT_PARSE_C */ 3351