1*c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /* 3817466cbSJens Wiklander * X.509 common functions for parsing and verification 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander * 19817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 20817466cbSJens Wiklander */ 21817466cbSJens Wiklander /* 22817466cbSJens Wiklander * The ITU-T X.509 standard defines a certificate format for PKI. 23817466cbSJens Wiklander * 24817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) 25817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) 26817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) 27817466cbSJens Wiklander * 28817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf 29817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf 30817466cbSJens Wiklander */ 31817466cbSJens Wiklander 32817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 33817466cbSJens Wiklander #include "mbedtls/config.h" 34817466cbSJens Wiklander #else 35817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 36817466cbSJens Wiklander #endif 37817466cbSJens Wiklander 38817466cbSJens Wiklander #if defined(MBEDTLS_X509_USE_C) 39817466cbSJens Wiklander 40817466cbSJens Wiklander #include "mbedtls/x509.h" 41817466cbSJens Wiklander #include "mbedtls/asn1.h" 42817466cbSJens Wiklander #include "mbedtls/oid.h" 43817466cbSJens Wiklander 44817466cbSJens Wiklander #include <stdio.h> 45817466cbSJens Wiklander #include <string.h> 46817466cbSJens Wiklander 47817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 48817466cbSJens Wiklander #include "mbedtls/pem.h" 49817466cbSJens Wiklander #endif 50817466cbSJens Wiklander 51817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 52817466cbSJens Wiklander #include "mbedtls/platform.h" 53817466cbSJens Wiklander #else 54817466cbSJens Wiklander #include <stdio.h> 55817466cbSJens Wiklander #include <stdlib.h> 56817466cbSJens Wiklander #define mbedtls_free free 57817466cbSJens Wiklander #define mbedtls_calloc calloc 58817466cbSJens Wiklander #define mbedtls_printf printf 59817466cbSJens Wiklander #define mbedtls_snprintf snprintf 60817466cbSJens Wiklander #endif 61817466cbSJens Wiklander 62817466cbSJens Wiklander 63817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_TIME) 64817466cbSJens Wiklander #include "mbedtls/platform_time.h" 65817466cbSJens Wiklander #endif 66817466cbSJens Wiklander 67817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 68817466cbSJens Wiklander #include <windows.h> 69817466cbSJens Wiklander #else 70817466cbSJens Wiklander #include <time.h> 71817466cbSJens Wiklander #endif 72817466cbSJens Wiklander 73817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 74817466cbSJens Wiklander #include <stdio.h> 75817466cbSJens Wiklander #if !defined(_WIN32) 76817466cbSJens Wiklander #include <sys/types.h> 77817466cbSJens Wiklander #include <sys/stat.h> 78817466cbSJens Wiklander #include <dirent.h> 79817466cbSJens Wiklander #endif 80817466cbSJens Wiklander #endif 81817466cbSJens Wiklander 82817466cbSJens Wiklander #define CHECK(code) if( ( ret = code ) != 0 ){ return( ret ); } 83817466cbSJens Wiklander #define CHECK_RANGE(min, max, val) if( val < min || val > max ){ return( ret ); } 84817466cbSJens Wiklander 85817466cbSJens Wiklander /* 86817466cbSJens Wiklander * CertificateSerialNumber ::= INTEGER 87817466cbSJens Wiklander */ 88817466cbSJens Wiklander int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, 89817466cbSJens Wiklander mbedtls_x509_buf *serial ) 90817466cbSJens Wiklander { 91817466cbSJens Wiklander int ret; 92817466cbSJens Wiklander 93817466cbSJens Wiklander if( ( end - *p ) < 1 ) 94817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_SERIAL + 95817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 96817466cbSJens Wiklander 97817466cbSJens Wiklander if( **p != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_PRIMITIVE | 2 ) && 98817466cbSJens Wiklander **p != MBEDTLS_ASN1_INTEGER ) 99817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_SERIAL + 100817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 101817466cbSJens Wiklander 102817466cbSJens Wiklander serial->tag = *(*p)++; 103817466cbSJens Wiklander 104817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_len( p, end, &serial->len ) ) != 0 ) 105817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_SERIAL + ret ); 106817466cbSJens Wiklander 107817466cbSJens Wiklander serial->p = *p; 108817466cbSJens Wiklander *p += serial->len; 109817466cbSJens Wiklander 110817466cbSJens Wiklander return( 0 ); 111817466cbSJens Wiklander } 112817466cbSJens Wiklander 113817466cbSJens Wiklander /* Get an algorithm identifier without parameters (eg for signatures) 114817466cbSJens Wiklander * 115817466cbSJens Wiklander * AlgorithmIdentifier ::= SEQUENCE { 116817466cbSJens Wiklander * algorithm OBJECT IDENTIFIER, 117817466cbSJens Wiklander * parameters ANY DEFINED BY algorithm OPTIONAL } 118817466cbSJens Wiklander */ 119817466cbSJens Wiklander int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, 120817466cbSJens Wiklander mbedtls_x509_buf *alg ) 121817466cbSJens Wiklander { 122817466cbSJens Wiklander int ret; 123817466cbSJens Wiklander 124817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 ) 125817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 126817466cbSJens Wiklander 127817466cbSJens Wiklander return( 0 ); 128817466cbSJens Wiklander } 129817466cbSJens Wiklander 130817466cbSJens Wiklander /* 131817466cbSJens Wiklander * Parse an algorithm identifier with (optional) paramaters 132817466cbSJens Wiklander */ 133817466cbSJens Wiklander int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, 134817466cbSJens Wiklander mbedtls_x509_buf *alg, mbedtls_x509_buf *params ) 135817466cbSJens Wiklander { 136817466cbSJens Wiklander int ret; 137817466cbSJens Wiklander 138817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_alg( p, end, alg, params ) ) != 0 ) 139817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 140817466cbSJens Wiklander 141817466cbSJens Wiklander return( 0 ); 142817466cbSJens Wiklander } 143817466cbSJens Wiklander 144817466cbSJens Wiklander #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) 145817466cbSJens Wiklander /* 146817466cbSJens Wiklander * HashAlgorithm ::= AlgorithmIdentifier 147817466cbSJens Wiklander * 148817466cbSJens Wiklander * AlgorithmIdentifier ::= SEQUENCE { 149817466cbSJens Wiklander * algorithm OBJECT IDENTIFIER, 150817466cbSJens Wiklander * parameters ANY DEFINED BY algorithm OPTIONAL } 151817466cbSJens Wiklander * 152817466cbSJens Wiklander * For HashAlgorithm, parameters MUST be NULL or absent. 153817466cbSJens Wiklander */ 154817466cbSJens Wiklander static int x509_get_hash_alg( const mbedtls_x509_buf *alg, mbedtls_md_type_t *md_alg ) 155817466cbSJens Wiklander { 156817466cbSJens Wiklander int ret; 157817466cbSJens Wiklander unsigned char *p; 158817466cbSJens Wiklander const unsigned char *end; 159817466cbSJens Wiklander mbedtls_x509_buf md_oid; 160817466cbSJens Wiklander size_t len; 161817466cbSJens Wiklander 162817466cbSJens Wiklander /* Make sure we got a SEQUENCE and setup bounds */ 163817466cbSJens Wiklander if( alg->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) 164817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + 165817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 166817466cbSJens Wiklander 167817466cbSJens Wiklander p = (unsigned char *) alg->p; 168817466cbSJens Wiklander end = p + alg->len; 169817466cbSJens Wiklander 170817466cbSJens Wiklander if( p >= end ) 171817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + 172817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 173817466cbSJens Wiklander 174817466cbSJens Wiklander /* Parse md_oid */ 175817466cbSJens Wiklander md_oid.tag = *p; 176817466cbSJens Wiklander 177817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &md_oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) 178817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 179817466cbSJens Wiklander 180817466cbSJens Wiklander md_oid.p = p; 181817466cbSJens Wiklander p += md_oid.len; 182817466cbSJens Wiklander 183817466cbSJens Wiklander /* Get md_alg from md_oid */ 184817466cbSJens Wiklander if( ( ret = mbedtls_oid_get_md_alg( &md_oid, md_alg ) ) != 0 ) 185817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 186817466cbSJens Wiklander 187817466cbSJens Wiklander /* Make sure params is absent of NULL */ 188817466cbSJens Wiklander if( p == end ) 189817466cbSJens Wiklander return( 0 ); 190817466cbSJens Wiklander 191817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_NULL ) ) != 0 || len != 0 ) 192817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 193817466cbSJens Wiklander 194817466cbSJens Wiklander if( p != end ) 195817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + 196817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 197817466cbSJens Wiklander 198817466cbSJens Wiklander return( 0 ); 199817466cbSJens Wiklander } 200817466cbSJens Wiklander 201817466cbSJens Wiklander /* 202817466cbSJens Wiklander * RSASSA-PSS-params ::= SEQUENCE { 203817466cbSJens Wiklander * hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, 204817466cbSJens Wiklander * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1Identifier, 205817466cbSJens Wiklander * saltLength [2] INTEGER DEFAULT 20, 206817466cbSJens Wiklander * trailerField [3] INTEGER DEFAULT 1 } 207817466cbSJens Wiklander * -- Note that the tags in this Sequence are explicit. 208817466cbSJens Wiklander * 209817466cbSJens Wiklander * RFC 4055 (which defines use of RSASSA-PSS in PKIX) states that the value 210817466cbSJens Wiklander * of trailerField MUST be 1, and PKCS#1 v2.2 doesn't even define any other 211817466cbSJens Wiklander * option. Enfore this at parsing time. 212817466cbSJens Wiklander */ 213817466cbSJens Wiklander int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, 214817466cbSJens Wiklander mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, 215817466cbSJens Wiklander int *salt_len ) 216817466cbSJens Wiklander { 217817466cbSJens Wiklander int ret; 218817466cbSJens Wiklander unsigned char *p; 219817466cbSJens Wiklander const unsigned char *end, *end2; 220817466cbSJens Wiklander size_t len; 221817466cbSJens Wiklander mbedtls_x509_buf alg_id, alg_params; 222817466cbSJens Wiklander 223817466cbSJens Wiklander /* First set everything to defaults */ 224817466cbSJens Wiklander *md_alg = MBEDTLS_MD_SHA1; 225817466cbSJens Wiklander *mgf_md = MBEDTLS_MD_SHA1; 226817466cbSJens Wiklander *salt_len = 20; 227817466cbSJens Wiklander 228817466cbSJens Wiklander /* Make sure params is a SEQUENCE and setup bounds */ 229817466cbSJens Wiklander if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) 230817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + 231817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 232817466cbSJens Wiklander 233817466cbSJens Wiklander p = (unsigned char *) params->p; 234817466cbSJens Wiklander end = p + params->len; 235817466cbSJens Wiklander 236817466cbSJens Wiklander if( p == end ) 237817466cbSJens Wiklander return( 0 ); 238817466cbSJens Wiklander 239817466cbSJens Wiklander /* 240817466cbSJens Wiklander * HashAlgorithm 241817466cbSJens Wiklander */ 242817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 243817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) 244817466cbSJens Wiklander { 245817466cbSJens Wiklander end2 = p + len; 246817466cbSJens Wiklander 247817466cbSJens Wiklander /* HashAlgorithm ::= AlgorithmIdentifier (without parameters) */ 248817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_alg_null( &p, end2, &alg_id ) ) != 0 ) 249817466cbSJens Wiklander return( ret ); 250817466cbSJens Wiklander 251817466cbSJens Wiklander if( ( ret = mbedtls_oid_get_md_alg( &alg_id, md_alg ) ) != 0 ) 252817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 253817466cbSJens Wiklander 254817466cbSJens Wiklander if( p != end2 ) 255817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + 256817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 257817466cbSJens Wiklander } 258817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 259817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 260817466cbSJens Wiklander 261817466cbSJens Wiklander if( p == end ) 262817466cbSJens Wiklander return( 0 ); 263817466cbSJens Wiklander 264817466cbSJens Wiklander /* 265817466cbSJens Wiklander * MaskGenAlgorithm 266817466cbSJens Wiklander */ 267817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 268817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) 269817466cbSJens Wiklander { 270817466cbSJens Wiklander end2 = p + len; 271817466cbSJens Wiklander 272817466cbSJens Wiklander /* MaskGenAlgorithm ::= AlgorithmIdentifier (params = HashAlgorithm) */ 273817466cbSJens Wiklander if( ( ret = mbedtls_x509_get_alg( &p, end2, &alg_id, &alg_params ) ) != 0 ) 274817466cbSJens Wiklander return( ret ); 275817466cbSJens Wiklander 276817466cbSJens Wiklander /* Only MFG1 is recognised for now */ 277817466cbSJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_MGF1, &alg_id ) != 0 ) 278817466cbSJens Wiklander return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE + 279817466cbSJens Wiklander MBEDTLS_ERR_OID_NOT_FOUND ); 280817466cbSJens Wiklander 281817466cbSJens Wiklander /* Parse HashAlgorithm */ 282817466cbSJens Wiklander if( ( ret = x509_get_hash_alg( &alg_params, mgf_md ) ) != 0 ) 283817466cbSJens Wiklander return( ret ); 284817466cbSJens Wiklander 285817466cbSJens Wiklander if( p != end2 ) 286817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + 287817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 288817466cbSJens Wiklander } 289817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 290817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 291817466cbSJens Wiklander 292817466cbSJens Wiklander if( p == end ) 293817466cbSJens Wiklander return( 0 ); 294817466cbSJens Wiklander 295817466cbSJens Wiklander /* 296817466cbSJens Wiklander * salt_len 297817466cbSJens Wiklander */ 298817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 299817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2 ) ) == 0 ) 300817466cbSJens Wiklander { 301817466cbSJens Wiklander end2 = p + len; 302817466cbSJens Wiklander 303817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end2, salt_len ) ) != 0 ) 304817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 305817466cbSJens Wiklander 306817466cbSJens Wiklander if( p != end2 ) 307817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + 308817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 309817466cbSJens Wiklander } 310817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 311817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 312817466cbSJens Wiklander 313817466cbSJens Wiklander if( p == end ) 314817466cbSJens Wiklander return( 0 ); 315817466cbSJens Wiklander 316817466cbSJens Wiklander /* 317817466cbSJens Wiklander * trailer_field (if present, must be 1) 318817466cbSJens Wiklander */ 319817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 320817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 3 ) ) == 0 ) 321817466cbSJens Wiklander { 322817466cbSJens Wiklander int trailer_field; 323817466cbSJens Wiklander 324817466cbSJens Wiklander end2 = p + len; 325817466cbSJens Wiklander 326817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end2, &trailer_field ) ) != 0 ) 327817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 328817466cbSJens Wiklander 329817466cbSJens Wiklander if( p != end2 ) 330817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + 331817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 332817466cbSJens Wiklander 333817466cbSJens Wiklander if( trailer_field != 1 ) 334817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG ); 335817466cbSJens Wiklander } 336817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 337817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); 338817466cbSJens Wiklander 339817466cbSJens Wiklander if( p != end ) 340817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG + 341817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 342817466cbSJens Wiklander 343817466cbSJens Wiklander return( 0 ); 344817466cbSJens Wiklander } 345817466cbSJens Wiklander #endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ 346817466cbSJens Wiklander 347817466cbSJens Wiklander /* 348817466cbSJens Wiklander * AttributeTypeAndValue ::= SEQUENCE { 349817466cbSJens Wiklander * type AttributeType, 350817466cbSJens Wiklander * value AttributeValue } 351817466cbSJens Wiklander * 352817466cbSJens Wiklander * AttributeType ::= OBJECT IDENTIFIER 353817466cbSJens Wiklander * 354817466cbSJens Wiklander * AttributeValue ::= ANY DEFINED BY AttributeType 355817466cbSJens Wiklander */ 356817466cbSJens Wiklander static int x509_get_attr_type_value( unsigned char **p, 357817466cbSJens Wiklander const unsigned char *end, 358817466cbSJens Wiklander mbedtls_x509_name *cur ) 359817466cbSJens Wiklander { 360817466cbSJens Wiklander int ret; 361817466cbSJens Wiklander size_t len; 362817466cbSJens Wiklander mbedtls_x509_buf *oid; 363817466cbSJens Wiklander mbedtls_x509_buf *val; 364817466cbSJens Wiklander 365817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 366817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 367817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); 368817466cbSJens Wiklander 369817466cbSJens Wiklander if( ( end - *p ) < 1 ) 370817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_NAME + 371817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 372817466cbSJens Wiklander 373817466cbSJens Wiklander oid = &cur->oid; 374817466cbSJens Wiklander oid->tag = **p; 375817466cbSJens Wiklander 376817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID ) ) != 0 ) 377817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); 378817466cbSJens Wiklander 379817466cbSJens Wiklander oid->p = *p; 380817466cbSJens Wiklander *p += oid->len; 381817466cbSJens Wiklander 382817466cbSJens Wiklander if( ( end - *p ) < 1 ) 383817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_NAME + 384817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 385817466cbSJens Wiklander 386817466cbSJens Wiklander if( **p != MBEDTLS_ASN1_BMP_STRING && **p != MBEDTLS_ASN1_UTF8_STRING && 387817466cbSJens Wiklander **p != MBEDTLS_ASN1_T61_STRING && **p != MBEDTLS_ASN1_PRINTABLE_STRING && 388817466cbSJens Wiklander **p != MBEDTLS_ASN1_IA5_STRING && **p != MBEDTLS_ASN1_UNIVERSAL_STRING && 389817466cbSJens Wiklander **p != MBEDTLS_ASN1_BIT_STRING ) 390817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_NAME + 391817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 392817466cbSJens Wiklander 393817466cbSJens Wiklander val = &cur->val; 394817466cbSJens Wiklander val->tag = *(*p)++; 395817466cbSJens Wiklander 396817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_len( p, end, &val->len ) ) != 0 ) 397817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); 398817466cbSJens Wiklander 399817466cbSJens Wiklander val->p = *p; 400817466cbSJens Wiklander *p += val->len; 401817466cbSJens Wiklander 402817466cbSJens Wiklander cur->next = NULL; 403817466cbSJens Wiklander 404817466cbSJens Wiklander return( 0 ); 405817466cbSJens Wiklander } 406817466cbSJens Wiklander 407817466cbSJens Wiklander /* 408817466cbSJens Wiklander * Name ::= CHOICE { -- only one possibility for now -- 409817466cbSJens Wiklander * rdnSequence RDNSequence } 410817466cbSJens Wiklander * 411817466cbSJens Wiklander * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName 412817466cbSJens Wiklander * 413817466cbSJens Wiklander * RelativeDistinguishedName ::= 414817466cbSJens Wiklander * SET OF AttributeTypeAndValue 415817466cbSJens Wiklander * 416817466cbSJens Wiklander * AttributeTypeAndValue ::= SEQUENCE { 417817466cbSJens Wiklander * type AttributeType, 418817466cbSJens Wiklander * value AttributeValue } 419817466cbSJens Wiklander * 420817466cbSJens Wiklander * AttributeType ::= OBJECT IDENTIFIER 421817466cbSJens Wiklander * 422817466cbSJens Wiklander * AttributeValue ::= ANY DEFINED BY AttributeType 423817466cbSJens Wiklander * 424817466cbSJens Wiklander * The data structure is optimized for the common case where each RDN has only 425817466cbSJens Wiklander * one element, which is represented as a list of AttributeTypeAndValue. 426817466cbSJens Wiklander * For the general case we still use a flat list, but we mark elements of the 427817466cbSJens Wiklander * same set so that they are "merged" together in the functions that consume 428817466cbSJens Wiklander * this list, eg mbedtls_x509_dn_gets(). 429817466cbSJens Wiklander */ 430817466cbSJens Wiklander int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, 431817466cbSJens Wiklander mbedtls_x509_name *cur ) 432817466cbSJens Wiklander { 433817466cbSJens Wiklander int ret; 434817466cbSJens Wiklander size_t set_len; 435817466cbSJens Wiklander const unsigned char *end_set; 436817466cbSJens Wiklander 437817466cbSJens Wiklander /* don't use recursion, we'd risk stack overflow if not optimized */ 438817466cbSJens Wiklander while( 1 ) 439817466cbSJens Wiklander { 440817466cbSJens Wiklander /* 441817466cbSJens Wiklander * parse SET 442817466cbSJens Wiklander */ 443817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &set_len, 444817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ) != 0 ) 445817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); 446817466cbSJens Wiklander 447817466cbSJens Wiklander end_set = *p + set_len; 448817466cbSJens Wiklander 449817466cbSJens Wiklander while( 1 ) 450817466cbSJens Wiklander { 451817466cbSJens Wiklander if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 ) 452817466cbSJens Wiklander return( ret ); 453817466cbSJens Wiklander 454817466cbSJens Wiklander if( *p == end_set ) 455817466cbSJens Wiklander break; 456817466cbSJens Wiklander 457817466cbSJens Wiklander /* Mark this item as being no the only one in a set */ 458817466cbSJens Wiklander cur->next_merged = 1; 459817466cbSJens Wiklander 460817466cbSJens Wiklander cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); 461817466cbSJens Wiklander 462817466cbSJens Wiklander if( cur->next == NULL ) 463817466cbSJens Wiklander return( MBEDTLS_ERR_X509_ALLOC_FAILED ); 464817466cbSJens Wiklander 465817466cbSJens Wiklander cur = cur->next; 466817466cbSJens Wiklander } 467817466cbSJens Wiklander 468817466cbSJens Wiklander /* 469817466cbSJens Wiklander * continue until end of SEQUENCE is reached 470817466cbSJens Wiklander */ 471817466cbSJens Wiklander if( *p == end ) 472817466cbSJens Wiklander return( 0 ); 473817466cbSJens Wiklander 474817466cbSJens Wiklander cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); 475817466cbSJens Wiklander 476817466cbSJens Wiklander if( cur->next == NULL ) 477817466cbSJens Wiklander return( MBEDTLS_ERR_X509_ALLOC_FAILED ); 478817466cbSJens Wiklander 479817466cbSJens Wiklander cur = cur->next; 480817466cbSJens Wiklander } 481817466cbSJens Wiklander } 482817466cbSJens Wiklander 483817466cbSJens Wiklander static int x509_parse_int( unsigned char **p, size_t n, int *res ) 484817466cbSJens Wiklander { 485817466cbSJens Wiklander *res = 0; 486817466cbSJens Wiklander 487817466cbSJens Wiklander for( ; n > 0; --n ) 488817466cbSJens Wiklander { 489817466cbSJens Wiklander if( ( **p < '0') || ( **p > '9' ) ) 490817466cbSJens Wiklander return ( MBEDTLS_ERR_X509_INVALID_DATE ); 491817466cbSJens Wiklander 492817466cbSJens Wiklander *res *= 10; 493817466cbSJens Wiklander *res += ( *(*p)++ - '0' ); 494817466cbSJens Wiklander } 495817466cbSJens Wiklander 496817466cbSJens Wiklander return( 0 ); 497817466cbSJens Wiklander } 498817466cbSJens Wiklander 499817466cbSJens Wiklander static int x509_date_is_valid(const mbedtls_x509_time *t) 500817466cbSJens Wiklander { 501817466cbSJens Wiklander int ret = MBEDTLS_ERR_X509_INVALID_DATE; 502817466cbSJens Wiklander 503817466cbSJens Wiklander CHECK_RANGE( 0, 9999, t->year ); 504817466cbSJens Wiklander CHECK_RANGE( 0, 23, t->hour ); 505817466cbSJens Wiklander CHECK_RANGE( 0, 59, t->min ); 506817466cbSJens Wiklander CHECK_RANGE( 0, 59, t->sec ); 507817466cbSJens Wiklander 508817466cbSJens Wiklander switch( t->mon ) 509817466cbSJens Wiklander { 510817466cbSJens Wiklander case 1: case 3: case 5: case 7: case 8: case 10: case 12: 511817466cbSJens Wiklander CHECK_RANGE( 1, 31, t->day ); 512817466cbSJens Wiklander break; 513817466cbSJens Wiklander case 4: case 6: case 9: case 11: 514817466cbSJens Wiklander CHECK_RANGE( 1, 30, t->day ); 515817466cbSJens Wiklander break; 516817466cbSJens Wiklander case 2: 517817466cbSJens Wiklander CHECK_RANGE( 1, 28 + (t->year % 4 == 0), t->day ); 518817466cbSJens Wiklander break; 519817466cbSJens Wiklander default: 520817466cbSJens Wiklander return( ret ); 521817466cbSJens Wiklander } 522817466cbSJens Wiklander 523817466cbSJens Wiklander return( 0 ); 524817466cbSJens Wiklander } 525817466cbSJens Wiklander 526817466cbSJens Wiklander /* 527817466cbSJens Wiklander * Parse an ASN1_UTC_TIME (yearlen=2) or ASN1_GENERALIZED_TIME (yearlen=4) 528817466cbSJens Wiklander * field. 529817466cbSJens Wiklander */ 530817466cbSJens Wiklander static int x509_parse_time( unsigned char **p, size_t len, size_t yearlen, 531817466cbSJens Wiklander mbedtls_x509_time *tm ) 532817466cbSJens Wiklander { 533817466cbSJens Wiklander int ret; 534817466cbSJens Wiklander 535817466cbSJens Wiklander /* 536817466cbSJens Wiklander * Minimum length is 10 or 12 depending on yearlen 537817466cbSJens Wiklander */ 538817466cbSJens Wiklander if ( len < yearlen + 8 ) 539817466cbSJens Wiklander return ( MBEDTLS_ERR_X509_INVALID_DATE ); 540817466cbSJens Wiklander len -= yearlen + 8; 541817466cbSJens Wiklander 542817466cbSJens Wiklander /* 543817466cbSJens Wiklander * Parse year, month, day, hour, minute 544817466cbSJens Wiklander */ 545817466cbSJens Wiklander CHECK( x509_parse_int( p, yearlen, &tm->year ) ); 546817466cbSJens Wiklander if ( 2 == yearlen ) 547817466cbSJens Wiklander { 548817466cbSJens Wiklander if ( tm->year < 50 ) 549817466cbSJens Wiklander tm->year += 100; 550817466cbSJens Wiklander 551817466cbSJens Wiklander tm->year += 1900; 552817466cbSJens Wiklander } 553817466cbSJens Wiklander 554817466cbSJens Wiklander CHECK( x509_parse_int( p, 2, &tm->mon ) ); 555817466cbSJens Wiklander CHECK( x509_parse_int( p, 2, &tm->day ) ); 556817466cbSJens Wiklander CHECK( x509_parse_int( p, 2, &tm->hour ) ); 557817466cbSJens Wiklander CHECK( x509_parse_int( p, 2, &tm->min ) ); 558817466cbSJens Wiklander 559817466cbSJens Wiklander /* 560817466cbSJens Wiklander * Parse seconds if present 561817466cbSJens Wiklander */ 562817466cbSJens Wiklander if ( len >= 2 ) 563817466cbSJens Wiklander { 564817466cbSJens Wiklander CHECK( x509_parse_int( p, 2, &tm->sec ) ); 565817466cbSJens Wiklander len -= 2; 566817466cbSJens Wiklander } 567817466cbSJens Wiklander else 568817466cbSJens Wiklander return ( MBEDTLS_ERR_X509_INVALID_DATE ); 569817466cbSJens Wiklander 570817466cbSJens Wiklander /* 571817466cbSJens Wiklander * Parse trailing 'Z' if present 572817466cbSJens Wiklander */ 573817466cbSJens Wiklander if ( 1 == len && 'Z' == **p ) 574817466cbSJens Wiklander { 575817466cbSJens Wiklander (*p)++; 576817466cbSJens Wiklander len--; 577817466cbSJens Wiklander } 578817466cbSJens Wiklander 579817466cbSJens Wiklander /* 580817466cbSJens Wiklander * We should have parsed all characters at this point 581817466cbSJens Wiklander */ 582817466cbSJens Wiklander if ( 0 != len ) 583817466cbSJens Wiklander return ( MBEDTLS_ERR_X509_INVALID_DATE ); 584817466cbSJens Wiklander 585817466cbSJens Wiklander CHECK( x509_date_is_valid( tm ) ); 586817466cbSJens Wiklander 587817466cbSJens Wiklander return ( 0 ); 588817466cbSJens Wiklander } 589817466cbSJens Wiklander 590817466cbSJens Wiklander /* 591817466cbSJens Wiklander * Time ::= CHOICE { 592817466cbSJens Wiklander * utcTime UTCTime, 593817466cbSJens Wiklander * generalTime GeneralizedTime } 594817466cbSJens Wiklander */ 595817466cbSJens Wiklander int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, 596817466cbSJens Wiklander mbedtls_x509_time *tm ) 597817466cbSJens Wiklander { 598817466cbSJens Wiklander int ret; 599817466cbSJens Wiklander size_t len, year_len; 600817466cbSJens Wiklander unsigned char tag; 601817466cbSJens Wiklander 602817466cbSJens Wiklander if( ( end - *p ) < 1 ) 603817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_DATE + 604817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 605817466cbSJens Wiklander 606817466cbSJens Wiklander tag = **p; 607817466cbSJens Wiklander 608817466cbSJens Wiklander if( tag == MBEDTLS_ASN1_UTC_TIME ) 609817466cbSJens Wiklander year_len = 2; 610817466cbSJens Wiklander else if( tag == MBEDTLS_ASN1_GENERALIZED_TIME ) 611817466cbSJens Wiklander year_len = 4; 612817466cbSJens Wiklander else 613817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_DATE + 614817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 615817466cbSJens Wiklander 616817466cbSJens Wiklander (*p)++; 617817466cbSJens Wiklander ret = mbedtls_asn1_get_len( p, end, &len ); 618817466cbSJens Wiklander 619817466cbSJens Wiklander if( ret != 0 ) 620817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); 621817466cbSJens Wiklander 622817466cbSJens Wiklander return x509_parse_time( p, len, year_len, tm ); 623817466cbSJens Wiklander } 624817466cbSJens Wiklander 625817466cbSJens Wiklander int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ) 626817466cbSJens Wiklander { 627817466cbSJens Wiklander int ret; 628817466cbSJens Wiklander size_t len; 629817466cbSJens Wiklander int tag_type; 630817466cbSJens Wiklander 631817466cbSJens Wiklander if( ( end - *p ) < 1 ) 632817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + 633817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 634817466cbSJens Wiklander 635817466cbSJens Wiklander tag_type = **p; 636817466cbSJens Wiklander 637817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) 638817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + ret ); 639817466cbSJens Wiklander 640817466cbSJens Wiklander sig->tag = tag_type; 641817466cbSJens Wiklander sig->len = len; 642817466cbSJens Wiklander sig->p = *p; 643817466cbSJens Wiklander 644817466cbSJens Wiklander *p += len; 645817466cbSJens Wiklander 646817466cbSJens Wiklander return( 0 ); 647817466cbSJens Wiklander } 648817466cbSJens Wiklander 649817466cbSJens Wiklander /* 650817466cbSJens Wiklander * Get signature algorithm from alg OID and optional parameters 651817466cbSJens Wiklander */ 652817466cbSJens Wiklander int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, 653817466cbSJens Wiklander mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, 654817466cbSJens Wiklander void **sig_opts ) 655817466cbSJens Wiklander { 656817466cbSJens Wiklander int ret; 657817466cbSJens Wiklander 658817466cbSJens Wiklander if( *sig_opts != NULL ) 659817466cbSJens Wiklander return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); 660817466cbSJens Wiklander 661817466cbSJens Wiklander if( ( ret = mbedtls_oid_get_sig_alg( sig_oid, md_alg, pk_alg ) ) != 0 ) 662817466cbSJens Wiklander return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + ret ); 663817466cbSJens Wiklander 664817466cbSJens Wiklander #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) 665817466cbSJens Wiklander if( *pk_alg == MBEDTLS_PK_RSASSA_PSS ) 666817466cbSJens Wiklander { 667817466cbSJens Wiklander mbedtls_pk_rsassa_pss_options *pss_opts; 668817466cbSJens Wiklander 669817466cbSJens Wiklander pss_opts = mbedtls_calloc( 1, sizeof( mbedtls_pk_rsassa_pss_options ) ); 670817466cbSJens Wiklander if( pss_opts == NULL ) 671817466cbSJens Wiklander return( MBEDTLS_ERR_X509_ALLOC_FAILED ); 672817466cbSJens Wiklander 673817466cbSJens Wiklander ret = mbedtls_x509_get_rsassa_pss_params( sig_params, 674817466cbSJens Wiklander md_alg, 675817466cbSJens Wiklander &pss_opts->mgf1_hash_id, 676817466cbSJens Wiklander &pss_opts->expected_salt_len ); 677817466cbSJens Wiklander if( ret != 0 ) 678817466cbSJens Wiklander { 679817466cbSJens Wiklander mbedtls_free( pss_opts ); 680817466cbSJens Wiklander return( ret ); 681817466cbSJens Wiklander } 682817466cbSJens Wiklander 683817466cbSJens Wiklander *sig_opts = (void *) pss_opts; 684817466cbSJens Wiklander } 685817466cbSJens Wiklander else 686817466cbSJens Wiklander #endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ 687817466cbSJens Wiklander { 688817466cbSJens Wiklander /* Make sure parameters are absent or NULL */ 689817466cbSJens Wiklander if( ( sig_params->tag != MBEDTLS_ASN1_NULL && sig_params->tag != 0 ) || 690817466cbSJens Wiklander sig_params->len != 0 ) 691817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG ); 692817466cbSJens Wiklander } 693817466cbSJens Wiklander 694817466cbSJens Wiklander return( 0 ); 695817466cbSJens Wiklander } 696817466cbSJens Wiklander 697817466cbSJens Wiklander /* 698817466cbSJens Wiklander * X.509 Extensions (No parsing of extensions, pointer should 699817466cbSJens Wiklander * be either manually updated or extensions should be parsed!) 700817466cbSJens Wiklander */ 701817466cbSJens Wiklander int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, 702817466cbSJens Wiklander mbedtls_x509_buf *ext, int tag ) 703817466cbSJens Wiklander { 704817466cbSJens Wiklander int ret; 705817466cbSJens Wiklander size_t len; 706817466cbSJens Wiklander 707817466cbSJens Wiklander if( *p == end ) 708817466cbSJens Wiklander return( 0 ); 709817466cbSJens Wiklander 710817466cbSJens Wiklander ext->tag = **p; 711817466cbSJens Wiklander 712817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len, 713817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag ) ) != 0 ) 714817466cbSJens Wiklander return( ret ); 715817466cbSJens Wiklander 716817466cbSJens Wiklander ext->p = *p; 717817466cbSJens Wiklander end = *p + ext->len; 718817466cbSJens Wiklander 719817466cbSJens Wiklander /* 720817466cbSJens Wiklander * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension 721817466cbSJens Wiklander * 722817466cbSJens Wiklander * Extension ::= SEQUENCE { 723817466cbSJens Wiklander * extnID OBJECT IDENTIFIER, 724817466cbSJens Wiklander * critical BOOLEAN DEFAULT FALSE, 725817466cbSJens Wiklander * extnValue OCTET STRING } 726817466cbSJens Wiklander */ 727817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 728817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 729817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); 730817466cbSJens Wiklander 731817466cbSJens Wiklander if( end != *p + len ) 732817466cbSJens Wiklander return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + 733817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 734817466cbSJens Wiklander 735817466cbSJens Wiklander return( 0 ); 736817466cbSJens Wiklander } 737817466cbSJens Wiklander 738817466cbSJens Wiklander /* 739817466cbSJens Wiklander * Store the name in printable form into buf; no more 740817466cbSJens Wiklander * than size characters will be written 741817466cbSJens Wiklander */ 742817466cbSJens Wiklander int mbedtls_x509_dn_gets( char *buf, size_t size, const mbedtls_x509_name *dn ) 743817466cbSJens Wiklander { 744817466cbSJens Wiklander int ret; 745817466cbSJens Wiklander size_t i, n; 746817466cbSJens Wiklander unsigned char c, merge = 0; 747817466cbSJens Wiklander const mbedtls_x509_name *name; 748817466cbSJens Wiklander const char *short_name = NULL; 749817466cbSJens Wiklander char s[MBEDTLS_X509_MAX_DN_NAME_SIZE], *p; 750817466cbSJens Wiklander 751817466cbSJens Wiklander memset( s, 0, sizeof( s ) ); 752817466cbSJens Wiklander 753817466cbSJens Wiklander name = dn; 754817466cbSJens Wiklander p = buf; 755817466cbSJens Wiklander n = size; 756817466cbSJens Wiklander 757817466cbSJens Wiklander while( name != NULL ) 758817466cbSJens Wiklander { 759817466cbSJens Wiklander if( !name->oid.p ) 760817466cbSJens Wiklander { 761817466cbSJens Wiklander name = name->next; 762817466cbSJens Wiklander continue; 763817466cbSJens Wiklander } 764817466cbSJens Wiklander 765817466cbSJens Wiklander if( name != dn ) 766817466cbSJens Wiklander { 767817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, merge ? " + " : ", " ); 768817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 769817466cbSJens Wiklander } 770817466cbSJens Wiklander 771817466cbSJens Wiklander ret = mbedtls_oid_get_attr_short_name( &name->oid, &short_name ); 772817466cbSJens Wiklander 773817466cbSJens Wiklander if( ret == 0 ) 774817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s=", short_name ); 775817466cbSJens Wiklander else 776817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "\?\?=" ); 777817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 778817466cbSJens Wiklander 779817466cbSJens Wiklander for( i = 0; i < name->val.len; i++ ) 780817466cbSJens Wiklander { 781817466cbSJens Wiklander if( i >= sizeof( s ) - 1 ) 782817466cbSJens Wiklander break; 783817466cbSJens Wiklander 784817466cbSJens Wiklander c = name->val.p[i]; 785817466cbSJens Wiklander if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) 786817466cbSJens Wiklander s[i] = '?'; 787817466cbSJens Wiklander else s[i] = c; 788817466cbSJens Wiklander } 789817466cbSJens Wiklander s[i] = '\0'; 790817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s", s ); 791817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 792817466cbSJens Wiklander 793817466cbSJens Wiklander merge = name->next_merged; 794817466cbSJens Wiklander name = name->next; 795817466cbSJens Wiklander } 796817466cbSJens Wiklander 797817466cbSJens Wiklander return( (int) ( size - n ) ); 798817466cbSJens Wiklander } 799817466cbSJens Wiklander 800817466cbSJens Wiklander /* 801817466cbSJens Wiklander * Store the serial in printable form into buf; no more 802817466cbSJens Wiklander * than size characters will be written 803817466cbSJens Wiklander */ 804817466cbSJens Wiklander int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *serial ) 805817466cbSJens Wiklander { 806817466cbSJens Wiklander int ret; 807817466cbSJens Wiklander size_t i, n, nr; 808817466cbSJens Wiklander char *p; 809817466cbSJens Wiklander 810817466cbSJens Wiklander p = buf; 811817466cbSJens Wiklander n = size; 812817466cbSJens Wiklander 813817466cbSJens Wiklander nr = ( serial->len <= 32 ) 814817466cbSJens Wiklander ? serial->len : 28; 815817466cbSJens Wiklander 816817466cbSJens Wiklander for( i = 0; i < nr; i++ ) 817817466cbSJens Wiklander { 818817466cbSJens Wiklander if( i == 0 && nr > 1 && serial->p[i] == 0x0 ) 819817466cbSJens Wiklander continue; 820817466cbSJens Wiklander 821817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%02X%s", 822817466cbSJens Wiklander serial->p[i], ( i < nr - 1 ) ? ":" : "" ); 823817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 824817466cbSJens Wiklander } 825817466cbSJens Wiklander 826817466cbSJens Wiklander if( nr != serial->len ) 827817466cbSJens Wiklander { 828817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "...." ); 829817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 830817466cbSJens Wiklander } 831817466cbSJens Wiklander 832817466cbSJens Wiklander return( (int) ( size - n ) ); 833817466cbSJens Wiklander } 834817466cbSJens Wiklander 835817466cbSJens Wiklander /* 836817466cbSJens Wiklander * Helper for writing signature algorithms 837817466cbSJens Wiklander */ 838817466cbSJens Wiklander int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, 839817466cbSJens Wiklander mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, 840817466cbSJens Wiklander const void *sig_opts ) 841817466cbSJens Wiklander { 842817466cbSJens Wiklander int ret; 843817466cbSJens Wiklander char *p = buf; 844817466cbSJens Wiklander size_t n = size; 845817466cbSJens Wiklander const char *desc = NULL; 846817466cbSJens Wiklander 847817466cbSJens Wiklander ret = mbedtls_oid_get_sig_alg_desc( sig_oid, &desc ); 848817466cbSJens Wiklander if( ret != 0 ) 849817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "???" ); 850817466cbSJens Wiklander else 851817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s", desc ); 852817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 853817466cbSJens Wiklander 854817466cbSJens Wiklander #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) 855817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSASSA_PSS ) 856817466cbSJens Wiklander { 857817466cbSJens Wiklander const mbedtls_pk_rsassa_pss_options *pss_opts; 858817466cbSJens Wiklander const mbedtls_md_info_t *md_info, *mgf_md_info; 859817466cbSJens Wiklander 860817466cbSJens Wiklander pss_opts = (const mbedtls_pk_rsassa_pss_options *) sig_opts; 861817466cbSJens Wiklander 862817466cbSJens Wiklander md_info = mbedtls_md_info_from_type( md_alg ); 863817466cbSJens Wiklander mgf_md_info = mbedtls_md_info_from_type( pss_opts->mgf1_hash_id ); 864817466cbSJens Wiklander 865817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, " (%s, MGF1-%s, 0x%02X)", 866817466cbSJens Wiklander md_info ? mbedtls_md_get_name( md_info ) : "???", 867817466cbSJens Wiklander mgf_md_info ? mbedtls_md_get_name( mgf_md_info ) : "???", 868817466cbSJens Wiklander pss_opts->expected_salt_len ); 869817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 870817466cbSJens Wiklander } 871817466cbSJens Wiklander #else 872817466cbSJens Wiklander ((void) pk_alg); 873817466cbSJens Wiklander ((void) md_alg); 874817466cbSJens Wiklander ((void) sig_opts); 875817466cbSJens Wiklander #endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ 876817466cbSJens Wiklander 877817466cbSJens Wiklander return( (int)( size - n ) ); 878817466cbSJens Wiklander } 879817466cbSJens Wiklander 880817466cbSJens Wiklander /* 881817466cbSJens Wiklander * Helper for writing "RSA key size", "EC key size", etc 882817466cbSJens Wiklander */ 883817466cbSJens Wiklander int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ) 884817466cbSJens Wiklander { 885817466cbSJens Wiklander char *p = buf; 886817466cbSJens Wiklander size_t n = buf_size; 887817466cbSJens Wiklander int ret; 888817466cbSJens Wiklander 889817466cbSJens Wiklander ret = mbedtls_snprintf( p, n, "%s key size", name ); 890817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 891817466cbSJens Wiklander 892817466cbSJens Wiklander return( 0 ); 893817466cbSJens Wiklander } 894817466cbSJens Wiklander 895817466cbSJens Wiklander #if defined(MBEDTLS_HAVE_TIME_DATE) 896817466cbSJens Wiklander /* 897817466cbSJens Wiklander * Set the time structure to the current time. 898817466cbSJens Wiklander * Return 0 on success, non-zero on failure. 899817466cbSJens Wiklander */ 900817466cbSJens Wiklander #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 901817466cbSJens Wiklander static int x509_get_current_time( mbedtls_x509_time *now ) 902817466cbSJens Wiklander { 903817466cbSJens Wiklander SYSTEMTIME st; 904817466cbSJens Wiklander 905817466cbSJens Wiklander GetSystemTime( &st ); 906817466cbSJens Wiklander 907817466cbSJens Wiklander now->year = st.wYear; 908817466cbSJens Wiklander now->mon = st.wMonth; 909817466cbSJens Wiklander now->day = st.wDay; 910817466cbSJens Wiklander now->hour = st.wHour; 911817466cbSJens Wiklander now->min = st.wMinute; 912817466cbSJens Wiklander now->sec = st.wSecond; 913817466cbSJens Wiklander 914817466cbSJens Wiklander return( 0 ); 915817466cbSJens Wiklander } 916817466cbSJens Wiklander #else 917817466cbSJens Wiklander static int x509_get_current_time( mbedtls_x509_time *now ) 918817466cbSJens Wiklander { 919817466cbSJens Wiklander struct tm *lt; 920817466cbSJens Wiklander mbedtls_time_t tt; 921817466cbSJens Wiklander int ret = 0; 922817466cbSJens Wiklander 923817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 924817466cbSJens Wiklander if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 ) 925817466cbSJens Wiklander return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); 926817466cbSJens Wiklander #endif 927817466cbSJens Wiklander 928817466cbSJens Wiklander tt = mbedtls_time( NULL ); 929817466cbSJens Wiklander lt = gmtime( &tt ); 930817466cbSJens Wiklander 931817466cbSJens Wiklander if( lt == NULL ) 932817466cbSJens Wiklander ret = -1; 933817466cbSJens Wiklander else 934817466cbSJens Wiklander { 935817466cbSJens Wiklander now->year = lt->tm_year + 1900; 936817466cbSJens Wiklander now->mon = lt->tm_mon + 1; 937817466cbSJens Wiklander now->day = lt->tm_mday; 938817466cbSJens Wiklander now->hour = lt->tm_hour; 939817466cbSJens Wiklander now->min = lt->tm_min; 940817466cbSJens Wiklander now->sec = lt->tm_sec; 941817466cbSJens Wiklander } 942817466cbSJens Wiklander 943817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C) 944817466cbSJens Wiklander if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 ) 945817466cbSJens Wiklander return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); 946817466cbSJens Wiklander #endif 947817466cbSJens Wiklander 948817466cbSJens Wiklander return( ret ); 949817466cbSJens Wiklander } 950817466cbSJens Wiklander #endif /* _WIN32 && !EFIX64 && !EFI32 */ 951817466cbSJens Wiklander 952817466cbSJens Wiklander /* 953817466cbSJens Wiklander * Return 0 if before <= after, 1 otherwise 954817466cbSJens Wiklander */ 955817466cbSJens Wiklander static int x509_check_time( const mbedtls_x509_time *before, const mbedtls_x509_time *after ) 956817466cbSJens Wiklander { 957817466cbSJens Wiklander if( before->year > after->year ) 958817466cbSJens Wiklander return( 1 ); 959817466cbSJens Wiklander 960817466cbSJens Wiklander if( before->year == after->year && 961817466cbSJens Wiklander before->mon > after->mon ) 962817466cbSJens Wiklander return( 1 ); 963817466cbSJens Wiklander 964817466cbSJens Wiklander if( before->year == after->year && 965817466cbSJens Wiklander before->mon == after->mon && 966817466cbSJens Wiklander before->day > after->day ) 967817466cbSJens Wiklander return( 1 ); 968817466cbSJens Wiklander 969817466cbSJens Wiklander if( before->year == after->year && 970817466cbSJens Wiklander before->mon == after->mon && 971817466cbSJens Wiklander before->day == after->day && 972817466cbSJens Wiklander before->hour > after->hour ) 973817466cbSJens Wiklander return( 1 ); 974817466cbSJens Wiklander 975817466cbSJens Wiklander if( before->year == after->year && 976817466cbSJens Wiklander before->mon == after->mon && 977817466cbSJens Wiklander before->day == after->day && 978817466cbSJens Wiklander before->hour == after->hour && 979817466cbSJens Wiklander before->min > after->min ) 980817466cbSJens Wiklander return( 1 ); 981817466cbSJens Wiklander 982817466cbSJens Wiklander if( before->year == after->year && 983817466cbSJens Wiklander before->mon == after->mon && 984817466cbSJens Wiklander before->day == after->day && 985817466cbSJens Wiklander before->hour == after->hour && 986817466cbSJens Wiklander before->min == after->min && 987817466cbSJens Wiklander before->sec > after->sec ) 988817466cbSJens Wiklander return( 1 ); 989817466cbSJens Wiklander 990817466cbSJens Wiklander return( 0 ); 991817466cbSJens Wiklander } 992817466cbSJens Wiklander 993817466cbSJens Wiklander int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ) 994817466cbSJens Wiklander { 995817466cbSJens Wiklander mbedtls_x509_time now; 996817466cbSJens Wiklander 997817466cbSJens Wiklander if( x509_get_current_time( &now ) != 0 ) 998817466cbSJens Wiklander return( 1 ); 999817466cbSJens Wiklander 1000817466cbSJens Wiklander return( x509_check_time( &now, to ) ); 1001817466cbSJens Wiklander } 1002817466cbSJens Wiklander 1003817466cbSJens Wiklander int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) 1004817466cbSJens Wiklander { 1005817466cbSJens Wiklander mbedtls_x509_time now; 1006817466cbSJens Wiklander 1007817466cbSJens Wiklander if( x509_get_current_time( &now ) != 0 ) 1008817466cbSJens Wiklander return( 1 ); 1009817466cbSJens Wiklander 1010817466cbSJens Wiklander return( x509_check_time( from, &now ) ); 1011817466cbSJens Wiklander } 1012817466cbSJens Wiklander 1013817466cbSJens Wiklander #else /* MBEDTLS_HAVE_TIME_DATE */ 1014817466cbSJens Wiklander 1015817466cbSJens Wiklander int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ) 1016817466cbSJens Wiklander { 1017817466cbSJens Wiklander ((void) to); 1018817466cbSJens Wiklander return( 0 ); 1019817466cbSJens Wiklander } 1020817466cbSJens Wiklander 1021817466cbSJens Wiklander int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) 1022817466cbSJens Wiklander { 1023817466cbSJens Wiklander ((void) from); 1024817466cbSJens Wiklander return( 0 ); 1025817466cbSJens Wiklander } 1026817466cbSJens Wiklander #endif /* MBEDTLS_HAVE_TIME_DATE */ 1027817466cbSJens Wiklander 1028817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 1029817466cbSJens Wiklander 1030817466cbSJens Wiklander #include "mbedtls/x509_crt.h" 1031817466cbSJens Wiklander #include "mbedtls/certs.h" 1032817466cbSJens Wiklander 1033817466cbSJens Wiklander /* 1034817466cbSJens Wiklander * Checkup routine 1035817466cbSJens Wiklander */ 1036817466cbSJens Wiklander int mbedtls_x509_self_test( int verbose ) 1037817466cbSJens Wiklander { 1038817466cbSJens Wiklander #if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA256_C) 1039817466cbSJens Wiklander int ret; 1040817466cbSJens Wiklander uint32_t flags; 1041817466cbSJens Wiklander mbedtls_x509_crt cacert; 1042817466cbSJens Wiklander mbedtls_x509_crt clicert; 1043817466cbSJens Wiklander 1044817466cbSJens Wiklander if( verbose != 0 ) 1045817466cbSJens Wiklander mbedtls_printf( " X.509 certificate load: " ); 1046817466cbSJens Wiklander 1047817466cbSJens Wiklander mbedtls_x509_crt_init( &clicert ); 1048817466cbSJens Wiklander 1049817466cbSJens Wiklander ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) mbedtls_test_cli_crt, 1050817466cbSJens Wiklander mbedtls_test_cli_crt_len ); 1051817466cbSJens Wiklander if( ret != 0 ) 1052817466cbSJens Wiklander { 1053817466cbSJens Wiklander if( verbose != 0 ) 1054817466cbSJens Wiklander mbedtls_printf( "failed\n" ); 1055817466cbSJens Wiklander 1056817466cbSJens Wiklander return( ret ); 1057817466cbSJens Wiklander } 1058817466cbSJens Wiklander 1059817466cbSJens Wiklander mbedtls_x509_crt_init( &cacert ); 1060817466cbSJens Wiklander 1061817466cbSJens Wiklander ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_ca_crt, 1062817466cbSJens Wiklander mbedtls_test_ca_crt_len ); 1063817466cbSJens Wiklander if( ret != 0 ) 1064817466cbSJens Wiklander { 1065817466cbSJens Wiklander if( verbose != 0 ) 1066817466cbSJens Wiklander mbedtls_printf( "failed\n" ); 1067817466cbSJens Wiklander 1068817466cbSJens Wiklander return( ret ); 1069817466cbSJens Wiklander } 1070817466cbSJens Wiklander 1071817466cbSJens Wiklander if( verbose != 0 ) 1072817466cbSJens Wiklander mbedtls_printf( "passed\n X.509 signature verify: "); 1073817466cbSJens Wiklander 1074817466cbSJens Wiklander ret = mbedtls_x509_crt_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL ); 1075817466cbSJens Wiklander if( ret != 0 ) 1076817466cbSJens Wiklander { 1077817466cbSJens Wiklander if( verbose != 0 ) 1078817466cbSJens Wiklander mbedtls_printf( "failed\n" ); 1079817466cbSJens Wiklander 1080817466cbSJens Wiklander return( ret ); 1081817466cbSJens Wiklander } 1082817466cbSJens Wiklander 1083817466cbSJens Wiklander if( verbose != 0 ) 1084817466cbSJens Wiklander mbedtls_printf( "passed\n\n"); 1085817466cbSJens Wiklander 1086817466cbSJens Wiklander mbedtls_x509_crt_free( &cacert ); 1087817466cbSJens Wiklander mbedtls_x509_crt_free( &clicert ); 1088817466cbSJens Wiklander 1089817466cbSJens Wiklander return( 0 ); 1090817466cbSJens Wiklander #else 1091817466cbSJens Wiklander ((void) verbose); 1092817466cbSJens Wiklander return( 0 ); 1093817466cbSJens Wiklander #endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */ 1094817466cbSJens Wiklander } 1095817466cbSJens Wiklander 1096817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 1097817466cbSJens Wiklander 1098817466cbSJens Wiklander #endif /* MBEDTLS_X509_USE_C */ 1099