1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * X.509 certificate parsing and verification 3817466cbSJens Wiklander * 4*7901324dSJerome Forissier * Copyright The Mbed TLS Contributors 5*7901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 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 /* 20817466cbSJens Wiklander * The ITU-T X.509 standard defines a certificate format for PKI. 21817466cbSJens Wiklander * 22817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) 23817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) 24817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) 25817466cbSJens Wiklander * 26817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf 27817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf 283d3b0591SJens Wiklander * 293d3b0591SJens Wiklander * [SIRO] https://cabforum.org/wp-content/uploads/Chunghwatelecom201503cabforumV4.pdf 30817466cbSJens Wiklander */ 31817466cbSJens Wiklander 32*7901324dSJerome Forissier #include "common.h" 33817466cbSJens Wiklander 34817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRT_PARSE_C) 35817466cbSJens Wiklander 36817466cbSJens Wiklander #include "mbedtls/x509_crt.h" 3711fa71b9SJerome Forissier #include "mbedtls/error.h" 38817466cbSJens Wiklander #include "mbedtls/oid.h" 393d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 40817466cbSJens Wiklander 41817466cbSJens Wiklander #include <string.h> 42817466cbSJens Wiklander 43817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 44817466cbSJens Wiklander #include "mbedtls/pem.h" 45817466cbSJens Wiklander #endif 46817466cbSJens Wiklander 4711fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 4811fa71b9SJerome Forissier #include "psa/crypto.h" 4911fa71b9SJerome Forissier #include "mbedtls/psa_util.h" 5011fa71b9SJerome Forissier #endif 5111fa71b9SJerome Forissier 52817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 53817466cbSJens Wiklander #include "mbedtls/platform.h" 54817466cbSJens Wiklander #else 553d3b0591SJens Wiklander #include <stdio.h> 56817466cbSJens Wiklander #include <stdlib.h> 57817466cbSJens Wiklander #define mbedtls_free free 58817466cbSJens Wiklander #define mbedtls_calloc calloc 59817466cbSJens Wiklander #define mbedtls_snprintf snprintf 60817466cbSJens Wiklander #endif 61817466cbSJens Wiklander 62817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 63817466cbSJens Wiklander #include "mbedtls/threading.h" 64817466cbSJens Wiklander #endif 65817466cbSJens Wiklander 66817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 67817466cbSJens Wiklander #include <windows.h> 68817466cbSJens Wiklander #else 69817466cbSJens Wiklander #include <time.h> 70817466cbSJens Wiklander #endif 71817466cbSJens Wiklander 72817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 73817466cbSJens Wiklander #include <stdio.h> 74817466cbSJens Wiklander #if !defined(_WIN32) || defined(EFIX64) || defined(EFI32) 75817466cbSJens Wiklander #include <sys/types.h> 76817466cbSJens Wiklander #include <sys/stat.h> 77817466cbSJens Wiklander #include <dirent.h> 78817466cbSJens Wiklander #endif /* !_WIN32 || EFIX64 || EFI32 */ 79817466cbSJens Wiklander #endif 80817466cbSJens Wiklander 813d3b0591SJens Wiklander /* 823d3b0591SJens Wiklander * Item in a verification chain: cert and flags for it 833d3b0591SJens Wiklander */ 843d3b0591SJens Wiklander typedef struct { 853d3b0591SJens Wiklander mbedtls_x509_crt *crt; 863d3b0591SJens Wiklander uint32_t flags; 873d3b0591SJens Wiklander } x509_crt_verify_chain_item; 883d3b0591SJens Wiklander 893d3b0591SJens Wiklander /* 903d3b0591SJens Wiklander * Max size of verification chain: end-entity + intermediates + trusted root 913d3b0591SJens Wiklander */ 923d3b0591SJens Wiklander #define X509_MAX_VERIFY_CHAIN_SIZE ( MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2 ) 93817466cbSJens Wiklander 94*7901324dSJerome Forissier /* Default profile. Do not remove items unless there are serious security 95*7901324dSJerome Forissier * concerns. */ 96817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default = 97817466cbSJens Wiklander { 98817466cbSJens Wiklander #if defined(MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES) 99817466cbSJens Wiklander /* Allow SHA-1 (weak, but still safe in controlled environments) */ 100817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | 101817466cbSJens Wiklander #endif 102817466cbSJens Wiklander /* Only SHA-2 hashes */ 103817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | 104817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | 105817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | 106817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), 107817466cbSJens Wiklander 0xFFFFFFF, /* Any PK alg */ 108817466cbSJens Wiklander 0xFFFFFFF, /* Any curve */ 109817466cbSJens Wiklander 2048, 110817466cbSJens Wiklander }; 111817466cbSJens Wiklander 112817466cbSJens Wiklander /* 113817466cbSJens Wiklander * Next-default profile 114817466cbSJens Wiklander */ 115817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next = 116817466cbSJens Wiklander { 117817466cbSJens Wiklander /* Hashes from SHA-256 and above */ 118817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | 119817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | 120817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), 121817466cbSJens Wiklander 0xFFFFFFF, /* Any PK alg */ 122817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 123817466cbSJens Wiklander /* Curves at or above 128-bit security level */ 124817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | 125817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ) | 126817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP521R1 ) | 127817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP256R1 ) | 128817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP384R1 ) | 129817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP512R1 ) | 130817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256K1 ), 131817466cbSJens Wiklander #else 132817466cbSJens Wiklander 0, 133817466cbSJens Wiklander #endif 134817466cbSJens Wiklander 2048, 135817466cbSJens Wiklander }; 136817466cbSJens Wiklander 137817466cbSJens Wiklander /* 138817466cbSJens Wiklander * NSA Suite B Profile 139817466cbSJens Wiklander */ 140817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb = 141817466cbSJens Wiklander { 142817466cbSJens Wiklander /* Only SHA-256 and 384 */ 143817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | 144817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), 145817466cbSJens Wiklander /* Only ECDSA */ 1463d3b0591SJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ) | 1473d3b0591SJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECKEY ), 148817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 149817466cbSJens Wiklander /* Only NIST P-256 and P-384 */ 150817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | 151817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ), 152817466cbSJens Wiklander #else 153817466cbSJens Wiklander 0, 154817466cbSJens Wiklander #endif 155817466cbSJens Wiklander 0, 156817466cbSJens Wiklander }; 157817466cbSJens Wiklander 158817466cbSJens Wiklander /* 159817466cbSJens Wiklander * Check md_alg against profile 1603d3b0591SJens Wiklander * Return 0 if md_alg is acceptable for this profile, -1 otherwise 161817466cbSJens Wiklander */ 162817466cbSJens Wiklander static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile, 163817466cbSJens Wiklander mbedtls_md_type_t md_alg ) 164817466cbSJens Wiklander { 1653d3b0591SJens Wiklander if( md_alg == MBEDTLS_MD_NONE ) 1663d3b0591SJens Wiklander return( -1 ); 1673d3b0591SJens Wiklander 168817466cbSJens Wiklander if( ( profile->allowed_mds & MBEDTLS_X509_ID_FLAG( md_alg ) ) != 0 ) 169817466cbSJens Wiklander return( 0 ); 170817466cbSJens Wiklander 171817466cbSJens Wiklander return( -1 ); 172817466cbSJens Wiklander } 173817466cbSJens Wiklander 174817466cbSJens Wiklander /* 175817466cbSJens Wiklander * Check pk_alg against profile 1763d3b0591SJens Wiklander * Return 0 if pk_alg is acceptable for this profile, -1 otherwise 177817466cbSJens Wiklander */ 178817466cbSJens Wiklander static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile, 179817466cbSJens Wiklander mbedtls_pk_type_t pk_alg ) 180817466cbSJens Wiklander { 1813d3b0591SJens Wiklander if( pk_alg == MBEDTLS_PK_NONE ) 1823d3b0591SJens Wiklander return( -1 ); 1833d3b0591SJens Wiklander 184817466cbSJens Wiklander if( ( profile->allowed_pks & MBEDTLS_X509_ID_FLAG( pk_alg ) ) != 0 ) 185817466cbSJens Wiklander return( 0 ); 186817466cbSJens Wiklander 187817466cbSJens Wiklander return( -1 ); 188817466cbSJens Wiklander } 189817466cbSJens Wiklander 190817466cbSJens Wiklander /* 191817466cbSJens Wiklander * Check key against profile 1923d3b0591SJens Wiklander * Return 0 if pk is acceptable for this profile, -1 otherwise 193817466cbSJens Wiklander */ 194817466cbSJens Wiklander static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, 195817466cbSJens Wiklander const mbedtls_pk_context *pk ) 196817466cbSJens Wiklander { 1973d3b0591SJens Wiklander const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type( pk ); 1983d3b0591SJens Wiklander 199817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 200817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS ) 201817466cbSJens Wiklander { 202817466cbSJens Wiklander if( mbedtls_pk_get_bitlen( pk ) >= profile->rsa_min_bitlen ) 203817466cbSJens Wiklander return( 0 ); 204817466cbSJens Wiklander 205817466cbSJens Wiklander return( -1 ); 206817466cbSJens Wiklander } 207817466cbSJens Wiklander #endif 208817466cbSJens Wiklander 209817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 210817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_ECDSA || 211817466cbSJens Wiklander pk_alg == MBEDTLS_PK_ECKEY || 212817466cbSJens Wiklander pk_alg == MBEDTLS_PK_ECKEY_DH ) 213817466cbSJens Wiklander { 2143d3b0591SJens Wiklander const mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id; 2153d3b0591SJens Wiklander 2163d3b0591SJens Wiklander if( gid == MBEDTLS_ECP_DP_NONE ) 2173d3b0591SJens Wiklander return( -1 ); 218817466cbSJens Wiklander 219817466cbSJens Wiklander if( ( profile->allowed_curves & MBEDTLS_X509_ID_FLAG( gid ) ) != 0 ) 220817466cbSJens Wiklander return( 0 ); 221817466cbSJens Wiklander 222817466cbSJens Wiklander return( -1 ); 223817466cbSJens Wiklander } 224817466cbSJens Wiklander #endif 225817466cbSJens Wiklander 226817466cbSJens Wiklander return( -1 ); 227817466cbSJens Wiklander } 228817466cbSJens Wiklander 229817466cbSJens Wiklander /* 2303d3b0591SJens Wiklander * Like memcmp, but case-insensitive and always returns -1 if different 2313d3b0591SJens Wiklander */ 2323d3b0591SJens Wiklander static int x509_memcasecmp( const void *s1, const void *s2, size_t len ) 2333d3b0591SJens Wiklander { 2343d3b0591SJens Wiklander size_t i; 2353d3b0591SJens Wiklander unsigned char diff; 2363d3b0591SJens Wiklander const unsigned char *n1 = s1, *n2 = s2; 2373d3b0591SJens Wiklander 2383d3b0591SJens Wiklander for( i = 0; i < len; i++ ) 2393d3b0591SJens Wiklander { 2403d3b0591SJens Wiklander diff = n1[i] ^ n2[i]; 2413d3b0591SJens Wiklander 2423d3b0591SJens Wiklander if( diff == 0 ) 2433d3b0591SJens Wiklander continue; 2443d3b0591SJens Wiklander 2453d3b0591SJens Wiklander if( diff == 32 && 2463d3b0591SJens Wiklander ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || 2473d3b0591SJens Wiklander ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) 2483d3b0591SJens Wiklander { 2493d3b0591SJens Wiklander continue; 2503d3b0591SJens Wiklander } 2513d3b0591SJens Wiklander 2523d3b0591SJens Wiklander return( -1 ); 2533d3b0591SJens Wiklander } 2543d3b0591SJens Wiklander 2553d3b0591SJens Wiklander return( 0 ); 2563d3b0591SJens Wiklander } 2573d3b0591SJens Wiklander 2583d3b0591SJens Wiklander /* 2593d3b0591SJens Wiklander * Return 0 if name matches wildcard, -1 otherwise 2603d3b0591SJens Wiklander */ 2613d3b0591SJens Wiklander static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name ) 2623d3b0591SJens Wiklander { 2633d3b0591SJens Wiklander size_t i; 2643d3b0591SJens Wiklander size_t cn_idx = 0, cn_len = strlen( cn ); 2653d3b0591SJens Wiklander 2663d3b0591SJens Wiklander /* We can't have a match if there is no wildcard to match */ 2673d3b0591SJens Wiklander if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) 2683d3b0591SJens Wiklander return( -1 ); 2693d3b0591SJens Wiklander 2703d3b0591SJens Wiklander for( i = 0; i < cn_len; ++i ) 2713d3b0591SJens Wiklander { 2723d3b0591SJens Wiklander if( cn[i] == '.' ) 2733d3b0591SJens Wiklander { 2743d3b0591SJens Wiklander cn_idx = i; 2753d3b0591SJens Wiklander break; 2763d3b0591SJens Wiklander } 2773d3b0591SJens Wiklander } 2783d3b0591SJens Wiklander 2793d3b0591SJens Wiklander if( cn_idx == 0 ) 2803d3b0591SJens Wiklander return( -1 ); 2813d3b0591SJens Wiklander 2823d3b0591SJens Wiklander if( cn_len - cn_idx == name->len - 1 && 2833d3b0591SJens Wiklander x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) 2843d3b0591SJens Wiklander { 2853d3b0591SJens Wiklander return( 0 ); 2863d3b0591SJens Wiklander } 2873d3b0591SJens Wiklander 2883d3b0591SJens Wiklander return( -1 ); 2893d3b0591SJens Wiklander } 2903d3b0591SJens Wiklander 2913d3b0591SJens Wiklander /* 2923d3b0591SJens Wiklander * Compare two X.509 strings, case-insensitive, and allowing for some encoding 2933d3b0591SJens Wiklander * variations (but not all). 2943d3b0591SJens Wiklander * 2953d3b0591SJens Wiklander * Return 0 if equal, -1 otherwise. 2963d3b0591SJens Wiklander */ 2973d3b0591SJens Wiklander static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ) 2983d3b0591SJens Wiklander { 2993d3b0591SJens Wiklander if( a->tag == b->tag && 3003d3b0591SJens Wiklander a->len == b->len && 3013d3b0591SJens Wiklander memcmp( a->p, b->p, b->len ) == 0 ) 3023d3b0591SJens Wiklander { 3033d3b0591SJens Wiklander return( 0 ); 3043d3b0591SJens Wiklander } 3053d3b0591SJens Wiklander 3063d3b0591SJens Wiklander if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && 3073d3b0591SJens Wiklander ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && 3083d3b0591SJens Wiklander a->len == b->len && 3093d3b0591SJens Wiklander x509_memcasecmp( a->p, b->p, b->len ) == 0 ) 3103d3b0591SJens Wiklander { 3113d3b0591SJens Wiklander return( 0 ); 3123d3b0591SJens Wiklander } 3133d3b0591SJens Wiklander 3143d3b0591SJens Wiklander return( -1 ); 3153d3b0591SJens Wiklander } 3163d3b0591SJens Wiklander 3173d3b0591SJens Wiklander /* 3183d3b0591SJens Wiklander * Compare two X.509 Names (aka rdnSequence). 3193d3b0591SJens Wiklander * 3203d3b0591SJens Wiklander * See RFC 5280 section 7.1, though we don't implement the whole algorithm: 3213d3b0591SJens Wiklander * we sometimes return unequal when the full algorithm would return equal, 3223d3b0591SJens Wiklander * but never the other way. (In particular, we don't do Unicode normalisation 3233d3b0591SJens Wiklander * or space folding.) 3243d3b0591SJens Wiklander * 3253d3b0591SJens Wiklander * Return 0 if equal, -1 otherwise. 3263d3b0591SJens Wiklander */ 3273d3b0591SJens Wiklander static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ) 3283d3b0591SJens Wiklander { 3293d3b0591SJens Wiklander /* Avoid recursion, it might not be optimised by the compiler */ 3303d3b0591SJens Wiklander while( a != NULL || b != NULL ) 3313d3b0591SJens Wiklander { 3323d3b0591SJens Wiklander if( a == NULL || b == NULL ) 3333d3b0591SJens Wiklander return( -1 ); 3343d3b0591SJens Wiklander 3353d3b0591SJens Wiklander /* type */ 3363d3b0591SJens Wiklander if( a->oid.tag != b->oid.tag || 3373d3b0591SJens Wiklander a->oid.len != b->oid.len || 3383d3b0591SJens Wiklander memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) 3393d3b0591SJens Wiklander { 3403d3b0591SJens Wiklander return( -1 ); 3413d3b0591SJens Wiklander } 3423d3b0591SJens Wiklander 3433d3b0591SJens Wiklander /* value */ 3443d3b0591SJens Wiklander if( x509_string_cmp( &a->val, &b->val ) != 0 ) 3453d3b0591SJens Wiklander return( -1 ); 3463d3b0591SJens Wiklander 3473d3b0591SJens Wiklander /* structure of the list of sets */ 3483d3b0591SJens Wiklander if( a->next_merged != b->next_merged ) 3493d3b0591SJens Wiklander return( -1 ); 3503d3b0591SJens Wiklander 3513d3b0591SJens Wiklander a = a->next; 3523d3b0591SJens Wiklander b = b->next; 3533d3b0591SJens Wiklander } 3543d3b0591SJens Wiklander 3553d3b0591SJens Wiklander /* a == NULL == b */ 3563d3b0591SJens Wiklander return( 0 ); 3573d3b0591SJens Wiklander } 3583d3b0591SJens Wiklander 3593d3b0591SJens Wiklander /* 3603d3b0591SJens Wiklander * Reset (init or clear) a verify_chain 3613d3b0591SJens Wiklander */ 3623d3b0591SJens Wiklander static void x509_crt_verify_chain_reset( 3633d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain *ver_chain ) 3643d3b0591SJens Wiklander { 3653d3b0591SJens Wiklander size_t i; 3663d3b0591SJens Wiklander 3673d3b0591SJens Wiklander for( i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++ ) 3683d3b0591SJens Wiklander { 3693d3b0591SJens Wiklander ver_chain->items[i].crt = NULL; 3705b25c76aSJerome Forissier ver_chain->items[i].flags = (uint32_t) -1; 3713d3b0591SJens Wiklander } 3723d3b0591SJens Wiklander 3733d3b0591SJens Wiklander ver_chain->len = 0; 37411fa71b9SJerome Forissier 37511fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 37611fa71b9SJerome Forissier ver_chain->trust_ca_cb_result = NULL; 37711fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 3783d3b0591SJens Wiklander } 3793d3b0591SJens Wiklander 3803d3b0591SJens Wiklander /* 381817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 382817466cbSJens Wiklander */ 383817466cbSJens Wiklander static int x509_get_version( unsigned char **p, 384817466cbSJens Wiklander const unsigned char *end, 385817466cbSJens Wiklander int *ver ) 386817466cbSJens Wiklander { 38711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 388817466cbSJens Wiklander size_t len; 389817466cbSJens Wiklander 390817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 391817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) != 0 ) 392817466cbSJens Wiklander { 393817466cbSJens Wiklander if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 394817466cbSJens Wiklander { 395817466cbSJens Wiklander *ver = 0; 396817466cbSJens Wiklander return( 0 ); 397817466cbSJens Wiklander } 398817466cbSJens Wiklander 399*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT, ret ) ); 400817466cbSJens Wiklander } 401817466cbSJens Wiklander 402817466cbSJens Wiklander end = *p + len; 403817466cbSJens Wiklander 404817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) 405*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_VERSION, ret ) ); 406817466cbSJens Wiklander 407817466cbSJens Wiklander if( *p != end ) 408*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_VERSION, 409*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 410817466cbSJens Wiklander 411817466cbSJens Wiklander return( 0 ); 412817466cbSJens Wiklander } 413817466cbSJens Wiklander 414817466cbSJens Wiklander /* 415817466cbSJens Wiklander * Validity ::= SEQUENCE { 416817466cbSJens Wiklander * notBefore Time, 417817466cbSJens Wiklander * notAfter Time } 418817466cbSJens Wiklander */ 419817466cbSJens Wiklander static int x509_get_dates( unsigned char **p, 420817466cbSJens Wiklander const unsigned char *end, 421817466cbSJens Wiklander mbedtls_x509_time *from, 422817466cbSJens Wiklander mbedtls_x509_time *to ) 423817466cbSJens Wiklander { 42411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 425817466cbSJens Wiklander size_t len; 426817466cbSJens Wiklander 427817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 428817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 429*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_DATE, ret ) ); 430817466cbSJens Wiklander 431817466cbSJens Wiklander end = *p + len; 432817466cbSJens Wiklander 433817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_time( p, end, from ) ) != 0 ) 434817466cbSJens Wiklander return( ret ); 435817466cbSJens Wiklander 436817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_time( p, end, to ) ) != 0 ) 437817466cbSJens Wiklander return( ret ); 438817466cbSJens Wiklander 439817466cbSJens Wiklander if( *p != end ) 440*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_DATE, 441*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 442817466cbSJens Wiklander 443817466cbSJens Wiklander return( 0 ); 444817466cbSJens Wiklander } 445817466cbSJens Wiklander 446817466cbSJens Wiklander /* 447817466cbSJens Wiklander * X.509 v2/v3 unique identifier (not parsed) 448817466cbSJens Wiklander */ 449817466cbSJens Wiklander static int x509_get_uid( unsigned char **p, 450817466cbSJens Wiklander const unsigned char *end, 451817466cbSJens Wiklander mbedtls_x509_buf *uid, int n ) 452817466cbSJens Wiklander { 45311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 454817466cbSJens Wiklander 455817466cbSJens Wiklander if( *p == end ) 456817466cbSJens Wiklander return( 0 ); 457817466cbSJens Wiklander 458817466cbSJens Wiklander uid->tag = **p; 459817466cbSJens Wiklander 460817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &uid->len, 461817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | n ) ) != 0 ) 462817466cbSJens Wiklander { 463817466cbSJens Wiklander if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 464817466cbSJens Wiklander return( 0 ); 465817466cbSJens Wiklander 466*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT, ret ) ); 467817466cbSJens Wiklander } 468817466cbSJens Wiklander 469817466cbSJens Wiklander uid->p = *p; 470817466cbSJens Wiklander *p += uid->len; 471817466cbSJens Wiklander 472817466cbSJens Wiklander return( 0 ); 473817466cbSJens Wiklander } 474817466cbSJens Wiklander 475817466cbSJens Wiklander static int x509_get_basic_constraints( unsigned char **p, 476817466cbSJens Wiklander const unsigned char *end, 477817466cbSJens Wiklander int *ca_istrue, 478817466cbSJens Wiklander int *max_pathlen ) 479817466cbSJens Wiklander { 48011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 481817466cbSJens Wiklander size_t len; 482817466cbSJens Wiklander 483817466cbSJens Wiklander /* 484817466cbSJens Wiklander * BasicConstraints ::= SEQUENCE { 485817466cbSJens Wiklander * cA BOOLEAN DEFAULT FALSE, 486817466cbSJens Wiklander * pathLenConstraint INTEGER (0..MAX) OPTIONAL } 487817466cbSJens Wiklander */ 488817466cbSJens Wiklander *ca_istrue = 0; /* DEFAULT FALSE */ 489817466cbSJens Wiklander *max_pathlen = 0; /* endless */ 490817466cbSJens Wiklander 491817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 492817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 493*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 494817466cbSJens Wiklander 495817466cbSJens Wiklander if( *p == end ) 496817466cbSJens Wiklander return( 0 ); 497817466cbSJens Wiklander 498817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bool( p, end, ca_istrue ) ) != 0 ) 499817466cbSJens Wiklander { 500817466cbSJens Wiklander if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 501817466cbSJens Wiklander ret = mbedtls_asn1_get_int( p, end, ca_istrue ); 502817466cbSJens Wiklander 503817466cbSJens Wiklander if( ret != 0 ) 504*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 505817466cbSJens Wiklander 506817466cbSJens Wiklander if( *ca_istrue != 0 ) 507817466cbSJens Wiklander *ca_istrue = 1; 508817466cbSJens Wiklander } 509817466cbSJens Wiklander 510817466cbSJens Wiklander if( *p == end ) 511817466cbSJens Wiklander return( 0 ); 512817466cbSJens Wiklander 513817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 ) 514*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 515817466cbSJens Wiklander 516817466cbSJens Wiklander if( *p != end ) 517*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 518*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 519*7901324dSJerome Forissier 520*7901324dSJerome Forissier /* Do not accept max_pathlen equal to INT_MAX to avoid a signed integer 521*7901324dSJerome Forissier * overflow, which is an undefined behavior. */ 522*7901324dSJerome Forissier if( *max_pathlen == INT_MAX ) 523*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 524*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_INVALID_LENGTH ) ); 525817466cbSJens Wiklander 526817466cbSJens Wiklander (*max_pathlen)++; 527817466cbSJens Wiklander 528817466cbSJens Wiklander return( 0 ); 529817466cbSJens Wiklander } 530817466cbSJens Wiklander 531817466cbSJens Wiklander static int x509_get_ns_cert_type( unsigned char **p, 532817466cbSJens Wiklander const unsigned char *end, 533817466cbSJens Wiklander unsigned char *ns_cert_type) 534817466cbSJens Wiklander { 53511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 536817466cbSJens Wiklander mbedtls_x509_bitstring bs = { 0, 0, NULL }; 537817466cbSJens Wiklander 538817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) 539*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 540817466cbSJens Wiklander 541817466cbSJens Wiklander if( bs.len != 1 ) 542*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 543*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_INVALID_LENGTH ) ); 544817466cbSJens Wiklander 545817466cbSJens Wiklander /* Get actual bitstring */ 546817466cbSJens Wiklander *ns_cert_type = *bs.p; 547817466cbSJens Wiklander return( 0 ); 548817466cbSJens Wiklander } 549817466cbSJens Wiklander 550817466cbSJens Wiklander static int x509_get_key_usage( unsigned char **p, 551817466cbSJens Wiklander const unsigned char *end, 552817466cbSJens Wiklander unsigned int *key_usage) 553817466cbSJens Wiklander { 55411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 555817466cbSJens Wiklander size_t i; 556817466cbSJens Wiklander mbedtls_x509_bitstring bs = { 0, 0, NULL }; 557817466cbSJens Wiklander 558817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) 559*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 560817466cbSJens Wiklander 561817466cbSJens Wiklander if( bs.len < 1 ) 562*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 563*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_INVALID_LENGTH ) ); 564817466cbSJens Wiklander 565817466cbSJens Wiklander /* Get actual bitstring */ 566817466cbSJens Wiklander *key_usage = 0; 567817466cbSJens Wiklander for( i = 0; i < bs.len && i < sizeof( unsigned int ); i++ ) 568817466cbSJens Wiklander { 569817466cbSJens Wiklander *key_usage |= (unsigned int) bs.p[i] << (8*i); 570817466cbSJens Wiklander } 571817466cbSJens Wiklander 572817466cbSJens Wiklander return( 0 ); 573817466cbSJens Wiklander } 574817466cbSJens Wiklander 575817466cbSJens Wiklander /* 576817466cbSJens Wiklander * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId 577817466cbSJens Wiklander * 578817466cbSJens Wiklander * KeyPurposeId ::= OBJECT IDENTIFIER 579817466cbSJens Wiklander */ 580817466cbSJens Wiklander static int x509_get_ext_key_usage( unsigned char **p, 581817466cbSJens Wiklander const unsigned char *end, 582817466cbSJens Wiklander mbedtls_x509_sequence *ext_key_usage) 583817466cbSJens Wiklander { 58411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 585817466cbSJens Wiklander 586817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, MBEDTLS_ASN1_OID ) ) != 0 ) 587*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 588817466cbSJens Wiklander 589817466cbSJens Wiklander /* Sequence length must be >= 1 */ 590817466cbSJens Wiklander if( ext_key_usage->buf.p == NULL ) 591*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 592*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_INVALID_LENGTH ) ); 593817466cbSJens Wiklander 594817466cbSJens Wiklander return( 0 ); 595817466cbSJens Wiklander } 596817466cbSJens Wiklander 597817466cbSJens Wiklander /* 598817466cbSJens Wiklander * SubjectAltName ::= GeneralNames 599817466cbSJens Wiklander * 600817466cbSJens Wiklander * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 601817466cbSJens Wiklander * 602817466cbSJens Wiklander * GeneralName ::= CHOICE { 603817466cbSJens Wiklander * otherName [0] OtherName, 604817466cbSJens Wiklander * rfc822Name [1] IA5String, 605817466cbSJens Wiklander * dNSName [2] IA5String, 606817466cbSJens Wiklander * x400Address [3] ORAddress, 607817466cbSJens Wiklander * directoryName [4] Name, 608817466cbSJens Wiklander * ediPartyName [5] EDIPartyName, 609817466cbSJens Wiklander * uniformResourceIdentifier [6] IA5String, 610817466cbSJens Wiklander * iPAddress [7] OCTET STRING, 611817466cbSJens Wiklander * registeredID [8] OBJECT IDENTIFIER } 612817466cbSJens Wiklander * 613817466cbSJens Wiklander * OtherName ::= SEQUENCE { 614817466cbSJens Wiklander * type-id OBJECT IDENTIFIER, 615817466cbSJens Wiklander * value [0] EXPLICIT ANY DEFINED BY type-id } 616817466cbSJens Wiklander * 617817466cbSJens Wiklander * EDIPartyName ::= SEQUENCE { 618817466cbSJens Wiklander * nameAssigner [0] DirectoryString OPTIONAL, 619817466cbSJens Wiklander * partyName [1] DirectoryString } 620817466cbSJens Wiklander * 62111fa71b9SJerome Forissier * NOTE: we list all types, but only use dNSName and otherName 62211fa71b9SJerome Forissier * of type HwModuleName, as defined in RFC 4108, at this point. 623817466cbSJens Wiklander */ 624817466cbSJens Wiklander static int x509_get_subject_alt_name( unsigned char **p, 625817466cbSJens Wiklander const unsigned char *end, 626817466cbSJens Wiklander mbedtls_x509_sequence *subject_alt_name ) 627817466cbSJens Wiklander { 62811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 629817466cbSJens Wiklander size_t len, tag_len; 630817466cbSJens Wiklander mbedtls_asn1_buf *buf; 631817466cbSJens Wiklander unsigned char tag; 632817466cbSJens Wiklander mbedtls_asn1_sequence *cur = subject_alt_name; 633817466cbSJens Wiklander 634817466cbSJens Wiklander /* Get main sequence tag */ 635817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 636817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 637*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 638817466cbSJens Wiklander 639817466cbSJens Wiklander if( *p + len != end ) 640*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 641*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 642817466cbSJens Wiklander 643817466cbSJens Wiklander while( *p < end ) 644817466cbSJens Wiklander { 64511fa71b9SJerome Forissier mbedtls_x509_subject_alternative_name dummy_san_buf; 64611fa71b9SJerome Forissier memset( &dummy_san_buf, 0, sizeof( dummy_san_buf ) ); 64711fa71b9SJerome Forissier 648817466cbSJens Wiklander tag = **p; 649817466cbSJens Wiklander (*p)++; 650817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_len( p, end, &tag_len ) ) != 0 ) 651*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 652817466cbSJens Wiklander 6533d3b0591SJens Wiklander if( ( tag & MBEDTLS_ASN1_TAG_CLASS_MASK ) != 6543d3b0591SJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC ) 6553d3b0591SJens Wiklander { 656*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 657*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ); 6583d3b0591SJens Wiklander } 659817466cbSJens Wiklander 66011fa71b9SJerome Forissier /* 661*7901324dSJerome Forissier * Check that the SAN is structured correctly. 66211fa71b9SJerome Forissier */ 66311fa71b9SJerome Forissier ret = mbedtls_x509_parse_subject_alt_name( &(cur->buf), &dummy_san_buf ); 66411fa71b9SJerome Forissier /* 66511fa71b9SJerome Forissier * In case the extension is malformed, return an error, 66611fa71b9SJerome Forissier * and clear the allocated sequences. 66711fa71b9SJerome Forissier */ 66811fa71b9SJerome Forissier if( ret != 0 && ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) 669817466cbSJens Wiklander { 67011fa71b9SJerome Forissier mbedtls_x509_sequence *seq_cur = subject_alt_name->next; 67111fa71b9SJerome Forissier mbedtls_x509_sequence *seq_prv; 67211fa71b9SJerome Forissier while( seq_cur != NULL ) 67311fa71b9SJerome Forissier { 67411fa71b9SJerome Forissier seq_prv = seq_cur; 67511fa71b9SJerome Forissier seq_cur = seq_cur->next; 67611fa71b9SJerome Forissier mbedtls_platform_zeroize( seq_prv, 67711fa71b9SJerome Forissier sizeof( mbedtls_x509_sequence ) ); 67811fa71b9SJerome Forissier mbedtls_free( seq_prv ); 67911fa71b9SJerome Forissier } 68011fa71b9SJerome Forissier subject_alt_name->next = NULL; 68111fa71b9SJerome Forissier return( ret ); 682817466cbSJens Wiklander } 683817466cbSJens Wiklander 684817466cbSJens Wiklander /* Allocate and assign next pointer */ 685817466cbSJens Wiklander if( cur->buf.p != NULL ) 686817466cbSJens Wiklander { 687817466cbSJens Wiklander if( cur->next != NULL ) 688817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); 689817466cbSJens Wiklander 690817466cbSJens Wiklander cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); 691817466cbSJens Wiklander 692817466cbSJens Wiklander if( cur->next == NULL ) 693*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 694*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_ALLOC_FAILED ) ); 695817466cbSJens Wiklander 696817466cbSJens Wiklander cur = cur->next; 697817466cbSJens Wiklander } 698817466cbSJens Wiklander 699817466cbSJens Wiklander buf = &(cur->buf); 700817466cbSJens Wiklander buf->tag = tag; 701817466cbSJens Wiklander buf->p = *p; 702817466cbSJens Wiklander buf->len = tag_len; 703817466cbSJens Wiklander *p += buf->len; 704817466cbSJens Wiklander } 705817466cbSJens Wiklander 706817466cbSJens Wiklander /* Set final sequence entry's next pointer to NULL */ 707817466cbSJens Wiklander cur->next = NULL; 708817466cbSJens Wiklander 709817466cbSJens Wiklander if( *p != end ) 710*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 711*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 712817466cbSJens Wiklander 713817466cbSJens Wiklander return( 0 ); 714817466cbSJens Wiklander } 715817466cbSJens Wiklander 716817466cbSJens Wiklander /* 71711fa71b9SJerome Forissier * id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } 71811fa71b9SJerome Forissier * 71911fa71b9SJerome Forissier * anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 } 72011fa71b9SJerome Forissier * 72111fa71b9SJerome Forissier * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation 72211fa71b9SJerome Forissier * 72311fa71b9SJerome Forissier * PolicyInformation ::= SEQUENCE { 72411fa71b9SJerome Forissier * policyIdentifier CertPolicyId, 72511fa71b9SJerome Forissier * policyQualifiers SEQUENCE SIZE (1..MAX) OF 72611fa71b9SJerome Forissier * PolicyQualifierInfo OPTIONAL } 72711fa71b9SJerome Forissier * 72811fa71b9SJerome Forissier * CertPolicyId ::= OBJECT IDENTIFIER 72911fa71b9SJerome Forissier * 73011fa71b9SJerome Forissier * PolicyQualifierInfo ::= SEQUENCE { 73111fa71b9SJerome Forissier * policyQualifierId PolicyQualifierId, 73211fa71b9SJerome Forissier * qualifier ANY DEFINED BY policyQualifierId } 73311fa71b9SJerome Forissier * 73411fa71b9SJerome Forissier * -- policyQualifierIds for Internet policy qualifiers 73511fa71b9SJerome Forissier * 73611fa71b9SJerome Forissier * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } 73711fa71b9SJerome Forissier * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } 73811fa71b9SJerome Forissier * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } 73911fa71b9SJerome Forissier * 74011fa71b9SJerome Forissier * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) 74111fa71b9SJerome Forissier * 74211fa71b9SJerome Forissier * Qualifier ::= CHOICE { 74311fa71b9SJerome Forissier * cPSuri CPSuri, 74411fa71b9SJerome Forissier * userNotice UserNotice } 74511fa71b9SJerome Forissier * 74611fa71b9SJerome Forissier * CPSuri ::= IA5String 74711fa71b9SJerome Forissier * 74811fa71b9SJerome Forissier * UserNotice ::= SEQUENCE { 74911fa71b9SJerome Forissier * noticeRef NoticeReference OPTIONAL, 75011fa71b9SJerome Forissier * explicitText DisplayText OPTIONAL } 75111fa71b9SJerome Forissier * 75211fa71b9SJerome Forissier * NoticeReference ::= SEQUENCE { 75311fa71b9SJerome Forissier * organization DisplayText, 75411fa71b9SJerome Forissier * noticeNumbers SEQUENCE OF INTEGER } 75511fa71b9SJerome Forissier * 75611fa71b9SJerome Forissier * DisplayText ::= CHOICE { 75711fa71b9SJerome Forissier * ia5String IA5String (SIZE (1..200)), 75811fa71b9SJerome Forissier * visibleString VisibleString (SIZE (1..200)), 75911fa71b9SJerome Forissier * bmpString BMPString (SIZE (1..200)), 76011fa71b9SJerome Forissier * utf8String UTF8String (SIZE (1..200)) } 76111fa71b9SJerome Forissier * 76211fa71b9SJerome Forissier * NOTE: we only parse and use anyPolicy without qualifiers at this point 76311fa71b9SJerome Forissier * as defined in RFC 5280. 76411fa71b9SJerome Forissier */ 76511fa71b9SJerome Forissier static int x509_get_certificate_policies( unsigned char **p, 76611fa71b9SJerome Forissier const unsigned char *end, 76711fa71b9SJerome Forissier mbedtls_x509_sequence *certificate_policies ) 76811fa71b9SJerome Forissier { 76911fa71b9SJerome Forissier int ret, parse_ret = 0; 77011fa71b9SJerome Forissier size_t len; 77111fa71b9SJerome Forissier mbedtls_asn1_buf *buf; 77211fa71b9SJerome Forissier mbedtls_asn1_sequence *cur = certificate_policies; 77311fa71b9SJerome Forissier 77411fa71b9SJerome Forissier /* Get main sequence tag */ 77511fa71b9SJerome Forissier ret = mbedtls_asn1_get_tag( p, end, &len, 77611fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ); 77711fa71b9SJerome Forissier if( ret != 0 ) 778*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 77911fa71b9SJerome Forissier 78011fa71b9SJerome Forissier if( *p + len != end ) 781*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 782*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 78311fa71b9SJerome Forissier 78411fa71b9SJerome Forissier /* 78511fa71b9SJerome Forissier * Cannot be an empty sequence. 78611fa71b9SJerome Forissier */ 78711fa71b9SJerome Forissier if( len == 0 ) 788*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 789*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 79011fa71b9SJerome Forissier 79111fa71b9SJerome Forissier while( *p < end ) 79211fa71b9SJerome Forissier { 79311fa71b9SJerome Forissier mbedtls_x509_buf policy_oid; 79411fa71b9SJerome Forissier const unsigned char *policy_end; 79511fa71b9SJerome Forissier 79611fa71b9SJerome Forissier /* 79711fa71b9SJerome Forissier * Get the policy sequence 79811fa71b9SJerome Forissier */ 79911fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 80011fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 801*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 80211fa71b9SJerome Forissier 80311fa71b9SJerome Forissier policy_end = *p + len; 80411fa71b9SJerome Forissier 80511fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len, 80611fa71b9SJerome Forissier MBEDTLS_ASN1_OID ) ) != 0 ) 807*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 80811fa71b9SJerome Forissier 80911fa71b9SJerome Forissier policy_oid.tag = MBEDTLS_ASN1_OID; 81011fa71b9SJerome Forissier policy_oid.len = len; 81111fa71b9SJerome Forissier policy_oid.p = *p; 81211fa71b9SJerome Forissier 81311fa71b9SJerome Forissier /* 81411fa71b9SJerome Forissier * Only AnyPolicy is currently supported when enforcing policy. 81511fa71b9SJerome Forissier */ 81611fa71b9SJerome Forissier if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_POLICY, &policy_oid ) != 0 ) 81711fa71b9SJerome Forissier { 81811fa71b9SJerome Forissier /* 81911fa71b9SJerome Forissier * Set the parsing return code but continue parsing, in case this 82011fa71b9SJerome Forissier * extension is critical and MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION 82111fa71b9SJerome Forissier * is configured. 82211fa71b9SJerome Forissier */ 82311fa71b9SJerome Forissier parse_ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; 82411fa71b9SJerome Forissier } 82511fa71b9SJerome Forissier 82611fa71b9SJerome Forissier /* Allocate and assign next pointer */ 82711fa71b9SJerome Forissier if( cur->buf.p != NULL ) 82811fa71b9SJerome Forissier { 82911fa71b9SJerome Forissier if( cur->next != NULL ) 83011fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); 83111fa71b9SJerome Forissier 83211fa71b9SJerome Forissier cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); 83311fa71b9SJerome Forissier 83411fa71b9SJerome Forissier if( cur->next == NULL ) 835*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 836*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_ALLOC_FAILED ) ); 83711fa71b9SJerome Forissier 83811fa71b9SJerome Forissier cur = cur->next; 83911fa71b9SJerome Forissier } 84011fa71b9SJerome Forissier 84111fa71b9SJerome Forissier buf = &( cur->buf ); 84211fa71b9SJerome Forissier buf->tag = policy_oid.tag; 84311fa71b9SJerome Forissier buf->p = policy_oid.p; 84411fa71b9SJerome Forissier buf->len = policy_oid.len; 84511fa71b9SJerome Forissier 84611fa71b9SJerome Forissier *p += len; 84711fa71b9SJerome Forissier 84811fa71b9SJerome Forissier /* 84911fa71b9SJerome Forissier * If there is an optional qualifier, then *p < policy_end 85011fa71b9SJerome Forissier * Check the Qualifier len to verify it doesn't exceed policy_end. 85111fa71b9SJerome Forissier */ 85211fa71b9SJerome Forissier if( *p < policy_end ) 85311fa71b9SJerome Forissier { 85411fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len, 85511fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 856*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 85711fa71b9SJerome Forissier /* 85811fa71b9SJerome Forissier * Skip the optional policy qualifiers. 85911fa71b9SJerome Forissier */ 86011fa71b9SJerome Forissier *p += len; 86111fa71b9SJerome Forissier } 86211fa71b9SJerome Forissier 86311fa71b9SJerome Forissier if( *p != policy_end ) 864*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 865*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 86611fa71b9SJerome Forissier } 86711fa71b9SJerome Forissier 86811fa71b9SJerome Forissier /* Set final sequence entry's next pointer to NULL */ 86911fa71b9SJerome Forissier cur->next = NULL; 87011fa71b9SJerome Forissier 87111fa71b9SJerome Forissier if( *p != end ) 872*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 873*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 87411fa71b9SJerome Forissier 87511fa71b9SJerome Forissier return( parse_ret ); 87611fa71b9SJerome Forissier } 87711fa71b9SJerome Forissier 87811fa71b9SJerome Forissier /* 879817466cbSJens Wiklander * X.509 v3 extensions 880817466cbSJens Wiklander * 881817466cbSJens Wiklander */ 882817466cbSJens Wiklander static int x509_get_crt_ext( unsigned char **p, 883817466cbSJens Wiklander const unsigned char *end, 884*7901324dSJerome Forissier mbedtls_x509_crt *crt, 885*7901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 886*7901324dSJerome Forissier void *p_ctx ) 887817466cbSJens Wiklander { 88811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 889817466cbSJens Wiklander size_t len; 890*7901324dSJerome Forissier unsigned char *end_ext_data, *start_ext_octet, *end_ext_octet; 891817466cbSJens Wiklander 8925b25c76aSJerome Forissier if( *p == end ) 893817466cbSJens Wiklander return( 0 ); 894817466cbSJens Wiklander 8955b25c76aSJerome Forissier if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) 896817466cbSJens Wiklander return( ret ); 897817466cbSJens Wiklander 8985b25c76aSJerome Forissier end = crt->v3_ext.p + crt->v3_ext.len; 899817466cbSJens Wiklander while( *p < end ) 900817466cbSJens Wiklander { 901817466cbSJens Wiklander /* 902817466cbSJens Wiklander * Extension ::= SEQUENCE { 903817466cbSJens Wiklander * extnID OBJECT IDENTIFIER, 904817466cbSJens Wiklander * critical BOOLEAN DEFAULT FALSE, 905817466cbSJens Wiklander * extnValue OCTET STRING } 906817466cbSJens Wiklander */ 907817466cbSJens Wiklander mbedtls_x509_buf extn_oid = {0, 0, NULL}; 908817466cbSJens Wiklander int is_critical = 0; /* DEFAULT FALSE */ 909817466cbSJens Wiklander int ext_type = 0; 910817466cbSJens Wiklander 911817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 912817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 913*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 914817466cbSJens Wiklander 915817466cbSJens Wiklander end_ext_data = *p + len; 916817466cbSJens Wiklander 917817466cbSJens Wiklander /* Get extension ID */ 9183d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &extn_oid.len, 9193d3b0591SJens Wiklander MBEDTLS_ASN1_OID ) ) != 0 ) 920*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 921817466cbSJens Wiklander 9223d3b0591SJens Wiklander extn_oid.tag = MBEDTLS_ASN1_OID; 923817466cbSJens Wiklander extn_oid.p = *p; 924817466cbSJens Wiklander *p += extn_oid.len; 925817466cbSJens Wiklander 926817466cbSJens Wiklander /* Get optional critical */ 927817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 && 928817466cbSJens Wiklander ( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) 929*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 930817466cbSJens Wiklander 931817466cbSJens Wiklander /* Data should be octet string type */ 932817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, 933817466cbSJens Wiklander MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 934*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 935817466cbSJens Wiklander 936*7901324dSJerome Forissier start_ext_octet = *p; 937817466cbSJens Wiklander end_ext_octet = *p + len; 938817466cbSJens Wiklander 939817466cbSJens Wiklander if( end_ext_octet != end_ext_data ) 940*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 941*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 942817466cbSJens Wiklander 943817466cbSJens Wiklander /* 944817466cbSJens Wiklander * Detect supported extensions 945817466cbSJens Wiklander */ 946817466cbSJens Wiklander ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type ); 947817466cbSJens Wiklander 948817466cbSJens Wiklander if( ret != 0 ) 949817466cbSJens Wiklander { 950*7901324dSJerome Forissier /* Give the callback (if any) a chance to handle the extension */ 951*7901324dSJerome Forissier if( cb != NULL ) 952*7901324dSJerome Forissier { 953*7901324dSJerome Forissier ret = cb( p_ctx, crt, &extn_oid, is_critical, *p, end_ext_octet ); 954*7901324dSJerome Forissier if( ret != 0 && is_critical ) 955*7901324dSJerome Forissier return( ret ); 956*7901324dSJerome Forissier *p = end_ext_octet; 957*7901324dSJerome Forissier continue; 958*7901324dSJerome Forissier } 959*7901324dSJerome Forissier 960817466cbSJens Wiklander /* No parser found, skip extension */ 961817466cbSJens Wiklander *p = end_ext_octet; 962817466cbSJens Wiklander 963817466cbSJens Wiklander #if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) 964817466cbSJens Wiklander if( is_critical ) 965817466cbSJens Wiklander { 966817466cbSJens Wiklander /* Data is marked as critical: fail */ 967*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 968*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ); 969817466cbSJens Wiklander } 970817466cbSJens Wiklander #endif 971817466cbSJens Wiklander continue; 972817466cbSJens Wiklander } 973817466cbSJens Wiklander 974817466cbSJens Wiklander /* Forbid repeated extensions */ 975817466cbSJens Wiklander if( ( crt->ext_types & ext_type ) != 0 ) 976817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); 977817466cbSJens Wiklander 978817466cbSJens Wiklander crt->ext_types |= ext_type; 979817466cbSJens Wiklander 980817466cbSJens Wiklander switch( ext_type ) 981817466cbSJens Wiklander { 982817466cbSJens Wiklander case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS: 983817466cbSJens Wiklander /* Parse basic constraints */ 984817466cbSJens Wiklander if( ( ret = x509_get_basic_constraints( p, end_ext_octet, 985817466cbSJens Wiklander &crt->ca_istrue, &crt->max_pathlen ) ) != 0 ) 986817466cbSJens Wiklander return( ret ); 987817466cbSJens Wiklander break; 988817466cbSJens Wiklander 989817466cbSJens Wiklander case MBEDTLS_X509_EXT_KEY_USAGE: 990817466cbSJens Wiklander /* Parse key usage */ 991817466cbSJens Wiklander if( ( ret = x509_get_key_usage( p, end_ext_octet, 992817466cbSJens Wiklander &crt->key_usage ) ) != 0 ) 993817466cbSJens Wiklander return( ret ); 994817466cbSJens Wiklander break; 995817466cbSJens Wiklander 996817466cbSJens Wiklander case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: 997817466cbSJens Wiklander /* Parse extended key usage */ 998817466cbSJens Wiklander if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, 999817466cbSJens Wiklander &crt->ext_key_usage ) ) != 0 ) 1000817466cbSJens Wiklander return( ret ); 1001817466cbSJens Wiklander break; 1002817466cbSJens Wiklander 1003817466cbSJens Wiklander case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: 1004817466cbSJens Wiklander /* Parse subject alt name */ 1005817466cbSJens Wiklander if( ( ret = x509_get_subject_alt_name( p, end_ext_octet, 1006817466cbSJens Wiklander &crt->subject_alt_names ) ) != 0 ) 1007817466cbSJens Wiklander return( ret ); 1008817466cbSJens Wiklander break; 1009817466cbSJens Wiklander 1010817466cbSJens Wiklander case MBEDTLS_X509_EXT_NS_CERT_TYPE: 1011817466cbSJens Wiklander /* Parse netscape certificate type */ 1012817466cbSJens Wiklander if( ( ret = x509_get_ns_cert_type( p, end_ext_octet, 1013817466cbSJens Wiklander &crt->ns_cert_type ) ) != 0 ) 1014817466cbSJens Wiklander return( ret ); 1015817466cbSJens Wiklander break; 1016817466cbSJens Wiklander 101711fa71b9SJerome Forissier case MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES: 101811fa71b9SJerome Forissier /* Parse certificate policies type */ 101911fa71b9SJerome Forissier if( ( ret = x509_get_certificate_policies( p, end_ext_octet, 102011fa71b9SJerome Forissier &crt->certificate_policies ) ) != 0 ) 102111fa71b9SJerome Forissier { 1022*7901324dSJerome Forissier /* Give the callback (if any) a chance to handle the extension 1023*7901324dSJerome Forissier * if it contains unsupported policies */ 1024*7901324dSJerome Forissier if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE && cb != NULL && 1025*7901324dSJerome Forissier cb( p_ctx, crt, &extn_oid, is_critical, 1026*7901324dSJerome Forissier start_ext_octet, end_ext_octet ) == 0 ) 1027*7901324dSJerome Forissier break; 1028*7901324dSJerome Forissier 102911fa71b9SJerome Forissier #if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) 103011fa71b9SJerome Forissier if( is_critical ) 103111fa71b9SJerome Forissier return( ret ); 103211fa71b9SJerome Forissier else 103311fa71b9SJerome Forissier #endif 103411fa71b9SJerome Forissier /* 103511fa71b9SJerome Forissier * If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, then we 103611fa71b9SJerome Forissier * cannot interpret or enforce the policy. However, it is up to 103711fa71b9SJerome Forissier * the user to choose how to enforce the policies, 103811fa71b9SJerome Forissier * unless the extension is critical. 103911fa71b9SJerome Forissier */ 104011fa71b9SJerome Forissier if( ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) 104111fa71b9SJerome Forissier return( ret ); 104211fa71b9SJerome Forissier } 104311fa71b9SJerome Forissier break; 104411fa71b9SJerome Forissier 1045817466cbSJens Wiklander default: 104611fa71b9SJerome Forissier /* 104711fa71b9SJerome Forissier * If this is a non-critical extension, which the oid layer 104811fa71b9SJerome Forissier * supports, but there isn't an x509 parser for it, 104911fa71b9SJerome Forissier * skip the extension. 105011fa71b9SJerome Forissier */ 105111fa71b9SJerome Forissier #if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) 105211fa71b9SJerome Forissier if( is_critical ) 1053817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); 105411fa71b9SJerome Forissier else 105511fa71b9SJerome Forissier #endif 105611fa71b9SJerome Forissier *p = end_ext_octet; 1057817466cbSJens Wiklander } 1058817466cbSJens Wiklander } 1059817466cbSJens Wiklander 1060817466cbSJens Wiklander if( *p != end ) 1061*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 1062*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 1063817466cbSJens Wiklander 1064817466cbSJens Wiklander return( 0 ); 1065817466cbSJens Wiklander } 1066817466cbSJens Wiklander 1067817466cbSJens Wiklander /* 1068817466cbSJens Wiklander * Parse and fill a single X.509 certificate in DER format 1069817466cbSJens Wiklander */ 107011fa71b9SJerome Forissier static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, 107111fa71b9SJerome Forissier const unsigned char *buf, 107211fa71b9SJerome Forissier size_t buflen, 1073*7901324dSJerome Forissier int make_copy, 1074*7901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 1075*7901324dSJerome Forissier void *p_ctx ) 1076817466cbSJens Wiklander { 107711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1078817466cbSJens Wiklander size_t len; 1079817466cbSJens Wiklander unsigned char *p, *end, *crt_end; 1080817466cbSJens Wiklander mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; 1081817466cbSJens Wiklander 1082817466cbSJens Wiklander memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); 1083817466cbSJens Wiklander memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); 1084817466cbSJens Wiklander memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); 1085817466cbSJens Wiklander 1086817466cbSJens Wiklander /* 1087817466cbSJens Wiklander * Check for valid input 1088817466cbSJens Wiklander */ 1089817466cbSJens Wiklander if( crt == NULL || buf == NULL ) 1090817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1091817466cbSJens Wiklander 109211fa71b9SJerome Forissier /* Use the original buffer until we figure out actual length. */ 1093817466cbSJens Wiklander p = (unsigned char*) buf; 1094817466cbSJens Wiklander len = buflen; 1095817466cbSJens Wiklander end = p + len; 1096817466cbSJens Wiklander 1097817466cbSJens Wiklander /* 1098817466cbSJens Wiklander * Certificate ::= SEQUENCE { 1099817466cbSJens Wiklander * tbsCertificate TBSCertificate, 1100817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 1101817466cbSJens Wiklander * signatureValue BIT STRING } 1102817466cbSJens Wiklander */ 1103817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1104817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1105817466cbSJens Wiklander { 1106817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1107817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT ); 1108817466cbSJens Wiklander } 1109817466cbSJens Wiklander 111011fa71b9SJerome Forissier end = crt_end = p + len; 1111817466cbSJens Wiklander crt->raw.len = crt_end - buf; 111211fa71b9SJerome Forissier if( make_copy != 0 ) 111311fa71b9SJerome Forissier { 111411fa71b9SJerome Forissier /* Create and populate a new buffer for the raw field. */ 1115817466cbSJens Wiklander crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len ); 111611fa71b9SJerome Forissier if( crt->raw.p == NULL ) 1117817466cbSJens Wiklander return( MBEDTLS_ERR_X509_ALLOC_FAILED ); 1118817466cbSJens Wiklander 111911fa71b9SJerome Forissier memcpy( crt->raw.p, buf, crt->raw.len ); 112011fa71b9SJerome Forissier crt->own_buffer = 1; 1121817466cbSJens Wiklander 1122817466cbSJens Wiklander p += crt->raw.len - len; 1123817466cbSJens Wiklander end = crt_end = p + len; 112411fa71b9SJerome Forissier } 112511fa71b9SJerome Forissier else 112611fa71b9SJerome Forissier { 112711fa71b9SJerome Forissier crt->raw.p = (unsigned char*) buf; 112811fa71b9SJerome Forissier crt->own_buffer = 0; 112911fa71b9SJerome Forissier } 1130817466cbSJens Wiklander 1131817466cbSJens Wiklander /* 1132817466cbSJens Wiklander * TBSCertificate ::= SEQUENCE { 1133817466cbSJens Wiklander */ 1134817466cbSJens Wiklander crt->tbs.p = p; 1135817466cbSJens Wiklander 1136817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1137817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1138817466cbSJens Wiklander { 1139817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1140*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT, ret ) ); 1141817466cbSJens Wiklander } 1142817466cbSJens Wiklander 1143817466cbSJens Wiklander end = p + len; 1144817466cbSJens Wiklander crt->tbs.len = end - crt->tbs.p; 1145817466cbSJens Wiklander 1146817466cbSJens Wiklander /* 1147817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 1148817466cbSJens Wiklander * 1149817466cbSJens Wiklander * CertificateSerialNumber ::= INTEGER 1150817466cbSJens Wiklander * 1151817466cbSJens Wiklander * signature AlgorithmIdentifier 1152817466cbSJens Wiklander */ 1153817466cbSJens Wiklander if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 || 1154817466cbSJens Wiklander ( ret = mbedtls_x509_get_serial( &p, end, &crt->serial ) ) != 0 || 1155817466cbSJens Wiklander ( ret = mbedtls_x509_get_alg( &p, end, &crt->sig_oid, 1156817466cbSJens Wiklander &sig_params1 ) ) != 0 ) 1157817466cbSJens Wiklander { 1158817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1159817466cbSJens Wiklander return( ret ); 1160817466cbSJens Wiklander } 1161817466cbSJens Wiklander 1162817466cbSJens Wiklander if( crt->version < 0 || crt->version > 2 ) 1163817466cbSJens Wiklander { 1164817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1165817466cbSJens Wiklander return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); 1166817466cbSJens Wiklander } 1167817466cbSJens Wiklander 1168817466cbSJens Wiklander crt->version++; 1169817466cbSJens Wiklander 1170817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1, 1171817466cbSJens Wiklander &crt->sig_md, &crt->sig_pk, 1172817466cbSJens Wiklander &crt->sig_opts ) ) != 0 ) 1173817466cbSJens Wiklander { 1174817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1175817466cbSJens Wiklander return( ret ); 1176817466cbSJens Wiklander } 1177817466cbSJens Wiklander 1178817466cbSJens Wiklander /* 1179817466cbSJens Wiklander * issuer Name 1180817466cbSJens Wiklander */ 1181817466cbSJens Wiklander crt->issuer_raw.p = p; 1182817466cbSJens Wiklander 1183817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1184817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1185817466cbSJens Wiklander { 1186817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1187*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT, ret ) ); 1188817466cbSJens Wiklander } 1189817466cbSJens Wiklander 1190817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) 1191817466cbSJens Wiklander { 1192817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1193817466cbSJens Wiklander return( ret ); 1194817466cbSJens Wiklander } 1195817466cbSJens Wiklander 1196817466cbSJens Wiklander crt->issuer_raw.len = p - crt->issuer_raw.p; 1197817466cbSJens Wiklander 1198817466cbSJens Wiklander /* 1199817466cbSJens Wiklander * Validity ::= SEQUENCE { 1200817466cbSJens Wiklander * notBefore Time, 1201817466cbSJens Wiklander * notAfter Time } 1202817466cbSJens Wiklander * 1203817466cbSJens Wiklander */ 1204817466cbSJens Wiklander if( ( ret = x509_get_dates( &p, end, &crt->valid_from, 1205817466cbSJens Wiklander &crt->valid_to ) ) != 0 ) 1206817466cbSJens Wiklander { 1207817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1208817466cbSJens Wiklander return( ret ); 1209817466cbSJens Wiklander } 1210817466cbSJens Wiklander 1211817466cbSJens Wiklander /* 1212817466cbSJens Wiklander * subject Name 1213817466cbSJens Wiklander */ 1214817466cbSJens Wiklander crt->subject_raw.p = p; 1215817466cbSJens Wiklander 1216817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1217817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1218817466cbSJens Wiklander { 1219817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1220*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT, ret ) ); 1221817466cbSJens Wiklander } 1222817466cbSJens Wiklander 1223817466cbSJens Wiklander if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) 1224817466cbSJens Wiklander { 1225817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1226817466cbSJens Wiklander return( ret ); 1227817466cbSJens Wiklander } 1228817466cbSJens Wiklander 1229817466cbSJens Wiklander crt->subject_raw.len = p - crt->subject_raw.p; 1230817466cbSJens Wiklander 1231817466cbSJens Wiklander /* 1232817466cbSJens Wiklander * SubjectPublicKeyInfo 1233817466cbSJens Wiklander */ 123411fa71b9SJerome Forissier crt->pk_raw.p = p; 1235817466cbSJens Wiklander if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 ) 1236817466cbSJens Wiklander { 1237817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1238817466cbSJens Wiklander return( ret ); 1239817466cbSJens Wiklander } 124011fa71b9SJerome Forissier crt->pk_raw.len = p - crt->pk_raw.p; 1241817466cbSJens Wiklander 1242817466cbSJens Wiklander /* 1243817466cbSJens Wiklander * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 1244817466cbSJens Wiklander * -- If present, version shall be v2 or v3 1245817466cbSJens Wiklander * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 1246817466cbSJens Wiklander * -- If present, version shall be v2 or v3 1247817466cbSJens Wiklander * extensions [3] EXPLICIT Extensions OPTIONAL 1248817466cbSJens Wiklander * -- If present, version shall be v3 1249817466cbSJens Wiklander */ 1250817466cbSJens Wiklander if( crt->version == 2 || crt->version == 3 ) 1251817466cbSJens Wiklander { 1252817466cbSJens Wiklander ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); 1253817466cbSJens Wiklander if( ret != 0 ) 1254817466cbSJens Wiklander { 1255817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1256817466cbSJens Wiklander return( ret ); 1257817466cbSJens Wiklander } 1258817466cbSJens Wiklander } 1259817466cbSJens Wiklander 1260817466cbSJens Wiklander if( crt->version == 2 || crt->version == 3 ) 1261817466cbSJens Wiklander { 1262817466cbSJens Wiklander ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); 1263817466cbSJens Wiklander if( ret != 0 ) 1264817466cbSJens Wiklander { 1265817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1266817466cbSJens Wiklander return( ret ); 1267817466cbSJens Wiklander } 1268817466cbSJens Wiklander } 1269817466cbSJens Wiklander 1270817466cbSJens Wiklander #if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) 1271817466cbSJens Wiklander if( crt->version == 3 ) 1272817466cbSJens Wiklander #endif 1273817466cbSJens Wiklander { 1274*7901324dSJerome Forissier ret = x509_get_crt_ext( &p, end, crt, cb, p_ctx ); 1275817466cbSJens Wiklander if( ret != 0 ) 1276817466cbSJens Wiklander { 1277817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1278817466cbSJens Wiklander return( ret ); 1279817466cbSJens Wiklander } 1280817466cbSJens Wiklander } 1281817466cbSJens Wiklander 1282817466cbSJens Wiklander if( p != end ) 1283817466cbSJens Wiklander { 1284817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1285*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT, 1286*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 1287817466cbSJens Wiklander } 1288817466cbSJens Wiklander 1289817466cbSJens Wiklander end = crt_end; 1290817466cbSJens Wiklander 1291817466cbSJens Wiklander /* 1292817466cbSJens Wiklander * } 1293817466cbSJens Wiklander * -- end of TBSCertificate 1294817466cbSJens Wiklander * 1295817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 1296817466cbSJens Wiklander * signatureValue BIT STRING 1297817466cbSJens Wiklander */ 1298817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) 1299817466cbSJens Wiklander { 1300817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1301817466cbSJens Wiklander return( ret ); 1302817466cbSJens Wiklander } 1303817466cbSJens Wiklander 1304817466cbSJens Wiklander if( crt->sig_oid.len != sig_oid2.len || 1305817466cbSJens Wiklander memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 || 1306*7901324dSJerome Forissier sig_params1.tag != sig_params2.tag || 1307817466cbSJens Wiklander sig_params1.len != sig_params2.len || 1308817466cbSJens Wiklander ( sig_params1.len != 0 && 1309817466cbSJens Wiklander memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) 1310817466cbSJens Wiklander { 1311817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1312817466cbSJens Wiklander return( MBEDTLS_ERR_X509_SIG_MISMATCH ); 1313817466cbSJens Wiklander } 1314817466cbSJens Wiklander 1315817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_sig( &p, end, &crt->sig ) ) != 0 ) 1316817466cbSJens Wiklander { 1317817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1318817466cbSJens Wiklander return( ret ); 1319817466cbSJens Wiklander } 1320817466cbSJens Wiklander 1321817466cbSJens Wiklander if( p != end ) 1322817466cbSJens Wiklander { 1323817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 1324*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT, 1325*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 1326817466cbSJens Wiklander } 1327817466cbSJens Wiklander 1328817466cbSJens Wiklander return( 0 ); 1329817466cbSJens Wiklander } 1330817466cbSJens Wiklander 1331817466cbSJens Wiklander /* 1332817466cbSJens Wiklander * Parse one X.509 certificate in DER format from a buffer and add them to a 1333817466cbSJens Wiklander * chained list 1334817466cbSJens Wiklander */ 133511fa71b9SJerome Forissier static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain, 133611fa71b9SJerome Forissier const unsigned char *buf, 133711fa71b9SJerome Forissier size_t buflen, 1338*7901324dSJerome Forissier int make_copy, 1339*7901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 1340*7901324dSJerome Forissier void *p_ctx ) 1341817466cbSJens Wiklander { 134211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1343817466cbSJens Wiklander mbedtls_x509_crt *crt = chain, *prev = NULL; 1344817466cbSJens Wiklander 1345817466cbSJens Wiklander /* 1346817466cbSJens Wiklander * Check for valid input 1347817466cbSJens Wiklander */ 1348817466cbSJens Wiklander if( crt == NULL || buf == NULL ) 1349817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1350817466cbSJens Wiklander 1351817466cbSJens Wiklander while( crt->version != 0 && crt->next != NULL ) 1352817466cbSJens Wiklander { 1353817466cbSJens Wiklander prev = crt; 1354817466cbSJens Wiklander crt = crt->next; 1355817466cbSJens Wiklander } 1356817466cbSJens Wiklander 1357817466cbSJens Wiklander /* 1358817466cbSJens Wiklander * Add new certificate on the end of the chain if needed. 1359817466cbSJens Wiklander */ 1360817466cbSJens Wiklander if( crt->version != 0 && crt->next == NULL ) 1361817466cbSJens Wiklander { 1362817466cbSJens Wiklander crt->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); 1363817466cbSJens Wiklander 1364817466cbSJens Wiklander if( crt->next == NULL ) 1365817466cbSJens Wiklander return( MBEDTLS_ERR_X509_ALLOC_FAILED ); 1366817466cbSJens Wiklander 1367817466cbSJens Wiklander prev = crt; 1368817466cbSJens Wiklander mbedtls_x509_crt_init( crt->next ); 1369817466cbSJens Wiklander crt = crt->next; 1370817466cbSJens Wiklander } 1371817466cbSJens Wiklander 1372*7901324dSJerome Forissier ret = x509_crt_parse_der_core( crt, buf, buflen, make_copy, cb, p_ctx ); 1373*7901324dSJerome Forissier if( ret != 0 ) 1374817466cbSJens Wiklander { 1375817466cbSJens Wiklander if( prev ) 1376817466cbSJens Wiklander prev->next = NULL; 1377817466cbSJens Wiklander 1378817466cbSJens Wiklander if( crt != chain ) 1379817466cbSJens Wiklander mbedtls_free( crt ); 1380817466cbSJens Wiklander 1381817466cbSJens Wiklander return( ret ); 1382817466cbSJens Wiklander } 1383817466cbSJens Wiklander 1384817466cbSJens Wiklander return( 0 ); 1385817466cbSJens Wiklander } 1386817466cbSJens Wiklander 138711fa71b9SJerome Forissier int mbedtls_x509_crt_parse_der_nocopy( mbedtls_x509_crt *chain, 138811fa71b9SJerome Forissier const unsigned char *buf, 138911fa71b9SJerome Forissier size_t buflen ) 139011fa71b9SJerome Forissier { 1391*7901324dSJerome Forissier return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 0, NULL, NULL ) ); 1392*7901324dSJerome Forissier } 1393*7901324dSJerome Forissier 1394*7901324dSJerome Forissier int mbedtls_x509_crt_parse_der_with_ext_cb( mbedtls_x509_crt *chain, 1395*7901324dSJerome Forissier const unsigned char *buf, 1396*7901324dSJerome Forissier size_t buflen, 1397*7901324dSJerome Forissier int make_copy, 1398*7901324dSJerome Forissier mbedtls_x509_crt_ext_cb_t cb, 1399*7901324dSJerome Forissier void *p_ctx ) 1400*7901324dSJerome Forissier { 1401*7901324dSJerome Forissier return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, make_copy, cb, p_ctx ) ); 140211fa71b9SJerome Forissier } 140311fa71b9SJerome Forissier 140411fa71b9SJerome Forissier int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, 140511fa71b9SJerome Forissier const unsigned char *buf, 140611fa71b9SJerome Forissier size_t buflen ) 140711fa71b9SJerome Forissier { 1408*7901324dSJerome Forissier return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1, NULL, NULL ) ); 140911fa71b9SJerome Forissier } 141011fa71b9SJerome Forissier 1411817466cbSJens Wiklander /* 1412817466cbSJens Wiklander * Parse one or more PEM certificates from a buffer and add them to the chained 1413817466cbSJens Wiklander * list 1414817466cbSJens Wiklander */ 141511fa71b9SJerome Forissier int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, 141611fa71b9SJerome Forissier const unsigned char *buf, 141711fa71b9SJerome Forissier size_t buflen ) 1418817466cbSJens Wiklander { 1419817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1420817466cbSJens Wiklander int success = 0, first_error = 0, total_failed = 0; 1421817466cbSJens Wiklander int buf_format = MBEDTLS_X509_FORMAT_DER; 1422817466cbSJens Wiklander #endif 1423817466cbSJens Wiklander 1424817466cbSJens Wiklander /* 1425817466cbSJens Wiklander * Check for valid input 1426817466cbSJens Wiklander */ 1427817466cbSJens Wiklander if( chain == NULL || buf == NULL ) 1428817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1429817466cbSJens Wiklander 1430817466cbSJens Wiklander /* 1431817466cbSJens Wiklander * Determine buffer content. Buffer contains either one DER certificate or 1432817466cbSJens Wiklander * one or more PEM certificates. 1433817466cbSJens Wiklander */ 1434817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1435817466cbSJens Wiklander if( buflen != 0 && buf[buflen - 1] == '\0' && 1436817466cbSJens Wiklander strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL ) 1437817466cbSJens Wiklander { 1438817466cbSJens Wiklander buf_format = MBEDTLS_X509_FORMAT_PEM; 1439817466cbSJens Wiklander } 1440817466cbSJens Wiklander 1441817466cbSJens Wiklander if( buf_format == MBEDTLS_X509_FORMAT_DER ) 1442817466cbSJens Wiklander return mbedtls_x509_crt_parse_der( chain, buf, buflen ); 1443817466cbSJens Wiklander #else 1444817466cbSJens Wiklander return mbedtls_x509_crt_parse_der( chain, buf, buflen ); 1445817466cbSJens Wiklander #endif 1446817466cbSJens Wiklander 1447817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1448817466cbSJens Wiklander if( buf_format == MBEDTLS_X509_FORMAT_PEM ) 1449817466cbSJens Wiklander { 145011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1451817466cbSJens Wiklander mbedtls_pem_context pem; 1452817466cbSJens Wiklander 1453817466cbSJens Wiklander /* 1 rather than 0 since the terminating NULL byte is counted in */ 1454817466cbSJens Wiklander while( buflen > 1 ) 1455817466cbSJens Wiklander { 1456817466cbSJens Wiklander size_t use_len; 1457817466cbSJens Wiklander mbedtls_pem_init( &pem ); 1458817466cbSJens Wiklander 1459817466cbSJens Wiklander /* If we get there, we know the string is null-terminated */ 1460817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1461817466cbSJens Wiklander "-----BEGIN CERTIFICATE-----", 1462817466cbSJens Wiklander "-----END CERTIFICATE-----", 1463817466cbSJens Wiklander buf, NULL, 0, &use_len ); 1464817466cbSJens Wiklander 1465817466cbSJens Wiklander if( ret == 0 ) 1466817466cbSJens Wiklander { 1467817466cbSJens Wiklander /* 1468817466cbSJens Wiklander * Was PEM encoded 1469817466cbSJens Wiklander */ 1470817466cbSJens Wiklander buflen -= use_len; 1471817466cbSJens Wiklander buf += use_len; 1472817466cbSJens Wiklander } 1473817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA ) 1474817466cbSJens Wiklander { 1475817466cbSJens Wiklander return( ret ); 1476817466cbSJens Wiklander } 1477817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1478817466cbSJens Wiklander { 1479817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1480817466cbSJens Wiklander 1481817466cbSJens Wiklander /* 1482817466cbSJens Wiklander * PEM header and footer were found 1483817466cbSJens Wiklander */ 1484817466cbSJens Wiklander buflen -= use_len; 1485817466cbSJens Wiklander buf += use_len; 1486817466cbSJens Wiklander 1487817466cbSJens Wiklander if( first_error == 0 ) 1488817466cbSJens Wiklander first_error = ret; 1489817466cbSJens Wiklander 1490817466cbSJens Wiklander total_failed++; 1491817466cbSJens Wiklander continue; 1492817466cbSJens Wiklander } 1493817466cbSJens Wiklander else 1494817466cbSJens Wiklander break; 1495817466cbSJens Wiklander 1496817466cbSJens Wiklander ret = mbedtls_x509_crt_parse_der( chain, pem.buf, pem.buflen ); 1497817466cbSJens Wiklander 1498817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1499817466cbSJens Wiklander 1500817466cbSJens Wiklander if( ret != 0 ) 1501817466cbSJens Wiklander { 1502817466cbSJens Wiklander /* 1503817466cbSJens Wiklander * Quit parsing on a memory error 1504817466cbSJens Wiklander */ 1505817466cbSJens Wiklander if( ret == MBEDTLS_ERR_X509_ALLOC_FAILED ) 1506817466cbSJens Wiklander return( ret ); 1507817466cbSJens Wiklander 1508817466cbSJens Wiklander if( first_error == 0 ) 1509817466cbSJens Wiklander first_error = ret; 1510817466cbSJens Wiklander 1511817466cbSJens Wiklander total_failed++; 1512817466cbSJens Wiklander continue; 1513817466cbSJens Wiklander } 1514817466cbSJens Wiklander 1515817466cbSJens Wiklander success = 1; 1516817466cbSJens Wiklander } 1517817466cbSJens Wiklander } 1518817466cbSJens Wiklander 1519817466cbSJens Wiklander if( success ) 1520817466cbSJens Wiklander return( total_failed ); 1521817466cbSJens Wiklander else if( first_error ) 1522817466cbSJens Wiklander return( first_error ); 1523817466cbSJens Wiklander else 1524817466cbSJens Wiklander return( MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT ); 1525817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1526817466cbSJens Wiklander } 1527817466cbSJens Wiklander 1528817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 1529817466cbSJens Wiklander /* 1530817466cbSJens Wiklander * Load one or more certificates and add them to the chained list 1531817466cbSJens Wiklander */ 1532817466cbSJens Wiklander int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ) 1533817466cbSJens Wiklander { 153411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1535817466cbSJens Wiklander size_t n; 1536817466cbSJens Wiklander unsigned char *buf; 1537817466cbSJens Wiklander 1538817466cbSJens Wiklander if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) 1539817466cbSJens Wiklander return( ret ); 1540817466cbSJens Wiklander 1541817466cbSJens Wiklander ret = mbedtls_x509_crt_parse( chain, buf, n ); 1542817466cbSJens Wiklander 15433d3b0591SJens Wiklander mbedtls_platform_zeroize( buf, n ); 1544817466cbSJens Wiklander mbedtls_free( buf ); 1545817466cbSJens Wiklander 1546817466cbSJens Wiklander return( ret ); 1547817466cbSJens Wiklander } 1548817466cbSJens Wiklander 1549817466cbSJens Wiklander int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) 1550817466cbSJens Wiklander { 1551817466cbSJens Wiklander int ret = 0; 1552817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 1553817466cbSJens Wiklander int w_ret; 1554817466cbSJens Wiklander WCHAR szDir[MAX_PATH]; 1555817466cbSJens Wiklander char filename[MAX_PATH]; 1556817466cbSJens Wiklander char *p; 1557817466cbSJens Wiklander size_t len = strlen( path ); 1558817466cbSJens Wiklander 1559817466cbSJens Wiklander WIN32_FIND_DATAW file_data; 1560817466cbSJens Wiklander HANDLE hFind; 1561817466cbSJens Wiklander 1562817466cbSJens Wiklander if( len > MAX_PATH - 3 ) 1563817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1564817466cbSJens Wiklander 1565817466cbSJens Wiklander memset( szDir, 0, sizeof(szDir) ); 1566817466cbSJens Wiklander memset( filename, 0, MAX_PATH ); 1567817466cbSJens Wiklander memcpy( filename, path, len ); 1568817466cbSJens Wiklander filename[len++] = '\\'; 1569817466cbSJens Wiklander p = filename + len; 1570817466cbSJens Wiklander filename[len++] = '*'; 1571817466cbSJens Wiklander 1572817466cbSJens Wiklander w_ret = MultiByteToWideChar( CP_ACP, 0, filename, (int)len, szDir, 1573817466cbSJens Wiklander MAX_PATH - 3 ); 1574817466cbSJens Wiklander if( w_ret == 0 ) 1575817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1576817466cbSJens Wiklander 1577817466cbSJens Wiklander hFind = FindFirstFileW( szDir, &file_data ); 1578817466cbSJens Wiklander if( hFind == INVALID_HANDLE_VALUE ) 1579817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); 1580817466cbSJens Wiklander 1581817466cbSJens Wiklander len = MAX_PATH - len; 1582817466cbSJens Wiklander do 1583817466cbSJens Wiklander { 1584817466cbSJens Wiklander memset( p, 0, len ); 1585817466cbSJens Wiklander 1586817466cbSJens Wiklander if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) 1587817466cbSJens Wiklander continue; 1588817466cbSJens Wiklander 1589817466cbSJens Wiklander w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName, 1590817466cbSJens Wiklander lstrlenW( file_data.cFileName ), 1591817466cbSJens Wiklander p, (int) len - 1, 1592817466cbSJens Wiklander NULL, NULL ); 1593817466cbSJens Wiklander if( w_ret == 0 ) 1594817466cbSJens Wiklander { 1595817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1596817466cbSJens Wiklander goto cleanup; 1597817466cbSJens Wiklander } 1598817466cbSJens Wiklander 1599817466cbSJens Wiklander w_ret = mbedtls_x509_crt_parse_file( chain, filename ); 1600817466cbSJens Wiklander if( w_ret < 0 ) 1601817466cbSJens Wiklander ret++; 1602817466cbSJens Wiklander else 1603817466cbSJens Wiklander ret += w_ret; 1604817466cbSJens Wiklander } 1605817466cbSJens Wiklander while( FindNextFileW( hFind, &file_data ) != 0 ); 1606817466cbSJens Wiklander 1607817466cbSJens Wiklander if( GetLastError() != ERROR_NO_MORE_FILES ) 1608817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1609817466cbSJens Wiklander 1610817466cbSJens Wiklander cleanup: 1611817466cbSJens Wiklander FindClose( hFind ); 1612817466cbSJens Wiklander #else /* _WIN32 */ 1613817466cbSJens Wiklander int t_ret; 1614817466cbSJens Wiklander int snp_ret; 1615817466cbSJens Wiklander struct stat sb; 1616817466cbSJens Wiklander struct dirent *entry; 1617817466cbSJens Wiklander char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN]; 1618817466cbSJens Wiklander DIR *dir = opendir( path ); 1619817466cbSJens Wiklander 1620817466cbSJens Wiklander if( dir == NULL ) 1621817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); 1622817466cbSJens Wiklander 1623817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 1624817466cbSJens Wiklander if( ( ret = mbedtls_mutex_lock( &mbedtls_threading_readdir_mutex ) ) != 0 ) 1625817466cbSJens Wiklander { 1626817466cbSJens Wiklander closedir( dir ); 1627817466cbSJens Wiklander return( ret ); 1628817466cbSJens Wiklander } 1629817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */ 1630817466cbSJens Wiklander 1631*7901324dSJerome Forissier memset( &sb, 0, sizeof( sb ) ); 1632*7901324dSJerome Forissier 1633817466cbSJens Wiklander while( ( entry = readdir( dir ) ) != NULL ) 1634817466cbSJens Wiklander { 1635817466cbSJens Wiklander snp_ret = mbedtls_snprintf( entry_name, sizeof entry_name, 1636817466cbSJens Wiklander "%s/%s", path, entry->d_name ); 1637817466cbSJens Wiklander 1638817466cbSJens Wiklander if( snp_ret < 0 || (size_t)snp_ret >= sizeof entry_name ) 1639817466cbSJens Wiklander { 1640817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; 1641817466cbSJens Wiklander goto cleanup; 1642817466cbSJens Wiklander } 1643817466cbSJens Wiklander else if( stat( entry_name, &sb ) == -1 ) 1644817466cbSJens Wiklander { 1645817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1646817466cbSJens Wiklander goto cleanup; 1647817466cbSJens Wiklander } 1648817466cbSJens Wiklander 1649817466cbSJens Wiklander if( !S_ISREG( sb.st_mode ) ) 1650817466cbSJens Wiklander continue; 1651817466cbSJens Wiklander 1652817466cbSJens Wiklander // Ignore parse errors 1653817466cbSJens Wiklander // 1654817466cbSJens Wiklander t_ret = mbedtls_x509_crt_parse_file( chain, entry_name ); 1655817466cbSJens Wiklander if( t_ret < 0 ) 1656817466cbSJens Wiklander ret++; 1657817466cbSJens Wiklander else 1658817466cbSJens Wiklander ret += t_ret; 1659817466cbSJens Wiklander } 1660817466cbSJens Wiklander 1661817466cbSJens Wiklander cleanup: 1662817466cbSJens Wiklander closedir( dir ); 1663817466cbSJens Wiklander 1664817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 1665817466cbSJens Wiklander if( mbedtls_mutex_unlock( &mbedtls_threading_readdir_mutex ) != 0 ) 1666817466cbSJens Wiklander ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR; 1667817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */ 1668817466cbSJens Wiklander 1669817466cbSJens Wiklander #endif /* _WIN32 */ 1670817466cbSJens Wiklander 1671817466cbSJens Wiklander return( ret ); 1672817466cbSJens Wiklander } 1673817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 1674817466cbSJens Wiklander 167511fa71b9SJerome Forissier /* 167611fa71b9SJerome Forissier * OtherName ::= SEQUENCE { 167711fa71b9SJerome Forissier * type-id OBJECT IDENTIFIER, 167811fa71b9SJerome Forissier * value [0] EXPLICIT ANY DEFINED BY type-id } 167911fa71b9SJerome Forissier * 168011fa71b9SJerome Forissier * HardwareModuleName ::= SEQUENCE { 168111fa71b9SJerome Forissier * hwType OBJECT IDENTIFIER, 168211fa71b9SJerome Forissier * hwSerialNum OCTET STRING } 168311fa71b9SJerome Forissier * 168411fa71b9SJerome Forissier * NOTE: we currently only parse and use otherName of type HwModuleName, 168511fa71b9SJerome Forissier * as defined in RFC 4108. 168611fa71b9SJerome Forissier */ 168711fa71b9SJerome Forissier static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name, 168811fa71b9SJerome Forissier mbedtls_x509_san_other_name *other_name ) 1689817466cbSJens Wiklander { 169011fa71b9SJerome Forissier int ret = 0; 169111fa71b9SJerome Forissier size_t len; 169211fa71b9SJerome Forissier unsigned char *p = subject_alt_name->p; 169311fa71b9SJerome Forissier const unsigned char *end = p + subject_alt_name->len; 169411fa71b9SJerome Forissier mbedtls_x509_buf cur_oid; 169511fa71b9SJerome Forissier 169611fa71b9SJerome Forissier if( ( subject_alt_name->tag & 169711fa71b9SJerome Forissier ( MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK ) ) != 169811fa71b9SJerome Forissier ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ) ) 169911fa71b9SJerome Forissier { 170011fa71b9SJerome Forissier /* 170111fa71b9SJerome Forissier * The given subject alternative name is not of type "othername". 170211fa71b9SJerome Forissier */ 170311fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 170411fa71b9SJerome Forissier } 170511fa71b9SJerome Forissier 170611fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 170711fa71b9SJerome Forissier MBEDTLS_ASN1_OID ) ) != 0 ) 1708*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 170911fa71b9SJerome Forissier 171011fa71b9SJerome Forissier cur_oid.tag = MBEDTLS_ASN1_OID; 171111fa71b9SJerome Forissier cur_oid.p = p; 171211fa71b9SJerome Forissier cur_oid.len = len; 171311fa71b9SJerome Forissier 171411fa71b9SJerome Forissier /* 171511fa71b9SJerome Forissier * Only HwModuleName is currently supported. 171611fa71b9SJerome Forissier */ 171711fa71b9SJerome Forissier if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME, &cur_oid ) != 0 ) 171811fa71b9SJerome Forissier { 171911fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); 172011fa71b9SJerome Forissier } 172111fa71b9SJerome Forissier 172211fa71b9SJerome Forissier if( p + len >= end ) 172311fa71b9SJerome Forissier { 172411fa71b9SJerome Forissier mbedtls_platform_zeroize( other_name, sizeof( *other_name ) ); 1725*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 1726*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 172711fa71b9SJerome Forissier } 172811fa71b9SJerome Forissier p += len; 172911fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 173011fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) 1731*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 173211fa71b9SJerome Forissier 173311fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 173411fa71b9SJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1735*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 173611fa71b9SJerome Forissier 173711fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OID ) ) != 0 ) 1738*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 173911fa71b9SJerome Forissier 174011fa71b9SJerome Forissier other_name->value.hardware_module_name.oid.tag = MBEDTLS_ASN1_OID; 174111fa71b9SJerome Forissier other_name->value.hardware_module_name.oid.p = p; 174211fa71b9SJerome Forissier other_name->value.hardware_module_name.oid.len = len; 174311fa71b9SJerome Forissier 174411fa71b9SJerome Forissier if( p + len >= end ) 174511fa71b9SJerome Forissier { 174611fa71b9SJerome Forissier mbedtls_platform_zeroize( other_name, sizeof( *other_name ) ); 1747*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 1748*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 174911fa71b9SJerome Forissier } 175011fa71b9SJerome Forissier p += len; 175111fa71b9SJerome Forissier if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 175211fa71b9SJerome Forissier MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 1753*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret ) ); 175411fa71b9SJerome Forissier 175511fa71b9SJerome Forissier other_name->value.hardware_module_name.val.tag = MBEDTLS_ASN1_OCTET_STRING; 175611fa71b9SJerome Forissier other_name->value.hardware_module_name.val.p = p; 175711fa71b9SJerome Forissier other_name->value.hardware_module_name.val.len = len; 175811fa71b9SJerome Forissier p += len; 175911fa71b9SJerome Forissier if( p != end ) 176011fa71b9SJerome Forissier { 176111fa71b9SJerome Forissier mbedtls_platform_zeroize( other_name, 176211fa71b9SJerome Forissier sizeof( *other_name ) ); 1763*7901324dSJerome Forissier return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 1764*7901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) ); 176511fa71b9SJerome Forissier } 176611fa71b9SJerome Forissier return( 0 ); 176711fa71b9SJerome Forissier } 176811fa71b9SJerome Forissier 176911fa71b9SJerome Forissier static int x509_info_subject_alt_name( char **buf, size_t *size, 177011fa71b9SJerome Forissier const mbedtls_x509_sequence 177111fa71b9SJerome Forissier *subject_alt_name, 177211fa71b9SJerome Forissier const char *prefix ) 177311fa71b9SJerome Forissier { 177411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1775817466cbSJens Wiklander size_t n = *size; 1776817466cbSJens Wiklander char *p = *buf; 1777817466cbSJens Wiklander const mbedtls_x509_sequence *cur = subject_alt_name; 177811fa71b9SJerome Forissier mbedtls_x509_subject_alternative_name san; 177911fa71b9SJerome Forissier int parse_ret; 1780817466cbSJens Wiklander 1781817466cbSJens Wiklander while( cur != NULL ) 1782817466cbSJens Wiklander { 178311fa71b9SJerome Forissier memset( &san, 0, sizeof( san ) ); 178411fa71b9SJerome Forissier parse_ret = mbedtls_x509_parse_subject_alt_name( &cur->buf, &san ); 178511fa71b9SJerome Forissier if( parse_ret != 0 ) 178611fa71b9SJerome Forissier { 178711fa71b9SJerome Forissier if( parse_ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) 178811fa71b9SJerome Forissier { 178911fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s <unsupported>", prefix ); 179011fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 179111fa71b9SJerome Forissier } 179211fa71b9SJerome Forissier else 179311fa71b9SJerome Forissier { 179411fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s <malformed>", prefix ); 179511fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 179611fa71b9SJerome Forissier } 179711fa71b9SJerome Forissier cur = cur->next; 179811fa71b9SJerome Forissier continue; 179911fa71b9SJerome Forissier } 180011fa71b9SJerome Forissier 180111fa71b9SJerome Forissier switch( san.type ) 180211fa71b9SJerome Forissier { 180311fa71b9SJerome Forissier /* 180411fa71b9SJerome Forissier * otherName 180511fa71b9SJerome Forissier */ 180611fa71b9SJerome Forissier case MBEDTLS_X509_SAN_OTHER_NAME: 180711fa71b9SJerome Forissier { 180811fa71b9SJerome Forissier mbedtls_x509_san_other_name *other_name = &san.san.other_name; 180911fa71b9SJerome Forissier 181011fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s otherName :", prefix ); 181111fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 181211fa71b9SJerome Forissier 181311fa71b9SJerome Forissier if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME, 181411fa71b9SJerome Forissier &other_name->value.hardware_module_name.oid ) != 0 ) 181511fa71b9SJerome Forissier { 181611fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s hardware module name :", prefix ); 181711fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 181811fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s hardware type : ", prefix ); 181911fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 182011fa71b9SJerome Forissier 182111fa71b9SJerome Forissier ret = mbedtls_oid_get_numeric_string( p, n, &other_name->value.hardware_module_name.oid ); 182211fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 182311fa71b9SJerome Forissier 182411fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s hardware serial number : ", prefix ); 182511fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 182611fa71b9SJerome Forissier 182711fa71b9SJerome Forissier if( other_name->value.hardware_module_name.val.len >= n ) 1828817466cbSJens Wiklander { 1829817466cbSJens Wiklander *p = '\0'; 1830817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); 1831817466cbSJens Wiklander } 1832817466cbSJens Wiklander 183311fa71b9SJerome Forissier memcpy( p, other_name->value.hardware_module_name.val.p, 183411fa71b9SJerome Forissier other_name->value.hardware_module_name.val.len ); 183511fa71b9SJerome Forissier p += other_name->value.hardware_module_name.val.len; 1836817466cbSJens Wiklander 183711fa71b9SJerome Forissier n -= other_name->value.hardware_module_name.val.len; 183811fa71b9SJerome Forissier 183911fa71b9SJerome Forissier }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ 184011fa71b9SJerome Forissier } 184111fa71b9SJerome Forissier break; 184211fa71b9SJerome Forissier 184311fa71b9SJerome Forissier /* 184411fa71b9SJerome Forissier * dNSName 184511fa71b9SJerome Forissier */ 184611fa71b9SJerome Forissier case MBEDTLS_X509_SAN_DNS_NAME: 184711fa71b9SJerome Forissier { 184811fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s dNSName : ", prefix ); 184911fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 185011fa71b9SJerome Forissier if( san.san.unstructured_name.len >= n ) 185111fa71b9SJerome Forissier { 185211fa71b9SJerome Forissier *p = '\0'; 185311fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); 185411fa71b9SJerome Forissier } 185511fa71b9SJerome Forissier 185611fa71b9SJerome Forissier memcpy( p, san.san.unstructured_name.p, san.san.unstructured_name.len ); 185711fa71b9SJerome Forissier p += san.san.unstructured_name.len; 185811fa71b9SJerome Forissier n -= san.san.unstructured_name.len; 185911fa71b9SJerome Forissier } 186011fa71b9SJerome Forissier break; 186111fa71b9SJerome Forissier 186211fa71b9SJerome Forissier /* 186311fa71b9SJerome Forissier * Type not supported, skip item. 186411fa71b9SJerome Forissier */ 186511fa71b9SJerome Forissier default: 186611fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%s <unsupported>", prefix ); 186711fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 186811fa71b9SJerome Forissier break; 186911fa71b9SJerome Forissier } 1870817466cbSJens Wiklander 1871817466cbSJens Wiklander cur = cur->next; 1872817466cbSJens Wiklander } 1873817466cbSJens Wiklander 1874817466cbSJens Wiklander *p = '\0'; 1875817466cbSJens Wiklander 1876817466cbSJens Wiklander *size = n; 1877817466cbSJens Wiklander *buf = p; 1878817466cbSJens Wiklander 1879817466cbSJens Wiklander return( 0 ); 1880817466cbSJens Wiklander } 1881817466cbSJens Wiklander 188211fa71b9SJerome Forissier int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf, 188311fa71b9SJerome Forissier mbedtls_x509_subject_alternative_name *san ) 188411fa71b9SJerome Forissier { 188511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 188611fa71b9SJerome Forissier switch( san_buf->tag & 188711fa71b9SJerome Forissier ( MBEDTLS_ASN1_TAG_CLASS_MASK | 188811fa71b9SJerome Forissier MBEDTLS_ASN1_TAG_VALUE_MASK ) ) 188911fa71b9SJerome Forissier { 189011fa71b9SJerome Forissier /* 189111fa71b9SJerome Forissier * otherName 189211fa71b9SJerome Forissier */ 189311fa71b9SJerome Forissier case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ): 189411fa71b9SJerome Forissier { 189511fa71b9SJerome Forissier mbedtls_x509_san_other_name other_name; 189611fa71b9SJerome Forissier 189711fa71b9SJerome Forissier ret = x509_get_other_name( san_buf, &other_name ); 189811fa71b9SJerome Forissier if( ret != 0 ) 189911fa71b9SJerome Forissier return( ret ); 190011fa71b9SJerome Forissier 190111fa71b9SJerome Forissier memset( san, 0, sizeof( mbedtls_x509_subject_alternative_name ) ); 190211fa71b9SJerome Forissier san->type = MBEDTLS_X509_SAN_OTHER_NAME; 190311fa71b9SJerome Forissier memcpy( &san->san.other_name, 190411fa71b9SJerome Forissier &other_name, sizeof( other_name ) ); 190511fa71b9SJerome Forissier 190611fa71b9SJerome Forissier } 190711fa71b9SJerome Forissier break; 190811fa71b9SJerome Forissier 190911fa71b9SJerome Forissier /* 191011fa71b9SJerome Forissier * dNSName 191111fa71b9SJerome Forissier */ 191211fa71b9SJerome Forissier case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ): 191311fa71b9SJerome Forissier { 191411fa71b9SJerome Forissier memset( san, 0, sizeof( mbedtls_x509_subject_alternative_name ) ); 191511fa71b9SJerome Forissier san->type = MBEDTLS_X509_SAN_DNS_NAME; 191611fa71b9SJerome Forissier 191711fa71b9SJerome Forissier memcpy( &san->san.unstructured_name, 191811fa71b9SJerome Forissier san_buf, sizeof( *san_buf ) ); 191911fa71b9SJerome Forissier 192011fa71b9SJerome Forissier } 192111fa71b9SJerome Forissier break; 192211fa71b9SJerome Forissier 192311fa71b9SJerome Forissier /* 192411fa71b9SJerome Forissier * Type not supported 192511fa71b9SJerome Forissier */ 192611fa71b9SJerome Forissier default: 192711fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); 192811fa71b9SJerome Forissier } 192911fa71b9SJerome Forissier return( 0 ); 193011fa71b9SJerome Forissier } 193111fa71b9SJerome Forissier 1932817466cbSJens Wiklander #define PRINT_ITEM(i) \ 1933817466cbSJens Wiklander { \ 1934817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s" i, sep ); \ 1935817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; \ 1936817466cbSJens Wiklander sep = ", "; \ 1937817466cbSJens Wiklander } 1938817466cbSJens Wiklander 1939817466cbSJens Wiklander #define CERT_TYPE(type,name) \ 19405b25c76aSJerome Forissier if( ns_cert_type & (type) ) \ 1941817466cbSJens Wiklander PRINT_ITEM( name ); 1942817466cbSJens Wiklander 1943817466cbSJens Wiklander static int x509_info_cert_type( char **buf, size_t *size, 1944817466cbSJens Wiklander unsigned char ns_cert_type ) 1945817466cbSJens Wiklander { 194611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1947817466cbSJens Wiklander size_t n = *size; 1948817466cbSJens Wiklander char *p = *buf; 1949817466cbSJens Wiklander const char *sep = ""; 1950817466cbSJens Wiklander 1951817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT, "SSL Client" ); 1952817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER, "SSL Server" ); 1953817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL, "Email" ); 1954817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING, "Object Signing" ); 1955817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_RESERVED, "Reserved" ); 1956817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CA, "SSL CA" ); 1957817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA, "Email CA" ); 1958817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA, "Object Signing CA" ); 1959817466cbSJens Wiklander 1960817466cbSJens Wiklander *size = n; 1961817466cbSJens Wiklander *buf = p; 1962817466cbSJens Wiklander 1963817466cbSJens Wiklander return( 0 ); 1964817466cbSJens Wiklander } 1965817466cbSJens Wiklander 1966817466cbSJens Wiklander #define KEY_USAGE(code,name) \ 19675b25c76aSJerome Forissier if( key_usage & (code) ) \ 1968817466cbSJens Wiklander PRINT_ITEM( name ); 1969817466cbSJens Wiklander 1970817466cbSJens Wiklander static int x509_info_key_usage( char **buf, size_t *size, 1971817466cbSJens Wiklander unsigned int key_usage ) 1972817466cbSJens Wiklander { 197311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1974817466cbSJens Wiklander size_t n = *size; 1975817466cbSJens Wiklander char *p = *buf; 1976817466cbSJens Wiklander const char *sep = ""; 1977817466cbSJens Wiklander 1978817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_DIGITAL_SIGNATURE, "Digital Signature" ); 1979817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_NON_REPUDIATION, "Non Repudiation" ); 1980817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_KEY_ENCIPHERMENT, "Key Encipherment" ); 1981817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_DATA_ENCIPHERMENT, "Data Encipherment" ); 1982817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_KEY_AGREEMENT, "Key Agreement" ); 1983817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_KEY_CERT_SIGN, "Key Cert Sign" ); 1984817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_CRL_SIGN, "CRL Sign" ); 1985817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_ENCIPHER_ONLY, "Encipher Only" ); 1986817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_DECIPHER_ONLY, "Decipher Only" ); 1987817466cbSJens Wiklander 1988817466cbSJens Wiklander *size = n; 1989817466cbSJens Wiklander *buf = p; 1990817466cbSJens Wiklander 1991817466cbSJens Wiklander return( 0 ); 1992817466cbSJens Wiklander } 1993817466cbSJens Wiklander 1994817466cbSJens Wiklander static int x509_info_ext_key_usage( char **buf, size_t *size, 1995817466cbSJens Wiklander const mbedtls_x509_sequence *extended_key_usage ) 1996817466cbSJens Wiklander { 199711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1998817466cbSJens Wiklander const char *desc; 1999817466cbSJens Wiklander size_t n = *size; 2000817466cbSJens Wiklander char *p = *buf; 2001817466cbSJens Wiklander const mbedtls_x509_sequence *cur = extended_key_usage; 2002817466cbSJens Wiklander const char *sep = ""; 2003817466cbSJens Wiklander 2004817466cbSJens Wiklander while( cur != NULL ) 2005817466cbSJens Wiklander { 2006817466cbSJens Wiklander if( mbedtls_oid_get_extended_key_usage( &cur->buf, &desc ) != 0 ) 2007817466cbSJens Wiklander desc = "???"; 2008817466cbSJens Wiklander 2009817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); 2010817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2011817466cbSJens Wiklander 2012817466cbSJens Wiklander sep = ", "; 2013817466cbSJens Wiklander 2014817466cbSJens Wiklander cur = cur->next; 2015817466cbSJens Wiklander } 2016817466cbSJens Wiklander 2017817466cbSJens Wiklander *size = n; 2018817466cbSJens Wiklander *buf = p; 2019817466cbSJens Wiklander 2020817466cbSJens Wiklander return( 0 ); 2021817466cbSJens Wiklander } 2022817466cbSJens Wiklander 202311fa71b9SJerome Forissier static int x509_info_cert_policies( char **buf, size_t *size, 202411fa71b9SJerome Forissier const mbedtls_x509_sequence *certificate_policies ) 202511fa71b9SJerome Forissier { 202611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 202711fa71b9SJerome Forissier const char *desc; 202811fa71b9SJerome Forissier size_t n = *size; 202911fa71b9SJerome Forissier char *p = *buf; 203011fa71b9SJerome Forissier const mbedtls_x509_sequence *cur = certificate_policies; 203111fa71b9SJerome Forissier const char *sep = ""; 203211fa71b9SJerome Forissier 203311fa71b9SJerome Forissier while( cur != NULL ) 203411fa71b9SJerome Forissier { 203511fa71b9SJerome Forissier if( mbedtls_oid_get_certificate_policies( &cur->buf, &desc ) != 0 ) 203611fa71b9SJerome Forissier desc = "???"; 203711fa71b9SJerome Forissier 203811fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); 203911fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 204011fa71b9SJerome Forissier 204111fa71b9SJerome Forissier sep = ", "; 204211fa71b9SJerome Forissier 204311fa71b9SJerome Forissier cur = cur->next; 204411fa71b9SJerome Forissier } 204511fa71b9SJerome Forissier 204611fa71b9SJerome Forissier *size = n; 204711fa71b9SJerome Forissier *buf = p; 204811fa71b9SJerome Forissier 204911fa71b9SJerome Forissier return( 0 ); 205011fa71b9SJerome Forissier } 205111fa71b9SJerome Forissier 2052817466cbSJens Wiklander /* 2053817466cbSJens Wiklander * Return an informational string about the certificate. 2054817466cbSJens Wiklander */ 2055817466cbSJens Wiklander #define BEFORE_COLON 18 2056817466cbSJens Wiklander #define BC "18" 2057817466cbSJens Wiklander int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, 2058817466cbSJens Wiklander const mbedtls_x509_crt *crt ) 2059817466cbSJens Wiklander { 206011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2061817466cbSJens Wiklander size_t n; 2062817466cbSJens Wiklander char *p; 2063817466cbSJens Wiklander char key_size_str[BEFORE_COLON]; 2064817466cbSJens Wiklander 2065817466cbSJens Wiklander p = buf; 2066817466cbSJens Wiklander n = size; 2067817466cbSJens Wiklander 2068817466cbSJens Wiklander if( NULL == crt ) 2069817466cbSJens Wiklander { 2070817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); 2071817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2072817466cbSJens Wiklander 2073817466cbSJens Wiklander return( (int) ( size - n ) ); 2074817466cbSJens Wiklander } 2075817466cbSJens Wiklander 2076817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", 2077817466cbSJens Wiklander prefix, crt->version ); 2078817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2079817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%sserial number : ", 2080817466cbSJens Wiklander prefix ); 2081817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2082817466cbSJens Wiklander 2083817466cbSJens Wiklander ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); 2084817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2085817466cbSJens Wiklander 2086817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); 2087817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2088817466cbSJens Wiklander ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); 2089817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2090817466cbSJens Wiklander 2091817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); 2092817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2093817466cbSJens Wiklander ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); 2094817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2095817466cbSJens Wiklander 2096817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ 2097817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix, 2098817466cbSJens Wiklander crt->valid_from.year, crt->valid_from.mon, 2099817466cbSJens Wiklander crt->valid_from.day, crt->valid_from.hour, 2100817466cbSJens Wiklander crt->valid_from.min, crt->valid_from.sec ); 2101817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2102817466cbSJens Wiklander 2103817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ 2104817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix, 2105817466cbSJens Wiklander crt->valid_to.year, crt->valid_to.mon, 2106817466cbSJens Wiklander crt->valid_to.day, crt->valid_to.hour, 2107817466cbSJens Wiklander crt->valid_to.min, crt->valid_to.sec ); 2108817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2109817466cbSJens Wiklander 2110817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); 2111817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2112817466cbSJens Wiklander 2113817466cbSJens Wiklander ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, 2114817466cbSJens Wiklander crt->sig_md, crt->sig_opts ); 2115817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2116817466cbSJens Wiklander 2117817466cbSJens Wiklander /* Key size */ 2118817466cbSJens Wiklander if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, 2119817466cbSJens Wiklander mbedtls_pk_get_name( &crt->pk ) ) ) != 0 ) 2120817466cbSJens Wiklander { 2121817466cbSJens Wiklander return( ret ); 2122817466cbSJens Wiklander } 2123817466cbSJens Wiklander 2124817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, 2125817466cbSJens Wiklander (int) mbedtls_pk_get_bitlen( &crt->pk ) ); 2126817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2127817466cbSJens Wiklander 2128817466cbSJens Wiklander /* 2129817466cbSJens Wiklander * Optional extensions 2130817466cbSJens Wiklander */ 2131817466cbSJens Wiklander 2132817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS ) 2133817466cbSJens Wiklander { 2134817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, 2135817466cbSJens Wiklander crt->ca_istrue ? "true" : "false" ); 2136817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2137817466cbSJens Wiklander 2138817466cbSJens Wiklander if( crt->max_pathlen > 0 ) 2139817466cbSJens Wiklander { 2140817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", crt->max_pathlen - 1 ); 2141817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2142817466cbSJens Wiklander } 2143817466cbSJens Wiklander } 2144817466cbSJens Wiklander 2145817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) 2146817466cbSJens Wiklander { 2147817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%ssubject alt name :", prefix ); 2148817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2149817466cbSJens Wiklander 2150817466cbSJens Wiklander if( ( ret = x509_info_subject_alt_name( &p, &n, 215111fa71b9SJerome Forissier &crt->subject_alt_names, 215211fa71b9SJerome Forissier prefix ) ) != 0 ) 2153817466cbSJens Wiklander return( ret ); 2154817466cbSJens Wiklander } 2155817466cbSJens Wiklander 2156817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) 2157817466cbSJens Wiklander { 2158817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); 2159817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2160817466cbSJens Wiklander 2161817466cbSJens Wiklander if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 ) 2162817466cbSJens Wiklander return( ret ); 2163817466cbSJens Wiklander } 2164817466cbSJens Wiklander 2165817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) 2166817466cbSJens Wiklander { 2167817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%skey usage : ", prefix ); 2168817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2169817466cbSJens Wiklander 2170817466cbSJens Wiklander if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 ) 2171817466cbSJens Wiklander return( ret ); 2172817466cbSJens Wiklander } 2173817466cbSJens Wiklander 2174817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) 2175817466cbSJens Wiklander { 2176817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sext key usage : ", prefix ); 2177817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2178817466cbSJens Wiklander 2179817466cbSJens Wiklander if( ( ret = x509_info_ext_key_usage( &p, &n, 2180817466cbSJens Wiklander &crt->ext_key_usage ) ) != 0 ) 2181817466cbSJens Wiklander return( ret ); 2182817466cbSJens Wiklander } 2183817466cbSJens Wiklander 218411fa71b9SJerome Forissier if( crt->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES ) 218511fa71b9SJerome Forissier { 218611fa71b9SJerome Forissier ret = mbedtls_snprintf( p, n, "\n%scertificate policies : ", prefix ); 218711fa71b9SJerome Forissier MBEDTLS_X509_SAFE_SNPRINTF; 218811fa71b9SJerome Forissier 218911fa71b9SJerome Forissier if( ( ret = x509_info_cert_policies( &p, &n, 219011fa71b9SJerome Forissier &crt->certificate_policies ) ) != 0 ) 219111fa71b9SJerome Forissier return( ret ); 219211fa71b9SJerome Forissier } 219311fa71b9SJerome Forissier 2194817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n" ); 2195817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2196817466cbSJens Wiklander 2197817466cbSJens Wiklander return( (int) ( size - n ) ); 2198817466cbSJens Wiklander } 2199817466cbSJens Wiklander 2200817466cbSJens Wiklander struct x509_crt_verify_string { 2201817466cbSJens Wiklander int code; 2202817466cbSJens Wiklander const char *string; 2203817466cbSJens Wiklander }; 2204817466cbSJens Wiklander 2205817466cbSJens Wiklander static const struct x509_crt_verify_string x509_crt_verify_strings[] = { 2206817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_EXPIRED, "The certificate validity has expired" }, 2207817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_REVOKED, "The certificate has been revoked (is on a CRL)" }, 2208817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_CN_MISMATCH, "The certificate Common Name (CN) does not match with the expected CN" }, 2209817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_NOT_TRUSTED, "The certificate is not correctly signed by the trusted CA" }, 2210817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_NOT_TRUSTED, "The CRL is not correctly signed by the trusted CA" }, 2211817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_EXPIRED, "The CRL is expired" }, 2212817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_MISSING, "Certificate was missing" }, 2213817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_SKIP_VERIFY, "Certificate verification was skipped" }, 2214817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_OTHER, "Other reason (can be used by verify callback)" }, 2215817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_FUTURE, "The certificate validity starts in the future" }, 2216817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_FUTURE, "The CRL is from the future" }, 2217817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_KEY_USAGE, "Usage does not match the keyUsage extension" }, 2218817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_EXT_KEY_USAGE, "Usage does not match the extendedKeyUsage extension" }, 2219817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_NS_CERT_TYPE, "Usage does not match the nsCertType extension" }, 2220817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_BAD_MD, "The certificate is signed with an unacceptable hash." }, 2221817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_BAD_PK, "The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, 2222817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_BAD_KEY, "The certificate is signed with an unacceptable key (eg bad curve, RSA too short)." }, 2223817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_BAD_MD, "The CRL is signed with an unacceptable hash." }, 2224817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_BAD_PK, "The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, 2225817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_BAD_KEY, "The CRL is signed with an unacceptable key (eg bad curve, RSA too short)." }, 2226817466cbSJens Wiklander { 0, NULL } 2227817466cbSJens Wiklander }; 2228817466cbSJens Wiklander 2229817466cbSJens Wiklander int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, 2230817466cbSJens Wiklander uint32_t flags ) 2231817466cbSJens Wiklander { 223211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2233817466cbSJens Wiklander const struct x509_crt_verify_string *cur; 2234817466cbSJens Wiklander char *p = buf; 2235817466cbSJens Wiklander size_t n = size; 2236817466cbSJens Wiklander 2237817466cbSJens Wiklander for( cur = x509_crt_verify_strings; cur->string != NULL ; cur++ ) 2238817466cbSJens Wiklander { 2239817466cbSJens Wiklander if( ( flags & cur->code ) == 0 ) 2240817466cbSJens Wiklander continue; 2241817466cbSJens Wiklander 2242817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s%s\n", prefix, cur->string ); 2243817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2244817466cbSJens Wiklander flags ^= cur->code; 2245817466cbSJens Wiklander } 2246817466cbSJens Wiklander 2247817466cbSJens Wiklander if( flags != 0 ) 2248817466cbSJens Wiklander { 2249817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%sUnknown reason " 2250817466cbSJens Wiklander "(this should not happen)\n", prefix ); 2251817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 2252817466cbSJens Wiklander } 2253817466cbSJens Wiklander 2254817466cbSJens Wiklander return( (int) ( size - n ) ); 2255817466cbSJens Wiklander } 2256817466cbSJens Wiklander 2257817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) 2258817466cbSJens Wiklander int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, 2259817466cbSJens Wiklander unsigned int usage ) 2260817466cbSJens Wiklander { 2261817466cbSJens Wiklander unsigned int usage_must, usage_may; 2262817466cbSJens Wiklander unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY 2263817466cbSJens Wiklander | MBEDTLS_X509_KU_DECIPHER_ONLY; 2264817466cbSJens Wiklander 2265817466cbSJens Wiklander if( ( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) == 0 ) 2266817466cbSJens Wiklander return( 0 ); 2267817466cbSJens Wiklander 2268817466cbSJens Wiklander usage_must = usage & ~may_mask; 2269817466cbSJens Wiklander 2270817466cbSJens Wiklander if( ( ( crt->key_usage & ~may_mask ) & usage_must ) != usage_must ) 2271817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 2272817466cbSJens Wiklander 2273817466cbSJens Wiklander usage_may = usage & may_mask; 2274817466cbSJens Wiklander 2275817466cbSJens Wiklander if( ( ( crt->key_usage & may_mask ) | usage_may ) != usage_may ) 2276817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 2277817466cbSJens Wiklander 2278817466cbSJens Wiklander return( 0 ); 2279817466cbSJens Wiklander } 2280817466cbSJens Wiklander #endif 2281817466cbSJens Wiklander 2282817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) 2283817466cbSJens Wiklander int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, 2284817466cbSJens Wiklander const char *usage_oid, 2285817466cbSJens Wiklander size_t usage_len ) 2286817466cbSJens Wiklander { 2287817466cbSJens Wiklander const mbedtls_x509_sequence *cur; 2288817466cbSJens Wiklander 2289817466cbSJens Wiklander /* Extension is not mandatory, absent means no restriction */ 2290817466cbSJens Wiklander if( ( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) 2291817466cbSJens Wiklander return( 0 ); 2292817466cbSJens Wiklander 2293817466cbSJens Wiklander /* 2294817466cbSJens Wiklander * Look for the requested usage (or wildcard ANY) in our list 2295817466cbSJens Wiklander */ 2296817466cbSJens Wiklander for( cur = &crt->ext_key_usage; cur != NULL; cur = cur->next ) 2297817466cbSJens Wiklander { 2298817466cbSJens Wiklander const mbedtls_x509_buf *cur_oid = &cur->buf; 2299817466cbSJens Wiklander 2300817466cbSJens Wiklander if( cur_oid->len == usage_len && 2301817466cbSJens Wiklander memcmp( cur_oid->p, usage_oid, usage_len ) == 0 ) 2302817466cbSJens Wiklander { 2303817466cbSJens Wiklander return( 0 ); 2304817466cbSJens Wiklander } 2305817466cbSJens Wiklander 2306817466cbSJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid ) == 0 ) 2307817466cbSJens Wiklander return( 0 ); 2308817466cbSJens Wiklander } 2309817466cbSJens Wiklander 2310817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 2311817466cbSJens Wiklander } 2312817466cbSJens Wiklander #endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ 2313817466cbSJens Wiklander 2314817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 2315817466cbSJens Wiklander /* 2316817466cbSJens Wiklander * Return 1 if the certificate is revoked, or 0 otherwise. 2317817466cbSJens Wiklander */ 2318817466cbSJens Wiklander int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ) 2319817466cbSJens Wiklander { 2320817466cbSJens Wiklander const mbedtls_x509_crl_entry *cur = &crl->entry; 2321817466cbSJens Wiklander 2322817466cbSJens Wiklander while( cur != NULL && cur->serial.len != 0 ) 2323817466cbSJens Wiklander { 2324817466cbSJens Wiklander if( crt->serial.len == cur->serial.len && 2325817466cbSJens Wiklander memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 ) 2326817466cbSJens Wiklander { 2327817466cbSJens Wiklander return( 1 ); 2328817466cbSJens Wiklander } 2329817466cbSJens Wiklander 2330817466cbSJens Wiklander cur = cur->next; 2331817466cbSJens Wiklander } 2332817466cbSJens Wiklander 2333817466cbSJens Wiklander return( 0 ); 2334817466cbSJens Wiklander } 2335817466cbSJens Wiklander 2336817466cbSJens Wiklander /* 2337817466cbSJens Wiklander * Check that the given certificate is not revoked according to the CRL. 23383d3b0591SJens Wiklander * Skip validation if no CRL for the given CA is present. 2339817466cbSJens Wiklander */ 2340817466cbSJens Wiklander static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, 2341817466cbSJens Wiklander mbedtls_x509_crl *crl_list, 2342817466cbSJens Wiklander const mbedtls_x509_crt_profile *profile ) 2343817466cbSJens Wiklander { 2344817466cbSJens Wiklander int flags = 0; 2345817466cbSJens Wiklander unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 2346817466cbSJens Wiklander const mbedtls_md_info_t *md_info; 2347817466cbSJens Wiklander 2348817466cbSJens Wiklander if( ca == NULL ) 2349817466cbSJens Wiklander return( flags ); 2350817466cbSJens Wiklander 2351817466cbSJens Wiklander while( crl_list != NULL ) 2352817466cbSJens Wiklander { 2353817466cbSJens Wiklander if( crl_list->version == 0 || 23543d3b0591SJens Wiklander x509_name_cmp( &crl_list->issuer, &ca->subject ) != 0 ) 2355817466cbSJens Wiklander { 2356817466cbSJens Wiklander crl_list = crl_list->next; 2357817466cbSJens Wiklander continue; 2358817466cbSJens Wiklander } 2359817466cbSJens Wiklander 2360817466cbSJens Wiklander /* 2361817466cbSJens Wiklander * Check if the CA is configured to sign CRLs 2362817466cbSJens Wiklander */ 2363817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) 23643d3b0591SJens Wiklander if( mbedtls_x509_crt_check_key_usage( ca, 23653d3b0591SJens Wiklander MBEDTLS_X509_KU_CRL_SIGN ) != 0 ) 2366817466cbSJens Wiklander { 2367817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 2368817466cbSJens Wiklander break; 2369817466cbSJens Wiklander } 2370817466cbSJens Wiklander #endif 2371817466cbSJens Wiklander 2372817466cbSJens Wiklander /* 2373817466cbSJens Wiklander * Check if CRL is correctly signed by the trusted CA 2374817466cbSJens Wiklander */ 2375817466cbSJens Wiklander if( x509_profile_check_md_alg( profile, crl_list->sig_md ) != 0 ) 2376817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_MD; 2377817466cbSJens Wiklander 2378817466cbSJens Wiklander if( x509_profile_check_pk_alg( profile, crl_list->sig_pk ) != 0 ) 2379817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_PK; 2380817466cbSJens Wiklander 2381817466cbSJens Wiklander md_info = mbedtls_md_info_from_type( crl_list->sig_md ); 23823d3b0591SJens Wiklander if( mbedtls_md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash ) != 0 ) 2383817466cbSJens Wiklander { 23843d3b0591SJens Wiklander /* Note: this can't happen except after an internal error */ 2385817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 2386817466cbSJens Wiklander break; 2387817466cbSJens Wiklander } 2388817466cbSJens Wiklander 23893d3b0591SJens Wiklander if( x509_profile_check_key( profile, &ca->pk ) != 0 ) 2390817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 2391817466cbSJens Wiklander 2392817466cbSJens Wiklander if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, &ca->pk, 2393817466cbSJens Wiklander crl_list->sig_md, hash, mbedtls_md_get_size( md_info ), 2394817466cbSJens Wiklander crl_list->sig.p, crl_list->sig.len ) != 0 ) 2395817466cbSJens Wiklander { 2396817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 2397817466cbSJens Wiklander break; 2398817466cbSJens Wiklander } 2399817466cbSJens Wiklander 2400817466cbSJens Wiklander /* 2401817466cbSJens Wiklander * Check for validity of CRL (Do not drop out) 2402817466cbSJens Wiklander */ 2403817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &crl_list->next_update ) ) 2404817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_EXPIRED; 2405817466cbSJens Wiklander 2406817466cbSJens Wiklander if( mbedtls_x509_time_is_future( &crl_list->this_update ) ) 2407817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_FUTURE; 2408817466cbSJens Wiklander 2409817466cbSJens Wiklander /* 2410817466cbSJens Wiklander * Check if certificate is revoked 2411817466cbSJens Wiklander */ 2412817466cbSJens Wiklander if( mbedtls_x509_crt_is_revoked( crt, crl_list ) ) 2413817466cbSJens Wiklander { 2414817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_REVOKED; 2415817466cbSJens Wiklander break; 2416817466cbSJens Wiklander } 2417817466cbSJens Wiklander 2418817466cbSJens Wiklander crl_list = crl_list->next; 2419817466cbSJens Wiklander } 2420817466cbSJens Wiklander 2421817466cbSJens Wiklander return( flags ); 2422817466cbSJens Wiklander } 2423817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRL_PARSE_C */ 2424817466cbSJens Wiklander 2425817466cbSJens Wiklander /* 24263d3b0591SJens Wiklander * Check the signature of a certificate by its parent 2427817466cbSJens Wiklander */ 24283d3b0591SJens Wiklander static int x509_crt_check_signature( const mbedtls_x509_crt *child, 24293d3b0591SJens Wiklander mbedtls_x509_crt *parent, 24303d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx ) 2431817466cbSJens Wiklander { 24323d3b0591SJens Wiklander unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 243311fa71b9SJerome Forissier size_t hash_len; 243411fa71b9SJerome Forissier #if !defined(MBEDTLS_USE_PSA_CRYPTO) 243511fa71b9SJerome Forissier const mbedtls_md_info_t *md_info; 24363d3b0591SJens Wiklander md_info = mbedtls_md_info_from_type( child->sig_md ); 243711fa71b9SJerome Forissier hash_len = mbedtls_md_get_size( md_info ); 243811fa71b9SJerome Forissier 243911fa71b9SJerome Forissier /* Note: hash errors can happen only after an internal error */ 24403d3b0591SJens Wiklander if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) 244111fa71b9SJerome Forissier return( -1 ); 244211fa71b9SJerome Forissier #else 244311fa71b9SJerome Forissier psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT; 244411fa71b9SJerome Forissier psa_algorithm_t hash_alg = mbedtls_psa_translate_md( child->sig_md ); 244511fa71b9SJerome Forissier 244611fa71b9SJerome Forissier if( psa_hash_setup( &hash_operation, hash_alg ) != PSA_SUCCESS ) 244711fa71b9SJerome Forissier return( -1 ); 244811fa71b9SJerome Forissier 244911fa71b9SJerome Forissier if( psa_hash_update( &hash_operation, child->tbs.p, child->tbs.len ) 245011fa71b9SJerome Forissier != PSA_SUCCESS ) 2451817466cbSJens Wiklander { 2452817466cbSJens Wiklander return( -1 ); 2453817466cbSJens Wiklander } 2454817466cbSJens Wiklander 245511fa71b9SJerome Forissier if( psa_hash_finish( &hash_operation, hash, sizeof( hash ), &hash_len ) 245611fa71b9SJerome Forissier != PSA_SUCCESS ) 245711fa71b9SJerome Forissier { 245811fa71b9SJerome Forissier return( -1 ); 245911fa71b9SJerome Forissier } 246011fa71b9SJerome Forissier #endif /* MBEDTLS_USE_PSA_CRYPTO */ 24613d3b0591SJens Wiklander /* Skip expensive computation on obvious mismatch */ 24623d3b0591SJens Wiklander if( ! mbedtls_pk_can_do( &parent->pk, child->sig_pk ) ) 2463817466cbSJens Wiklander return( -1 ); 2464817466cbSJens Wiklander 24653d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 24663d3b0591SJens Wiklander if( rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA ) 2467817466cbSJens Wiklander { 24683d3b0591SJens Wiklander return( mbedtls_pk_verify_restartable( &parent->pk, 246911fa71b9SJerome Forissier child->sig_md, hash, hash_len, 24703d3b0591SJens Wiklander child->sig.p, child->sig.len, &rs_ctx->pk ) ); 2471817466cbSJens Wiklander } 24723d3b0591SJens Wiklander #else 24733d3b0591SJens Wiklander (void) rs_ctx; 24743d3b0591SJens Wiklander #endif 2475817466cbSJens Wiklander 24763d3b0591SJens Wiklander return( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, 247711fa71b9SJerome Forissier child->sig_md, hash, hash_len, 24783d3b0591SJens Wiklander child->sig.p, child->sig.len ) ); 2479817466cbSJens Wiklander } 2480817466cbSJens Wiklander 2481817466cbSJens Wiklander /* 2482817466cbSJens Wiklander * Check if 'parent' is a suitable parent (signing CA) for 'child'. 2483817466cbSJens Wiklander * Return 0 if yes, -1 if not. 2484817466cbSJens Wiklander * 2485817466cbSJens Wiklander * top means parent is a locally-trusted certificate 2486817466cbSJens Wiklander */ 2487817466cbSJens Wiklander static int x509_crt_check_parent( const mbedtls_x509_crt *child, 2488817466cbSJens Wiklander const mbedtls_x509_crt *parent, 24893d3b0591SJens Wiklander int top ) 2490817466cbSJens Wiklander { 2491817466cbSJens Wiklander int need_ca_bit; 2492817466cbSJens Wiklander 2493817466cbSJens Wiklander /* Parent must be the issuer */ 2494817466cbSJens Wiklander if( x509_name_cmp( &child->issuer, &parent->subject ) != 0 ) 2495817466cbSJens Wiklander return( -1 ); 2496817466cbSJens Wiklander 2497817466cbSJens Wiklander /* Parent must have the basicConstraints CA bit set as a general rule */ 2498817466cbSJens Wiklander need_ca_bit = 1; 2499817466cbSJens Wiklander 2500817466cbSJens Wiklander /* Exception: v1/v2 certificates that are locally trusted. */ 2501817466cbSJens Wiklander if( top && parent->version < 3 ) 2502817466cbSJens Wiklander need_ca_bit = 0; 2503817466cbSJens Wiklander 2504817466cbSJens Wiklander if( need_ca_bit && ! parent->ca_istrue ) 2505817466cbSJens Wiklander return( -1 ); 2506817466cbSJens Wiklander 2507817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) 2508817466cbSJens Wiklander if( need_ca_bit && 2509817466cbSJens Wiklander mbedtls_x509_crt_check_key_usage( parent, MBEDTLS_X509_KU_KEY_CERT_SIGN ) != 0 ) 2510817466cbSJens Wiklander { 2511817466cbSJens Wiklander return( -1 ); 2512817466cbSJens Wiklander } 2513817466cbSJens Wiklander #endif 2514817466cbSJens Wiklander 2515817466cbSJens Wiklander return( 0 ); 2516817466cbSJens Wiklander } 2517817466cbSJens Wiklander 25183d3b0591SJens Wiklander /* 25193d3b0591SJens Wiklander * Find a suitable parent for child in candidates, or return NULL. 25203d3b0591SJens Wiklander * 25213d3b0591SJens Wiklander * Here suitable is defined as: 25223d3b0591SJens Wiklander * 1. subject name matches child's issuer 25233d3b0591SJens Wiklander * 2. if necessary, the CA bit is set and key usage allows signing certs 25243d3b0591SJens Wiklander * 3. for trusted roots, the signature is correct 25253d3b0591SJens Wiklander * (for intermediates, the signature is checked and the result reported) 25263d3b0591SJens Wiklander * 4. pathlen constraints are satisfied 25273d3b0591SJens Wiklander * 25283d3b0591SJens Wiklander * If there's a suitable candidate which is also time-valid, return the first 25293d3b0591SJens Wiklander * such. Otherwise, return the first suitable candidate (or NULL if there is 25303d3b0591SJens Wiklander * none). 25313d3b0591SJens Wiklander * 25323d3b0591SJens Wiklander * The rationale for this rule is that someone could have a list of trusted 25333d3b0591SJens Wiklander * roots with two versions on the same root with different validity periods. 25343d3b0591SJens Wiklander * (At least one user reported having such a list and wanted it to just work.) 25353d3b0591SJens Wiklander * The reason we don't just require time-validity is that generally there is 25363d3b0591SJens Wiklander * only one version, and if it's expired we want the flags to state that 25373d3b0591SJens Wiklander * rather than NOT_TRUSTED, as would be the case if we required it here. 25383d3b0591SJens Wiklander * 25393d3b0591SJens Wiklander * The rationale for rule 3 (signature for trusted roots) is that users might 25403d3b0591SJens Wiklander * have two versions of the same CA with different keys in their list, and the 25413d3b0591SJens Wiklander * way we select the correct one is by checking the signature (as we don't 25423d3b0591SJens Wiklander * rely on key identifier extensions). (This is one way users might choose to 25433d3b0591SJens Wiklander * handle key rollover, another relies on self-issued certs, see [SIRO].) 25443d3b0591SJens Wiklander * 25453d3b0591SJens Wiklander * Arguments: 25463d3b0591SJens Wiklander * - [in] child: certificate for which we're looking for a parent 25473d3b0591SJens Wiklander * - [in] candidates: chained list of potential parents 25483d3b0591SJens Wiklander * - [out] r_parent: parent found (or NULL) 25493d3b0591SJens Wiklander * - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0 25503d3b0591SJens Wiklander * - [in] top: 1 if candidates consists of trusted roots, ie we're at the top 25513d3b0591SJens Wiklander * of the chain, 0 otherwise 25523d3b0591SJens Wiklander * - [in] path_cnt: number of intermediates seen so far 25533d3b0591SJens Wiklander * - [in] self_cnt: number of self-signed intermediates seen so far 25543d3b0591SJens Wiklander * (will never be greater than path_cnt) 25553d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 25563d3b0591SJens Wiklander * 25573d3b0591SJens Wiklander * Return value: 25583d3b0591SJens Wiklander * - 0 on success 25593d3b0591SJens Wiklander * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise 25603d3b0591SJens Wiklander */ 25613d3b0591SJens Wiklander static int x509_crt_find_parent_in( 25623d3b0591SJens Wiklander mbedtls_x509_crt *child, 25633d3b0591SJens Wiklander mbedtls_x509_crt *candidates, 25643d3b0591SJens Wiklander mbedtls_x509_crt **r_parent, 25653d3b0591SJens Wiklander int *r_signature_is_good, 25663d3b0591SJens Wiklander int top, 25673d3b0591SJens Wiklander unsigned path_cnt, 25683d3b0591SJens Wiklander unsigned self_cnt, 25693d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx ) 2570817466cbSJens Wiklander { 257111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 25723d3b0591SJens Wiklander mbedtls_x509_crt *parent, *fallback_parent; 257311fa71b9SJerome Forissier int signature_is_good = 0, fallback_signature_is_good; 2574817466cbSJens Wiklander 25753d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 25763d3b0591SJens Wiklander /* did we have something in progress? */ 25773d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->parent != NULL ) 2578817466cbSJens Wiklander { 25793d3b0591SJens Wiklander /* restore saved state */ 25803d3b0591SJens Wiklander parent = rs_ctx->parent; 25813d3b0591SJens Wiklander fallback_parent = rs_ctx->fallback_parent; 25823d3b0591SJens Wiklander fallback_signature_is_good = rs_ctx->fallback_signature_is_good; 25833d3b0591SJens Wiklander 25843d3b0591SJens Wiklander /* clear saved state */ 25853d3b0591SJens Wiklander rs_ctx->parent = NULL; 25863d3b0591SJens Wiklander rs_ctx->fallback_parent = NULL; 25873d3b0591SJens Wiklander rs_ctx->fallback_signature_is_good = 0; 25883d3b0591SJens Wiklander 25893d3b0591SJens Wiklander /* resume where we left */ 25903d3b0591SJens Wiklander goto check_signature; 2591817466cbSJens Wiklander } 25923d3b0591SJens Wiklander #endif 2593817466cbSJens Wiklander 25943d3b0591SJens Wiklander fallback_parent = NULL; 25953d3b0591SJens Wiklander fallback_signature_is_good = 0; 25963d3b0591SJens Wiklander 25973d3b0591SJens Wiklander for( parent = candidates; parent != NULL; parent = parent->next ) 2598817466cbSJens Wiklander { 25993d3b0591SJens Wiklander /* basic parenting skills (name, CA bit, key usage) */ 26003d3b0591SJens Wiklander if( x509_crt_check_parent( child, parent, top ) != 0 ) 2601817466cbSJens Wiklander continue; 2602817466cbSJens Wiklander 26033d3b0591SJens Wiklander /* +1 because stored max_pathlen is 1 higher that the actual value */ 26043d3b0591SJens Wiklander if( parent->max_pathlen > 0 && 26053d3b0591SJens Wiklander (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt ) 2606817466cbSJens Wiklander { 2607817466cbSJens Wiklander continue; 2608817466cbSJens Wiklander } 2609817466cbSJens Wiklander 26103d3b0591SJens Wiklander /* Signature */ 26113d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 26123d3b0591SJens Wiklander check_signature: 26133d3b0591SJens Wiklander #endif 26143d3b0591SJens Wiklander ret = x509_crt_check_signature( child, parent, rs_ctx ); 2615817466cbSJens Wiklander 26163d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 26173d3b0591SJens Wiklander if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) 2618817466cbSJens Wiklander { 26193d3b0591SJens Wiklander /* save state */ 26203d3b0591SJens Wiklander rs_ctx->parent = parent; 26213d3b0591SJens Wiklander rs_ctx->fallback_parent = fallback_parent; 26223d3b0591SJens Wiklander rs_ctx->fallback_signature_is_good = fallback_signature_is_good; 26233d3b0591SJens Wiklander 26243d3b0591SJens Wiklander return( ret ); 26253d3b0591SJens Wiklander } 26263d3b0591SJens Wiklander #else 26273d3b0591SJens Wiklander (void) ret; 26283d3b0591SJens Wiklander #endif 26293d3b0591SJens Wiklander 26303d3b0591SJens Wiklander signature_is_good = ret == 0; 26313d3b0591SJens Wiklander if( top && ! signature_is_good ) 26323d3b0591SJens Wiklander continue; 26333d3b0591SJens Wiklander 26343d3b0591SJens Wiklander /* optional time check */ 26353d3b0591SJens Wiklander if( mbedtls_x509_time_is_past( &parent->valid_to ) || 26363d3b0591SJens Wiklander mbedtls_x509_time_is_future( &parent->valid_from ) ) 26373d3b0591SJens Wiklander { 26383d3b0591SJens Wiklander if( fallback_parent == NULL ) 26393d3b0591SJens Wiklander { 26403d3b0591SJens Wiklander fallback_parent = parent; 26413d3b0591SJens Wiklander fallback_signature_is_good = signature_is_good; 26423d3b0591SJens Wiklander } 2643817466cbSJens Wiklander 2644817466cbSJens Wiklander continue; 2645817466cbSJens Wiklander } 2646817466cbSJens Wiklander 26475b25c76aSJerome Forissier *r_parent = parent; 26485b25c76aSJerome Forissier *r_signature_is_good = signature_is_good; 26495b25c76aSJerome Forissier 2650817466cbSJens Wiklander break; 2651817466cbSJens Wiklander } 2652817466cbSJens Wiklander 26535b25c76aSJerome Forissier if( parent == NULL ) 2654817466cbSJens Wiklander { 26553d3b0591SJens Wiklander *r_parent = fallback_parent; 26563d3b0591SJens Wiklander *r_signature_is_good = fallback_signature_is_good; 2657817466cbSJens Wiklander } 2658817466cbSJens Wiklander 2659817466cbSJens Wiklander return( 0 ); 2660817466cbSJens Wiklander } 2661817466cbSJens Wiklander 26623d3b0591SJens Wiklander /* 26633d3b0591SJens Wiklander * Find a parent in trusted CAs or the provided chain, or return NULL. 26643d3b0591SJens Wiklander * 26653d3b0591SJens Wiklander * Searches in trusted CAs first, and return the first suitable parent found 26663d3b0591SJens Wiklander * (see find_parent_in() for definition of suitable). 26673d3b0591SJens Wiklander * 26683d3b0591SJens Wiklander * Arguments: 26693d3b0591SJens Wiklander * - [in] child: certificate for which we're looking for a parent, followed 26703d3b0591SJens Wiklander * by a chain of possible intermediates 26713d3b0591SJens Wiklander * - [in] trust_ca: list of locally trusted certificates 26723d3b0591SJens Wiklander * - [out] parent: parent found (or NULL) 26733d3b0591SJens Wiklander * - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0 26743d3b0591SJens Wiklander * - [out] signature_is_good: 1 if child signature by parent is valid, or 0 26753d3b0591SJens Wiklander * - [in] path_cnt: number of links in the chain so far (EE -> ... -> child) 26763d3b0591SJens Wiklander * - [in] self_cnt: number of self-signed certs in the chain so far 26773d3b0591SJens Wiklander * (will always be no greater than path_cnt) 26783d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 26793d3b0591SJens Wiklander * 26803d3b0591SJens Wiklander * Return value: 26813d3b0591SJens Wiklander * - 0 on success 26823d3b0591SJens Wiklander * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise 26833d3b0591SJens Wiklander */ 26843d3b0591SJens Wiklander static int x509_crt_find_parent( 26853d3b0591SJens Wiklander mbedtls_x509_crt *child, 26863d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 26873d3b0591SJens Wiklander mbedtls_x509_crt **parent, 26883d3b0591SJens Wiklander int *parent_is_trusted, 26893d3b0591SJens Wiklander int *signature_is_good, 26903d3b0591SJens Wiklander unsigned path_cnt, 26913d3b0591SJens Wiklander unsigned self_cnt, 26923d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx ) 2693817466cbSJens Wiklander { 269411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 26953d3b0591SJens Wiklander mbedtls_x509_crt *search_list; 2696817466cbSJens Wiklander 26973d3b0591SJens Wiklander *parent_is_trusted = 1; 2698817466cbSJens Wiklander 26993d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 27003d3b0591SJens Wiklander /* restore then clear saved state if we have some stored */ 27013d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->parent_is_trusted != -1 ) 2702817466cbSJens Wiklander { 27033d3b0591SJens Wiklander *parent_is_trusted = rs_ctx->parent_is_trusted; 27043d3b0591SJens Wiklander rs_ctx->parent_is_trusted = -1; 27053d3b0591SJens Wiklander } 27063d3b0591SJens Wiklander #endif 27073d3b0591SJens Wiklander 27083d3b0591SJens Wiklander while( 1 ) { 27093d3b0591SJens Wiklander search_list = *parent_is_trusted ? trust_ca : child->next; 27103d3b0591SJens Wiklander 27113d3b0591SJens Wiklander ret = x509_crt_find_parent_in( child, search_list, 27123d3b0591SJens Wiklander parent, signature_is_good, 27133d3b0591SJens Wiklander *parent_is_trusted, 27143d3b0591SJens Wiklander path_cnt, self_cnt, rs_ctx ); 27153d3b0591SJens Wiklander 27163d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 27173d3b0591SJens Wiklander if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) 27183d3b0591SJens Wiklander { 27193d3b0591SJens Wiklander /* save state */ 27203d3b0591SJens Wiklander rs_ctx->parent_is_trusted = *parent_is_trusted; 27213d3b0591SJens Wiklander return( ret ); 27223d3b0591SJens Wiklander } 27233d3b0591SJens Wiklander #else 27243d3b0591SJens Wiklander (void) ret; 27253d3b0591SJens Wiklander #endif 27263d3b0591SJens Wiklander 27273d3b0591SJens Wiklander /* stop here if found or already in second iteration */ 27283d3b0591SJens Wiklander if( *parent != NULL || *parent_is_trusted == 0 ) 27293d3b0591SJens Wiklander break; 27303d3b0591SJens Wiklander 27313d3b0591SJens Wiklander /* prepare second iteration */ 27323d3b0591SJens Wiklander *parent_is_trusted = 0; 2733817466cbSJens Wiklander } 2734817466cbSJens Wiklander 27353d3b0591SJens Wiklander /* extra precaution against mistakes in the caller */ 27363d3b0591SJens Wiklander if( *parent == NULL ) 27373d3b0591SJens Wiklander { 27383d3b0591SJens Wiklander *parent_is_trusted = 0; 27393d3b0591SJens Wiklander *signature_is_good = 0; 27403d3b0591SJens Wiklander } 27413d3b0591SJens Wiklander 27423d3b0591SJens Wiklander return( 0 ); 27433d3b0591SJens Wiklander } 27443d3b0591SJens Wiklander 27453d3b0591SJens Wiklander /* 27463d3b0591SJens Wiklander * Check if an end-entity certificate is locally trusted 27473d3b0591SJens Wiklander * 27483d3b0591SJens Wiklander * Currently we require such certificates to be self-signed (actually only 27493d3b0591SJens Wiklander * check for self-issued as self-signatures are not checked) 27503d3b0591SJens Wiklander */ 27513d3b0591SJens Wiklander static int x509_crt_check_ee_locally_trusted( 27523d3b0591SJens Wiklander mbedtls_x509_crt *crt, 27533d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca ) 27543d3b0591SJens Wiklander { 27553d3b0591SJens Wiklander mbedtls_x509_crt *cur; 27563d3b0591SJens Wiklander 27573d3b0591SJens Wiklander /* must be self-issued */ 27583d3b0591SJens Wiklander if( x509_name_cmp( &crt->issuer, &crt->subject ) != 0 ) 27593d3b0591SJens Wiklander return( -1 ); 27603d3b0591SJens Wiklander 27613d3b0591SJens Wiklander /* look for an exact match with trusted cert */ 27623d3b0591SJens Wiklander for( cur = trust_ca; cur != NULL; cur = cur->next ) 27633d3b0591SJens Wiklander { 27643d3b0591SJens Wiklander if( crt->raw.len == cur->raw.len && 27653d3b0591SJens Wiklander memcmp( crt->raw.p, cur->raw.p, crt->raw.len ) == 0 ) 27663d3b0591SJens Wiklander { 27673d3b0591SJens Wiklander return( 0 ); 27683d3b0591SJens Wiklander } 27693d3b0591SJens Wiklander } 27703d3b0591SJens Wiklander 27713d3b0591SJens Wiklander /* too bad */ 27723d3b0591SJens Wiklander return( -1 ); 27733d3b0591SJens Wiklander } 27743d3b0591SJens Wiklander 27753d3b0591SJens Wiklander /* 27763d3b0591SJens Wiklander * Build and verify a certificate chain 27773d3b0591SJens Wiklander * 27783d3b0591SJens Wiklander * Given a peer-provided list of certificates EE, C1, ..., Cn and 27793d3b0591SJens Wiklander * a list of trusted certs R1, ... Rp, try to build and verify a chain 27803d3b0591SJens Wiklander * EE, Ci1, ... Ciq [, Rj] 27813d3b0591SJens Wiklander * such that every cert in the chain is a child of the next one, 27823d3b0591SJens Wiklander * jumping to a trusted root as early as possible. 27833d3b0591SJens Wiklander * 27843d3b0591SJens Wiklander * Verify that chain and return it with flags for all issues found. 27853d3b0591SJens Wiklander * 27863d3b0591SJens Wiklander * Special cases: 27873d3b0591SJens Wiklander * - EE == Rj -> return a one-element list containing it 27883d3b0591SJens Wiklander * - EE, Ci1, ..., Ciq cannot be continued with a trusted root 27893d3b0591SJens Wiklander * -> return that chain with NOT_TRUSTED set on Ciq 27903d3b0591SJens Wiklander * 27913d3b0591SJens Wiklander * Tests for (aspects of) this function should include at least: 27923d3b0591SJens Wiklander * - trusted EE 27933d3b0591SJens Wiklander * - EE -> trusted root 27945b25c76aSJerome Forissier * - EE -> intermediate CA -> trusted root 27953d3b0591SJens Wiklander * - if relevant: EE untrusted 27963d3b0591SJens Wiklander * - if relevant: EE -> intermediate, untrusted 27973d3b0591SJens Wiklander * with the aspect under test checked at each relevant level (EE, int, root). 27983d3b0591SJens Wiklander * For some aspects longer chains are required, but usually length 2 is 27993d3b0591SJens Wiklander * enough (but length 1 is not in general). 28003d3b0591SJens Wiklander * 28013d3b0591SJens Wiklander * Arguments: 28023d3b0591SJens Wiklander * - [in] crt: the cert list EE, C1, ..., Cn 28033d3b0591SJens Wiklander * - [in] trust_ca: the trusted list R1, ..., Rp 28043d3b0591SJens Wiklander * - [in] ca_crl, profile: as in verify_with_profile() 28053d3b0591SJens Wiklander * - [out] ver_chain: the built and verified chain 28063d3b0591SJens Wiklander * Only valid when return value is 0, may contain garbage otherwise! 28073d3b0591SJens Wiklander * Restart note: need not be the same when calling again to resume. 28083d3b0591SJens Wiklander * - [in-out] rs_ctx: context for restarting operations 28093d3b0591SJens Wiklander * 28103d3b0591SJens Wiklander * Return value: 28113d3b0591SJens Wiklander * - non-zero if the chain could not be fully built and examined 28123d3b0591SJens Wiklander * - 0 is the chain was successfully built and examined, 28133d3b0591SJens Wiklander * even if it was found to be invalid 28143d3b0591SJens Wiklander */ 28153d3b0591SJens Wiklander static int x509_crt_verify_chain( 28163d3b0591SJens Wiklander mbedtls_x509_crt *crt, 28173d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 28183d3b0591SJens Wiklander mbedtls_x509_crl *ca_crl, 281911fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 282011fa71b9SJerome Forissier void *p_ca_cb, 28213d3b0591SJens Wiklander const mbedtls_x509_crt_profile *profile, 28223d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain *ver_chain, 28233d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx ) 28243d3b0591SJens Wiklander { 28253d3b0591SJens Wiklander /* Don't initialize any of those variables here, so that the compiler can 28263d3b0591SJens Wiklander * catch potential issues with jumping ahead when restarting */ 282711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 28283d3b0591SJens Wiklander uint32_t *flags; 28293d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain_item *cur; 28303d3b0591SJens Wiklander mbedtls_x509_crt *child; 28313d3b0591SJens Wiklander mbedtls_x509_crt *parent; 28323d3b0591SJens Wiklander int parent_is_trusted; 28333d3b0591SJens Wiklander int child_is_trusted; 28343d3b0591SJens Wiklander int signature_is_good; 28353d3b0591SJens Wiklander unsigned self_cnt; 283611fa71b9SJerome Forissier mbedtls_x509_crt *cur_trust_ca = NULL; 28373d3b0591SJens Wiklander 28383d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 28393d3b0591SJens Wiklander /* resume if we had an operation in progress */ 28403d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent ) 28413d3b0591SJens Wiklander { 28423d3b0591SJens Wiklander /* restore saved state */ 28433d3b0591SJens Wiklander *ver_chain = rs_ctx->ver_chain; /* struct copy */ 28443d3b0591SJens Wiklander self_cnt = rs_ctx->self_cnt; 28453d3b0591SJens Wiklander 28463d3b0591SJens Wiklander /* restore derived state */ 28473d3b0591SJens Wiklander cur = &ver_chain->items[ver_chain->len - 1]; 28483d3b0591SJens Wiklander child = cur->crt; 28493d3b0591SJens Wiklander flags = &cur->flags; 28503d3b0591SJens Wiklander 28513d3b0591SJens Wiklander goto find_parent; 28523d3b0591SJens Wiklander } 28533d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ 28543d3b0591SJens Wiklander 28553d3b0591SJens Wiklander child = crt; 28563d3b0591SJens Wiklander self_cnt = 0; 28573d3b0591SJens Wiklander parent_is_trusted = 0; 28583d3b0591SJens Wiklander child_is_trusted = 0; 28593d3b0591SJens Wiklander 28603d3b0591SJens Wiklander while( 1 ) { 28613d3b0591SJens Wiklander /* Add certificate to the verification chain */ 28623d3b0591SJens Wiklander cur = &ver_chain->items[ver_chain->len]; 28633d3b0591SJens Wiklander cur->crt = child; 28643d3b0591SJens Wiklander cur->flags = 0; 28653d3b0591SJens Wiklander ver_chain->len++; 28663d3b0591SJens Wiklander flags = &cur->flags; 28673d3b0591SJens Wiklander 28683d3b0591SJens Wiklander /* Check time-validity (all certificates) */ 2869817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &child->valid_to ) ) 2870817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_EXPIRED; 2871817466cbSJens Wiklander 2872817466cbSJens Wiklander if( mbedtls_x509_time_is_future( &child->valid_from ) ) 2873817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_FUTURE; 2874817466cbSJens Wiklander 28753d3b0591SJens Wiklander /* Stop here for trusted roots (but not for trusted EE certs) */ 28763d3b0591SJens Wiklander if( child_is_trusted ) 28773d3b0591SJens Wiklander return( 0 ); 28783d3b0591SJens Wiklander 28793d3b0591SJens Wiklander /* Check signature algorithm: MD & PK algs */ 2880817466cbSJens Wiklander if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) 2881817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_MD; 2882817466cbSJens Wiklander 2883817466cbSJens Wiklander if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) 2884817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_PK; 2885817466cbSJens Wiklander 28863d3b0591SJens Wiklander /* Special case: EE certs that are locally trusted */ 28873d3b0591SJens Wiklander if( ver_chain->len == 1 && 28883d3b0591SJens Wiklander x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 ) 2889817466cbSJens Wiklander { 28903d3b0591SJens Wiklander return( 0 ); 2891817466cbSJens Wiklander } 2892817466cbSJens Wiklander 28933d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 28943d3b0591SJens Wiklander find_parent: 28953d3b0591SJens Wiklander #endif 289611fa71b9SJerome Forissier 289711fa71b9SJerome Forissier /* Obtain list of potential trusted signers from CA callback, 289811fa71b9SJerome Forissier * or use statically provided list. */ 289911fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 290011fa71b9SJerome Forissier if( f_ca_cb != NULL ) 290111fa71b9SJerome Forissier { 290211fa71b9SJerome Forissier mbedtls_x509_crt_free( ver_chain->trust_ca_cb_result ); 290311fa71b9SJerome Forissier mbedtls_free( ver_chain->trust_ca_cb_result ); 290411fa71b9SJerome Forissier ver_chain->trust_ca_cb_result = NULL; 290511fa71b9SJerome Forissier 290611fa71b9SJerome Forissier ret = f_ca_cb( p_ca_cb, child, &ver_chain->trust_ca_cb_result ); 290711fa71b9SJerome Forissier if( ret != 0 ) 290811fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_FATAL_ERROR ); 290911fa71b9SJerome Forissier 291011fa71b9SJerome Forissier cur_trust_ca = ver_chain->trust_ca_cb_result; 291111fa71b9SJerome Forissier } 291211fa71b9SJerome Forissier else 291311fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 291411fa71b9SJerome Forissier { 291511fa71b9SJerome Forissier ((void) f_ca_cb); 291611fa71b9SJerome Forissier ((void) p_ca_cb); 291711fa71b9SJerome Forissier cur_trust_ca = trust_ca; 291811fa71b9SJerome Forissier } 291911fa71b9SJerome Forissier 29203d3b0591SJens Wiklander /* Look for a parent in trusted CAs or up the chain */ 292111fa71b9SJerome Forissier ret = x509_crt_find_parent( child, cur_trust_ca, &parent, 29223d3b0591SJens Wiklander &parent_is_trusted, &signature_is_good, 29233d3b0591SJens Wiklander ver_chain->len - 1, self_cnt, rs_ctx ); 29243d3b0591SJens Wiklander 29253d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 29263d3b0591SJens Wiklander if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) 29273d3b0591SJens Wiklander { 29283d3b0591SJens Wiklander /* save state */ 29293d3b0591SJens Wiklander rs_ctx->in_progress = x509_crt_rs_find_parent; 29303d3b0591SJens Wiklander rs_ctx->self_cnt = self_cnt; 29313d3b0591SJens Wiklander rs_ctx->ver_chain = *ver_chain; /* struct copy */ 29323d3b0591SJens Wiklander 29333d3b0591SJens Wiklander return( ret ); 29343d3b0591SJens Wiklander } 29353d3b0591SJens Wiklander #else 29363d3b0591SJens Wiklander (void) ret; 29373d3b0591SJens Wiklander #endif 29383d3b0591SJens Wiklander 29393d3b0591SJens Wiklander /* No parent? We're done here */ 29403d3b0591SJens Wiklander if( parent == NULL ) 29413d3b0591SJens Wiklander { 29423d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 29433d3b0591SJens Wiklander return( 0 ); 29443d3b0591SJens Wiklander } 29453d3b0591SJens Wiklander 29463d3b0591SJens Wiklander /* Count intermediate self-issued (not necessarily self-signed) certs. 29473d3b0591SJens Wiklander * These can occur with some strategies for key rollover, see [SIRO], 29483d3b0591SJens Wiklander * and should be excluded from max_pathlen checks. */ 29493d3b0591SJens Wiklander if( ver_chain->len != 1 && 29503d3b0591SJens Wiklander x509_name_cmp( &child->issuer, &child->subject ) == 0 ) 29513d3b0591SJens Wiklander { 29523d3b0591SJens Wiklander self_cnt++; 29533d3b0591SJens Wiklander } 29543d3b0591SJens Wiklander 29553d3b0591SJens Wiklander /* path_cnt is 0 for the first intermediate CA, 29563d3b0591SJens Wiklander * and if parent is trusted it's not an intermediate CA */ 29573d3b0591SJens Wiklander if( ! parent_is_trusted && 29583d3b0591SJens Wiklander ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) 29593d3b0591SJens Wiklander { 29603d3b0591SJens Wiklander /* return immediately to avoid overflow the chain array */ 29613d3b0591SJens Wiklander return( MBEDTLS_ERR_X509_FATAL_ERROR ); 29623d3b0591SJens Wiklander } 29633d3b0591SJens Wiklander 29643d3b0591SJens Wiklander /* signature was checked while searching parent */ 29653d3b0591SJens Wiklander if( ! signature_is_good ) 29663d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 29673d3b0591SJens Wiklander 29683d3b0591SJens Wiklander /* check size of signing key */ 29693d3b0591SJens Wiklander if( x509_profile_check_key( profile, &parent->pk ) != 0 ) 2970817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 2971817466cbSJens Wiklander 2972817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 2973817466cbSJens Wiklander /* Check trusted CA's CRL for the given crt */ 2974817466cbSJens Wiklander *flags |= x509_crt_verifycrl( child, parent, ca_crl, profile ); 29753d3b0591SJens Wiklander #else 29763d3b0591SJens Wiklander (void) ca_crl; 2977817466cbSJens Wiklander #endif 2978817466cbSJens Wiklander 29793d3b0591SJens Wiklander /* prepare for next iteration */ 29803d3b0591SJens Wiklander child = parent; 29813d3b0591SJens Wiklander parent = NULL; 29823d3b0591SJens Wiklander child_is_trusted = parent_is_trusted; 29833d3b0591SJens Wiklander signature_is_good = 0; 29843d3b0591SJens Wiklander } 29853d3b0591SJens Wiklander } 29863d3b0591SJens Wiklander 29873d3b0591SJens Wiklander /* 29883d3b0591SJens Wiklander * Check for CN match 29893d3b0591SJens Wiklander */ 29903d3b0591SJens Wiklander static int x509_crt_check_cn( const mbedtls_x509_buf *name, 29913d3b0591SJens Wiklander const char *cn, size_t cn_len ) 2992817466cbSJens Wiklander { 29933d3b0591SJens Wiklander /* try exact match */ 29943d3b0591SJens Wiklander if( name->len == cn_len && 29953d3b0591SJens Wiklander x509_memcasecmp( cn, name->p, cn_len ) == 0 ) 29963d3b0591SJens Wiklander { 29973d3b0591SJens Wiklander return( 0 ); 29983d3b0591SJens Wiklander } 29993d3b0591SJens Wiklander 30003d3b0591SJens Wiklander /* try wildcard match */ 30013d3b0591SJens Wiklander if( x509_check_wildcard( cn, name ) == 0 ) 30023d3b0591SJens Wiklander { 30033d3b0591SJens Wiklander return( 0 ); 30043d3b0591SJens Wiklander } 30053d3b0591SJens Wiklander 30063d3b0591SJens Wiklander return( -1 ); 30073d3b0591SJens Wiklander } 30083d3b0591SJens Wiklander 30093d3b0591SJens Wiklander /* 3010*7901324dSJerome Forissier * Check for SAN match, see RFC 5280 Section 4.2.1.6 3011*7901324dSJerome Forissier */ 3012*7901324dSJerome Forissier static int x509_crt_check_san( const mbedtls_x509_buf *name, 3013*7901324dSJerome Forissier const char *cn, size_t cn_len ) 3014*7901324dSJerome Forissier { 3015*7901324dSJerome Forissier const unsigned char san_type = (unsigned char) name->tag & 3016*7901324dSJerome Forissier MBEDTLS_ASN1_TAG_VALUE_MASK; 3017*7901324dSJerome Forissier 3018*7901324dSJerome Forissier /* dNSName */ 3019*7901324dSJerome Forissier if( san_type == MBEDTLS_X509_SAN_DNS_NAME ) 3020*7901324dSJerome Forissier return( x509_crt_check_cn( name, cn, cn_len ) ); 3021*7901324dSJerome Forissier 3022*7901324dSJerome Forissier /* (We may handle other types here later.) */ 3023*7901324dSJerome Forissier 3024*7901324dSJerome Forissier /* Unrecognized type */ 3025*7901324dSJerome Forissier return( -1 ); 3026*7901324dSJerome Forissier } 3027*7901324dSJerome Forissier 3028*7901324dSJerome Forissier /* 30293d3b0591SJens Wiklander * Verify the requested CN - only call this if cn is not NULL! 30303d3b0591SJens Wiklander */ 30313d3b0591SJens Wiklander static void x509_crt_verify_name( const mbedtls_x509_crt *crt, 30323d3b0591SJens Wiklander const char *cn, 30333d3b0591SJens Wiklander uint32_t *flags ) 30343d3b0591SJens Wiklander { 30353d3b0591SJens Wiklander const mbedtls_x509_name *name; 30363d3b0591SJens Wiklander const mbedtls_x509_sequence *cur; 30373d3b0591SJens Wiklander size_t cn_len = strlen( cn ); 30383d3b0591SJens Wiklander 30393d3b0591SJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) 30403d3b0591SJens Wiklander { 30413d3b0591SJens Wiklander for( cur = &crt->subject_alt_names; cur != NULL; cur = cur->next ) 30423d3b0591SJens Wiklander { 3043*7901324dSJerome Forissier if( x509_crt_check_san( &cur->buf, cn, cn_len ) == 0 ) 3044817466cbSJens Wiklander break; 3045817466cbSJens Wiklander } 3046817466cbSJens Wiklander 30473d3b0591SJens Wiklander if( cur == NULL ) 30483d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; 3049817466cbSJens Wiklander } 3050817466cbSJens Wiklander else 3051817466cbSJens Wiklander { 30523d3b0591SJens Wiklander for( name = &crt->subject; name != NULL; name = name->next ) 3053817466cbSJens Wiklander { 30543d3b0591SJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 && 30553d3b0591SJens Wiklander x509_crt_check_cn( &name->val, cn, cn_len ) == 0 ) 3056817466cbSJens Wiklander { 3057817466cbSJens Wiklander break; 3058817466cbSJens Wiklander } 3059817466cbSJens Wiklander } 30603d3b0591SJens Wiklander 30613d3b0591SJens Wiklander if( name == NULL ) 30623d3b0591SJens Wiklander *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; 3063817466cbSJens Wiklander } 3064817466cbSJens Wiklander } 3065817466cbSJens Wiklander 30663d3b0591SJens Wiklander /* 30673d3b0591SJens Wiklander * Merge the flags for all certs in the chain, after calling callback 30683d3b0591SJens Wiklander */ 30693d3b0591SJens Wiklander static int x509_crt_merge_flags_with_cb( 30703d3b0591SJens Wiklander uint32_t *flags, 30713d3b0591SJens Wiklander const mbedtls_x509_crt_verify_chain *ver_chain, 30723d3b0591SJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 30733d3b0591SJens Wiklander void *p_vrfy ) 30743d3b0591SJens Wiklander { 307511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 30763d3b0591SJens Wiklander unsigned i; 30773d3b0591SJens Wiklander uint32_t cur_flags; 30783d3b0591SJens Wiklander const mbedtls_x509_crt_verify_chain_item *cur; 30793d3b0591SJens Wiklander 30803d3b0591SJens Wiklander for( i = ver_chain->len; i != 0; --i ) 30813d3b0591SJens Wiklander { 30823d3b0591SJens Wiklander cur = &ver_chain->items[i-1]; 30833d3b0591SJens Wiklander cur_flags = cur->flags; 30843d3b0591SJens Wiklander 3085817466cbSJens Wiklander if( NULL != f_vrfy ) 30863d3b0591SJens Wiklander if( ( ret = f_vrfy( p_vrfy, cur->crt, (int) i-1, &cur_flags ) ) != 0 ) 3087817466cbSJens Wiklander return( ret ); 3088817466cbSJens Wiklander 30893d3b0591SJens Wiklander *flags |= cur_flags; 30903d3b0591SJens Wiklander } 3091817466cbSJens Wiklander 3092817466cbSJens Wiklander return( 0 ); 3093817466cbSJens Wiklander } 3094817466cbSJens Wiklander 3095817466cbSJens Wiklander /* 30963d3b0591SJens Wiklander * Verify the certificate validity, with profile, restartable version 30973d3b0591SJens Wiklander * 30983d3b0591SJens Wiklander * This function: 30993d3b0591SJens Wiklander * - checks the requested CN (if any) 31003d3b0591SJens Wiklander * - checks the type and size of the EE cert's key, 31013d3b0591SJens Wiklander * as that isn't done as part of chain building/verification currently 31023d3b0591SJens Wiklander * - builds and verifies the chain 31033d3b0591SJens Wiklander * - then calls the callback and merges the flags 310411fa71b9SJerome Forissier * 310511fa71b9SJerome Forissier * The parameters pairs `trust_ca`, `ca_crl` and `f_ca_cb`, `p_ca_cb` 310611fa71b9SJerome Forissier * are mutually exclusive: If `f_ca_cb != NULL`, it will be used by the 310711fa71b9SJerome Forissier * verification routine to search for trusted signers, and CRLs will 310811fa71b9SJerome Forissier * be disabled. Otherwise, `trust_ca` will be used as the static list 310911fa71b9SJerome Forissier * of trusted signers, and `ca_crl` will be use as the static list 311011fa71b9SJerome Forissier * of CRLs. 31113d3b0591SJens Wiklander */ 311211fa71b9SJerome Forissier static int x509_crt_verify_restartable_ca_cb( mbedtls_x509_crt *crt, 31133d3b0591SJens Wiklander mbedtls_x509_crt *trust_ca, 31143d3b0591SJens Wiklander mbedtls_x509_crl *ca_crl, 311511fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 311611fa71b9SJerome Forissier void *p_ca_cb, 31173d3b0591SJens Wiklander const mbedtls_x509_crt_profile *profile, 31183d3b0591SJens Wiklander const char *cn, uint32_t *flags, 31193d3b0591SJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 31203d3b0591SJens Wiklander void *p_vrfy, 31213d3b0591SJens Wiklander mbedtls_x509_crt_restart_ctx *rs_ctx ) 31223d3b0591SJens Wiklander { 312311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3124817466cbSJens Wiklander mbedtls_pk_type_t pk_type; 31253d3b0591SJens Wiklander mbedtls_x509_crt_verify_chain ver_chain; 31263d3b0591SJens Wiklander uint32_t ee_flags; 3127817466cbSJens Wiklander 3128817466cbSJens Wiklander *flags = 0; 31293d3b0591SJens Wiklander ee_flags = 0; 31303d3b0591SJens Wiklander x509_crt_verify_chain_reset( &ver_chain ); 3131817466cbSJens Wiklander 3132817466cbSJens Wiklander if( profile == NULL ) 3133817466cbSJens Wiklander { 3134817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; 3135817466cbSJens Wiklander goto exit; 3136817466cbSJens Wiklander } 3137817466cbSJens Wiklander 31383d3b0591SJens Wiklander /* check name if requested */ 3139817466cbSJens Wiklander if( cn != NULL ) 31403d3b0591SJens Wiklander x509_crt_verify_name( crt, cn, &ee_flags ); 3141817466cbSJens Wiklander 3142817466cbSJens Wiklander /* Check the type and size of the key */ 3143817466cbSJens Wiklander pk_type = mbedtls_pk_get_type( &crt->pk ); 3144817466cbSJens Wiklander 3145817466cbSJens Wiklander if( x509_profile_check_pk_alg( profile, pk_type ) != 0 ) 31463d3b0591SJens Wiklander ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK; 3147817466cbSJens Wiklander 31483d3b0591SJens Wiklander if( x509_profile_check_key( profile, &crt->pk ) != 0 ) 31493d3b0591SJens Wiklander ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 3150817466cbSJens Wiklander 31513d3b0591SJens Wiklander /* Check the chain */ 315211fa71b9SJerome Forissier ret = x509_crt_verify_chain( crt, trust_ca, ca_crl, 315311fa71b9SJerome Forissier f_ca_cb, p_ca_cb, profile, 31543d3b0591SJens Wiklander &ver_chain, rs_ctx ); 3155817466cbSJens Wiklander 3156817466cbSJens Wiklander if( ret != 0 ) 3157817466cbSJens Wiklander goto exit; 3158817466cbSJens Wiklander 31593d3b0591SJens Wiklander /* Merge end-entity flags */ 31603d3b0591SJens Wiklander ver_chain.items[0].flags |= ee_flags; 31613d3b0591SJens Wiklander 31623d3b0591SJens Wiklander /* Build final flags, calling callback on the way if any */ 31633d3b0591SJens Wiklander ret = x509_crt_merge_flags_with_cb( flags, &ver_chain, f_vrfy, p_vrfy ); 3164817466cbSJens Wiklander 3165817466cbSJens Wiklander exit: 316611fa71b9SJerome Forissier 316711fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 316811fa71b9SJerome Forissier mbedtls_x509_crt_free( ver_chain.trust_ca_cb_result ); 316911fa71b9SJerome Forissier mbedtls_free( ver_chain.trust_ca_cb_result ); 317011fa71b9SJerome Forissier ver_chain.trust_ca_cb_result = NULL; 317111fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 317211fa71b9SJerome Forissier 31733d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 31743d3b0591SJens Wiklander if( rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) 31753d3b0591SJens Wiklander mbedtls_x509_crt_restart_free( rs_ctx ); 31763d3b0591SJens Wiklander #endif 31773d3b0591SJens Wiklander 3178817466cbSJens Wiklander /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by 3179817466cbSJens Wiklander * the SSL module for authmode optional, but non-zero return from the 3180817466cbSJens Wiklander * callback means a fatal error so it shouldn't be ignored */ 3181817466cbSJens Wiklander if( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ) 3182817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FATAL_ERROR; 3183817466cbSJens Wiklander 3184817466cbSJens Wiklander if( ret != 0 ) 3185817466cbSJens Wiklander { 3186817466cbSJens Wiklander *flags = (uint32_t) -1; 3187817466cbSJens Wiklander return( ret ); 3188817466cbSJens Wiklander } 3189817466cbSJens Wiklander 3190817466cbSJens Wiklander if( *flags != 0 ) 3191817466cbSJens Wiklander return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); 3192817466cbSJens Wiklander 3193817466cbSJens Wiklander return( 0 ); 3194817466cbSJens Wiklander } 3195817466cbSJens Wiklander 319611fa71b9SJerome Forissier 319711fa71b9SJerome Forissier /* 319811fa71b9SJerome Forissier * Verify the certificate validity (default profile, not restartable) 319911fa71b9SJerome Forissier */ 320011fa71b9SJerome Forissier int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, 320111fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 320211fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 320311fa71b9SJerome Forissier const char *cn, uint32_t *flags, 320411fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 320511fa71b9SJerome Forissier void *p_vrfy ) 320611fa71b9SJerome Forissier { 320711fa71b9SJerome Forissier return( x509_crt_verify_restartable_ca_cb( crt, trust_ca, ca_crl, 320811fa71b9SJerome Forissier NULL, NULL, 320911fa71b9SJerome Forissier &mbedtls_x509_crt_profile_default, 321011fa71b9SJerome Forissier cn, flags, 321111fa71b9SJerome Forissier f_vrfy, p_vrfy, NULL ) ); 321211fa71b9SJerome Forissier } 321311fa71b9SJerome Forissier 321411fa71b9SJerome Forissier /* 321511fa71b9SJerome Forissier * Verify the certificate validity (user-chosen profile, not restartable) 321611fa71b9SJerome Forissier */ 321711fa71b9SJerome Forissier int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, 321811fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 321911fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 322011fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 322111fa71b9SJerome Forissier const char *cn, uint32_t *flags, 322211fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 322311fa71b9SJerome Forissier void *p_vrfy ) 322411fa71b9SJerome Forissier { 322511fa71b9SJerome Forissier return( x509_crt_verify_restartable_ca_cb( crt, trust_ca, ca_crl, 322611fa71b9SJerome Forissier NULL, NULL, 322711fa71b9SJerome Forissier profile, cn, flags, 322811fa71b9SJerome Forissier f_vrfy, p_vrfy, NULL ) ); 322911fa71b9SJerome Forissier } 323011fa71b9SJerome Forissier 323111fa71b9SJerome Forissier #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) 323211fa71b9SJerome Forissier /* 323311fa71b9SJerome Forissier * Verify the certificate validity (user-chosen profile, CA callback, 323411fa71b9SJerome Forissier * not restartable). 323511fa71b9SJerome Forissier */ 323611fa71b9SJerome Forissier int mbedtls_x509_crt_verify_with_ca_cb( mbedtls_x509_crt *crt, 323711fa71b9SJerome Forissier mbedtls_x509_crt_ca_cb_t f_ca_cb, 323811fa71b9SJerome Forissier void *p_ca_cb, 323911fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 324011fa71b9SJerome Forissier const char *cn, uint32_t *flags, 324111fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 324211fa71b9SJerome Forissier void *p_vrfy ) 324311fa71b9SJerome Forissier { 324411fa71b9SJerome Forissier return( x509_crt_verify_restartable_ca_cb( crt, NULL, NULL, 324511fa71b9SJerome Forissier f_ca_cb, p_ca_cb, 324611fa71b9SJerome Forissier profile, cn, flags, 324711fa71b9SJerome Forissier f_vrfy, p_vrfy, NULL ) ); 324811fa71b9SJerome Forissier } 324911fa71b9SJerome Forissier #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ 325011fa71b9SJerome Forissier 325111fa71b9SJerome Forissier int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, 325211fa71b9SJerome Forissier mbedtls_x509_crt *trust_ca, 325311fa71b9SJerome Forissier mbedtls_x509_crl *ca_crl, 325411fa71b9SJerome Forissier const mbedtls_x509_crt_profile *profile, 325511fa71b9SJerome Forissier const char *cn, uint32_t *flags, 325611fa71b9SJerome Forissier int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 325711fa71b9SJerome Forissier void *p_vrfy, 325811fa71b9SJerome Forissier mbedtls_x509_crt_restart_ctx *rs_ctx ) 325911fa71b9SJerome Forissier { 326011fa71b9SJerome Forissier return( x509_crt_verify_restartable_ca_cb( crt, trust_ca, ca_crl, 326111fa71b9SJerome Forissier NULL, NULL, 326211fa71b9SJerome Forissier profile, cn, flags, 326311fa71b9SJerome Forissier f_vrfy, p_vrfy, rs_ctx ) ); 326411fa71b9SJerome Forissier } 326511fa71b9SJerome Forissier 326611fa71b9SJerome Forissier 3267817466cbSJens Wiklander /* 3268817466cbSJens Wiklander * Initialize a certificate chain 3269817466cbSJens Wiklander */ 3270817466cbSJens Wiklander void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ) 3271817466cbSJens Wiklander { 3272817466cbSJens Wiklander memset( crt, 0, sizeof(mbedtls_x509_crt) ); 3273817466cbSJens Wiklander } 3274817466cbSJens Wiklander 3275817466cbSJens Wiklander /* 3276817466cbSJens Wiklander * Unallocate all certificate data 3277817466cbSJens Wiklander */ 3278817466cbSJens Wiklander void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) 3279817466cbSJens Wiklander { 3280817466cbSJens Wiklander mbedtls_x509_crt *cert_cur = crt; 3281817466cbSJens Wiklander mbedtls_x509_crt *cert_prv; 3282817466cbSJens Wiklander mbedtls_x509_name *name_cur; 3283817466cbSJens Wiklander mbedtls_x509_name *name_prv; 3284817466cbSJens Wiklander mbedtls_x509_sequence *seq_cur; 3285817466cbSJens Wiklander mbedtls_x509_sequence *seq_prv; 3286817466cbSJens Wiklander 3287817466cbSJens Wiklander if( crt == NULL ) 3288817466cbSJens Wiklander return; 3289817466cbSJens Wiklander 3290817466cbSJens Wiklander do 3291817466cbSJens Wiklander { 3292817466cbSJens Wiklander mbedtls_pk_free( &cert_cur->pk ); 3293817466cbSJens Wiklander 3294817466cbSJens Wiklander #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) 3295817466cbSJens Wiklander mbedtls_free( cert_cur->sig_opts ); 3296817466cbSJens Wiklander #endif 3297817466cbSJens Wiklander 3298817466cbSJens Wiklander name_cur = cert_cur->issuer.next; 3299817466cbSJens Wiklander while( name_cur != NULL ) 3300817466cbSJens Wiklander { 3301817466cbSJens Wiklander name_prv = name_cur; 3302817466cbSJens Wiklander name_cur = name_cur->next; 33033d3b0591SJens Wiklander mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); 3304817466cbSJens Wiklander mbedtls_free( name_prv ); 3305817466cbSJens Wiklander } 3306817466cbSJens Wiklander 3307817466cbSJens Wiklander name_cur = cert_cur->subject.next; 3308817466cbSJens Wiklander while( name_cur != NULL ) 3309817466cbSJens Wiklander { 3310817466cbSJens Wiklander name_prv = name_cur; 3311817466cbSJens Wiklander name_cur = name_cur->next; 33123d3b0591SJens Wiklander mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); 3313817466cbSJens Wiklander mbedtls_free( name_prv ); 3314817466cbSJens Wiklander } 3315817466cbSJens Wiklander 3316817466cbSJens Wiklander seq_cur = cert_cur->ext_key_usage.next; 3317817466cbSJens Wiklander while( seq_cur != NULL ) 3318817466cbSJens Wiklander { 3319817466cbSJens Wiklander seq_prv = seq_cur; 3320817466cbSJens Wiklander seq_cur = seq_cur->next; 33213d3b0591SJens Wiklander mbedtls_platform_zeroize( seq_prv, 33223d3b0591SJens Wiklander sizeof( mbedtls_x509_sequence ) ); 3323817466cbSJens Wiklander mbedtls_free( seq_prv ); 3324817466cbSJens Wiklander } 3325817466cbSJens Wiklander 3326817466cbSJens Wiklander seq_cur = cert_cur->subject_alt_names.next; 3327817466cbSJens Wiklander while( seq_cur != NULL ) 3328817466cbSJens Wiklander { 3329817466cbSJens Wiklander seq_prv = seq_cur; 3330817466cbSJens Wiklander seq_cur = seq_cur->next; 33313d3b0591SJens Wiklander mbedtls_platform_zeroize( seq_prv, 33323d3b0591SJens Wiklander sizeof( mbedtls_x509_sequence ) ); 3333817466cbSJens Wiklander mbedtls_free( seq_prv ); 3334817466cbSJens Wiklander } 3335817466cbSJens Wiklander 333611fa71b9SJerome Forissier seq_cur = cert_cur->certificate_policies.next; 333711fa71b9SJerome Forissier while( seq_cur != NULL ) 333811fa71b9SJerome Forissier { 333911fa71b9SJerome Forissier seq_prv = seq_cur; 334011fa71b9SJerome Forissier seq_cur = seq_cur->next; 334111fa71b9SJerome Forissier mbedtls_platform_zeroize( seq_prv, 334211fa71b9SJerome Forissier sizeof( mbedtls_x509_sequence ) ); 334311fa71b9SJerome Forissier mbedtls_free( seq_prv ); 334411fa71b9SJerome Forissier } 334511fa71b9SJerome Forissier 334611fa71b9SJerome Forissier if( cert_cur->raw.p != NULL && cert_cur->own_buffer ) 3347817466cbSJens Wiklander { 33483d3b0591SJens Wiklander mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len ); 3349817466cbSJens Wiklander mbedtls_free( cert_cur->raw.p ); 3350817466cbSJens Wiklander } 3351817466cbSJens Wiklander 3352817466cbSJens Wiklander cert_cur = cert_cur->next; 3353817466cbSJens Wiklander } 3354817466cbSJens Wiklander while( cert_cur != NULL ); 3355817466cbSJens Wiklander 3356817466cbSJens Wiklander cert_cur = crt; 3357817466cbSJens Wiklander do 3358817466cbSJens Wiklander { 3359817466cbSJens Wiklander cert_prv = cert_cur; 3360817466cbSJens Wiklander cert_cur = cert_cur->next; 3361817466cbSJens Wiklander 33623d3b0591SJens Wiklander mbedtls_platform_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) ); 3363817466cbSJens Wiklander if( cert_prv != crt ) 3364817466cbSJens Wiklander mbedtls_free( cert_prv ); 3365817466cbSJens Wiklander } 3366817466cbSJens Wiklander while( cert_cur != NULL ); 3367817466cbSJens Wiklander } 3368817466cbSJens Wiklander 33693d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) 33703d3b0591SJens Wiklander /* 33713d3b0591SJens Wiklander * Initialize a restart context 33723d3b0591SJens Wiklander */ 33733d3b0591SJens Wiklander void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx ) 33743d3b0591SJens Wiklander { 33753d3b0591SJens Wiklander mbedtls_pk_restart_init( &ctx->pk ); 33763d3b0591SJens Wiklander 33773d3b0591SJens Wiklander ctx->parent = NULL; 33783d3b0591SJens Wiklander ctx->fallback_parent = NULL; 33793d3b0591SJens Wiklander ctx->fallback_signature_is_good = 0; 33803d3b0591SJens Wiklander 33813d3b0591SJens Wiklander ctx->parent_is_trusted = -1; 33823d3b0591SJens Wiklander 33833d3b0591SJens Wiklander ctx->in_progress = x509_crt_rs_none; 33843d3b0591SJens Wiklander ctx->self_cnt = 0; 33853d3b0591SJens Wiklander x509_crt_verify_chain_reset( &ctx->ver_chain ); 33863d3b0591SJens Wiklander } 33873d3b0591SJens Wiklander 33883d3b0591SJens Wiklander /* 33893d3b0591SJens Wiklander * Free the components of a restart context 33903d3b0591SJens Wiklander */ 33913d3b0591SJens Wiklander void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx ) 33923d3b0591SJens Wiklander { 33933d3b0591SJens Wiklander if( ctx == NULL ) 33943d3b0591SJens Wiklander return; 33953d3b0591SJens Wiklander 33963d3b0591SJens Wiklander mbedtls_pk_restart_free( &ctx->pk ); 33973d3b0591SJens Wiklander mbedtls_x509_crt_restart_init( ctx ); 33983d3b0591SJens Wiklander } 33993d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ 34003d3b0591SJens Wiklander 3401817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRT_PARSE_C */ 3402