1*817466cbSJens Wiklander /* 2*817466cbSJens Wiklander * X.509 certificate parsing and verification 3*817466cbSJens Wiklander * 4*817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 5*817466cbSJens Wiklander * SPDX-License-Identifier: Apache-2.0 6*817466cbSJens Wiklander * 7*817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8*817466cbSJens Wiklander * not use this file except in compliance with the License. 9*817466cbSJens Wiklander * You may obtain a copy of the License at 10*817466cbSJens Wiklander * 11*817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12*817466cbSJens Wiklander * 13*817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14*817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15*817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16*817466cbSJens Wiklander * See the License for the specific language governing permissions and 17*817466cbSJens Wiklander * limitations under the License. 18*817466cbSJens Wiklander * 19*817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 20*817466cbSJens Wiklander */ 21*817466cbSJens Wiklander /* 22*817466cbSJens Wiklander * The ITU-T X.509 standard defines a certificate format for PKI. 23*817466cbSJens Wiklander * 24*817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) 25*817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) 26*817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) 27*817466cbSJens Wiklander * 28*817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf 29*817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf 30*817466cbSJens Wiklander */ 31*817466cbSJens Wiklander 32*817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 33*817466cbSJens Wiklander #include "mbedtls/config.h" 34*817466cbSJens Wiklander #else 35*817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 36*817466cbSJens Wiklander #endif 37*817466cbSJens Wiklander 38*817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRT_PARSE_C) 39*817466cbSJens Wiklander 40*817466cbSJens Wiklander #include "mbedtls/x509_crt.h" 41*817466cbSJens Wiklander #include "mbedtls/oid.h" 42*817466cbSJens Wiklander 43*817466cbSJens Wiklander #include <stdio.h> 44*817466cbSJens Wiklander #include <string.h> 45*817466cbSJens Wiklander 46*817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 47*817466cbSJens Wiklander #include "mbedtls/pem.h" 48*817466cbSJens Wiklander #endif 49*817466cbSJens Wiklander 50*817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 51*817466cbSJens Wiklander #include "mbedtls/platform.h" 52*817466cbSJens Wiklander #else 53*817466cbSJens Wiklander #include <stdlib.h> 54*817466cbSJens Wiklander #define mbedtls_free free 55*817466cbSJens Wiklander #define mbedtls_calloc calloc 56*817466cbSJens Wiklander #define mbedtls_snprintf snprintf 57*817466cbSJens Wiklander #endif 58*817466cbSJens Wiklander 59*817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 60*817466cbSJens Wiklander #include "mbedtls/threading.h" 61*817466cbSJens Wiklander #endif 62*817466cbSJens Wiklander 63*817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 64*817466cbSJens Wiklander #include <windows.h> 65*817466cbSJens Wiklander #else 66*817466cbSJens Wiklander #include <time.h> 67*817466cbSJens Wiklander #endif 68*817466cbSJens Wiklander 69*817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 70*817466cbSJens Wiklander #include <stdio.h> 71*817466cbSJens Wiklander #if !defined(_WIN32) || defined(EFIX64) || defined(EFI32) 72*817466cbSJens Wiklander #include <sys/types.h> 73*817466cbSJens Wiklander #include <sys/stat.h> 74*817466cbSJens Wiklander #include <dirent.h> 75*817466cbSJens Wiklander #endif /* !_WIN32 || EFIX64 || EFI32 */ 76*817466cbSJens Wiklander #endif 77*817466cbSJens Wiklander 78*817466cbSJens Wiklander /* Implementation that should never be optimized out by the compiler */ 79*817466cbSJens Wiklander static void mbedtls_zeroize( void *v, size_t n ) { 80*817466cbSJens Wiklander volatile unsigned char *p = v; while( n-- ) *p++ = 0; 81*817466cbSJens Wiklander } 82*817466cbSJens Wiklander 83*817466cbSJens Wiklander /* 84*817466cbSJens Wiklander * Default profile 85*817466cbSJens Wiklander */ 86*817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default = 87*817466cbSJens Wiklander { 88*817466cbSJens Wiklander #if defined(MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES) 89*817466cbSJens Wiklander /* Allow SHA-1 (weak, but still safe in controlled environments) */ 90*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | 91*817466cbSJens Wiklander #endif 92*817466cbSJens Wiklander /* Only SHA-2 hashes */ 93*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | 94*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | 95*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | 96*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), 97*817466cbSJens Wiklander 0xFFFFFFF, /* Any PK alg */ 98*817466cbSJens Wiklander 0xFFFFFFF, /* Any curve */ 99*817466cbSJens Wiklander 2048, 100*817466cbSJens Wiklander }; 101*817466cbSJens Wiklander 102*817466cbSJens Wiklander /* 103*817466cbSJens Wiklander * Next-default profile 104*817466cbSJens Wiklander */ 105*817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next = 106*817466cbSJens Wiklander { 107*817466cbSJens Wiklander /* Hashes from SHA-256 and above */ 108*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | 109*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | 110*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), 111*817466cbSJens Wiklander 0xFFFFFFF, /* Any PK alg */ 112*817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 113*817466cbSJens Wiklander /* Curves at or above 128-bit security level */ 114*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | 115*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ) | 116*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP521R1 ) | 117*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP256R1 ) | 118*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP384R1 ) | 119*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP512R1 ) | 120*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256K1 ), 121*817466cbSJens Wiklander #else 122*817466cbSJens Wiklander 0, 123*817466cbSJens Wiklander #endif 124*817466cbSJens Wiklander 2048, 125*817466cbSJens Wiklander }; 126*817466cbSJens Wiklander 127*817466cbSJens Wiklander /* 128*817466cbSJens Wiklander * NSA Suite B Profile 129*817466cbSJens Wiklander */ 130*817466cbSJens Wiklander const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb = 131*817466cbSJens Wiklander { 132*817466cbSJens Wiklander /* Only SHA-256 and 384 */ 133*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | 134*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), 135*817466cbSJens Wiklander /* Only ECDSA */ 136*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ), 137*817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 138*817466cbSJens Wiklander /* Only NIST P-256 and P-384 */ 139*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | 140*817466cbSJens Wiklander MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ), 141*817466cbSJens Wiklander #else 142*817466cbSJens Wiklander 0, 143*817466cbSJens Wiklander #endif 144*817466cbSJens Wiklander 0, 145*817466cbSJens Wiklander }; 146*817466cbSJens Wiklander 147*817466cbSJens Wiklander /* 148*817466cbSJens Wiklander * Check md_alg against profile 149*817466cbSJens Wiklander * Return 0 if md_alg acceptable for this profile, -1 otherwise 150*817466cbSJens Wiklander */ 151*817466cbSJens Wiklander static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile, 152*817466cbSJens Wiklander mbedtls_md_type_t md_alg ) 153*817466cbSJens Wiklander { 154*817466cbSJens Wiklander if( ( profile->allowed_mds & MBEDTLS_X509_ID_FLAG( md_alg ) ) != 0 ) 155*817466cbSJens Wiklander return( 0 ); 156*817466cbSJens Wiklander 157*817466cbSJens Wiklander return( -1 ); 158*817466cbSJens Wiklander } 159*817466cbSJens Wiklander 160*817466cbSJens Wiklander /* 161*817466cbSJens Wiklander * Check pk_alg against profile 162*817466cbSJens Wiklander * Return 0 if pk_alg acceptable for this profile, -1 otherwise 163*817466cbSJens Wiklander */ 164*817466cbSJens Wiklander static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile, 165*817466cbSJens Wiklander mbedtls_pk_type_t pk_alg ) 166*817466cbSJens Wiklander { 167*817466cbSJens Wiklander if( ( profile->allowed_pks & MBEDTLS_X509_ID_FLAG( pk_alg ) ) != 0 ) 168*817466cbSJens Wiklander return( 0 ); 169*817466cbSJens Wiklander 170*817466cbSJens Wiklander return( -1 ); 171*817466cbSJens Wiklander } 172*817466cbSJens Wiklander 173*817466cbSJens Wiklander /* 174*817466cbSJens Wiklander * Check key against profile 175*817466cbSJens Wiklander * Return 0 if pk_alg acceptable for this profile, -1 otherwise 176*817466cbSJens Wiklander */ 177*817466cbSJens Wiklander static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, 178*817466cbSJens Wiklander mbedtls_pk_type_t pk_alg, 179*817466cbSJens Wiklander const mbedtls_pk_context *pk ) 180*817466cbSJens Wiklander { 181*817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 182*817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS ) 183*817466cbSJens Wiklander { 184*817466cbSJens Wiklander if( mbedtls_pk_get_bitlen( pk ) >= profile->rsa_min_bitlen ) 185*817466cbSJens Wiklander return( 0 ); 186*817466cbSJens Wiklander 187*817466cbSJens Wiklander return( -1 ); 188*817466cbSJens Wiklander } 189*817466cbSJens Wiklander #endif 190*817466cbSJens Wiklander 191*817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 192*817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_ECDSA || 193*817466cbSJens Wiklander pk_alg == MBEDTLS_PK_ECKEY || 194*817466cbSJens Wiklander pk_alg == MBEDTLS_PK_ECKEY_DH ) 195*817466cbSJens Wiklander { 196*817466cbSJens Wiklander mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id; 197*817466cbSJens Wiklander 198*817466cbSJens Wiklander if( ( profile->allowed_curves & MBEDTLS_X509_ID_FLAG( gid ) ) != 0 ) 199*817466cbSJens Wiklander return( 0 ); 200*817466cbSJens Wiklander 201*817466cbSJens Wiklander return( -1 ); 202*817466cbSJens Wiklander } 203*817466cbSJens Wiklander #endif 204*817466cbSJens Wiklander 205*817466cbSJens Wiklander return( -1 ); 206*817466cbSJens Wiklander } 207*817466cbSJens Wiklander 208*817466cbSJens Wiklander /* 209*817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 210*817466cbSJens Wiklander */ 211*817466cbSJens Wiklander static int x509_get_version( unsigned char **p, 212*817466cbSJens Wiklander const unsigned char *end, 213*817466cbSJens Wiklander int *ver ) 214*817466cbSJens Wiklander { 215*817466cbSJens Wiklander int ret; 216*817466cbSJens Wiklander size_t len; 217*817466cbSJens Wiklander 218*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 219*817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) != 0 ) 220*817466cbSJens Wiklander { 221*817466cbSJens Wiklander if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 222*817466cbSJens Wiklander { 223*817466cbSJens Wiklander *ver = 0; 224*817466cbSJens Wiklander return( 0 ); 225*817466cbSJens Wiklander } 226*817466cbSJens Wiklander 227*817466cbSJens Wiklander return( ret ); 228*817466cbSJens Wiklander } 229*817466cbSJens Wiklander 230*817466cbSJens Wiklander end = *p + len; 231*817466cbSJens Wiklander 232*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) 233*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); 234*817466cbSJens Wiklander 235*817466cbSJens Wiklander if( *p != end ) 236*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_VERSION + 237*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 238*817466cbSJens Wiklander 239*817466cbSJens Wiklander return( 0 ); 240*817466cbSJens Wiklander } 241*817466cbSJens Wiklander 242*817466cbSJens Wiklander /* 243*817466cbSJens Wiklander * Validity ::= SEQUENCE { 244*817466cbSJens Wiklander * notBefore Time, 245*817466cbSJens Wiklander * notAfter Time } 246*817466cbSJens Wiklander */ 247*817466cbSJens Wiklander static int x509_get_dates( unsigned char **p, 248*817466cbSJens Wiklander const unsigned char *end, 249*817466cbSJens Wiklander mbedtls_x509_time *from, 250*817466cbSJens Wiklander mbedtls_x509_time *to ) 251*817466cbSJens Wiklander { 252*817466cbSJens Wiklander int ret; 253*817466cbSJens Wiklander size_t len; 254*817466cbSJens Wiklander 255*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 256*817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 257*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); 258*817466cbSJens Wiklander 259*817466cbSJens Wiklander end = *p + len; 260*817466cbSJens Wiklander 261*817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_time( p, end, from ) ) != 0 ) 262*817466cbSJens Wiklander return( ret ); 263*817466cbSJens Wiklander 264*817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_time( p, end, to ) ) != 0 ) 265*817466cbSJens Wiklander return( ret ); 266*817466cbSJens Wiklander 267*817466cbSJens Wiklander if( *p != end ) 268*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_DATE + 269*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 270*817466cbSJens Wiklander 271*817466cbSJens Wiklander return( 0 ); 272*817466cbSJens Wiklander } 273*817466cbSJens Wiklander 274*817466cbSJens Wiklander /* 275*817466cbSJens Wiklander * X.509 v2/v3 unique identifier (not parsed) 276*817466cbSJens Wiklander */ 277*817466cbSJens Wiklander static int x509_get_uid( unsigned char **p, 278*817466cbSJens Wiklander const unsigned char *end, 279*817466cbSJens Wiklander mbedtls_x509_buf *uid, int n ) 280*817466cbSJens Wiklander { 281*817466cbSJens Wiklander int ret; 282*817466cbSJens Wiklander 283*817466cbSJens Wiklander if( *p == end ) 284*817466cbSJens Wiklander return( 0 ); 285*817466cbSJens Wiklander 286*817466cbSJens Wiklander uid->tag = **p; 287*817466cbSJens Wiklander 288*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &uid->len, 289*817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | n ) ) != 0 ) 290*817466cbSJens Wiklander { 291*817466cbSJens Wiklander if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 292*817466cbSJens Wiklander return( 0 ); 293*817466cbSJens Wiklander 294*817466cbSJens Wiklander return( ret ); 295*817466cbSJens Wiklander } 296*817466cbSJens Wiklander 297*817466cbSJens Wiklander uid->p = *p; 298*817466cbSJens Wiklander *p += uid->len; 299*817466cbSJens Wiklander 300*817466cbSJens Wiklander return( 0 ); 301*817466cbSJens Wiklander } 302*817466cbSJens Wiklander 303*817466cbSJens Wiklander static int x509_get_basic_constraints( unsigned char **p, 304*817466cbSJens Wiklander const unsigned char *end, 305*817466cbSJens Wiklander int *ca_istrue, 306*817466cbSJens Wiklander int *max_pathlen ) 307*817466cbSJens Wiklander { 308*817466cbSJens Wiklander int ret; 309*817466cbSJens Wiklander size_t len; 310*817466cbSJens Wiklander 311*817466cbSJens Wiklander /* 312*817466cbSJens Wiklander * BasicConstraints ::= SEQUENCE { 313*817466cbSJens Wiklander * cA BOOLEAN DEFAULT FALSE, 314*817466cbSJens Wiklander * pathLenConstraint INTEGER (0..MAX) OPTIONAL } 315*817466cbSJens Wiklander */ 316*817466cbSJens Wiklander *ca_istrue = 0; /* DEFAULT FALSE */ 317*817466cbSJens Wiklander *max_pathlen = 0; /* endless */ 318*817466cbSJens Wiklander 319*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 320*817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 321*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 322*817466cbSJens Wiklander 323*817466cbSJens Wiklander if( *p == end ) 324*817466cbSJens Wiklander return( 0 ); 325*817466cbSJens Wiklander 326*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bool( p, end, ca_istrue ) ) != 0 ) 327*817466cbSJens Wiklander { 328*817466cbSJens Wiklander if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 329*817466cbSJens Wiklander ret = mbedtls_asn1_get_int( p, end, ca_istrue ); 330*817466cbSJens Wiklander 331*817466cbSJens Wiklander if( ret != 0 ) 332*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 333*817466cbSJens Wiklander 334*817466cbSJens Wiklander if( *ca_istrue != 0 ) 335*817466cbSJens Wiklander *ca_istrue = 1; 336*817466cbSJens Wiklander } 337*817466cbSJens Wiklander 338*817466cbSJens Wiklander if( *p == end ) 339*817466cbSJens Wiklander return( 0 ); 340*817466cbSJens Wiklander 341*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 ) 342*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 343*817466cbSJens Wiklander 344*817466cbSJens Wiklander if( *p != end ) 345*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 346*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 347*817466cbSJens Wiklander 348*817466cbSJens Wiklander (*max_pathlen)++; 349*817466cbSJens Wiklander 350*817466cbSJens Wiklander return( 0 ); 351*817466cbSJens Wiklander } 352*817466cbSJens Wiklander 353*817466cbSJens Wiklander static int x509_get_ns_cert_type( unsigned char **p, 354*817466cbSJens Wiklander const unsigned char *end, 355*817466cbSJens Wiklander unsigned char *ns_cert_type) 356*817466cbSJens Wiklander { 357*817466cbSJens Wiklander int ret; 358*817466cbSJens Wiklander mbedtls_x509_bitstring bs = { 0, 0, NULL }; 359*817466cbSJens Wiklander 360*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) 361*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 362*817466cbSJens Wiklander 363*817466cbSJens Wiklander if( bs.len != 1 ) 364*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 365*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH ); 366*817466cbSJens Wiklander 367*817466cbSJens Wiklander /* Get actual bitstring */ 368*817466cbSJens Wiklander *ns_cert_type = *bs.p; 369*817466cbSJens Wiklander return( 0 ); 370*817466cbSJens Wiklander } 371*817466cbSJens Wiklander 372*817466cbSJens Wiklander static int x509_get_key_usage( unsigned char **p, 373*817466cbSJens Wiklander const unsigned char *end, 374*817466cbSJens Wiklander unsigned int *key_usage) 375*817466cbSJens Wiklander { 376*817466cbSJens Wiklander int ret; 377*817466cbSJens Wiklander size_t i; 378*817466cbSJens Wiklander mbedtls_x509_bitstring bs = { 0, 0, NULL }; 379*817466cbSJens Wiklander 380*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) 381*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 382*817466cbSJens Wiklander 383*817466cbSJens Wiklander if( bs.len < 1 ) 384*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 385*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH ); 386*817466cbSJens Wiklander 387*817466cbSJens Wiklander /* Get actual bitstring */ 388*817466cbSJens Wiklander *key_usage = 0; 389*817466cbSJens Wiklander for( i = 0; i < bs.len && i < sizeof( unsigned int ); i++ ) 390*817466cbSJens Wiklander { 391*817466cbSJens Wiklander *key_usage |= (unsigned int) bs.p[i] << (8*i); 392*817466cbSJens Wiklander } 393*817466cbSJens Wiklander 394*817466cbSJens Wiklander return( 0 ); 395*817466cbSJens Wiklander } 396*817466cbSJens Wiklander 397*817466cbSJens Wiklander /* 398*817466cbSJens Wiklander * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId 399*817466cbSJens Wiklander * 400*817466cbSJens Wiklander * KeyPurposeId ::= OBJECT IDENTIFIER 401*817466cbSJens Wiklander */ 402*817466cbSJens Wiklander static int x509_get_ext_key_usage( unsigned char **p, 403*817466cbSJens Wiklander const unsigned char *end, 404*817466cbSJens Wiklander mbedtls_x509_sequence *ext_key_usage) 405*817466cbSJens Wiklander { 406*817466cbSJens Wiklander int ret; 407*817466cbSJens Wiklander 408*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, MBEDTLS_ASN1_OID ) ) != 0 ) 409*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 410*817466cbSJens Wiklander 411*817466cbSJens Wiklander /* Sequence length must be >= 1 */ 412*817466cbSJens Wiklander if( ext_key_usage->buf.p == NULL ) 413*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 414*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_INVALID_LENGTH ); 415*817466cbSJens Wiklander 416*817466cbSJens Wiklander return( 0 ); 417*817466cbSJens Wiklander } 418*817466cbSJens Wiklander 419*817466cbSJens Wiklander /* 420*817466cbSJens Wiklander * SubjectAltName ::= GeneralNames 421*817466cbSJens Wiklander * 422*817466cbSJens Wiklander * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 423*817466cbSJens Wiklander * 424*817466cbSJens Wiklander * GeneralName ::= CHOICE { 425*817466cbSJens Wiklander * otherName [0] OtherName, 426*817466cbSJens Wiklander * rfc822Name [1] IA5String, 427*817466cbSJens Wiklander * dNSName [2] IA5String, 428*817466cbSJens Wiklander * x400Address [3] ORAddress, 429*817466cbSJens Wiklander * directoryName [4] Name, 430*817466cbSJens Wiklander * ediPartyName [5] EDIPartyName, 431*817466cbSJens Wiklander * uniformResourceIdentifier [6] IA5String, 432*817466cbSJens Wiklander * iPAddress [7] OCTET STRING, 433*817466cbSJens Wiklander * registeredID [8] OBJECT IDENTIFIER } 434*817466cbSJens Wiklander * 435*817466cbSJens Wiklander * OtherName ::= SEQUENCE { 436*817466cbSJens Wiklander * type-id OBJECT IDENTIFIER, 437*817466cbSJens Wiklander * value [0] EXPLICIT ANY DEFINED BY type-id } 438*817466cbSJens Wiklander * 439*817466cbSJens Wiklander * EDIPartyName ::= SEQUENCE { 440*817466cbSJens Wiklander * nameAssigner [0] DirectoryString OPTIONAL, 441*817466cbSJens Wiklander * partyName [1] DirectoryString } 442*817466cbSJens Wiklander * 443*817466cbSJens Wiklander * NOTE: we only parse and use dNSName at this point. 444*817466cbSJens Wiklander */ 445*817466cbSJens Wiklander static int x509_get_subject_alt_name( unsigned char **p, 446*817466cbSJens Wiklander const unsigned char *end, 447*817466cbSJens Wiklander mbedtls_x509_sequence *subject_alt_name ) 448*817466cbSJens Wiklander { 449*817466cbSJens Wiklander int ret; 450*817466cbSJens Wiklander size_t len, tag_len; 451*817466cbSJens Wiklander mbedtls_asn1_buf *buf; 452*817466cbSJens Wiklander unsigned char tag; 453*817466cbSJens Wiklander mbedtls_asn1_sequence *cur = subject_alt_name; 454*817466cbSJens Wiklander 455*817466cbSJens Wiklander /* Get main sequence tag */ 456*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 457*817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 458*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 459*817466cbSJens Wiklander 460*817466cbSJens Wiklander if( *p + len != end ) 461*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 462*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 463*817466cbSJens Wiklander 464*817466cbSJens Wiklander while( *p < end ) 465*817466cbSJens Wiklander { 466*817466cbSJens Wiklander if( ( end - *p ) < 1 ) 467*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 468*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 469*817466cbSJens Wiklander 470*817466cbSJens Wiklander tag = **p; 471*817466cbSJens Wiklander (*p)++; 472*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_len( p, end, &tag_len ) ) != 0 ) 473*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 474*817466cbSJens Wiklander 475*817466cbSJens Wiklander if( ( tag & MBEDTLS_ASN1_CONTEXT_SPECIFIC ) != MBEDTLS_ASN1_CONTEXT_SPECIFIC ) 476*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 477*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 478*817466cbSJens Wiklander 479*817466cbSJens Wiklander /* Skip everything but DNS name */ 480*817466cbSJens Wiklander if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) 481*817466cbSJens Wiklander { 482*817466cbSJens Wiklander *p += tag_len; 483*817466cbSJens Wiklander continue; 484*817466cbSJens Wiklander } 485*817466cbSJens Wiklander 486*817466cbSJens Wiklander /* Allocate and assign next pointer */ 487*817466cbSJens Wiklander if( cur->buf.p != NULL ) 488*817466cbSJens Wiklander { 489*817466cbSJens Wiklander if( cur->next != NULL ) 490*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); 491*817466cbSJens Wiklander 492*817466cbSJens Wiklander cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); 493*817466cbSJens Wiklander 494*817466cbSJens Wiklander if( cur->next == NULL ) 495*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 496*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_ALLOC_FAILED ); 497*817466cbSJens Wiklander 498*817466cbSJens Wiklander cur = cur->next; 499*817466cbSJens Wiklander } 500*817466cbSJens Wiklander 501*817466cbSJens Wiklander buf = &(cur->buf); 502*817466cbSJens Wiklander buf->tag = tag; 503*817466cbSJens Wiklander buf->p = *p; 504*817466cbSJens Wiklander buf->len = tag_len; 505*817466cbSJens Wiklander *p += buf->len; 506*817466cbSJens Wiklander } 507*817466cbSJens Wiklander 508*817466cbSJens Wiklander /* Set final sequence entry's next pointer to NULL */ 509*817466cbSJens Wiklander cur->next = NULL; 510*817466cbSJens Wiklander 511*817466cbSJens Wiklander if( *p != end ) 512*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 513*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 514*817466cbSJens Wiklander 515*817466cbSJens Wiklander return( 0 ); 516*817466cbSJens Wiklander } 517*817466cbSJens Wiklander 518*817466cbSJens Wiklander /* 519*817466cbSJens Wiklander * X.509 v3 extensions 520*817466cbSJens Wiklander * 521*817466cbSJens Wiklander */ 522*817466cbSJens Wiklander static int x509_get_crt_ext( unsigned char **p, 523*817466cbSJens Wiklander const unsigned char *end, 524*817466cbSJens Wiklander mbedtls_x509_crt *crt ) 525*817466cbSJens Wiklander { 526*817466cbSJens Wiklander int ret; 527*817466cbSJens Wiklander size_t len; 528*817466cbSJens Wiklander unsigned char *end_ext_data, *end_ext_octet; 529*817466cbSJens Wiklander 530*817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) 531*817466cbSJens Wiklander { 532*817466cbSJens Wiklander if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 533*817466cbSJens Wiklander return( 0 ); 534*817466cbSJens Wiklander 535*817466cbSJens Wiklander return( ret ); 536*817466cbSJens Wiklander } 537*817466cbSJens Wiklander 538*817466cbSJens Wiklander while( *p < end ) 539*817466cbSJens Wiklander { 540*817466cbSJens Wiklander /* 541*817466cbSJens Wiklander * Extension ::= SEQUENCE { 542*817466cbSJens Wiklander * extnID OBJECT IDENTIFIER, 543*817466cbSJens Wiklander * critical BOOLEAN DEFAULT FALSE, 544*817466cbSJens Wiklander * extnValue OCTET STRING } 545*817466cbSJens Wiklander */ 546*817466cbSJens Wiklander mbedtls_x509_buf extn_oid = {0, 0, NULL}; 547*817466cbSJens Wiklander int is_critical = 0; /* DEFAULT FALSE */ 548*817466cbSJens Wiklander int ext_type = 0; 549*817466cbSJens Wiklander 550*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 551*817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 552*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 553*817466cbSJens Wiklander 554*817466cbSJens Wiklander end_ext_data = *p + len; 555*817466cbSJens Wiklander 556*817466cbSJens Wiklander /* Get extension ID */ 557*817466cbSJens Wiklander extn_oid.tag = **p; 558*817466cbSJens Wiklander 559*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &extn_oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) 560*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 561*817466cbSJens Wiklander 562*817466cbSJens Wiklander extn_oid.p = *p; 563*817466cbSJens Wiklander *p += extn_oid.len; 564*817466cbSJens Wiklander 565*817466cbSJens Wiklander if( ( end - *p ) < 1 ) 566*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 567*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 568*817466cbSJens Wiklander 569*817466cbSJens Wiklander /* Get optional critical */ 570*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 && 571*817466cbSJens Wiklander ( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) 572*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 573*817466cbSJens Wiklander 574*817466cbSJens Wiklander /* Data should be octet string type */ 575*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, 576*817466cbSJens Wiklander MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 577*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 578*817466cbSJens Wiklander 579*817466cbSJens Wiklander end_ext_octet = *p + len; 580*817466cbSJens Wiklander 581*817466cbSJens Wiklander if( end_ext_octet != end_ext_data ) 582*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 583*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 584*817466cbSJens Wiklander 585*817466cbSJens Wiklander /* 586*817466cbSJens Wiklander * Detect supported extensions 587*817466cbSJens Wiklander */ 588*817466cbSJens Wiklander ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type ); 589*817466cbSJens Wiklander 590*817466cbSJens Wiklander if( ret != 0 ) 591*817466cbSJens Wiklander { 592*817466cbSJens Wiklander /* No parser found, skip extension */ 593*817466cbSJens Wiklander *p = end_ext_octet; 594*817466cbSJens Wiklander 595*817466cbSJens Wiklander #if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) 596*817466cbSJens Wiklander if( is_critical ) 597*817466cbSJens Wiklander { 598*817466cbSJens Wiklander /* Data is marked as critical: fail */ 599*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 600*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 601*817466cbSJens Wiklander } 602*817466cbSJens Wiklander #endif 603*817466cbSJens Wiklander continue; 604*817466cbSJens Wiklander } 605*817466cbSJens Wiklander 606*817466cbSJens Wiklander /* Forbid repeated extensions */ 607*817466cbSJens Wiklander if( ( crt->ext_types & ext_type ) != 0 ) 608*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); 609*817466cbSJens Wiklander 610*817466cbSJens Wiklander crt->ext_types |= ext_type; 611*817466cbSJens Wiklander 612*817466cbSJens Wiklander switch( ext_type ) 613*817466cbSJens Wiklander { 614*817466cbSJens Wiklander case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS: 615*817466cbSJens Wiklander /* Parse basic constraints */ 616*817466cbSJens Wiklander if( ( ret = x509_get_basic_constraints( p, end_ext_octet, 617*817466cbSJens Wiklander &crt->ca_istrue, &crt->max_pathlen ) ) != 0 ) 618*817466cbSJens Wiklander return( ret ); 619*817466cbSJens Wiklander break; 620*817466cbSJens Wiklander 621*817466cbSJens Wiklander case MBEDTLS_X509_EXT_KEY_USAGE: 622*817466cbSJens Wiklander /* Parse key usage */ 623*817466cbSJens Wiklander if( ( ret = x509_get_key_usage( p, end_ext_octet, 624*817466cbSJens Wiklander &crt->key_usage ) ) != 0 ) 625*817466cbSJens Wiklander return( ret ); 626*817466cbSJens Wiklander break; 627*817466cbSJens Wiklander 628*817466cbSJens Wiklander case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: 629*817466cbSJens Wiklander /* Parse extended key usage */ 630*817466cbSJens Wiklander if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, 631*817466cbSJens Wiklander &crt->ext_key_usage ) ) != 0 ) 632*817466cbSJens Wiklander return( ret ); 633*817466cbSJens Wiklander break; 634*817466cbSJens Wiklander 635*817466cbSJens Wiklander case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: 636*817466cbSJens Wiklander /* Parse subject alt name */ 637*817466cbSJens Wiklander if( ( ret = x509_get_subject_alt_name( p, end_ext_octet, 638*817466cbSJens Wiklander &crt->subject_alt_names ) ) != 0 ) 639*817466cbSJens Wiklander return( ret ); 640*817466cbSJens Wiklander break; 641*817466cbSJens Wiklander 642*817466cbSJens Wiklander case MBEDTLS_X509_EXT_NS_CERT_TYPE: 643*817466cbSJens Wiklander /* Parse netscape certificate type */ 644*817466cbSJens Wiklander if( ( ret = x509_get_ns_cert_type( p, end_ext_octet, 645*817466cbSJens Wiklander &crt->ns_cert_type ) ) != 0 ) 646*817466cbSJens Wiklander return( ret ); 647*817466cbSJens Wiklander break; 648*817466cbSJens Wiklander 649*817466cbSJens Wiklander default: 650*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); 651*817466cbSJens Wiklander } 652*817466cbSJens Wiklander } 653*817466cbSJens Wiklander 654*817466cbSJens Wiklander if( *p != end ) 655*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 656*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 657*817466cbSJens Wiklander 658*817466cbSJens Wiklander return( 0 ); 659*817466cbSJens Wiklander } 660*817466cbSJens Wiklander 661*817466cbSJens Wiklander /* 662*817466cbSJens Wiklander * Parse and fill a single X.509 certificate in DER format 663*817466cbSJens Wiklander */ 664*817466cbSJens Wiklander static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *buf, 665*817466cbSJens Wiklander size_t buflen ) 666*817466cbSJens Wiklander { 667*817466cbSJens Wiklander int ret; 668*817466cbSJens Wiklander size_t len; 669*817466cbSJens Wiklander unsigned char *p, *end, *crt_end; 670*817466cbSJens Wiklander mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; 671*817466cbSJens Wiklander 672*817466cbSJens Wiklander memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); 673*817466cbSJens Wiklander memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); 674*817466cbSJens Wiklander memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); 675*817466cbSJens Wiklander 676*817466cbSJens Wiklander /* 677*817466cbSJens Wiklander * Check for valid input 678*817466cbSJens Wiklander */ 679*817466cbSJens Wiklander if( crt == NULL || buf == NULL ) 680*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 681*817466cbSJens Wiklander 682*817466cbSJens Wiklander // Use the original buffer until we figure out actual length 683*817466cbSJens Wiklander p = (unsigned char*) buf; 684*817466cbSJens Wiklander len = buflen; 685*817466cbSJens Wiklander end = p + len; 686*817466cbSJens Wiklander 687*817466cbSJens Wiklander /* 688*817466cbSJens Wiklander * Certificate ::= SEQUENCE { 689*817466cbSJens Wiklander * tbsCertificate TBSCertificate, 690*817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 691*817466cbSJens Wiklander * signatureValue BIT STRING } 692*817466cbSJens Wiklander */ 693*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 694*817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 695*817466cbSJens Wiklander { 696*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 697*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT ); 698*817466cbSJens Wiklander } 699*817466cbSJens Wiklander 700*817466cbSJens Wiklander if( len > (size_t) ( end - p ) ) 701*817466cbSJens Wiklander { 702*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 703*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + 704*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 705*817466cbSJens Wiklander } 706*817466cbSJens Wiklander crt_end = p + len; 707*817466cbSJens Wiklander 708*817466cbSJens Wiklander // Create and populate a new buffer for the raw field 709*817466cbSJens Wiklander crt->raw.len = crt_end - buf; 710*817466cbSJens Wiklander crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len ); 711*817466cbSJens Wiklander if( p == NULL ) 712*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_ALLOC_FAILED ); 713*817466cbSJens Wiklander 714*817466cbSJens Wiklander memcpy( p, buf, crt->raw.len ); 715*817466cbSJens Wiklander 716*817466cbSJens Wiklander // Direct pointers to the new buffer 717*817466cbSJens Wiklander p += crt->raw.len - len; 718*817466cbSJens Wiklander end = crt_end = p + len; 719*817466cbSJens Wiklander 720*817466cbSJens Wiklander /* 721*817466cbSJens Wiklander * TBSCertificate ::= SEQUENCE { 722*817466cbSJens Wiklander */ 723*817466cbSJens Wiklander crt->tbs.p = p; 724*817466cbSJens Wiklander 725*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 726*817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 727*817466cbSJens Wiklander { 728*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 729*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); 730*817466cbSJens Wiklander } 731*817466cbSJens Wiklander 732*817466cbSJens Wiklander end = p + len; 733*817466cbSJens Wiklander crt->tbs.len = end - crt->tbs.p; 734*817466cbSJens Wiklander 735*817466cbSJens Wiklander /* 736*817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 737*817466cbSJens Wiklander * 738*817466cbSJens Wiklander * CertificateSerialNumber ::= INTEGER 739*817466cbSJens Wiklander * 740*817466cbSJens Wiklander * signature AlgorithmIdentifier 741*817466cbSJens Wiklander */ 742*817466cbSJens Wiklander if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 || 743*817466cbSJens Wiklander ( ret = mbedtls_x509_get_serial( &p, end, &crt->serial ) ) != 0 || 744*817466cbSJens Wiklander ( ret = mbedtls_x509_get_alg( &p, end, &crt->sig_oid, 745*817466cbSJens Wiklander &sig_params1 ) ) != 0 ) 746*817466cbSJens Wiklander { 747*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 748*817466cbSJens Wiklander return( ret ); 749*817466cbSJens Wiklander } 750*817466cbSJens Wiklander 751*817466cbSJens Wiklander if( crt->version < 0 || crt->version > 2 ) 752*817466cbSJens Wiklander { 753*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 754*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); 755*817466cbSJens Wiklander } 756*817466cbSJens Wiklander 757*817466cbSJens Wiklander crt->version++; 758*817466cbSJens Wiklander 759*817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1, 760*817466cbSJens Wiklander &crt->sig_md, &crt->sig_pk, 761*817466cbSJens Wiklander &crt->sig_opts ) ) != 0 ) 762*817466cbSJens Wiklander { 763*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 764*817466cbSJens Wiklander return( ret ); 765*817466cbSJens Wiklander } 766*817466cbSJens Wiklander 767*817466cbSJens Wiklander /* 768*817466cbSJens Wiklander * issuer Name 769*817466cbSJens Wiklander */ 770*817466cbSJens Wiklander crt->issuer_raw.p = p; 771*817466cbSJens Wiklander 772*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 773*817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 774*817466cbSJens Wiklander { 775*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 776*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); 777*817466cbSJens Wiklander } 778*817466cbSJens Wiklander 779*817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) 780*817466cbSJens Wiklander { 781*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 782*817466cbSJens Wiklander return( ret ); 783*817466cbSJens Wiklander } 784*817466cbSJens Wiklander 785*817466cbSJens Wiklander crt->issuer_raw.len = p - crt->issuer_raw.p; 786*817466cbSJens Wiklander 787*817466cbSJens Wiklander /* 788*817466cbSJens Wiklander * Validity ::= SEQUENCE { 789*817466cbSJens Wiklander * notBefore Time, 790*817466cbSJens Wiklander * notAfter Time } 791*817466cbSJens Wiklander * 792*817466cbSJens Wiklander */ 793*817466cbSJens Wiklander if( ( ret = x509_get_dates( &p, end, &crt->valid_from, 794*817466cbSJens Wiklander &crt->valid_to ) ) != 0 ) 795*817466cbSJens Wiklander { 796*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 797*817466cbSJens Wiklander return( ret ); 798*817466cbSJens Wiklander } 799*817466cbSJens Wiklander 800*817466cbSJens Wiklander /* 801*817466cbSJens Wiklander * subject Name 802*817466cbSJens Wiklander */ 803*817466cbSJens Wiklander crt->subject_raw.p = p; 804*817466cbSJens Wiklander 805*817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 806*817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 807*817466cbSJens Wiklander { 808*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 809*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); 810*817466cbSJens Wiklander } 811*817466cbSJens Wiklander 812*817466cbSJens Wiklander if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) 813*817466cbSJens Wiklander { 814*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 815*817466cbSJens Wiklander return( ret ); 816*817466cbSJens Wiklander } 817*817466cbSJens Wiklander 818*817466cbSJens Wiklander crt->subject_raw.len = p - crt->subject_raw.p; 819*817466cbSJens Wiklander 820*817466cbSJens Wiklander /* 821*817466cbSJens Wiklander * SubjectPublicKeyInfo 822*817466cbSJens Wiklander */ 823*817466cbSJens Wiklander if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 ) 824*817466cbSJens Wiklander { 825*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 826*817466cbSJens Wiklander return( ret ); 827*817466cbSJens Wiklander } 828*817466cbSJens Wiklander 829*817466cbSJens Wiklander /* 830*817466cbSJens Wiklander * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 831*817466cbSJens Wiklander * -- If present, version shall be v2 or v3 832*817466cbSJens Wiklander * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 833*817466cbSJens Wiklander * -- If present, version shall be v2 or v3 834*817466cbSJens Wiklander * extensions [3] EXPLICIT Extensions OPTIONAL 835*817466cbSJens Wiklander * -- If present, version shall be v3 836*817466cbSJens Wiklander */ 837*817466cbSJens Wiklander if( crt->version == 2 || crt->version == 3 ) 838*817466cbSJens Wiklander { 839*817466cbSJens Wiklander ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); 840*817466cbSJens Wiklander if( ret != 0 ) 841*817466cbSJens Wiklander { 842*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 843*817466cbSJens Wiklander return( ret ); 844*817466cbSJens Wiklander } 845*817466cbSJens Wiklander } 846*817466cbSJens Wiklander 847*817466cbSJens Wiklander if( crt->version == 2 || crt->version == 3 ) 848*817466cbSJens Wiklander { 849*817466cbSJens Wiklander ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); 850*817466cbSJens Wiklander if( ret != 0 ) 851*817466cbSJens Wiklander { 852*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 853*817466cbSJens Wiklander return( ret ); 854*817466cbSJens Wiklander } 855*817466cbSJens Wiklander } 856*817466cbSJens Wiklander 857*817466cbSJens Wiklander #if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) 858*817466cbSJens Wiklander if( crt->version == 3 ) 859*817466cbSJens Wiklander #endif 860*817466cbSJens Wiklander { 861*817466cbSJens Wiklander ret = x509_get_crt_ext( &p, end, crt ); 862*817466cbSJens Wiklander if( ret != 0 ) 863*817466cbSJens Wiklander { 864*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 865*817466cbSJens Wiklander return( ret ); 866*817466cbSJens Wiklander } 867*817466cbSJens Wiklander } 868*817466cbSJens Wiklander 869*817466cbSJens Wiklander if( p != end ) 870*817466cbSJens Wiklander { 871*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 872*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + 873*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 874*817466cbSJens Wiklander } 875*817466cbSJens Wiklander 876*817466cbSJens Wiklander end = crt_end; 877*817466cbSJens Wiklander 878*817466cbSJens Wiklander /* 879*817466cbSJens Wiklander * } 880*817466cbSJens Wiklander * -- end of TBSCertificate 881*817466cbSJens Wiklander * 882*817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 883*817466cbSJens Wiklander * signatureValue BIT STRING 884*817466cbSJens Wiklander */ 885*817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) 886*817466cbSJens Wiklander { 887*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 888*817466cbSJens Wiklander return( ret ); 889*817466cbSJens Wiklander } 890*817466cbSJens Wiklander 891*817466cbSJens Wiklander if( crt->sig_oid.len != sig_oid2.len || 892*817466cbSJens Wiklander memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 || 893*817466cbSJens Wiklander sig_params1.len != sig_params2.len || 894*817466cbSJens Wiklander ( sig_params1.len != 0 && 895*817466cbSJens Wiklander memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) 896*817466cbSJens Wiklander { 897*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 898*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_SIG_MISMATCH ); 899*817466cbSJens Wiklander } 900*817466cbSJens Wiklander 901*817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_sig( &p, end, &crt->sig ) ) != 0 ) 902*817466cbSJens Wiklander { 903*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 904*817466cbSJens Wiklander return( ret ); 905*817466cbSJens Wiklander } 906*817466cbSJens Wiklander 907*817466cbSJens Wiklander if( p != end ) 908*817466cbSJens Wiklander { 909*817466cbSJens Wiklander mbedtls_x509_crt_free( crt ); 910*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_FORMAT + 911*817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 912*817466cbSJens Wiklander } 913*817466cbSJens Wiklander 914*817466cbSJens Wiklander return( 0 ); 915*817466cbSJens Wiklander } 916*817466cbSJens Wiklander 917*817466cbSJens Wiklander /* 918*817466cbSJens Wiklander * Parse one X.509 certificate in DER format from a buffer and add them to a 919*817466cbSJens Wiklander * chained list 920*817466cbSJens Wiklander */ 921*817466cbSJens Wiklander int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf, 922*817466cbSJens Wiklander size_t buflen ) 923*817466cbSJens Wiklander { 924*817466cbSJens Wiklander int ret; 925*817466cbSJens Wiklander mbedtls_x509_crt *crt = chain, *prev = NULL; 926*817466cbSJens Wiklander 927*817466cbSJens Wiklander /* 928*817466cbSJens Wiklander * Check for valid input 929*817466cbSJens Wiklander */ 930*817466cbSJens Wiklander if( crt == NULL || buf == NULL ) 931*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 932*817466cbSJens Wiklander 933*817466cbSJens Wiklander while( crt->version != 0 && crt->next != NULL ) 934*817466cbSJens Wiklander { 935*817466cbSJens Wiklander prev = crt; 936*817466cbSJens Wiklander crt = crt->next; 937*817466cbSJens Wiklander } 938*817466cbSJens Wiklander 939*817466cbSJens Wiklander /* 940*817466cbSJens Wiklander * Add new certificate on the end of the chain if needed. 941*817466cbSJens Wiklander */ 942*817466cbSJens Wiklander if( crt->version != 0 && crt->next == NULL ) 943*817466cbSJens Wiklander { 944*817466cbSJens Wiklander crt->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); 945*817466cbSJens Wiklander 946*817466cbSJens Wiklander if( crt->next == NULL ) 947*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_ALLOC_FAILED ); 948*817466cbSJens Wiklander 949*817466cbSJens Wiklander prev = crt; 950*817466cbSJens Wiklander mbedtls_x509_crt_init( crt->next ); 951*817466cbSJens Wiklander crt = crt->next; 952*817466cbSJens Wiklander } 953*817466cbSJens Wiklander 954*817466cbSJens Wiklander if( ( ret = x509_crt_parse_der_core( crt, buf, buflen ) ) != 0 ) 955*817466cbSJens Wiklander { 956*817466cbSJens Wiklander if( prev ) 957*817466cbSJens Wiklander prev->next = NULL; 958*817466cbSJens Wiklander 959*817466cbSJens Wiklander if( crt != chain ) 960*817466cbSJens Wiklander mbedtls_free( crt ); 961*817466cbSJens Wiklander 962*817466cbSJens Wiklander return( ret ); 963*817466cbSJens Wiklander } 964*817466cbSJens Wiklander 965*817466cbSJens Wiklander return( 0 ); 966*817466cbSJens Wiklander } 967*817466cbSJens Wiklander 968*817466cbSJens Wiklander /* 969*817466cbSJens Wiklander * Parse one or more PEM certificates from a buffer and add them to the chained 970*817466cbSJens Wiklander * list 971*817466cbSJens Wiklander */ 972*817466cbSJens Wiklander int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ) 973*817466cbSJens Wiklander { 974*817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 975*817466cbSJens Wiklander int success = 0, first_error = 0, total_failed = 0; 976*817466cbSJens Wiklander int buf_format = MBEDTLS_X509_FORMAT_DER; 977*817466cbSJens Wiklander #endif 978*817466cbSJens Wiklander 979*817466cbSJens Wiklander /* 980*817466cbSJens Wiklander * Check for valid input 981*817466cbSJens Wiklander */ 982*817466cbSJens Wiklander if( chain == NULL || buf == NULL ) 983*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 984*817466cbSJens Wiklander 985*817466cbSJens Wiklander /* 986*817466cbSJens Wiklander * Determine buffer content. Buffer contains either one DER certificate or 987*817466cbSJens Wiklander * one or more PEM certificates. 988*817466cbSJens Wiklander */ 989*817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 990*817466cbSJens Wiklander if( buflen != 0 && buf[buflen - 1] == '\0' && 991*817466cbSJens Wiklander strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL ) 992*817466cbSJens Wiklander { 993*817466cbSJens Wiklander buf_format = MBEDTLS_X509_FORMAT_PEM; 994*817466cbSJens Wiklander } 995*817466cbSJens Wiklander 996*817466cbSJens Wiklander if( buf_format == MBEDTLS_X509_FORMAT_DER ) 997*817466cbSJens Wiklander return mbedtls_x509_crt_parse_der( chain, buf, buflen ); 998*817466cbSJens Wiklander #else 999*817466cbSJens Wiklander return mbedtls_x509_crt_parse_der( chain, buf, buflen ); 1000*817466cbSJens Wiklander #endif 1001*817466cbSJens Wiklander 1002*817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1003*817466cbSJens Wiklander if( buf_format == MBEDTLS_X509_FORMAT_PEM ) 1004*817466cbSJens Wiklander { 1005*817466cbSJens Wiklander int ret; 1006*817466cbSJens Wiklander mbedtls_pem_context pem; 1007*817466cbSJens Wiklander 1008*817466cbSJens Wiklander /* 1 rather than 0 since the terminating NULL byte is counted in */ 1009*817466cbSJens Wiklander while( buflen > 1 ) 1010*817466cbSJens Wiklander { 1011*817466cbSJens Wiklander size_t use_len; 1012*817466cbSJens Wiklander mbedtls_pem_init( &pem ); 1013*817466cbSJens Wiklander 1014*817466cbSJens Wiklander /* If we get there, we know the string is null-terminated */ 1015*817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1016*817466cbSJens Wiklander "-----BEGIN CERTIFICATE-----", 1017*817466cbSJens Wiklander "-----END CERTIFICATE-----", 1018*817466cbSJens Wiklander buf, NULL, 0, &use_len ); 1019*817466cbSJens Wiklander 1020*817466cbSJens Wiklander if( ret == 0 ) 1021*817466cbSJens Wiklander { 1022*817466cbSJens Wiklander /* 1023*817466cbSJens Wiklander * Was PEM encoded 1024*817466cbSJens Wiklander */ 1025*817466cbSJens Wiklander buflen -= use_len; 1026*817466cbSJens Wiklander buf += use_len; 1027*817466cbSJens Wiklander } 1028*817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA ) 1029*817466cbSJens Wiklander { 1030*817466cbSJens Wiklander return( ret ); 1031*817466cbSJens Wiklander } 1032*817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1033*817466cbSJens Wiklander { 1034*817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1035*817466cbSJens Wiklander 1036*817466cbSJens Wiklander /* 1037*817466cbSJens Wiklander * PEM header and footer were found 1038*817466cbSJens Wiklander */ 1039*817466cbSJens Wiklander buflen -= use_len; 1040*817466cbSJens Wiklander buf += use_len; 1041*817466cbSJens Wiklander 1042*817466cbSJens Wiklander if( first_error == 0 ) 1043*817466cbSJens Wiklander first_error = ret; 1044*817466cbSJens Wiklander 1045*817466cbSJens Wiklander total_failed++; 1046*817466cbSJens Wiklander continue; 1047*817466cbSJens Wiklander } 1048*817466cbSJens Wiklander else 1049*817466cbSJens Wiklander break; 1050*817466cbSJens Wiklander 1051*817466cbSJens Wiklander ret = mbedtls_x509_crt_parse_der( chain, pem.buf, pem.buflen ); 1052*817466cbSJens Wiklander 1053*817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1054*817466cbSJens Wiklander 1055*817466cbSJens Wiklander if( ret != 0 ) 1056*817466cbSJens Wiklander { 1057*817466cbSJens Wiklander /* 1058*817466cbSJens Wiklander * Quit parsing on a memory error 1059*817466cbSJens Wiklander */ 1060*817466cbSJens Wiklander if( ret == MBEDTLS_ERR_X509_ALLOC_FAILED ) 1061*817466cbSJens Wiklander return( ret ); 1062*817466cbSJens Wiklander 1063*817466cbSJens Wiklander if( first_error == 0 ) 1064*817466cbSJens Wiklander first_error = ret; 1065*817466cbSJens Wiklander 1066*817466cbSJens Wiklander total_failed++; 1067*817466cbSJens Wiklander continue; 1068*817466cbSJens Wiklander } 1069*817466cbSJens Wiklander 1070*817466cbSJens Wiklander success = 1; 1071*817466cbSJens Wiklander } 1072*817466cbSJens Wiklander } 1073*817466cbSJens Wiklander 1074*817466cbSJens Wiklander if( success ) 1075*817466cbSJens Wiklander return( total_failed ); 1076*817466cbSJens Wiklander else if( first_error ) 1077*817466cbSJens Wiklander return( first_error ); 1078*817466cbSJens Wiklander else 1079*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT ); 1080*817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1081*817466cbSJens Wiklander } 1082*817466cbSJens Wiklander 1083*817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 1084*817466cbSJens Wiklander /* 1085*817466cbSJens Wiklander * Load one or more certificates and add them to the chained list 1086*817466cbSJens Wiklander */ 1087*817466cbSJens Wiklander int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ) 1088*817466cbSJens Wiklander { 1089*817466cbSJens Wiklander int ret; 1090*817466cbSJens Wiklander size_t n; 1091*817466cbSJens Wiklander unsigned char *buf; 1092*817466cbSJens Wiklander 1093*817466cbSJens Wiklander if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) 1094*817466cbSJens Wiklander return( ret ); 1095*817466cbSJens Wiklander 1096*817466cbSJens Wiklander ret = mbedtls_x509_crt_parse( chain, buf, n ); 1097*817466cbSJens Wiklander 1098*817466cbSJens Wiklander mbedtls_zeroize( buf, n ); 1099*817466cbSJens Wiklander mbedtls_free( buf ); 1100*817466cbSJens Wiklander 1101*817466cbSJens Wiklander return( ret ); 1102*817466cbSJens Wiklander } 1103*817466cbSJens Wiklander 1104*817466cbSJens Wiklander int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) 1105*817466cbSJens Wiklander { 1106*817466cbSJens Wiklander int ret = 0; 1107*817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 1108*817466cbSJens Wiklander int w_ret; 1109*817466cbSJens Wiklander WCHAR szDir[MAX_PATH]; 1110*817466cbSJens Wiklander char filename[MAX_PATH]; 1111*817466cbSJens Wiklander char *p; 1112*817466cbSJens Wiklander size_t len = strlen( path ); 1113*817466cbSJens Wiklander 1114*817466cbSJens Wiklander WIN32_FIND_DATAW file_data; 1115*817466cbSJens Wiklander HANDLE hFind; 1116*817466cbSJens Wiklander 1117*817466cbSJens Wiklander if( len > MAX_PATH - 3 ) 1118*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1119*817466cbSJens Wiklander 1120*817466cbSJens Wiklander memset( szDir, 0, sizeof(szDir) ); 1121*817466cbSJens Wiklander memset( filename, 0, MAX_PATH ); 1122*817466cbSJens Wiklander memcpy( filename, path, len ); 1123*817466cbSJens Wiklander filename[len++] = '\\'; 1124*817466cbSJens Wiklander p = filename + len; 1125*817466cbSJens Wiklander filename[len++] = '*'; 1126*817466cbSJens Wiklander 1127*817466cbSJens Wiklander w_ret = MultiByteToWideChar( CP_ACP, 0, filename, (int)len, szDir, 1128*817466cbSJens Wiklander MAX_PATH - 3 ); 1129*817466cbSJens Wiklander if( w_ret == 0 ) 1130*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1131*817466cbSJens Wiklander 1132*817466cbSJens Wiklander hFind = FindFirstFileW( szDir, &file_data ); 1133*817466cbSJens Wiklander if( hFind == INVALID_HANDLE_VALUE ) 1134*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); 1135*817466cbSJens Wiklander 1136*817466cbSJens Wiklander len = MAX_PATH - len; 1137*817466cbSJens Wiklander do 1138*817466cbSJens Wiklander { 1139*817466cbSJens Wiklander memset( p, 0, len ); 1140*817466cbSJens Wiklander 1141*817466cbSJens Wiklander if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) 1142*817466cbSJens Wiklander continue; 1143*817466cbSJens Wiklander 1144*817466cbSJens Wiklander w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName, 1145*817466cbSJens Wiklander lstrlenW( file_data.cFileName ), 1146*817466cbSJens Wiklander p, (int) len - 1, 1147*817466cbSJens Wiklander NULL, NULL ); 1148*817466cbSJens Wiklander if( w_ret == 0 ) 1149*817466cbSJens Wiklander { 1150*817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1151*817466cbSJens Wiklander goto cleanup; 1152*817466cbSJens Wiklander } 1153*817466cbSJens Wiklander 1154*817466cbSJens Wiklander w_ret = mbedtls_x509_crt_parse_file( chain, filename ); 1155*817466cbSJens Wiklander if( w_ret < 0 ) 1156*817466cbSJens Wiklander ret++; 1157*817466cbSJens Wiklander else 1158*817466cbSJens Wiklander ret += w_ret; 1159*817466cbSJens Wiklander } 1160*817466cbSJens Wiklander while( FindNextFileW( hFind, &file_data ) != 0 ); 1161*817466cbSJens Wiklander 1162*817466cbSJens Wiklander if( GetLastError() != ERROR_NO_MORE_FILES ) 1163*817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1164*817466cbSJens Wiklander 1165*817466cbSJens Wiklander cleanup: 1166*817466cbSJens Wiklander FindClose( hFind ); 1167*817466cbSJens Wiklander #else /* _WIN32 */ 1168*817466cbSJens Wiklander int t_ret; 1169*817466cbSJens Wiklander int snp_ret; 1170*817466cbSJens Wiklander struct stat sb; 1171*817466cbSJens Wiklander struct dirent *entry; 1172*817466cbSJens Wiklander char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN]; 1173*817466cbSJens Wiklander DIR *dir = opendir( path ); 1174*817466cbSJens Wiklander 1175*817466cbSJens Wiklander if( dir == NULL ) 1176*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); 1177*817466cbSJens Wiklander 1178*817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 1179*817466cbSJens Wiklander if( ( ret = mbedtls_mutex_lock( &mbedtls_threading_readdir_mutex ) ) != 0 ) 1180*817466cbSJens Wiklander { 1181*817466cbSJens Wiklander closedir( dir ); 1182*817466cbSJens Wiklander return( ret ); 1183*817466cbSJens Wiklander } 1184*817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */ 1185*817466cbSJens Wiklander 1186*817466cbSJens Wiklander while( ( entry = readdir( dir ) ) != NULL ) 1187*817466cbSJens Wiklander { 1188*817466cbSJens Wiklander snp_ret = mbedtls_snprintf( entry_name, sizeof entry_name, 1189*817466cbSJens Wiklander "%s/%s", path, entry->d_name ); 1190*817466cbSJens Wiklander 1191*817466cbSJens Wiklander if( snp_ret < 0 || (size_t)snp_ret >= sizeof entry_name ) 1192*817466cbSJens Wiklander { 1193*817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; 1194*817466cbSJens Wiklander goto cleanup; 1195*817466cbSJens Wiklander } 1196*817466cbSJens Wiklander else if( stat( entry_name, &sb ) == -1 ) 1197*817466cbSJens Wiklander { 1198*817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; 1199*817466cbSJens Wiklander goto cleanup; 1200*817466cbSJens Wiklander } 1201*817466cbSJens Wiklander 1202*817466cbSJens Wiklander if( !S_ISREG( sb.st_mode ) ) 1203*817466cbSJens Wiklander continue; 1204*817466cbSJens Wiklander 1205*817466cbSJens Wiklander // Ignore parse errors 1206*817466cbSJens Wiklander // 1207*817466cbSJens Wiklander t_ret = mbedtls_x509_crt_parse_file( chain, entry_name ); 1208*817466cbSJens Wiklander if( t_ret < 0 ) 1209*817466cbSJens Wiklander ret++; 1210*817466cbSJens Wiklander else 1211*817466cbSJens Wiklander ret += t_ret; 1212*817466cbSJens Wiklander } 1213*817466cbSJens Wiklander 1214*817466cbSJens Wiklander cleanup: 1215*817466cbSJens Wiklander closedir( dir ); 1216*817466cbSJens Wiklander 1217*817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 1218*817466cbSJens Wiklander if( mbedtls_mutex_unlock( &mbedtls_threading_readdir_mutex ) != 0 ) 1219*817466cbSJens Wiklander ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR; 1220*817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */ 1221*817466cbSJens Wiklander 1222*817466cbSJens Wiklander #endif /* _WIN32 */ 1223*817466cbSJens Wiklander 1224*817466cbSJens Wiklander return( ret ); 1225*817466cbSJens Wiklander } 1226*817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 1227*817466cbSJens Wiklander 1228*817466cbSJens Wiklander static int x509_info_subject_alt_name( char **buf, size_t *size, 1229*817466cbSJens Wiklander const mbedtls_x509_sequence *subject_alt_name ) 1230*817466cbSJens Wiklander { 1231*817466cbSJens Wiklander size_t i; 1232*817466cbSJens Wiklander size_t n = *size; 1233*817466cbSJens Wiklander char *p = *buf; 1234*817466cbSJens Wiklander const mbedtls_x509_sequence *cur = subject_alt_name; 1235*817466cbSJens Wiklander const char *sep = ""; 1236*817466cbSJens Wiklander size_t sep_len = 0; 1237*817466cbSJens Wiklander 1238*817466cbSJens Wiklander while( cur != NULL ) 1239*817466cbSJens Wiklander { 1240*817466cbSJens Wiklander if( cur->buf.len + sep_len >= n ) 1241*817466cbSJens Wiklander { 1242*817466cbSJens Wiklander *p = '\0'; 1243*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); 1244*817466cbSJens Wiklander } 1245*817466cbSJens Wiklander 1246*817466cbSJens Wiklander n -= cur->buf.len + sep_len; 1247*817466cbSJens Wiklander for( i = 0; i < sep_len; i++ ) 1248*817466cbSJens Wiklander *p++ = sep[i]; 1249*817466cbSJens Wiklander for( i = 0; i < cur->buf.len; i++ ) 1250*817466cbSJens Wiklander *p++ = cur->buf.p[i]; 1251*817466cbSJens Wiklander 1252*817466cbSJens Wiklander sep = ", "; 1253*817466cbSJens Wiklander sep_len = 2; 1254*817466cbSJens Wiklander 1255*817466cbSJens Wiklander cur = cur->next; 1256*817466cbSJens Wiklander } 1257*817466cbSJens Wiklander 1258*817466cbSJens Wiklander *p = '\0'; 1259*817466cbSJens Wiklander 1260*817466cbSJens Wiklander *size = n; 1261*817466cbSJens Wiklander *buf = p; 1262*817466cbSJens Wiklander 1263*817466cbSJens Wiklander return( 0 ); 1264*817466cbSJens Wiklander } 1265*817466cbSJens Wiklander 1266*817466cbSJens Wiklander #define PRINT_ITEM(i) \ 1267*817466cbSJens Wiklander { \ 1268*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s" i, sep ); \ 1269*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; \ 1270*817466cbSJens Wiklander sep = ", "; \ 1271*817466cbSJens Wiklander } 1272*817466cbSJens Wiklander 1273*817466cbSJens Wiklander #define CERT_TYPE(type,name) \ 1274*817466cbSJens Wiklander if( ns_cert_type & type ) \ 1275*817466cbSJens Wiklander PRINT_ITEM( name ); 1276*817466cbSJens Wiklander 1277*817466cbSJens Wiklander static int x509_info_cert_type( char **buf, size_t *size, 1278*817466cbSJens Wiklander unsigned char ns_cert_type ) 1279*817466cbSJens Wiklander { 1280*817466cbSJens Wiklander int ret; 1281*817466cbSJens Wiklander size_t n = *size; 1282*817466cbSJens Wiklander char *p = *buf; 1283*817466cbSJens Wiklander const char *sep = ""; 1284*817466cbSJens Wiklander 1285*817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT, "SSL Client" ); 1286*817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER, "SSL Server" ); 1287*817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL, "Email" ); 1288*817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING, "Object Signing" ); 1289*817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_RESERVED, "Reserved" ); 1290*817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CA, "SSL CA" ); 1291*817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA, "Email CA" ); 1292*817466cbSJens Wiklander CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA, "Object Signing CA" ); 1293*817466cbSJens Wiklander 1294*817466cbSJens Wiklander *size = n; 1295*817466cbSJens Wiklander *buf = p; 1296*817466cbSJens Wiklander 1297*817466cbSJens Wiklander return( 0 ); 1298*817466cbSJens Wiklander } 1299*817466cbSJens Wiklander 1300*817466cbSJens Wiklander #define KEY_USAGE(code,name) \ 1301*817466cbSJens Wiklander if( key_usage & code ) \ 1302*817466cbSJens Wiklander PRINT_ITEM( name ); 1303*817466cbSJens Wiklander 1304*817466cbSJens Wiklander static int x509_info_key_usage( char **buf, size_t *size, 1305*817466cbSJens Wiklander unsigned int key_usage ) 1306*817466cbSJens Wiklander { 1307*817466cbSJens Wiklander int ret; 1308*817466cbSJens Wiklander size_t n = *size; 1309*817466cbSJens Wiklander char *p = *buf; 1310*817466cbSJens Wiklander const char *sep = ""; 1311*817466cbSJens Wiklander 1312*817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_DIGITAL_SIGNATURE, "Digital Signature" ); 1313*817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_NON_REPUDIATION, "Non Repudiation" ); 1314*817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_KEY_ENCIPHERMENT, "Key Encipherment" ); 1315*817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_DATA_ENCIPHERMENT, "Data Encipherment" ); 1316*817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_KEY_AGREEMENT, "Key Agreement" ); 1317*817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_KEY_CERT_SIGN, "Key Cert Sign" ); 1318*817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_CRL_SIGN, "CRL Sign" ); 1319*817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_ENCIPHER_ONLY, "Encipher Only" ); 1320*817466cbSJens Wiklander KEY_USAGE( MBEDTLS_X509_KU_DECIPHER_ONLY, "Decipher Only" ); 1321*817466cbSJens Wiklander 1322*817466cbSJens Wiklander *size = n; 1323*817466cbSJens Wiklander *buf = p; 1324*817466cbSJens Wiklander 1325*817466cbSJens Wiklander return( 0 ); 1326*817466cbSJens Wiklander } 1327*817466cbSJens Wiklander 1328*817466cbSJens Wiklander static int x509_info_ext_key_usage( char **buf, size_t *size, 1329*817466cbSJens Wiklander const mbedtls_x509_sequence *extended_key_usage ) 1330*817466cbSJens Wiklander { 1331*817466cbSJens Wiklander int ret; 1332*817466cbSJens Wiklander const char *desc; 1333*817466cbSJens Wiklander size_t n = *size; 1334*817466cbSJens Wiklander char *p = *buf; 1335*817466cbSJens Wiklander const mbedtls_x509_sequence *cur = extended_key_usage; 1336*817466cbSJens Wiklander const char *sep = ""; 1337*817466cbSJens Wiklander 1338*817466cbSJens Wiklander while( cur != NULL ) 1339*817466cbSJens Wiklander { 1340*817466cbSJens Wiklander if( mbedtls_oid_get_extended_key_usage( &cur->buf, &desc ) != 0 ) 1341*817466cbSJens Wiklander desc = "???"; 1342*817466cbSJens Wiklander 1343*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); 1344*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1345*817466cbSJens Wiklander 1346*817466cbSJens Wiklander sep = ", "; 1347*817466cbSJens Wiklander 1348*817466cbSJens Wiklander cur = cur->next; 1349*817466cbSJens Wiklander } 1350*817466cbSJens Wiklander 1351*817466cbSJens Wiklander *size = n; 1352*817466cbSJens Wiklander *buf = p; 1353*817466cbSJens Wiklander 1354*817466cbSJens Wiklander return( 0 ); 1355*817466cbSJens Wiklander } 1356*817466cbSJens Wiklander 1357*817466cbSJens Wiklander /* 1358*817466cbSJens Wiklander * Return an informational string about the certificate. 1359*817466cbSJens Wiklander */ 1360*817466cbSJens Wiklander #define BEFORE_COLON 18 1361*817466cbSJens Wiklander #define BC "18" 1362*817466cbSJens Wiklander int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, 1363*817466cbSJens Wiklander const mbedtls_x509_crt *crt ) 1364*817466cbSJens Wiklander { 1365*817466cbSJens Wiklander int ret; 1366*817466cbSJens Wiklander size_t n; 1367*817466cbSJens Wiklander char *p; 1368*817466cbSJens Wiklander char key_size_str[BEFORE_COLON]; 1369*817466cbSJens Wiklander 1370*817466cbSJens Wiklander p = buf; 1371*817466cbSJens Wiklander n = size; 1372*817466cbSJens Wiklander 1373*817466cbSJens Wiklander if( NULL == crt ) 1374*817466cbSJens Wiklander { 1375*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); 1376*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1377*817466cbSJens Wiklander 1378*817466cbSJens Wiklander return( (int) ( size - n ) ); 1379*817466cbSJens Wiklander } 1380*817466cbSJens Wiklander 1381*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", 1382*817466cbSJens Wiklander prefix, crt->version ); 1383*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1384*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%sserial number : ", 1385*817466cbSJens Wiklander prefix ); 1386*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1387*817466cbSJens Wiklander 1388*817466cbSJens Wiklander ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); 1389*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1390*817466cbSJens Wiklander 1391*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); 1392*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1393*817466cbSJens Wiklander ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); 1394*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1395*817466cbSJens Wiklander 1396*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); 1397*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1398*817466cbSJens Wiklander ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); 1399*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1400*817466cbSJens Wiklander 1401*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ 1402*817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix, 1403*817466cbSJens Wiklander crt->valid_from.year, crt->valid_from.mon, 1404*817466cbSJens Wiklander crt->valid_from.day, crt->valid_from.hour, 1405*817466cbSJens Wiklander crt->valid_from.min, crt->valid_from.sec ); 1406*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1407*817466cbSJens Wiklander 1408*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ 1409*817466cbSJens Wiklander "%04d-%02d-%02d %02d:%02d:%02d", prefix, 1410*817466cbSJens Wiklander crt->valid_to.year, crt->valid_to.mon, 1411*817466cbSJens Wiklander crt->valid_to.day, crt->valid_to.hour, 1412*817466cbSJens Wiklander crt->valid_to.min, crt->valid_to.sec ); 1413*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1414*817466cbSJens Wiklander 1415*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); 1416*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1417*817466cbSJens Wiklander 1418*817466cbSJens Wiklander ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, 1419*817466cbSJens Wiklander crt->sig_md, crt->sig_opts ); 1420*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1421*817466cbSJens Wiklander 1422*817466cbSJens Wiklander /* Key size */ 1423*817466cbSJens Wiklander if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, 1424*817466cbSJens Wiklander mbedtls_pk_get_name( &crt->pk ) ) ) != 0 ) 1425*817466cbSJens Wiklander { 1426*817466cbSJens Wiklander return( ret ); 1427*817466cbSJens Wiklander } 1428*817466cbSJens Wiklander 1429*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, 1430*817466cbSJens Wiklander (int) mbedtls_pk_get_bitlen( &crt->pk ) ); 1431*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1432*817466cbSJens Wiklander 1433*817466cbSJens Wiklander /* 1434*817466cbSJens Wiklander * Optional extensions 1435*817466cbSJens Wiklander */ 1436*817466cbSJens Wiklander 1437*817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS ) 1438*817466cbSJens Wiklander { 1439*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, 1440*817466cbSJens Wiklander crt->ca_istrue ? "true" : "false" ); 1441*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1442*817466cbSJens Wiklander 1443*817466cbSJens Wiklander if( crt->max_pathlen > 0 ) 1444*817466cbSJens Wiklander { 1445*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", crt->max_pathlen - 1 ); 1446*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1447*817466cbSJens Wiklander } 1448*817466cbSJens Wiklander } 1449*817466cbSJens Wiklander 1450*817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) 1451*817466cbSJens Wiklander { 1452*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%ssubject alt name : ", prefix ); 1453*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1454*817466cbSJens Wiklander 1455*817466cbSJens Wiklander if( ( ret = x509_info_subject_alt_name( &p, &n, 1456*817466cbSJens Wiklander &crt->subject_alt_names ) ) != 0 ) 1457*817466cbSJens Wiklander return( ret ); 1458*817466cbSJens Wiklander } 1459*817466cbSJens Wiklander 1460*817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) 1461*817466cbSJens Wiklander { 1462*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); 1463*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1464*817466cbSJens Wiklander 1465*817466cbSJens Wiklander if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 ) 1466*817466cbSJens Wiklander return( ret ); 1467*817466cbSJens Wiklander } 1468*817466cbSJens Wiklander 1469*817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) 1470*817466cbSJens Wiklander { 1471*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%skey usage : ", prefix ); 1472*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1473*817466cbSJens Wiklander 1474*817466cbSJens Wiklander if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 ) 1475*817466cbSJens Wiklander return( ret ); 1476*817466cbSJens Wiklander } 1477*817466cbSJens Wiklander 1478*817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) 1479*817466cbSJens Wiklander { 1480*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n%sext key usage : ", prefix ); 1481*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1482*817466cbSJens Wiklander 1483*817466cbSJens Wiklander if( ( ret = x509_info_ext_key_usage( &p, &n, 1484*817466cbSJens Wiklander &crt->ext_key_usage ) ) != 0 ) 1485*817466cbSJens Wiklander return( ret ); 1486*817466cbSJens Wiklander } 1487*817466cbSJens Wiklander 1488*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\n" ); 1489*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1490*817466cbSJens Wiklander 1491*817466cbSJens Wiklander return( (int) ( size - n ) ); 1492*817466cbSJens Wiklander } 1493*817466cbSJens Wiklander 1494*817466cbSJens Wiklander struct x509_crt_verify_string { 1495*817466cbSJens Wiklander int code; 1496*817466cbSJens Wiklander const char *string; 1497*817466cbSJens Wiklander }; 1498*817466cbSJens Wiklander 1499*817466cbSJens Wiklander static const struct x509_crt_verify_string x509_crt_verify_strings[] = { 1500*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_EXPIRED, "The certificate validity has expired" }, 1501*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_REVOKED, "The certificate has been revoked (is on a CRL)" }, 1502*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_CN_MISMATCH, "The certificate Common Name (CN) does not match with the expected CN" }, 1503*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_NOT_TRUSTED, "The certificate is not correctly signed by the trusted CA" }, 1504*817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_NOT_TRUSTED, "The CRL is not correctly signed by the trusted CA" }, 1505*817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_EXPIRED, "The CRL is expired" }, 1506*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_MISSING, "Certificate was missing" }, 1507*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_SKIP_VERIFY, "Certificate verification was skipped" }, 1508*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_OTHER, "Other reason (can be used by verify callback)" }, 1509*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_FUTURE, "The certificate validity starts in the future" }, 1510*817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_FUTURE, "The CRL is from the future" }, 1511*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_KEY_USAGE, "Usage does not match the keyUsage extension" }, 1512*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_EXT_KEY_USAGE, "Usage does not match the extendedKeyUsage extension" }, 1513*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_NS_CERT_TYPE, "Usage does not match the nsCertType extension" }, 1514*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_BAD_MD, "The certificate is signed with an unacceptable hash." }, 1515*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_BAD_PK, "The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, 1516*817466cbSJens Wiklander { MBEDTLS_X509_BADCERT_BAD_KEY, "The certificate is signed with an unacceptable key (eg bad curve, RSA too short)." }, 1517*817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_BAD_MD, "The CRL is signed with an unacceptable hash." }, 1518*817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_BAD_PK, "The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, 1519*817466cbSJens Wiklander { MBEDTLS_X509_BADCRL_BAD_KEY, "The CRL is signed with an unacceptable key (eg bad curve, RSA too short)." }, 1520*817466cbSJens Wiklander { 0, NULL } 1521*817466cbSJens Wiklander }; 1522*817466cbSJens Wiklander 1523*817466cbSJens Wiklander int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, 1524*817466cbSJens Wiklander uint32_t flags ) 1525*817466cbSJens Wiklander { 1526*817466cbSJens Wiklander int ret; 1527*817466cbSJens Wiklander const struct x509_crt_verify_string *cur; 1528*817466cbSJens Wiklander char *p = buf; 1529*817466cbSJens Wiklander size_t n = size; 1530*817466cbSJens Wiklander 1531*817466cbSJens Wiklander for( cur = x509_crt_verify_strings; cur->string != NULL ; cur++ ) 1532*817466cbSJens Wiklander { 1533*817466cbSJens Wiklander if( ( flags & cur->code ) == 0 ) 1534*817466cbSJens Wiklander continue; 1535*817466cbSJens Wiklander 1536*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s%s\n", prefix, cur->string ); 1537*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1538*817466cbSJens Wiklander flags ^= cur->code; 1539*817466cbSJens Wiklander } 1540*817466cbSJens Wiklander 1541*817466cbSJens Wiklander if( flags != 0 ) 1542*817466cbSJens Wiklander { 1543*817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%sUnknown reason " 1544*817466cbSJens Wiklander "(this should not happen)\n", prefix ); 1545*817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 1546*817466cbSJens Wiklander } 1547*817466cbSJens Wiklander 1548*817466cbSJens Wiklander return( (int) ( size - n ) ); 1549*817466cbSJens Wiklander } 1550*817466cbSJens Wiklander 1551*817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) 1552*817466cbSJens Wiklander int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, 1553*817466cbSJens Wiklander unsigned int usage ) 1554*817466cbSJens Wiklander { 1555*817466cbSJens Wiklander unsigned int usage_must, usage_may; 1556*817466cbSJens Wiklander unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY 1557*817466cbSJens Wiklander | MBEDTLS_X509_KU_DECIPHER_ONLY; 1558*817466cbSJens Wiklander 1559*817466cbSJens Wiklander if( ( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) == 0 ) 1560*817466cbSJens Wiklander return( 0 ); 1561*817466cbSJens Wiklander 1562*817466cbSJens Wiklander usage_must = usage & ~may_mask; 1563*817466cbSJens Wiklander 1564*817466cbSJens Wiklander if( ( ( crt->key_usage & ~may_mask ) & usage_must ) != usage_must ) 1565*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1566*817466cbSJens Wiklander 1567*817466cbSJens Wiklander usage_may = usage & may_mask; 1568*817466cbSJens Wiklander 1569*817466cbSJens Wiklander if( ( ( crt->key_usage & may_mask ) | usage_may ) != usage_may ) 1570*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1571*817466cbSJens Wiklander 1572*817466cbSJens Wiklander return( 0 ); 1573*817466cbSJens Wiklander } 1574*817466cbSJens Wiklander #endif 1575*817466cbSJens Wiklander 1576*817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) 1577*817466cbSJens Wiklander int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, 1578*817466cbSJens Wiklander const char *usage_oid, 1579*817466cbSJens Wiklander size_t usage_len ) 1580*817466cbSJens Wiklander { 1581*817466cbSJens Wiklander const mbedtls_x509_sequence *cur; 1582*817466cbSJens Wiklander 1583*817466cbSJens Wiklander /* Extension is not mandatory, absent means no restriction */ 1584*817466cbSJens Wiklander if( ( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) 1585*817466cbSJens Wiklander return( 0 ); 1586*817466cbSJens Wiklander 1587*817466cbSJens Wiklander /* 1588*817466cbSJens Wiklander * Look for the requested usage (or wildcard ANY) in our list 1589*817466cbSJens Wiklander */ 1590*817466cbSJens Wiklander for( cur = &crt->ext_key_usage; cur != NULL; cur = cur->next ) 1591*817466cbSJens Wiklander { 1592*817466cbSJens Wiklander const mbedtls_x509_buf *cur_oid = &cur->buf; 1593*817466cbSJens Wiklander 1594*817466cbSJens Wiklander if( cur_oid->len == usage_len && 1595*817466cbSJens Wiklander memcmp( cur_oid->p, usage_oid, usage_len ) == 0 ) 1596*817466cbSJens Wiklander { 1597*817466cbSJens Wiklander return( 0 ); 1598*817466cbSJens Wiklander } 1599*817466cbSJens Wiklander 1600*817466cbSJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid ) == 0 ) 1601*817466cbSJens Wiklander return( 0 ); 1602*817466cbSJens Wiklander } 1603*817466cbSJens Wiklander 1604*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 1605*817466cbSJens Wiklander } 1606*817466cbSJens Wiklander #endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ 1607*817466cbSJens Wiklander 1608*817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 1609*817466cbSJens Wiklander /* 1610*817466cbSJens Wiklander * Return 1 if the certificate is revoked, or 0 otherwise. 1611*817466cbSJens Wiklander */ 1612*817466cbSJens Wiklander int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ) 1613*817466cbSJens Wiklander { 1614*817466cbSJens Wiklander const mbedtls_x509_crl_entry *cur = &crl->entry; 1615*817466cbSJens Wiklander 1616*817466cbSJens Wiklander while( cur != NULL && cur->serial.len != 0 ) 1617*817466cbSJens Wiklander { 1618*817466cbSJens Wiklander if( crt->serial.len == cur->serial.len && 1619*817466cbSJens Wiklander memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 ) 1620*817466cbSJens Wiklander { 1621*817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &cur->revocation_date ) ) 1622*817466cbSJens Wiklander return( 1 ); 1623*817466cbSJens Wiklander } 1624*817466cbSJens Wiklander 1625*817466cbSJens Wiklander cur = cur->next; 1626*817466cbSJens Wiklander } 1627*817466cbSJens Wiklander 1628*817466cbSJens Wiklander return( 0 ); 1629*817466cbSJens Wiklander } 1630*817466cbSJens Wiklander 1631*817466cbSJens Wiklander /* 1632*817466cbSJens Wiklander * Check that the given certificate is not revoked according to the CRL. 1633*817466cbSJens Wiklander * Skip validation is no CRL for the given CA is present. 1634*817466cbSJens Wiklander */ 1635*817466cbSJens Wiklander static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, 1636*817466cbSJens Wiklander mbedtls_x509_crl *crl_list, 1637*817466cbSJens Wiklander const mbedtls_x509_crt_profile *profile ) 1638*817466cbSJens Wiklander { 1639*817466cbSJens Wiklander int flags = 0; 1640*817466cbSJens Wiklander unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 1641*817466cbSJens Wiklander const mbedtls_md_info_t *md_info; 1642*817466cbSJens Wiklander 1643*817466cbSJens Wiklander if( ca == NULL ) 1644*817466cbSJens Wiklander return( flags ); 1645*817466cbSJens Wiklander 1646*817466cbSJens Wiklander while( crl_list != NULL ) 1647*817466cbSJens Wiklander { 1648*817466cbSJens Wiklander if( crl_list->version == 0 || 1649*817466cbSJens Wiklander crl_list->issuer_raw.len != ca->subject_raw.len || 1650*817466cbSJens Wiklander memcmp( crl_list->issuer_raw.p, ca->subject_raw.p, 1651*817466cbSJens Wiklander crl_list->issuer_raw.len ) != 0 ) 1652*817466cbSJens Wiklander { 1653*817466cbSJens Wiklander crl_list = crl_list->next; 1654*817466cbSJens Wiklander continue; 1655*817466cbSJens Wiklander } 1656*817466cbSJens Wiklander 1657*817466cbSJens Wiklander /* 1658*817466cbSJens Wiklander * Check if the CA is configured to sign CRLs 1659*817466cbSJens Wiklander */ 1660*817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) 1661*817466cbSJens Wiklander if( mbedtls_x509_crt_check_key_usage( ca, MBEDTLS_X509_KU_CRL_SIGN ) != 0 ) 1662*817466cbSJens Wiklander { 1663*817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 1664*817466cbSJens Wiklander break; 1665*817466cbSJens Wiklander } 1666*817466cbSJens Wiklander #endif 1667*817466cbSJens Wiklander 1668*817466cbSJens Wiklander /* 1669*817466cbSJens Wiklander * Check if CRL is correctly signed by the trusted CA 1670*817466cbSJens Wiklander */ 1671*817466cbSJens Wiklander if( x509_profile_check_md_alg( profile, crl_list->sig_md ) != 0 ) 1672*817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_MD; 1673*817466cbSJens Wiklander 1674*817466cbSJens Wiklander if( x509_profile_check_pk_alg( profile, crl_list->sig_pk ) != 0 ) 1675*817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_BAD_PK; 1676*817466cbSJens Wiklander 1677*817466cbSJens Wiklander md_info = mbedtls_md_info_from_type( crl_list->sig_md ); 1678*817466cbSJens Wiklander if( md_info == NULL ) 1679*817466cbSJens Wiklander { 1680*817466cbSJens Wiklander /* 1681*817466cbSJens Wiklander * Cannot check 'unknown' hash 1682*817466cbSJens Wiklander */ 1683*817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 1684*817466cbSJens Wiklander break; 1685*817466cbSJens Wiklander } 1686*817466cbSJens Wiklander 1687*817466cbSJens Wiklander mbedtls_md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash ); 1688*817466cbSJens Wiklander 1689*817466cbSJens Wiklander if( x509_profile_check_key( profile, crl_list->sig_pk, &ca->pk ) != 0 ) 1690*817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 1691*817466cbSJens Wiklander 1692*817466cbSJens Wiklander if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, &ca->pk, 1693*817466cbSJens Wiklander crl_list->sig_md, hash, mbedtls_md_get_size( md_info ), 1694*817466cbSJens Wiklander crl_list->sig.p, crl_list->sig.len ) != 0 ) 1695*817466cbSJens Wiklander { 1696*817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; 1697*817466cbSJens Wiklander break; 1698*817466cbSJens Wiklander } 1699*817466cbSJens Wiklander 1700*817466cbSJens Wiklander /* 1701*817466cbSJens Wiklander * Check for validity of CRL (Do not drop out) 1702*817466cbSJens Wiklander */ 1703*817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &crl_list->next_update ) ) 1704*817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_EXPIRED; 1705*817466cbSJens Wiklander 1706*817466cbSJens Wiklander if( mbedtls_x509_time_is_future( &crl_list->this_update ) ) 1707*817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCRL_FUTURE; 1708*817466cbSJens Wiklander 1709*817466cbSJens Wiklander /* 1710*817466cbSJens Wiklander * Check if certificate is revoked 1711*817466cbSJens Wiklander */ 1712*817466cbSJens Wiklander if( mbedtls_x509_crt_is_revoked( crt, crl_list ) ) 1713*817466cbSJens Wiklander { 1714*817466cbSJens Wiklander flags |= MBEDTLS_X509_BADCERT_REVOKED; 1715*817466cbSJens Wiklander break; 1716*817466cbSJens Wiklander } 1717*817466cbSJens Wiklander 1718*817466cbSJens Wiklander crl_list = crl_list->next; 1719*817466cbSJens Wiklander } 1720*817466cbSJens Wiklander 1721*817466cbSJens Wiklander return( flags ); 1722*817466cbSJens Wiklander } 1723*817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRL_PARSE_C */ 1724*817466cbSJens Wiklander 1725*817466cbSJens Wiklander /* 1726*817466cbSJens Wiklander * Like memcmp, but case-insensitive and always returns -1 if different 1727*817466cbSJens Wiklander */ 1728*817466cbSJens Wiklander static int x509_memcasecmp( const void *s1, const void *s2, size_t len ) 1729*817466cbSJens Wiklander { 1730*817466cbSJens Wiklander size_t i; 1731*817466cbSJens Wiklander unsigned char diff; 1732*817466cbSJens Wiklander const unsigned char *n1 = s1, *n2 = s2; 1733*817466cbSJens Wiklander 1734*817466cbSJens Wiklander for( i = 0; i < len; i++ ) 1735*817466cbSJens Wiklander { 1736*817466cbSJens Wiklander diff = n1[i] ^ n2[i]; 1737*817466cbSJens Wiklander 1738*817466cbSJens Wiklander if( diff == 0 ) 1739*817466cbSJens Wiklander continue; 1740*817466cbSJens Wiklander 1741*817466cbSJens Wiklander if( diff == 32 && 1742*817466cbSJens Wiklander ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || 1743*817466cbSJens Wiklander ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) 1744*817466cbSJens Wiklander { 1745*817466cbSJens Wiklander continue; 1746*817466cbSJens Wiklander } 1747*817466cbSJens Wiklander 1748*817466cbSJens Wiklander return( -1 ); 1749*817466cbSJens Wiklander } 1750*817466cbSJens Wiklander 1751*817466cbSJens Wiklander return( 0 ); 1752*817466cbSJens Wiklander } 1753*817466cbSJens Wiklander 1754*817466cbSJens Wiklander /* 1755*817466cbSJens Wiklander * Return 0 if name matches wildcard, -1 otherwise 1756*817466cbSJens Wiklander */ 1757*817466cbSJens Wiklander static int x509_check_wildcard( const char *cn, mbedtls_x509_buf *name ) 1758*817466cbSJens Wiklander { 1759*817466cbSJens Wiklander size_t i; 1760*817466cbSJens Wiklander size_t cn_idx = 0, cn_len = strlen( cn ); 1761*817466cbSJens Wiklander 1762*817466cbSJens Wiklander if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) 1763*817466cbSJens Wiklander return( 0 ); 1764*817466cbSJens Wiklander 1765*817466cbSJens Wiklander for( i = 0; i < cn_len; ++i ) 1766*817466cbSJens Wiklander { 1767*817466cbSJens Wiklander if( cn[i] == '.' ) 1768*817466cbSJens Wiklander { 1769*817466cbSJens Wiklander cn_idx = i; 1770*817466cbSJens Wiklander break; 1771*817466cbSJens Wiklander } 1772*817466cbSJens Wiklander } 1773*817466cbSJens Wiklander 1774*817466cbSJens Wiklander if( cn_idx == 0 ) 1775*817466cbSJens Wiklander return( -1 ); 1776*817466cbSJens Wiklander 1777*817466cbSJens Wiklander if( cn_len - cn_idx == name->len - 1 && 1778*817466cbSJens Wiklander x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) 1779*817466cbSJens Wiklander { 1780*817466cbSJens Wiklander return( 0 ); 1781*817466cbSJens Wiklander } 1782*817466cbSJens Wiklander 1783*817466cbSJens Wiklander return( -1 ); 1784*817466cbSJens Wiklander } 1785*817466cbSJens Wiklander 1786*817466cbSJens Wiklander /* 1787*817466cbSJens Wiklander * Compare two X.509 strings, case-insensitive, and allowing for some encoding 1788*817466cbSJens Wiklander * variations (but not all). 1789*817466cbSJens Wiklander * 1790*817466cbSJens Wiklander * Return 0 if equal, -1 otherwise. 1791*817466cbSJens Wiklander */ 1792*817466cbSJens Wiklander static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ) 1793*817466cbSJens Wiklander { 1794*817466cbSJens Wiklander if( a->tag == b->tag && 1795*817466cbSJens Wiklander a->len == b->len && 1796*817466cbSJens Wiklander memcmp( a->p, b->p, b->len ) == 0 ) 1797*817466cbSJens Wiklander { 1798*817466cbSJens Wiklander return( 0 ); 1799*817466cbSJens Wiklander } 1800*817466cbSJens Wiklander 1801*817466cbSJens Wiklander if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && 1802*817466cbSJens Wiklander ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && 1803*817466cbSJens Wiklander a->len == b->len && 1804*817466cbSJens Wiklander x509_memcasecmp( a->p, b->p, b->len ) == 0 ) 1805*817466cbSJens Wiklander { 1806*817466cbSJens Wiklander return( 0 ); 1807*817466cbSJens Wiklander } 1808*817466cbSJens Wiklander 1809*817466cbSJens Wiklander return( -1 ); 1810*817466cbSJens Wiklander } 1811*817466cbSJens Wiklander 1812*817466cbSJens Wiklander /* 1813*817466cbSJens Wiklander * Compare two X.509 Names (aka rdnSequence). 1814*817466cbSJens Wiklander * 1815*817466cbSJens Wiklander * See RFC 5280 section 7.1, though we don't implement the whole algorithm: 1816*817466cbSJens Wiklander * we sometimes return unequal when the full algorithm would return equal, 1817*817466cbSJens Wiklander * but never the other way. (In particular, we don't do Unicode normalisation 1818*817466cbSJens Wiklander * or space folding.) 1819*817466cbSJens Wiklander * 1820*817466cbSJens Wiklander * Return 0 if equal, -1 otherwise. 1821*817466cbSJens Wiklander */ 1822*817466cbSJens Wiklander static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ) 1823*817466cbSJens Wiklander { 1824*817466cbSJens Wiklander /* Avoid recursion, it might not be optimised by the compiler */ 1825*817466cbSJens Wiklander while( a != NULL || b != NULL ) 1826*817466cbSJens Wiklander { 1827*817466cbSJens Wiklander if( a == NULL || b == NULL ) 1828*817466cbSJens Wiklander return( -1 ); 1829*817466cbSJens Wiklander 1830*817466cbSJens Wiklander /* type */ 1831*817466cbSJens Wiklander if( a->oid.tag != b->oid.tag || 1832*817466cbSJens Wiklander a->oid.len != b->oid.len || 1833*817466cbSJens Wiklander memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) 1834*817466cbSJens Wiklander { 1835*817466cbSJens Wiklander return( -1 ); 1836*817466cbSJens Wiklander } 1837*817466cbSJens Wiklander 1838*817466cbSJens Wiklander /* value */ 1839*817466cbSJens Wiklander if( x509_string_cmp( &a->val, &b->val ) != 0 ) 1840*817466cbSJens Wiklander return( -1 ); 1841*817466cbSJens Wiklander 1842*817466cbSJens Wiklander /* structure of the list of sets */ 1843*817466cbSJens Wiklander if( a->next_merged != b->next_merged ) 1844*817466cbSJens Wiklander return( -1 ); 1845*817466cbSJens Wiklander 1846*817466cbSJens Wiklander a = a->next; 1847*817466cbSJens Wiklander b = b->next; 1848*817466cbSJens Wiklander } 1849*817466cbSJens Wiklander 1850*817466cbSJens Wiklander /* a == NULL == b */ 1851*817466cbSJens Wiklander return( 0 ); 1852*817466cbSJens Wiklander } 1853*817466cbSJens Wiklander 1854*817466cbSJens Wiklander /* 1855*817466cbSJens Wiklander * Check if 'parent' is a suitable parent (signing CA) for 'child'. 1856*817466cbSJens Wiklander * Return 0 if yes, -1 if not. 1857*817466cbSJens Wiklander * 1858*817466cbSJens Wiklander * top means parent is a locally-trusted certificate 1859*817466cbSJens Wiklander * bottom means child is the end entity cert 1860*817466cbSJens Wiklander */ 1861*817466cbSJens Wiklander static int x509_crt_check_parent( const mbedtls_x509_crt *child, 1862*817466cbSJens Wiklander const mbedtls_x509_crt *parent, 1863*817466cbSJens Wiklander int top, int bottom ) 1864*817466cbSJens Wiklander { 1865*817466cbSJens Wiklander int need_ca_bit; 1866*817466cbSJens Wiklander 1867*817466cbSJens Wiklander /* Parent must be the issuer */ 1868*817466cbSJens Wiklander if( x509_name_cmp( &child->issuer, &parent->subject ) != 0 ) 1869*817466cbSJens Wiklander return( -1 ); 1870*817466cbSJens Wiklander 1871*817466cbSJens Wiklander /* Parent must have the basicConstraints CA bit set as a general rule */ 1872*817466cbSJens Wiklander need_ca_bit = 1; 1873*817466cbSJens Wiklander 1874*817466cbSJens Wiklander /* Exception: v1/v2 certificates that are locally trusted. */ 1875*817466cbSJens Wiklander if( top && parent->version < 3 ) 1876*817466cbSJens Wiklander need_ca_bit = 0; 1877*817466cbSJens Wiklander 1878*817466cbSJens Wiklander /* Exception: self-signed end-entity certs that are locally trusted. */ 1879*817466cbSJens Wiklander if( top && bottom && 1880*817466cbSJens Wiklander child->raw.len == parent->raw.len && 1881*817466cbSJens Wiklander memcmp( child->raw.p, parent->raw.p, child->raw.len ) == 0 ) 1882*817466cbSJens Wiklander { 1883*817466cbSJens Wiklander need_ca_bit = 0; 1884*817466cbSJens Wiklander } 1885*817466cbSJens Wiklander 1886*817466cbSJens Wiklander if( need_ca_bit && ! parent->ca_istrue ) 1887*817466cbSJens Wiklander return( -1 ); 1888*817466cbSJens Wiklander 1889*817466cbSJens Wiklander #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) 1890*817466cbSJens Wiklander if( need_ca_bit && 1891*817466cbSJens Wiklander mbedtls_x509_crt_check_key_usage( parent, MBEDTLS_X509_KU_KEY_CERT_SIGN ) != 0 ) 1892*817466cbSJens Wiklander { 1893*817466cbSJens Wiklander return( -1 ); 1894*817466cbSJens Wiklander } 1895*817466cbSJens Wiklander #endif 1896*817466cbSJens Wiklander 1897*817466cbSJens Wiklander return( 0 ); 1898*817466cbSJens Wiklander } 1899*817466cbSJens Wiklander 1900*817466cbSJens Wiklander static int x509_crt_verify_top( 1901*817466cbSJens Wiklander mbedtls_x509_crt *child, mbedtls_x509_crt *trust_ca, 1902*817466cbSJens Wiklander mbedtls_x509_crl *ca_crl, 1903*817466cbSJens Wiklander const mbedtls_x509_crt_profile *profile, 1904*817466cbSJens Wiklander int path_cnt, int self_cnt, uint32_t *flags, 1905*817466cbSJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 1906*817466cbSJens Wiklander void *p_vrfy ) 1907*817466cbSJens Wiklander { 1908*817466cbSJens Wiklander int ret; 1909*817466cbSJens Wiklander uint32_t ca_flags = 0; 1910*817466cbSJens Wiklander int check_path_cnt; 1911*817466cbSJens Wiklander unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 1912*817466cbSJens Wiklander const mbedtls_md_info_t *md_info; 1913*817466cbSJens Wiklander mbedtls_x509_crt *future_past_ca = NULL; 1914*817466cbSJens Wiklander 1915*817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &child->valid_to ) ) 1916*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_EXPIRED; 1917*817466cbSJens Wiklander 1918*817466cbSJens Wiklander if( mbedtls_x509_time_is_future( &child->valid_from ) ) 1919*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_FUTURE; 1920*817466cbSJens Wiklander 1921*817466cbSJens Wiklander if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) 1922*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_MD; 1923*817466cbSJens Wiklander 1924*817466cbSJens Wiklander if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) 1925*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_PK; 1926*817466cbSJens Wiklander 1927*817466cbSJens Wiklander /* 1928*817466cbSJens Wiklander * Child is the top of the chain. Check against the trust_ca list. 1929*817466cbSJens Wiklander */ 1930*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 1931*817466cbSJens Wiklander 1932*817466cbSJens Wiklander md_info = mbedtls_md_info_from_type( child->sig_md ); 1933*817466cbSJens Wiklander if( md_info == NULL ) 1934*817466cbSJens Wiklander { 1935*817466cbSJens Wiklander /* 1936*817466cbSJens Wiklander * Cannot check 'unknown', no need to try any CA 1937*817466cbSJens Wiklander */ 1938*817466cbSJens Wiklander trust_ca = NULL; 1939*817466cbSJens Wiklander } 1940*817466cbSJens Wiklander else 1941*817466cbSJens Wiklander mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ); 1942*817466cbSJens Wiklander 1943*817466cbSJens Wiklander for( /* trust_ca */ ; trust_ca != NULL; trust_ca = trust_ca->next ) 1944*817466cbSJens Wiklander { 1945*817466cbSJens Wiklander if( x509_crt_check_parent( child, trust_ca, 1, path_cnt == 0 ) != 0 ) 1946*817466cbSJens Wiklander continue; 1947*817466cbSJens Wiklander 1948*817466cbSJens Wiklander check_path_cnt = path_cnt + 1; 1949*817466cbSJens Wiklander 1950*817466cbSJens Wiklander /* 1951*817466cbSJens Wiklander * Reduce check_path_cnt to check against if top of the chain is 1952*817466cbSJens Wiklander * the same as the trusted CA 1953*817466cbSJens Wiklander */ 1954*817466cbSJens Wiklander if( child->subject_raw.len == trust_ca->subject_raw.len && 1955*817466cbSJens Wiklander memcmp( child->subject_raw.p, trust_ca->subject_raw.p, 1956*817466cbSJens Wiklander child->issuer_raw.len ) == 0 ) 1957*817466cbSJens Wiklander { 1958*817466cbSJens Wiklander check_path_cnt--; 1959*817466cbSJens Wiklander } 1960*817466cbSJens Wiklander 1961*817466cbSJens Wiklander /* Self signed certificates do not count towards the limit */ 1962*817466cbSJens Wiklander if( trust_ca->max_pathlen > 0 && 1963*817466cbSJens Wiklander trust_ca->max_pathlen < check_path_cnt - self_cnt ) 1964*817466cbSJens Wiklander { 1965*817466cbSJens Wiklander continue; 1966*817466cbSJens Wiklander } 1967*817466cbSJens Wiklander 1968*817466cbSJens Wiklander if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &trust_ca->pk, 1969*817466cbSJens Wiklander child->sig_md, hash, mbedtls_md_get_size( md_info ), 1970*817466cbSJens Wiklander child->sig.p, child->sig.len ) != 0 ) 1971*817466cbSJens Wiklander { 1972*817466cbSJens Wiklander continue; 1973*817466cbSJens Wiklander } 1974*817466cbSJens Wiklander 1975*817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) || 1976*817466cbSJens Wiklander mbedtls_x509_time_is_future( &trust_ca->valid_from ) ) 1977*817466cbSJens Wiklander { 1978*817466cbSJens Wiklander if ( future_past_ca == NULL ) 1979*817466cbSJens Wiklander future_past_ca = trust_ca; 1980*817466cbSJens Wiklander 1981*817466cbSJens Wiklander continue; 1982*817466cbSJens Wiklander } 1983*817466cbSJens Wiklander 1984*817466cbSJens Wiklander break; 1985*817466cbSJens Wiklander } 1986*817466cbSJens Wiklander 1987*817466cbSJens Wiklander if( trust_ca != NULL || ( trust_ca = future_past_ca ) != NULL ) 1988*817466cbSJens Wiklander { 1989*817466cbSJens Wiklander /* 1990*817466cbSJens Wiklander * Top of chain is signed by a trusted CA 1991*817466cbSJens Wiklander */ 1992*817466cbSJens Wiklander *flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED; 1993*817466cbSJens Wiklander 1994*817466cbSJens Wiklander if( x509_profile_check_key( profile, child->sig_pk, &trust_ca->pk ) != 0 ) 1995*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 1996*817466cbSJens Wiklander } 1997*817466cbSJens Wiklander 1998*817466cbSJens Wiklander /* 1999*817466cbSJens Wiklander * If top of chain is not the same as the trusted CA send a verify request 2000*817466cbSJens Wiklander * to the callback for any issues with validity and CRL presence for the 2001*817466cbSJens Wiklander * trusted CA certificate. 2002*817466cbSJens Wiklander */ 2003*817466cbSJens Wiklander if( trust_ca != NULL && 2004*817466cbSJens Wiklander ( child->subject_raw.len != trust_ca->subject_raw.len || 2005*817466cbSJens Wiklander memcmp( child->subject_raw.p, trust_ca->subject_raw.p, 2006*817466cbSJens Wiklander child->issuer_raw.len ) != 0 ) ) 2007*817466cbSJens Wiklander { 2008*817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 2009*817466cbSJens Wiklander /* Check trusted CA's CRL for the chain's top crt */ 2010*817466cbSJens Wiklander *flags |= x509_crt_verifycrl( child, trust_ca, ca_crl, profile ); 2011*817466cbSJens Wiklander #else 2012*817466cbSJens Wiklander ((void) ca_crl); 2013*817466cbSJens Wiklander #endif 2014*817466cbSJens Wiklander 2015*817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) ) 2016*817466cbSJens Wiklander ca_flags |= MBEDTLS_X509_BADCERT_EXPIRED; 2017*817466cbSJens Wiklander 2018*817466cbSJens Wiklander if( mbedtls_x509_time_is_future( &trust_ca->valid_from ) ) 2019*817466cbSJens Wiklander ca_flags |= MBEDTLS_X509_BADCERT_FUTURE; 2020*817466cbSJens Wiklander 2021*817466cbSJens Wiklander if( NULL != f_vrfy ) 2022*817466cbSJens Wiklander { 2023*817466cbSJens Wiklander if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1, 2024*817466cbSJens Wiklander &ca_flags ) ) != 0 ) 2025*817466cbSJens Wiklander { 2026*817466cbSJens Wiklander return( ret ); 2027*817466cbSJens Wiklander } 2028*817466cbSJens Wiklander } 2029*817466cbSJens Wiklander } 2030*817466cbSJens Wiklander 2031*817466cbSJens Wiklander /* Call callback on top cert */ 2032*817466cbSJens Wiklander if( NULL != f_vrfy ) 2033*817466cbSJens Wiklander { 2034*817466cbSJens Wiklander if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) 2035*817466cbSJens Wiklander return( ret ); 2036*817466cbSJens Wiklander } 2037*817466cbSJens Wiklander 2038*817466cbSJens Wiklander *flags |= ca_flags; 2039*817466cbSJens Wiklander 2040*817466cbSJens Wiklander return( 0 ); 2041*817466cbSJens Wiklander } 2042*817466cbSJens Wiklander 2043*817466cbSJens Wiklander static int x509_crt_verify_child( 2044*817466cbSJens Wiklander mbedtls_x509_crt *child, mbedtls_x509_crt *parent, 2045*817466cbSJens Wiklander mbedtls_x509_crt *trust_ca, mbedtls_x509_crl *ca_crl, 2046*817466cbSJens Wiklander const mbedtls_x509_crt_profile *profile, 2047*817466cbSJens Wiklander int path_cnt, int self_cnt, uint32_t *flags, 2048*817466cbSJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 2049*817466cbSJens Wiklander void *p_vrfy ) 2050*817466cbSJens Wiklander { 2051*817466cbSJens Wiklander int ret; 2052*817466cbSJens Wiklander uint32_t parent_flags = 0; 2053*817466cbSJens Wiklander unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 2054*817466cbSJens Wiklander mbedtls_x509_crt *grandparent; 2055*817466cbSJens Wiklander const mbedtls_md_info_t *md_info; 2056*817466cbSJens Wiklander 2057*817466cbSJens Wiklander /* Counting intermediate self signed certificates */ 2058*817466cbSJens Wiklander if( ( path_cnt != 0 ) && x509_name_cmp( &child->issuer, &child->subject ) == 0 ) 2059*817466cbSJens Wiklander self_cnt++; 2060*817466cbSJens Wiklander 2061*817466cbSJens Wiklander /* path_cnt is 0 for the first intermediate CA */ 2062*817466cbSJens Wiklander if( 1 + path_cnt > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) 2063*817466cbSJens Wiklander { 2064*817466cbSJens Wiklander /* return immediately as the goal is to avoid unbounded recursion */ 2065*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FATAL_ERROR ); 2066*817466cbSJens Wiklander } 2067*817466cbSJens Wiklander 2068*817466cbSJens Wiklander if( mbedtls_x509_time_is_past( &child->valid_to ) ) 2069*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_EXPIRED; 2070*817466cbSJens Wiklander 2071*817466cbSJens Wiklander if( mbedtls_x509_time_is_future( &child->valid_from ) ) 2072*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_FUTURE; 2073*817466cbSJens Wiklander 2074*817466cbSJens Wiklander if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) 2075*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_MD; 2076*817466cbSJens Wiklander 2077*817466cbSJens Wiklander if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) 2078*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_PK; 2079*817466cbSJens Wiklander 2080*817466cbSJens Wiklander md_info = mbedtls_md_info_from_type( child->sig_md ); 2081*817466cbSJens Wiklander if( md_info == NULL ) 2082*817466cbSJens Wiklander { 2083*817466cbSJens Wiklander /* 2084*817466cbSJens Wiklander * Cannot check 'unknown' hash 2085*817466cbSJens Wiklander */ 2086*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 2087*817466cbSJens Wiklander } 2088*817466cbSJens Wiklander else 2089*817466cbSJens Wiklander { 2090*817466cbSJens Wiklander mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ); 2091*817466cbSJens Wiklander 2092*817466cbSJens Wiklander if( x509_profile_check_key( profile, child->sig_pk, &parent->pk ) != 0 ) 2093*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 2094*817466cbSJens Wiklander 2095*817466cbSJens Wiklander if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, 2096*817466cbSJens Wiklander child->sig_md, hash, mbedtls_md_get_size( md_info ), 2097*817466cbSJens Wiklander child->sig.p, child->sig.len ) != 0 ) 2098*817466cbSJens Wiklander { 2099*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; 2100*817466cbSJens Wiklander } 2101*817466cbSJens Wiklander } 2102*817466cbSJens Wiklander 2103*817466cbSJens Wiklander #if defined(MBEDTLS_X509_CRL_PARSE_C) 2104*817466cbSJens Wiklander /* Check trusted CA's CRL for the given crt */ 2105*817466cbSJens Wiklander *flags |= x509_crt_verifycrl(child, parent, ca_crl, profile ); 2106*817466cbSJens Wiklander #endif 2107*817466cbSJens Wiklander 2108*817466cbSJens Wiklander /* Look for a grandparent in trusted CAs */ 2109*817466cbSJens Wiklander for( grandparent = trust_ca; 2110*817466cbSJens Wiklander grandparent != NULL; 2111*817466cbSJens Wiklander grandparent = grandparent->next ) 2112*817466cbSJens Wiklander { 2113*817466cbSJens Wiklander if( x509_crt_check_parent( parent, grandparent, 2114*817466cbSJens Wiklander 0, path_cnt == 0 ) == 0 ) 2115*817466cbSJens Wiklander break; 2116*817466cbSJens Wiklander } 2117*817466cbSJens Wiklander 2118*817466cbSJens Wiklander if( grandparent != NULL ) 2119*817466cbSJens Wiklander { 2120*817466cbSJens Wiklander ret = x509_crt_verify_top( parent, grandparent, ca_crl, profile, 2121*817466cbSJens Wiklander path_cnt + 1, self_cnt, &parent_flags, f_vrfy, p_vrfy ); 2122*817466cbSJens Wiklander if( ret != 0 ) 2123*817466cbSJens Wiklander return( ret ); 2124*817466cbSJens Wiklander } 2125*817466cbSJens Wiklander else 2126*817466cbSJens Wiklander { 2127*817466cbSJens Wiklander /* Look for a grandparent upwards the chain */ 2128*817466cbSJens Wiklander for( grandparent = parent->next; 2129*817466cbSJens Wiklander grandparent != NULL; 2130*817466cbSJens Wiklander grandparent = grandparent->next ) 2131*817466cbSJens Wiklander { 2132*817466cbSJens Wiklander /* +2 because the current step is not yet accounted for 2133*817466cbSJens Wiklander * and because max_pathlen is one higher than it should be. 2134*817466cbSJens Wiklander * Also self signed certificates do not count to the limit. */ 2135*817466cbSJens Wiklander if( grandparent->max_pathlen > 0 && 2136*817466cbSJens Wiklander grandparent->max_pathlen < 2 + path_cnt - self_cnt ) 2137*817466cbSJens Wiklander { 2138*817466cbSJens Wiklander continue; 2139*817466cbSJens Wiklander } 2140*817466cbSJens Wiklander 2141*817466cbSJens Wiklander if( x509_crt_check_parent( parent, grandparent, 2142*817466cbSJens Wiklander 0, path_cnt == 0 ) == 0 ) 2143*817466cbSJens Wiklander break; 2144*817466cbSJens Wiklander } 2145*817466cbSJens Wiklander 2146*817466cbSJens Wiklander /* Is our parent part of the chain or at the top? */ 2147*817466cbSJens Wiklander if( grandparent != NULL ) 2148*817466cbSJens Wiklander { 2149*817466cbSJens Wiklander ret = x509_crt_verify_child( parent, grandparent, trust_ca, ca_crl, 2150*817466cbSJens Wiklander profile, path_cnt + 1, self_cnt, &parent_flags, 2151*817466cbSJens Wiklander f_vrfy, p_vrfy ); 2152*817466cbSJens Wiklander if( ret != 0 ) 2153*817466cbSJens Wiklander return( ret ); 2154*817466cbSJens Wiklander } 2155*817466cbSJens Wiklander else 2156*817466cbSJens Wiklander { 2157*817466cbSJens Wiklander ret = x509_crt_verify_top( parent, trust_ca, ca_crl, profile, 2158*817466cbSJens Wiklander path_cnt + 1, self_cnt, &parent_flags, 2159*817466cbSJens Wiklander f_vrfy, p_vrfy ); 2160*817466cbSJens Wiklander if( ret != 0 ) 2161*817466cbSJens Wiklander return( ret ); 2162*817466cbSJens Wiklander } 2163*817466cbSJens Wiklander } 2164*817466cbSJens Wiklander 2165*817466cbSJens Wiklander /* child is verified to be a child of the parent, call verify callback */ 2166*817466cbSJens Wiklander if( NULL != f_vrfy ) 2167*817466cbSJens Wiklander if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) 2168*817466cbSJens Wiklander return( ret ); 2169*817466cbSJens Wiklander 2170*817466cbSJens Wiklander *flags |= parent_flags; 2171*817466cbSJens Wiklander 2172*817466cbSJens Wiklander return( 0 ); 2173*817466cbSJens Wiklander } 2174*817466cbSJens Wiklander 2175*817466cbSJens Wiklander /* 2176*817466cbSJens Wiklander * Verify the certificate validity 2177*817466cbSJens Wiklander */ 2178*817466cbSJens Wiklander int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, 2179*817466cbSJens Wiklander mbedtls_x509_crt *trust_ca, 2180*817466cbSJens Wiklander mbedtls_x509_crl *ca_crl, 2181*817466cbSJens Wiklander const char *cn, uint32_t *flags, 2182*817466cbSJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 2183*817466cbSJens Wiklander void *p_vrfy ) 2184*817466cbSJens Wiklander { 2185*817466cbSJens Wiklander return( mbedtls_x509_crt_verify_with_profile( crt, trust_ca, ca_crl, 2186*817466cbSJens Wiklander &mbedtls_x509_crt_profile_default, cn, flags, f_vrfy, p_vrfy ) ); 2187*817466cbSJens Wiklander } 2188*817466cbSJens Wiklander 2189*817466cbSJens Wiklander 2190*817466cbSJens Wiklander /* 2191*817466cbSJens Wiklander * Verify the certificate validity, with profile 2192*817466cbSJens Wiklander */ 2193*817466cbSJens Wiklander int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, 2194*817466cbSJens Wiklander mbedtls_x509_crt *trust_ca, 2195*817466cbSJens Wiklander mbedtls_x509_crl *ca_crl, 2196*817466cbSJens Wiklander const mbedtls_x509_crt_profile *profile, 2197*817466cbSJens Wiklander const char *cn, uint32_t *flags, 2198*817466cbSJens Wiklander int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), 2199*817466cbSJens Wiklander void *p_vrfy ) 2200*817466cbSJens Wiklander { 2201*817466cbSJens Wiklander size_t cn_len; 2202*817466cbSJens Wiklander int ret; 2203*817466cbSJens Wiklander int pathlen = 0, selfsigned = 0; 2204*817466cbSJens Wiklander mbedtls_x509_crt *parent; 2205*817466cbSJens Wiklander mbedtls_x509_name *name; 2206*817466cbSJens Wiklander mbedtls_x509_sequence *cur = NULL; 2207*817466cbSJens Wiklander mbedtls_pk_type_t pk_type; 2208*817466cbSJens Wiklander 2209*817466cbSJens Wiklander *flags = 0; 2210*817466cbSJens Wiklander 2211*817466cbSJens Wiklander if( profile == NULL ) 2212*817466cbSJens Wiklander { 2213*817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; 2214*817466cbSJens Wiklander goto exit; 2215*817466cbSJens Wiklander } 2216*817466cbSJens Wiklander 2217*817466cbSJens Wiklander if( cn != NULL ) 2218*817466cbSJens Wiklander { 2219*817466cbSJens Wiklander name = &crt->subject; 2220*817466cbSJens Wiklander cn_len = strlen( cn ); 2221*817466cbSJens Wiklander 2222*817466cbSJens Wiklander if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) 2223*817466cbSJens Wiklander { 2224*817466cbSJens Wiklander cur = &crt->subject_alt_names; 2225*817466cbSJens Wiklander 2226*817466cbSJens Wiklander while( cur != NULL ) 2227*817466cbSJens Wiklander { 2228*817466cbSJens Wiklander if( cur->buf.len == cn_len && 2229*817466cbSJens Wiklander x509_memcasecmp( cn, cur->buf.p, cn_len ) == 0 ) 2230*817466cbSJens Wiklander break; 2231*817466cbSJens Wiklander 2232*817466cbSJens Wiklander if( cur->buf.len > 2 && 2233*817466cbSJens Wiklander memcmp( cur->buf.p, "*.", 2 ) == 0 && 2234*817466cbSJens Wiklander x509_check_wildcard( cn, &cur->buf ) == 0 ) 2235*817466cbSJens Wiklander { 2236*817466cbSJens Wiklander break; 2237*817466cbSJens Wiklander } 2238*817466cbSJens Wiklander 2239*817466cbSJens Wiklander cur = cur->next; 2240*817466cbSJens Wiklander } 2241*817466cbSJens Wiklander 2242*817466cbSJens Wiklander if( cur == NULL ) 2243*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; 2244*817466cbSJens Wiklander } 2245*817466cbSJens Wiklander else 2246*817466cbSJens Wiklander { 2247*817466cbSJens Wiklander while( name != NULL ) 2248*817466cbSJens Wiklander { 2249*817466cbSJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 ) 2250*817466cbSJens Wiklander { 2251*817466cbSJens Wiklander if( name->val.len == cn_len && 2252*817466cbSJens Wiklander x509_memcasecmp( name->val.p, cn, cn_len ) == 0 ) 2253*817466cbSJens Wiklander break; 2254*817466cbSJens Wiklander 2255*817466cbSJens Wiklander if( name->val.len > 2 && 2256*817466cbSJens Wiklander memcmp( name->val.p, "*.", 2 ) == 0 && 2257*817466cbSJens Wiklander x509_check_wildcard( cn, &name->val ) == 0 ) 2258*817466cbSJens Wiklander break; 2259*817466cbSJens Wiklander } 2260*817466cbSJens Wiklander 2261*817466cbSJens Wiklander name = name->next; 2262*817466cbSJens Wiklander } 2263*817466cbSJens Wiklander 2264*817466cbSJens Wiklander if( name == NULL ) 2265*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; 2266*817466cbSJens Wiklander } 2267*817466cbSJens Wiklander } 2268*817466cbSJens Wiklander 2269*817466cbSJens Wiklander /* Check the type and size of the key */ 2270*817466cbSJens Wiklander pk_type = mbedtls_pk_get_type( &crt->pk ); 2271*817466cbSJens Wiklander 2272*817466cbSJens Wiklander if( x509_profile_check_pk_alg( profile, pk_type ) != 0 ) 2273*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_PK; 2274*817466cbSJens Wiklander 2275*817466cbSJens Wiklander if( x509_profile_check_key( profile, pk_type, &crt->pk ) != 0 ) 2276*817466cbSJens Wiklander *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; 2277*817466cbSJens Wiklander 2278*817466cbSJens Wiklander /* Look for a parent in trusted CAs */ 2279*817466cbSJens Wiklander for( parent = trust_ca; parent != NULL; parent = parent->next ) 2280*817466cbSJens Wiklander { 2281*817466cbSJens Wiklander if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) 2282*817466cbSJens Wiklander break; 2283*817466cbSJens Wiklander } 2284*817466cbSJens Wiklander 2285*817466cbSJens Wiklander if( parent != NULL ) 2286*817466cbSJens Wiklander { 2287*817466cbSJens Wiklander ret = x509_crt_verify_top( crt, parent, ca_crl, profile, 2288*817466cbSJens Wiklander pathlen, selfsigned, flags, f_vrfy, p_vrfy ); 2289*817466cbSJens Wiklander if( ret != 0 ) 2290*817466cbSJens Wiklander goto exit; 2291*817466cbSJens Wiklander } 2292*817466cbSJens Wiklander else 2293*817466cbSJens Wiklander { 2294*817466cbSJens Wiklander /* Look for a parent upwards the chain */ 2295*817466cbSJens Wiklander for( parent = crt->next; parent != NULL; parent = parent->next ) 2296*817466cbSJens Wiklander if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) 2297*817466cbSJens Wiklander break; 2298*817466cbSJens Wiklander 2299*817466cbSJens Wiklander /* Are we part of the chain or at the top? */ 2300*817466cbSJens Wiklander if( parent != NULL ) 2301*817466cbSJens Wiklander { 2302*817466cbSJens Wiklander ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, profile, 2303*817466cbSJens Wiklander pathlen, selfsigned, flags, f_vrfy, p_vrfy ); 2304*817466cbSJens Wiklander if( ret != 0 ) 2305*817466cbSJens Wiklander goto exit; 2306*817466cbSJens Wiklander } 2307*817466cbSJens Wiklander else 2308*817466cbSJens Wiklander { 2309*817466cbSJens Wiklander ret = x509_crt_verify_top( crt, trust_ca, ca_crl, profile, 2310*817466cbSJens Wiklander pathlen, selfsigned, flags, f_vrfy, p_vrfy ); 2311*817466cbSJens Wiklander if( ret != 0 ) 2312*817466cbSJens Wiklander goto exit; 2313*817466cbSJens Wiklander } 2314*817466cbSJens Wiklander } 2315*817466cbSJens Wiklander 2316*817466cbSJens Wiklander exit: 2317*817466cbSJens Wiklander /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by 2318*817466cbSJens Wiklander * the SSL module for authmode optional, but non-zero return from the 2319*817466cbSJens Wiklander * callback means a fatal error so it shouldn't be ignored */ 2320*817466cbSJens Wiklander if( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ) 2321*817466cbSJens Wiklander ret = MBEDTLS_ERR_X509_FATAL_ERROR; 2322*817466cbSJens Wiklander 2323*817466cbSJens Wiklander if( ret != 0 ) 2324*817466cbSJens Wiklander { 2325*817466cbSJens Wiklander *flags = (uint32_t) -1; 2326*817466cbSJens Wiklander return( ret ); 2327*817466cbSJens Wiklander } 2328*817466cbSJens Wiklander 2329*817466cbSJens Wiklander if( *flags != 0 ) 2330*817466cbSJens Wiklander return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); 2331*817466cbSJens Wiklander 2332*817466cbSJens Wiklander return( 0 ); 2333*817466cbSJens Wiklander } 2334*817466cbSJens Wiklander 2335*817466cbSJens Wiklander /* 2336*817466cbSJens Wiklander * Initialize a certificate chain 2337*817466cbSJens Wiklander */ 2338*817466cbSJens Wiklander void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ) 2339*817466cbSJens Wiklander { 2340*817466cbSJens Wiklander memset( crt, 0, sizeof(mbedtls_x509_crt) ); 2341*817466cbSJens Wiklander } 2342*817466cbSJens Wiklander 2343*817466cbSJens Wiklander /* 2344*817466cbSJens Wiklander * Unallocate all certificate data 2345*817466cbSJens Wiklander */ 2346*817466cbSJens Wiklander void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) 2347*817466cbSJens Wiklander { 2348*817466cbSJens Wiklander mbedtls_x509_crt *cert_cur = crt; 2349*817466cbSJens Wiklander mbedtls_x509_crt *cert_prv; 2350*817466cbSJens Wiklander mbedtls_x509_name *name_cur; 2351*817466cbSJens Wiklander mbedtls_x509_name *name_prv; 2352*817466cbSJens Wiklander mbedtls_x509_sequence *seq_cur; 2353*817466cbSJens Wiklander mbedtls_x509_sequence *seq_prv; 2354*817466cbSJens Wiklander 2355*817466cbSJens Wiklander if( crt == NULL ) 2356*817466cbSJens Wiklander return; 2357*817466cbSJens Wiklander 2358*817466cbSJens Wiklander do 2359*817466cbSJens Wiklander { 2360*817466cbSJens Wiklander mbedtls_pk_free( &cert_cur->pk ); 2361*817466cbSJens Wiklander 2362*817466cbSJens Wiklander #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) 2363*817466cbSJens Wiklander mbedtls_free( cert_cur->sig_opts ); 2364*817466cbSJens Wiklander #endif 2365*817466cbSJens Wiklander 2366*817466cbSJens Wiklander name_cur = cert_cur->issuer.next; 2367*817466cbSJens Wiklander while( name_cur != NULL ) 2368*817466cbSJens Wiklander { 2369*817466cbSJens Wiklander name_prv = name_cur; 2370*817466cbSJens Wiklander name_cur = name_cur->next; 2371*817466cbSJens Wiklander mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); 2372*817466cbSJens Wiklander mbedtls_free( name_prv ); 2373*817466cbSJens Wiklander } 2374*817466cbSJens Wiklander 2375*817466cbSJens Wiklander name_cur = cert_cur->subject.next; 2376*817466cbSJens Wiklander while( name_cur != NULL ) 2377*817466cbSJens Wiklander { 2378*817466cbSJens Wiklander name_prv = name_cur; 2379*817466cbSJens Wiklander name_cur = name_cur->next; 2380*817466cbSJens Wiklander mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); 2381*817466cbSJens Wiklander mbedtls_free( name_prv ); 2382*817466cbSJens Wiklander } 2383*817466cbSJens Wiklander 2384*817466cbSJens Wiklander seq_cur = cert_cur->ext_key_usage.next; 2385*817466cbSJens Wiklander while( seq_cur != NULL ) 2386*817466cbSJens Wiklander { 2387*817466cbSJens Wiklander seq_prv = seq_cur; 2388*817466cbSJens Wiklander seq_cur = seq_cur->next; 2389*817466cbSJens Wiklander mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) ); 2390*817466cbSJens Wiklander mbedtls_free( seq_prv ); 2391*817466cbSJens Wiklander } 2392*817466cbSJens Wiklander 2393*817466cbSJens Wiklander seq_cur = cert_cur->subject_alt_names.next; 2394*817466cbSJens Wiklander while( seq_cur != NULL ) 2395*817466cbSJens Wiklander { 2396*817466cbSJens Wiklander seq_prv = seq_cur; 2397*817466cbSJens Wiklander seq_cur = seq_cur->next; 2398*817466cbSJens Wiklander mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) ); 2399*817466cbSJens Wiklander mbedtls_free( seq_prv ); 2400*817466cbSJens Wiklander } 2401*817466cbSJens Wiklander 2402*817466cbSJens Wiklander if( cert_cur->raw.p != NULL ) 2403*817466cbSJens Wiklander { 2404*817466cbSJens Wiklander mbedtls_zeroize( cert_cur->raw.p, cert_cur->raw.len ); 2405*817466cbSJens Wiklander mbedtls_free( cert_cur->raw.p ); 2406*817466cbSJens Wiklander } 2407*817466cbSJens Wiklander 2408*817466cbSJens Wiklander cert_cur = cert_cur->next; 2409*817466cbSJens Wiklander } 2410*817466cbSJens Wiklander while( cert_cur != NULL ); 2411*817466cbSJens Wiklander 2412*817466cbSJens Wiklander cert_cur = crt; 2413*817466cbSJens Wiklander do 2414*817466cbSJens Wiklander { 2415*817466cbSJens Wiklander cert_prv = cert_cur; 2416*817466cbSJens Wiklander cert_cur = cert_cur->next; 2417*817466cbSJens Wiklander 2418*817466cbSJens Wiklander mbedtls_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) ); 2419*817466cbSJens Wiklander if( cert_prv != crt ) 2420*817466cbSJens Wiklander mbedtls_free( cert_prv ); 2421*817466cbSJens Wiklander } 2422*817466cbSJens Wiklander while( cert_cur != NULL ); 2423*817466cbSJens Wiklander } 2424*817466cbSJens Wiklander 2425*817466cbSJens Wiklander #endif /* MBEDTLS_X509_CRT_PARSE_C */ 2426