RTC auf true

Committer:
kevman
Date:
Wed Mar 13 11:03:24 2019 +0000
Revision:
2:7aab896b1a3b
Parent:
0:38ceb79fef03
2019-03-13

Who changed what in which revision?

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