x509_crt.c 65.7 KB
Newer Older
1
/*
2
 *  X.509 certificate parsing and verification
3
 *
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
4
 *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
Paul Bakker's avatar
Paul Bakker committed
5
 *
6
 *  This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakker's avatar
Paul Bakker committed
7
 *
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
/*
Paul Bakker's avatar
Paul Bakker committed
23
 *  The ITU-T X.509 standard defines a certificate format for PKI.
24
 *
25 26 27
 *  http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs)
 *  http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs)
 *  http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10)
28 29 30 31 32
 *
 *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
 *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
 */

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
33
#if !defined(MBEDTLS_CONFIG_FILE)
34
#include "mbedtls/config.h"
35
#else
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
36
#include MBEDTLS_CONFIG_FILE
37
#endif
38

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
39
#if defined(MBEDTLS_X509_CRT_PARSE_C)
40

41 42
#include "mbedtls/x509_crt.h"
#include "mbedtls/oid.h"
43 44 45 46

#include <stdio.h>
#include <string.h>

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
47
#if defined(MBEDTLS_PEM_PARSE_C)
48
#include "mbedtls/pem.h"
49
#endif
50

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
51
#if defined(MBEDTLS_PLATFORM_C)
52
#include "mbedtls/platform.h"
53
#else
54
#include <stdlib.h>
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
55
#define mbedtls_free       free
56
#define mbedtls_calloc    calloc
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
57
#define mbedtls_snprintf   snprintf
58 59
#endif

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
60
#if defined(MBEDTLS_THREADING_C)
61
#include "mbedtls/threading.h"
62 63
#endif

64
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
65 66
#include <windows.h>
#else
67
#include <time.h>
68
#endif
69

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
70
#if defined(MBEDTLS_FS_IO)
71
#include <stdio.h>
72
#if !defined(_WIN32) || defined(EFIX64) || defined(EFI32)
Paul Bakker's avatar
Paul Bakker committed
73
#include <sys/types.h>
74
#include <sys/stat.h>
Paul Bakker's avatar
Paul Bakker committed
75
#include <dirent.h>
76
#endif /* !_WIN32 || EFIX64 || EFI32 */
77 78
#endif

79
/* Implementation that should never be optimized out by the compiler */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
80
static void mbedtls_zeroize( void *v, size_t n ) {
81 82 83
    volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}

84 85 86 87 88
/*
 * Default profile
 */
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default =
{
89 90 91 92 93 94 95 96 97
    /* Hashes from SHA-1 and above */
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
    0xFFFFFFF, /* Any PK alg    */
    0xFFFFFFF, /* Any curve     */
98 99 100 101 102 103
    2048,
};

/*
 * Next-default profile
 */
104
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next =
105
{
106 107 108 109 110
    /* Hashes from SHA-256 and above */
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
    0xFFFFFFF, /* Any PK alg    */
111
#if defined(MBEDTLS_ECP_C)
112 113 114 115 116 117 118 119
    /* Curves at or above 128-bit security level */
    MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP521R1 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP256R1 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP384R1 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP512R1 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256K1 ),
120
#else
121
    0,
122 123 124 125 126 127 128
#endif
    2048,
};

/*
 * NSA Suite B Profile
 */
129
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb =
130
{
131 132 133 134 135
    /* Only SHA-256 and 384 */
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ),
    /* Only ECDSA */
    MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ),
136
#if defined(MBEDTLS_ECP_C)
137 138 139
    /* Only NIST P-256 and P-384 */
    MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) |
    MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ),
140
#else
141
    0,
142
#endif
143
    0,
144 145
};

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
/*
 * Check md_alg against profile
 * Return 0 if md_alg acceptable for this profile, -1 otherwise
 */
static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile,
                                      mbedtls_md_type_t md_alg )
{
    if( ( profile->allowed_mds & MBEDTLS_X509_ID_FLAG( md_alg ) ) != 0 )
        return( 0 );

    return( -1 );
}

/*
 * Check pk_alg against profile
 * Return 0 if pk_alg acceptable for this profile, -1 otherwise
 */
static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile,
                                      mbedtls_pk_type_t pk_alg )
{
    if( ( profile->allowed_pks & MBEDTLS_X509_ID_FLAG( pk_alg ) ) != 0 )
        return( 0 );

    return( -1 );
}

/*
 * Check key against profile
 * Return 0 if pk_alg acceptable for this profile, -1 otherwise
 */
static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile,
                                   mbedtls_pk_type_t pk_alg,
                                   const mbedtls_pk_context *pk )
{
#if defined(MBEDTLS_RSA_C)
    if( pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS )
    {
183
        if( mbedtls_pk_get_bitlen( pk ) >= profile->rsa_min_bitlen )
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
            return( 0 );

        return( -1 );
    }
#endif

#if defined(MBEDTLS_ECDSA_C)
    if( pk_alg == MBEDTLS_PK_ECDSA )
    {
        mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id;

        if( ( profile->allowed_curves & MBEDTLS_X509_ID_FLAG( gid ) ) != 0 )
            return( 0 );

        return( -1 );
    }
#endif

    return( -1 );
}

205 206 207 208
/*
 *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
 */
static int x509_get_version( unsigned char **p,
209
                             const unsigned char *end,
210 211
                             int *ver )
{
212 213
    int ret;
    size_t len;
214

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
215 216
    if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
            MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) != 0 )
217
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
218
        if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
Paul Bakker's avatar
Paul Bakker committed
219 220 221 222
        {
            *ver = 0;
            return( 0 );
        }
223 224 225 226 227 228

        return( ret );
    }

    end = *p + len;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
229 230
    if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 )
        return( MBEDTLS_ERR_X509_INVALID_VERSION + ret );
231 232

    if( *p != end )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
233 234
        return( MBEDTLS_ERR_X509_INVALID_VERSION +
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
235 236 237 238

    return( 0 );
}

239 240 241 242 243 244
/*
 *  Validity ::= SEQUENCE {
 *       notBefore      Time,
 *       notAfter       Time }
 */
static int x509_get_dates( unsigned char **p,
245
                           const unsigned char *end,
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
246 247
                           mbedtls_x509_time *from,
                           mbedtls_x509_time *to )
248
{
249 250
    int ret;
    size_t len;
251

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
252 253 254
    if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
        return( MBEDTLS_ERR_X509_INVALID_DATE + ret );
255

256 257
    end = *p + len;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
258
    if( ( ret = mbedtls_x509_get_time( p, end, from ) ) != 0 )
259 260
        return( ret );

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
261
    if( ( ret = mbedtls_x509_get_time( p, end, to ) ) != 0 )
262
        return( ret );
263 264

    if( *p != end )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
265 266
        return( MBEDTLS_ERR_X509_INVALID_DATE +
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
267 268 269 270 271 272 273 274

    return( 0 );
}

/*
 * X.509 v2/v3 unique identifier (not parsed)
 */
static int x509_get_uid( unsigned char **p,
275
                         const unsigned char *end,
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
276
                         mbedtls_x509_buf *uid, int n )
277 278 279 280 281 282 283 284
{
    int ret;

    if( *p == end )
        return( 0 );

    uid->tag = **p;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
285 286
    if( ( ret = mbedtls_asn1_get_tag( p, end, &uid->len,
            MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | n ) ) != 0 )
287
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
288
        if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
289 290 291 292 293 294 295 296 297 298 299
            return( 0 );

        return( ret );
    }

    uid->p = *p;
    *p += uid->len;

    return( 0 );
}

300 301 302 303
static int x509_get_basic_constraints( unsigned char **p,
                                       const unsigned char *end,
                                       int *ca_istrue,
                                       int *max_pathlen )
304
{
305 306
    int ret;
    size_t len;
307 308

    /*
309 310 311
     * BasicConstraints ::= SEQUENCE {
     *      cA                      BOOLEAN DEFAULT FALSE,
     *      pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
312
     */
313 314 315
    *ca_istrue = 0; /* DEFAULT FALSE */
    *max_pathlen = 0; /* endless */

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
316 317 318
    if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
319

320
    if( *p == end )
321
        return( 0 );
322

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
323
    if( ( ret = mbedtls_asn1_get_bool( p, end, ca_istrue ) ) != 0 )
324
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
325 326
        if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
            ret = mbedtls_asn1_get_int( p, end, ca_istrue );
327

328
        if( ret != 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
329
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
330

331 332
        if( *ca_istrue != 0 )
            *ca_istrue = 1;
333 334
    }

335
    if( *p == end )
336
        return( 0 );
337

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
338 339
    if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 )
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
340

341
    if( *p != end )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
342 343
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
344

345 346
    (*max_pathlen)++;

347
    return( 0 );
348 349
}

350 351 352
static int x509_get_ns_cert_type( unsigned char **p,
                                       const unsigned char *end,
                                       unsigned char *ns_cert_type)
353 354
{
    int ret;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
355
    mbedtls_x509_bitstring bs = { 0, 0, NULL };
356

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
357 358
    if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 )
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
359

360
    if( bs.len != 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
361 362
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                MBEDTLS_ERR_ASN1_INVALID_LENGTH );
363 364 365

    /* Get actual bitstring */
    *ns_cert_type = *bs.p;
366
    return( 0 );
367 368 369 370
}

static int x509_get_key_usage( unsigned char **p,
                               const unsigned char *end,
371
                               unsigned int *key_usage)
372 373
{
    int ret;
374
    size_t i;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
375
    mbedtls_x509_bitstring bs = { 0, 0, NULL };
376

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
377 378
    if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 )
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
379

380
    if( bs.len < 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
381 382
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                MBEDTLS_ERR_ASN1_INVALID_LENGTH );
383 384

    /* Get actual bitstring */
385 386 387 388 389 390
    *key_usage = 0;
    for( i = 0; i < bs.len && i < sizeof( unsigned int ); i++ )
    {
        *key_usage |= (unsigned int) bs.p[i] << (8*i);
    }

391
    return( 0 );
392 393
}

394
/*
395 396 397 398 399 400
 * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
 *
 * KeyPurposeId ::= OBJECT IDENTIFIER
 */
static int x509_get_ext_key_usage( unsigned char **p,
                               const unsigned char *end,
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
401
                               mbedtls_x509_sequence *ext_key_usage)
402 403 404
{
    int ret;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
405 406
    if( ( ret = mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, MBEDTLS_ASN1_OID ) ) != 0 )
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
407 408 409

    /* Sequence length must be >= 1 */
    if( ext_key_usage->buf.p == NULL )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
410 411
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                MBEDTLS_ERR_ASN1_INVALID_LENGTH );
412

413
    return( 0 );
414 415
}

416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
/*
 * SubjectAltName ::= GeneralNames
 *
 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
 *
 * GeneralName ::= CHOICE {
 *      otherName                       [0]     OtherName,
 *      rfc822Name                      [1]     IA5String,
 *      dNSName                         [2]     IA5String,
 *      x400Address                     [3]     ORAddress,
 *      directoryName                   [4]     Name,
 *      ediPartyName                    [5]     EDIPartyName,
 *      uniformResourceIdentifier       [6]     IA5String,
 *      iPAddress                       [7]     OCTET STRING,
 *      registeredID                    [8]     OBJECT IDENTIFIER }
 *
 * OtherName ::= SEQUENCE {
 *      type-id    OBJECT IDENTIFIER,
 *      value      [0] EXPLICIT ANY DEFINED BY type-id }
 *
 * EDIPartyName ::= SEQUENCE {
 *      nameAssigner            [0]     DirectoryString OPTIONAL,
 *      partyName               [1]     DirectoryString }
 *
440
 * NOTE: we only parse and use dNSName at this point.
441 442 443
 */
static int x509_get_subject_alt_name( unsigned char **p,
                                      const unsigned char *end,
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
444
                                      mbedtls_x509_sequence *subject_alt_name )
445 446 447
{
    int ret;
    size_t len, tag_len;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
448
    mbedtls_asn1_buf *buf;
449
    unsigned char tag;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
450
    mbedtls_asn1_sequence *cur = subject_alt_name;
451 452

    /* Get main sequence tag */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
453 454 455
    if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
456 457

    if( *p + len != end )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
458 459
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
460 461 462 463

    while( *p < end )
    {
        if( ( end - *p ) < 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
464 465
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                    MBEDTLS_ERR_ASN1_OUT_OF_DATA );
466 467 468

        tag = **p;
        (*p)++;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
469 470
        if( ( ret = mbedtls_asn1_get_len( p, end, &tag_len ) ) != 0 )
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
471

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
472 473 474
        if( ( tag & MBEDTLS_ASN1_CONTEXT_SPECIFIC ) != MBEDTLS_ASN1_CONTEXT_SPECIFIC )
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                    MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
475

476
        /* Skip everything but DNS name */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
477
        if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) )
478 479 480 481 482 483
        {
            *p += tag_len;
            continue;
        }

        /* Allocate and assign next pointer */
484
        if( cur->buf.p != NULL )
485
        {
486
            if( cur->next != NULL )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
487
                return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS );
488

489
            cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) );
490 491

            if( cur->next == NULL )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
492
                return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
493
                        MBEDTLS_ERR_ASN1_ALLOC_FAILED );
494 495 496

            cur = cur->next;
        }
497 498 499 500 501 502

        buf = &(cur->buf);
        buf->tag = tag;
        buf->p = *p;
        buf->len = tag_len;
        *p += buf->len;
503 504 505 506 507 508
    }

    /* Set final sequence entry's next pointer to NULL */
    cur->next = NULL;

    if( *p != end )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
509 510
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
511 512 513 514

    return( 0 );
}

515 516 517 518 519 520
/*
 * X.509 v3 extensions
 *
 * TODO: Perform all of the basic constraints tests required by the RFC
 * TODO: Set values for undetected extensions to a sane default?
 *
521 522
 */
static int x509_get_crt_ext( unsigned char **p,
523
                             const unsigned char *end,
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
524
                             mbedtls_x509_crt *crt )
525
{
526 527
    int ret;
    size_t len;
528
    unsigned char *end_ext_data, *end_ext_octet;
529

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
530
    if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 )
531
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
532
        if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
533 534 535 536 537
            return( 0 );

        return( ret );
    }

538 539
    while( *p < end )
    {
540 541 542 543 544 545
        /*
         * Extension  ::=  SEQUENCE  {
         *      extnID      OBJECT IDENTIFIER,
         *      critical    BOOLEAN DEFAULT FALSE,
         *      extnValue   OCTET STRING  }
         */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
546
        mbedtls_x509_buf extn_oid = {0, 0, NULL};
547
        int is_critical = 0; /* DEFAULT FALSE */
548
        int ext_type = 0;
549

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
550 551 552
        if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
                MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
553

554 555
        end_ext_data = *p + len;

556 557 558
        /* Get extension ID */
        extn_oid.tag = **p;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
559 560
        if( ( ret = mbedtls_asn1_get_tag( p, end, &extn_oid.len, MBEDTLS_ASN1_OID ) ) != 0 )
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
561

562 563
        extn_oid.p = *p;
        *p += extn_oid.len;
564

565
        if( ( end - *p ) < 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
566 567
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                    MBEDTLS_ERR_ASN1_OUT_OF_DATA );
568 569

        /* Get optional critical */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
570 571 572
        if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 &&
            ( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) )
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
573

574
        /* Data should be octet string type */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
575 576 577
        if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len,
                MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
578

579
        end_ext_octet = *p + len;
580

581
        if( end_ext_octet != end_ext_data )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
582 583
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                    MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
584

585 586 587
        /*
         * Detect supported extensions
         */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
588
        ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type );
589 590

        if( ret != 0 )
591
        {
592 593 594
            /* No parser found, skip extension */
            *p = end_ext_octet;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
595
#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
596 597 598
            if( is_critical )
            {
                /* Data is marked as critical: fail */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
599 600
                return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                        MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
601 602 603 604 605
            }
#endif
            continue;
        }

606 607
        /* Forbid repeated extensions */
        if( ( crt->ext_types & ext_type ) != 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
608
            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS );
609

610 611 612 613
        crt->ext_types |= ext_type;

        switch( ext_type )
        {
614
        case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS:
615 616
            /* Parse basic constraints */
            if( ( ret = x509_get_basic_constraints( p, end_ext_octet,
617
                    &crt->ca_istrue, &crt->max_pathlen ) ) != 0 )
618
                return( ret );
619 620
            break;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
621
        case MBEDTLS_X509_EXT_KEY_USAGE:
622 623 624
            /* Parse key usage */
            if( ( ret = x509_get_key_usage( p, end_ext_octet,
                    &crt->key_usage ) ) != 0 )
625
                return( ret );
626 627
            break;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
628
        case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE:
629 630 631
            /* Parse extended key usage */
            if( ( ret = x509_get_ext_key_usage( p, end_ext_octet,
                    &crt->ext_key_usage ) ) != 0 )
632
                return( ret );
633 634
            break;

635
        case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME:
636
            /* Parse subject alt name */
637 638
            if( ( ret = x509_get_subject_alt_name( p, end_ext_octet,
                    &crt->subject_alt_names ) ) != 0 )
639
                return( ret );
640
            break;
641

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
642
        case MBEDTLS_X509_EXT_NS_CERT_TYPE:
643 644 645
            /* Parse netscape certificate type */
            if( ( ret = x509_get_ns_cert_type( p, end_ext_octet,
                    &crt->ns_cert_type ) ) != 0 )
646
                return( ret );
647 648 649
            break;

        default:
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
650
            return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
651
        }
652 653 654
    }

    if( *p != end )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
655 656
        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
657 658 659 660 661

    return( 0 );
}

/*
662
 * Parse and fill a single X.509 certificate in DER format
663
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
664
static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *buf,
665
                                    size_t buflen )
666
{
667
    int ret;
668
    size_t len;
669
    unsigned char *p, *end, *crt_end;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
670
    mbedtls_x509_buf sig_params1, sig_params2, sig_oid2;
671

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
672 673 674
    memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) );
    memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) );
    memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) );
675

676 677 678 679
    /*
     * Check for valid input
     */
    if( crt == NULL || buf == NULL )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
680
        return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
681

682
    p = mbedtls_calloc( 1, len = buflen );
683
    if( p == NULL )
684
        return( MBEDTLS_ERR_X509_ALLOC_FAILED );
685 686 687

    memcpy( p, buf, buflen );

688 689 690 691 692 693 694 695 696 697
    crt->raw.p = p;
    crt->raw.len = len;
    end = p + len;

    /*
     * Certificate  ::=  SEQUENCE  {
     *      tbsCertificate       TBSCertificate,
     *      signatureAlgorithm   AlgorithmIdentifier,
     *      signatureValue       BIT STRING  }
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
698 699
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
700
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
701 702
        mbedtls_x509_crt_free( crt );
        return( MBEDTLS_ERR_X509_INVALID_FORMAT );
703 704
    }

705
    if( len > (size_t) ( end - p ) )
706
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
707 708 709
        mbedtls_x509_crt_free( crt );
        return( MBEDTLS_ERR_X509_INVALID_FORMAT +
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
710
    }
711
    crt_end = p + len;
712

713 714 715 716 717
    /*
     * TBSCertificate  ::=  SEQUENCE  {
     */
    crt->tbs.p = p;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
718 719
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
720
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
721 722
        mbedtls_x509_crt_free( crt );
        return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
723 724 725 726 727 728 729 730 731 732 733 734
    }

    end = p + len;
    crt->tbs.len = end - crt->tbs.p;

    /*
     * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
     *
     * CertificateSerialNumber  ::=  INTEGER
     *
     * signature            AlgorithmIdentifier
     */
735
    if( ( ret = x509_get_version(  &p, end, &crt->version  ) ) != 0 ||
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
736 737
        ( ret = mbedtls_x509_get_serial(   &p, end, &crt->serial   ) ) != 0 ||
        ( ret = mbedtls_x509_get_alg(      &p, end, &crt->sig_oid,
738
                                            &sig_params1 ) ) != 0 )
739
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
740
        mbedtls_x509_crt_free( crt );
741 742 743 744 745 746 747
        return( ret );
    }

    crt->version++;

    if( crt->version > 3 )
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
748 749
        mbedtls_x509_crt_free( crt );
        return( MBEDTLS_ERR_X509_UNKNOWN_VERSION );
750 751
    }

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
752
    if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1,
753 754
                                  &crt->sig_md, &crt->sig_pk,
                                  &crt->sig_opts ) ) != 0 )
755
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
756
        mbedtls_x509_crt_free( crt );
757
        return( ret );
758 759 760 761 762 763 764
    }

    /*
     * issuer               Name
     */
    crt->issuer_raw.p = p;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
765 766
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
767
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
768 769
        mbedtls_x509_crt_free( crt );
        return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
770 771
    }

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
772
    if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 )
773
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
774
        mbedtls_x509_crt_free( crt );
775 776 777 778 779 780 781 782 783 784 785 786 787 788
        return( ret );
    }

    crt->issuer_raw.len = p - crt->issuer_raw.p;

    /*
     * Validity ::= SEQUENCE {
     *      notBefore      Time,
     *      notAfter       Time }
     *
     */
    if( ( ret = x509_get_dates( &p, end, &crt->valid_from,
                                         &crt->valid_to ) ) != 0 )
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
789
        mbedtls_x509_crt_free( crt );
790 791 792 793 794 795 796 797
        return( ret );
    }

    /*
     * subject              Name
     */
    crt->subject_raw.p = p;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
798 799
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
800
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
801 802
        mbedtls_x509_crt_free( crt );
        return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
803 804
    }

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
805
    if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 )
806
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
807
        mbedtls_x509_crt_free( crt );
808 809 810 811 812 813
        return( ret );
    }

    crt->subject_raw.len = p - crt->subject_raw.p;

    /*
814
     * SubjectPublicKeyInfo
815
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
816
    if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 )
817
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
818
        mbedtls_x509_crt_free( crt );
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
        return( ret );
    }

    /*
     *  issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
     *                       -- If present, version shall be v2 or v3
     *  subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
     *                       -- If present, version shall be v2 or v3
     *  extensions      [3]  EXPLICIT Extensions OPTIONAL
     *                       -- If present, version shall be v3
     */
    if( crt->version == 2 || crt->version == 3 )
    {
        ret = x509_get_uid( &p, end, &crt->issuer_id,  1 );
        if( ret != 0 )
        {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
835
            mbedtls_x509_crt_free( crt );
836 837 838 839 840 841 842 843
            return( ret );
        }
    }

    if( crt->version == 2 || crt->version == 3 )
    {
        ret = x509_get_uid( &p, end, &crt->subject_id,  2 );
        if( ret != 0 )
844
        {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
845
            mbedtls_x509_crt_free( crt );
846 847
            return( ret );
        }
848 849
    }

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
850
#if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3)
851
    if( crt->version == 3 )
852
#endif
853
    {
854
        ret = x509_get_crt_ext( &p, end, crt );
855 856
        if( ret != 0 )
        {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
857
            mbedtls_x509_crt_free( crt );
858 859 860 861 862 863
            return( ret );
        }
    }

    if( p != end )
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
864 865 866
        mbedtls_x509_crt_free( crt );
        return( MBEDTLS_ERR_X509_INVALID_FORMAT +
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
867 868
    }

869
    end = crt_end;
870 871

    /*
872 873 874
     *  }
     *  -- end of TBSCertificate
     *
875 876 877
     *  signatureAlgorithm   AlgorithmIdentifier,
     *  signatureValue       BIT STRING
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
878
    if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 )
879
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
880
        mbedtls_x509_crt_free( crt );
881 882 883
        return( ret );
    }

884 885
    if( crt->sig_oid.len != sig_oid2.len ||
        memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 ||
886
        sig_params1.len != sig_params2.len ||
887 888
        ( sig_params1.len != 0 &&
          memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) )
889
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
890 891
        mbedtls_x509_crt_free( crt );
        return( MBEDTLS_ERR_X509_SIG_MISMATCH );
892 893
    }

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
894
    if( ( ret = mbedtls_x509_get_sig( &p, end, &crt->sig ) ) != 0 )
895
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
896
        mbedtls_x509_crt_free( crt );
897 898 899 900 901
        return( ret );
    }

    if( p != end )
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
902 903 904
        mbedtls_x509_crt_free( crt );
        return( MBEDTLS_ERR_X509_INVALID_FORMAT +
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
905 906
    }

907 908 909 910 911 912 913
    return( 0 );
}

/*
 * Parse one X.509 certificate in DER format from a buffer and add them to a
 * chained list
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
914
int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf,
915
                        size_t buflen )
916 917
{
    int ret;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
918
    mbedtls_x509_crt *crt = chain, *prev = NULL;
919 920 921 922 923

    /*
     * Check for valid input
     */
    if( crt == NULL || buf == NULL )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
924
        return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
925 926 927 928 929 930 931 932 933 934

    while( crt->version != 0 && crt->next != NULL )
    {
        prev = crt;
        crt = crt->next;
    }

    /*
     * Add new certificate on the end of the chain if needed.
     */
935
    if( crt->version != 0 && crt->next == NULL )
936
    {
937
        crt->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
938