From e9f0daec49f77c23b4ea3c435f6be0be519c0421 Mon Sep 17 00:00:00 2001 From: Kevin Kane Date: Tue, 20 Dec 2016 12:51:27 -0800 Subject: [PATCH] Add support for needed functionality to mbedTLS Support for directoryName-based subject alternative name Creating certificates containing this extension Specifying a particular EKU to check for in TLS negotiation instead of standard client/server authentication EKUs This work will be offered upstream to the mbedTLS maintainers; if they accept it, this will later be reverted when IoTivity ingests a newer version of mbedTLS. Change-Id: I4f81d75b767683327564e27758d1aa1bc02613de Signed-off-by: Kevin Kane Reviewed-on: https://gerrit.iotivity.org/gerrit/15733 Reviewed-by: Alex Kelley Reviewed-by: Pawel Winogrodzki Tested-by: jenkins-iotivity Reviewed-by: Oleksii Beketov Reviewed-by: dongik Lee Reviewed-by: Greg Zaverucha --- extlibs/mbedtls/.gitattributes | 1 + extlibs/mbedtls/SConscript | 2 +- extlibs/mbedtls/ocf.patch | 1703 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 1689 insertions(+), 17 deletions(-) create mode 100644 extlibs/mbedtls/.gitattributes diff --git a/extlibs/mbedtls/.gitattributes b/extlibs/mbedtls/.gitattributes new file mode 100644 index 0000000..edcf997 --- /dev/null +++ b/extlibs/mbedtls/.gitattributes @@ -0,0 +1 @@ +ocf.patch text eol=lf diff --git a/extlibs/mbedtls/SConscript b/extlibs/mbedtls/SConscript index 2170618..9400c95 100644 --- a/extlibs/mbedtls/SConscript +++ b/extlibs/mbedtls/SConscript @@ -66,7 +66,7 @@ if target_os != 'tizen': # Apply ocf patch on git revision if os.path.exists('.git/HEAD'): - cmd = 'git checkout development && git reset --hard ' + mbedtls_revision + ' && git apply --whitespace=fix ../ocf.patch' + cmd = 'git checkout development && git reset --hard ' + mbedtls_revision + ' && git clean -f && git apply --whitespace=fix ../ocf.patch' os.system(cmd) else: print 'mbedtls: Assume ocf.patch (TLS_ECDH_ANON_WITH_AES_128_CBC_SHA256) was applied in %s' % mbedtls_dir diff --git a/extlibs/mbedtls/ocf.patch b/extlibs/mbedtls/ocf.patch index 972577d..04bf27d 100644 --- a/extlibs/mbedtls/ocf.patch +++ b/extlibs/mbedtls/ocf.patch @@ -1,3 +1,18 @@ +diff --git a/include/mbedtls/certs.h b/include/mbedtls/certs.h +index ca49086..e41de29 100644 +--- a/include/mbedtls/certs.h ++++ b/include/mbedtls/certs.h +@@ -73,6 +73,10 @@ extern const char mbedtls_test_cli_crt_ec[]; + extern const size_t mbedtls_test_cli_crt_ec_len; + extern const char mbedtls_test_cli_key_ec[]; + extern const size_t mbedtls_test_cli_key_ec_len; ++#if defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ++extern const char mbedtls_test_srv_directoryname_ec_crt[]; ++extern const size_t mbedtls_test_srv_directoryname_ec_crt_len; ++#endif + #endif + + #if defined(MBEDTLS_RSA_C) diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index fe86c1e..e4583d6 100644 --- a/include/mbedtls/check_config.h @@ -44,8 +59,73 @@ index 27abbd9..fa4db26 100644 #define TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA #define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA #define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 +diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h +index 6fc9c77..e6d300e 100644 +--- a/include/mbedtls/config.h ++++ b/include/mbedtls/config.h +@@ -648,6 +648,21 @@ + #define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + + /** ++ * \def MBEDTLS_KEY_EXCHANGE_ECDH_ANON_ENABLED ++ * ++ * Enable the ECDHE-ANON based ciphersuite modes in SSL / TLS. ++ * ++ * Requires: MBEDTLS_ECDH_C ++ * ++ * ++ * This enables the following ciphersuites (if other requisites are ++ * enabled as well): ++ * MBEDTLS_TLS_ECDH_ANON_WITH_AES_128_CBC_SHA256 ++ */ ++#define MBEDTLS_KEY_EXCHANGE_ECDH_ANON_ENABLED ++ ++ ++/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. +@@ -1233,7 +1248,7 @@ + * + * Comment this macro to disable support for SSL session tickets + */ +-#define MBEDTLS_SSL_SESSION_TICKETS ++//#define MBEDTLS_SSL_SESSION_TICKETS + + /** + * \def MBEDTLS_SSL_EXPORT_KEYS +@@ -1360,6 +1375,21 @@ + #define MBEDTLS_X509_RSASSA_PSS_SUPPORT + + /** ++ * \def MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT ++ * ++ * Enable parsing of all supported subtypes of the Subject Alternative Name ++ * extension. When enabled, the subject_alt_names field of mbedtls_x509_crt ++ * is defined as an mbedtls_x509_subject_alt_name_sequence, each element of ++ * which can describe a different subtype of the GeneralName choice as defined ++ * by the standard. ++ * ++ * Comment this macro to only support dNSName subtypes, and to define the ++ * subject_alt_names field as an mbedtls_x509_sequence. Any other subtypes will ++ * be ignored. This was the behavior in earlier versions. ++ */ ++#define MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT ++ ++/** + * \def MBEDTLS_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and +@@ -1473,6 +1503,7 @@ + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA ++ * MBEDTLS_TLS_ECDH_ANON_WITH_AES_128_CBC_SHA256 + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h -index ba499d2..8046e6e 100644 +index ba499d2..807bff6 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -358,7 +358,8 @@ union mbedtls_ssl_premaster_secret @@ -58,6 +138,67 @@ index ba499d2..8046e6e 100644 unsigned char _pms_ecdh[MBEDTLS_ECP_MAX_BYTES]; /* RFC 4492 5.10 */ #endif #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) +@@ -652,6 +653,12 @@ struct mbedtls_ssl_config + mbedtls_ssl_key_cert *key_cert; /*!< own certificate/key pair(s) */ + mbedtls_x509_crt *ca_chain; /*!< trusted CAs */ + mbedtls_x509_crl *ca_crl; /*!< trusted CAs CRLs */ ++#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) ++ const char *client_oid; /*!< OID to check on client certs */ ++ size_t client_oid_len; /*!< length of client OID */ ++ const char *server_oid; /*!< OID to check on server certs */ ++ size_t server_oid_len; /*!< length of server OID */ ++#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + #endif /* MBEDTLS_X509_CRT_PARSE_C */ + + #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +@@ -1615,6 +1622,47 @@ void mbedtls_ssl_conf_ca_chain( mbedtls_ssl_config *conf, + int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ); ++ ++#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) ++/** ++ * \brief Set custom EKU OIDs to be checked on certificates during TLS negotiation, ++ * and for selecting suitable certificates for TLS negotation. ++ * ++ * \note By default, if this function is not called, clients will ++ * check for the server authentication EKU (1.3.6.1.5.5.7.3.1) in ++ * a server's certificate, and servers will check for the ++ * client authentication EKU (1.3.6.1.5.5.7.3.2) if a client ++ * presents a certificate. ++ * ++ * \param conf SSL configuration ++ * \param client_oid OID to check for when verifying client certificates as a server. ++ * This must be an MBEDTLS_OID_* constant from oid.h, or a custom OID ++ * supplied by the caller. If a custom OID is used, it must be provided in ++ * its ASN.1 encoding; human-readable dotted numeric strings are not supported. ++ * Additionally, callers using custom OID buffers must ensure those buffers remain ++ * live while this SSL configuration is live. Passing NULL will ++ * disable EKU checking of client certificates. ++ * \param client_oid_len The length of client_oid, not counting a terminating NULL if present; for constants ++ * from oid.h, this can be obtained with MBEDTLS_OID_SIZE(x) where x is the OID constant. ++ * If client_oid is NULL, this must be zero. ++ * \param server_oid OID to check for when verifying server certificates as a client. ++ * This must be an MBEDTLS_OID_* constant from oid.h, or a custom OID ++ * supplied by the caller. If a custom OID is used, it must be provided in ++ * its ASN.1 encoding; human-readable dotted numeric strings are not supported. ++ * Additionally, callers using custom OID buffers must ensure those buffers remain ++ * live while this SSL configuration is live. Passing NULL will ++ * disable EKU checking of server certificates. ++ * \param server_oid_len The length of server_oid not counting a terminating NULL if present; for constants ++ * from oid.h, this can be obtained with MBEDTLS_OID_SIZE(x) where x is the OID constant. ++ * If client_oid is NULL, this must be zero. ++ * ++ * \return 0 on success or MBEDTLS_ERR_SSL_BAD_INPUT_DATA for invalid arguments. ++ * On failure, existing behavior is unchanged. ++ */ ++int mbedtls_ssl_conf_ekus( mbedtls_ssl_config *conf, ++ const char *client_oid, size_t client_oid_len, ++ const char *server_oid, size_t server_oid_len ); ++#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + #endif /* MBEDTLS_X509_CRT_PARSE_C */ + + #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) diff --git a/include/mbedtls/ssl_ciphersuites.h b/include/mbedtls/ssl_ciphersuites.h index deaaa37..4f10540 100644 --- a/include/mbedtls/ssl_ciphersuites.h @@ -89,6 +230,130 @@ index deaaa37..4f10540 100644 #define MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED #endif +diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h +index 668c0f5..e1035f9 100644 +--- a/include/mbedtls/ssl_internal.h ++++ b/include/mbedtls/ssl_internal.h +@@ -437,6 +437,8 @@ static inline mbedtls_x509_crt *mbedtls_ssl_own_cert( mbedtls_ssl_context *ssl ) + int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, + const mbedtls_ssl_ciphersuite_t *ciphersuite, + int cert_endpoint, ++ const char *client_oid, size_t client_oid_len, ++ const char *server_oid, size_t server_oid_len, + uint32_t *flags ); + #endif /* MBEDTLS_X509_CRT_PARSE_C */ + +diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h +index 54dac16..21f11a4 100644 +--- a/include/mbedtls/x509.h ++++ b/include/mbedtls/x509.h +@@ -310,7 +310,7 @@ int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, + int mbedtls_x509_write_extensions( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); + int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, +- mbedtls_asn1_named_data *first ); ++ const mbedtls_asn1_named_data *first ); + int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ); +diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h +index 383e484..d4cdae1 100644 +--- a/include/mbedtls/x509_crt.h ++++ b/include/mbedtls/x509_crt.h +@@ -46,6 +46,31 @@ extern "C" { + * \{ + */ + ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++typedef enum ++{ ++ /* Don't use the value zero in this enum, because we use zero to denote an unset struct. */ ++ MBEDTLS_X509_GENERALNAME_DNSNAME = 1, ++ MBEDTLS_X509_GENERALNAME_DIRECTORYNAME ++} mbedtls_x509_general_name_choice; ++ ++typedef struct mbedtls_x509_general_name ++{ ++ mbedtls_x509_general_name_choice name_type; ++ union ++ { ++ mbedtls_x509_buf dns_name; ++ mbedtls_x509_name *directory_name; ++ }; ++} mbedtls_x509_general_name; ++ ++typedef struct mbedtls_x509_general_names ++{ ++ mbedtls_x509_general_name general_name; ++ struct mbedtls_x509_general_names *next; ++} mbedtls_x509_general_names; ++#endif ++ + /** + * Container for an X.509 certificate. The certificate may be chained. + */ +@@ -72,7 +97,11 @@ typedef struct mbedtls_x509_crt + mbedtls_x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ + mbedtls_x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ + mbedtls_x509_buf v3_ext; /**< Optional X.509 v3 extensions. */ ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ mbedtls_x509_general_names subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName and directoryName supported). */ ++#else + mbedtls_x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName supported). */ ++#endif + + int ext_types; /**< Bit string containing detected and parsed extensions */ + int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ +@@ -593,6 +622,21 @@ int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, + int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, + unsigned char ns_cert_type ); + ++ ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++/** ++ * \brief Set the subject alternative name extension ++ * ++ * \param ctx CRT context to use ++ * \param names subject alternative names. For each dNSName element, the tag field of the dns_name ++ * member does not need to be set and will be ignored. ++ * ++ * \return 0 if successful, or a specific error code ++ */ ++int mbedtls_x509write_crt_set_subject_alt_names( mbedtls_x509write_cert *ctx, ++ const mbedtls_x509_general_names *names ); ++#endif /* MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT */ ++ + /** + * \brief Free the contents of a CRT write context + * +diff --git a/library/certs.c b/library/certs.c +index ffe6bc9..812969d 100644 +--- a/library/certs.c ++++ b/library/certs.c +@@ -114,6 +114,23 @@ const size_t mbedtls_test_srv_crt_ec_len = sizeof( mbedtls_test_srv_crt_ec ); + const size_t mbedtls_test_srv_key_ec_len = sizeof( mbedtls_test_srv_key_ec ); + const size_t mbedtls_test_cli_crt_ec_len = sizeof( mbedtls_test_cli_crt_ec ); + const size_t mbedtls_test_cli_key_ec_len = sizeof( mbedtls_test_cli_key_ec ); ++ ++#if defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ++const char mbedtls_test_srv_directoryname_ec_crt[] = ++"-----BEGIN CERTIFICATE-----\r\n" ++"MIIBVzCB/qADAgECAgkAkWvgYjFeWV0wCgYIKoZIzj0EAwIwEzERMA8GA1UEAwwI\r\n" ++"VGVzdENlcnQwHhcNMTYxMjEzMjMwNDM3WhcNMzAwODIyMjMwNDM3WjATMREwDwYD\r\n" ++"VQQDDAhUZXN0Q2VydDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOkrKfbStoGN\r\n" ++"oOUTet2ryyRul++FE++6vpEup83bHywiOO1a4JtDgzNJcjj8/uAKsECYQrI1T4Y/\r\n" ++"rpnYu8ff9VGjOzA5MDcGA1UdEQQwMC6kLDAqMRYwFAYDVQQLDA1OYW1lIEFzc2ln\r\n" ++"bmVyMRAwDgYDVQQDDAdNeSBSb2xlMAoGCCqGSM49BAMCA0gAMEUCIGdd/GGuoOXJ\r\n" ++"8Ipl3hy69gb35MmkwEQKuYrud+Qs5XfFAiEAsmEOP4KFZadL23XJfMfGuPn2MDLr\r\n" ++"G9lDDpiediVxGO0=\r\n" ++"-----END CERTIFICATE-----\r\n"; ++ ++const size_t mbedtls_test_srv_directoryname_ec_crt_len = sizeof( mbedtls_test_srv_directoryname_ec_crt ); ++#endif ++ + #else + #define TEST_CA_CRT_EC + #endif /* MBEDTLS_ECDSA_C */ diff --git a/library/entropy_poll.c b/library/entropy_poll.c index a116e60..c022caf 100644 --- a/library/entropy_poll.c @@ -406,10 +671,27 @@ index 223823b..945c973 100644 MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); ssl->state++; diff --git a/library/ssl_srv.c b/library/ssl_srv.c -index fc0d2d7..6965f1f 100644 +index fc0d2d7..18f89cd 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c -@@ -2498,6 +2498,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) +@@ -648,7 +648,15 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, + * and decrypting with the same RSA key. + */ + if( mbedtls_ssl_check_cert_usage( cur->cert, ciphersuite_info, +- MBEDTLS_SSL_IS_SERVER, &flags ) != 0 ) ++ MBEDTLS_SSL_IS_SERVER, ++#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) ++ ssl->conf->client_oid, ssl->conf->client_oid_len, ++ ssl->conf->server_oid, ssl->conf->server_oid_len, ++#else ++ NULL, 0, ++ NULL, 0, ++#endif ++ &flags ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: " + "(extended) key usage extension" ) ); +@@ -2498,6 +2506,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE || @@ -417,7 +699,7 @@ index fc0d2d7..6965f1f 100644 authmode == MBEDTLS_SSL_VERIFY_NONE ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) ); -@@ -2675,7 +2676,8 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) +@@ -2675,7 +2684,8 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) || \ defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ @@ -427,7 +709,7 @@ index fc0d2d7..6965f1f 100644 unsigned char *p = ssl->out_msg + 4; unsigned char *dig_signed = p; size_t dig_signed_len = 0, len; -@@ -2736,12 +2738,11 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) +@@ -2736,12 +2746,11 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) { @@ -445,7 +727,7 @@ index fc0d2d7..6965f1f 100644 } #endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED || MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ -@@ -2798,7 +2799,8 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) +@@ -2798,7 +2807,8 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED) if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || @@ -455,7 +737,7 @@ index fc0d2d7..6965f1f 100644 { /* * Ephemeral ECDH parameters: -@@ -3336,11 +3338,13 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) +@@ -3336,11 +3346,13 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ @@ -471,7 +753,7 @@ index fc0d2d7..6965f1f 100644 { if( ( ret = mbedtls_ecdh_read_public( &ssl->handshake->ecdh_ctx, p, end - p) ) != 0 ) -@@ -3539,7 +3543,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) +@@ -3539,7 +3551,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || @@ -481,7 +763,7 @@ index fc0d2d7..6965f1f 100644 { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); ssl->state++; -@@ -3570,6 +3575,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) +@@ -3570,6 +3583,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE || @@ -490,7 +772,7 @@ index fc0d2d7..6965f1f 100644 { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c -index 84a04ae..938b840 100644 +index 84a04ae..2f23a3e 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -4066,7 +4066,8 @@ int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) @@ -533,7 +815,84 @@ index 84a04ae..938b840 100644 { MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); ssl->state++; -@@ -7539,6 +7543,7 @@ int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, +@@ -4476,6 +4480,13 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) + if( mbedtls_ssl_check_cert_usage( ssl->session_negotiate->peer_cert, + ciphersuite_info, + ! ssl->conf->endpoint, ++#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) ++ ssl->conf->client_oid, ssl->conf->client_oid_len, ++ ssl->conf->server_oid, ssl->conf->server_oid_len, ++#else ++ NULL, 0, ++ NULL, 0, ++#endif + &ssl->session_negotiate->verify_result ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) ); +@@ -5759,6 +5770,28 @@ int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, + return( ssl_append_key_cert( &conf->key_cert, own_cert, pk_key ) ); + } + ++#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) ++int mbedtls_ssl_conf_ekus( mbedtls_ssl_config *conf, ++ const char *client_oid, size_t client_oid_len, ++ const char *server_oid, size_t server_oid_len ) ++{ ++ if( ( client_oid_len == 0 && client_oid ) || ++ ( client_oid_len != 0 && !client_oid ) || ++ ( server_oid_len == 0 && server_oid ) || ++ ( server_oid_len != 0 && !server_oid ) ) ++ { ++ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); ++ } ++ ++ conf->client_oid = client_oid; ++ conf->client_oid_len = client_oid_len; ++ conf->server_oid = server_oid; ++ conf->server_oid_len = server_oid_len; ++ ++ return( 0 ); ++} ++#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ ++ + void mbedtls_ssl_conf_ca_chain( mbedtls_ssl_config *conf, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ) +@@ -7246,6 +7279,13 @@ int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, + } + #endif + ++#if defined(MBEDTLS_X509_CRT_PARSE_C) && defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) ++ conf->client_oid = MBEDTLS_OID_CLIENT_AUTH; ++ conf->client_oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_CLIENT_AUTH ); ++ conf->server_oid = MBEDTLS_OID_SERVER_AUTH; ++ conf->server_oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_SERVER_AUTH ); ++#endif ++ + /* + * Preset-specific defaults + */ +@@ -7493,6 +7533,8 @@ int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, + int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, + const mbedtls_ssl_ciphersuite_t *ciphersuite, + int cert_endpoint, ++ const char *client_oid, size_t client_oid_len, ++ const char *server_oid, size_t server_oid_len, + uint32_t *flags ) + { + int ret = 0; +@@ -7509,6 +7551,10 @@ int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, + ((void) cert); + ((void) cert_endpoint); + ((void) flags); ++ ((void) client_oid); ++ ((void) client_oid_len); ++ ((void) server_oid); ++ ((void) server_oid_len); + #endif + + #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) +@@ -7539,6 +7585,7 @@ int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, case MBEDTLS_KEY_EXCHANGE_DHE_PSK: case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: case MBEDTLS_KEY_EXCHANGE_ECJPAKE: @@ -541,8 +900,26 @@ index 84a04ae..938b840 100644 usage = 0; } } +@@ -7560,13 +7607,13 @@ int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, + #if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + if( cert_endpoint == MBEDTLS_SSL_IS_SERVER ) + { +- ext_oid = MBEDTLS_OID_SERVER_AUTH; +- ext_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_SERVER_AUTH ); ++ ext_oid = server_oid; ++ ext_len = server_oid_len; + } + else + { +- ext_oid = MBEDTLS_OID_CLIENT_AUTH; +- ext_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_CLIENT_AUTH ); ++ ext_oid = client_oid; ++ ext_len = client_oid_len; + } + + if( mbedtls_x509_crt_check_extended_key_usage( cert, ext_oid, ext_len ) != 0 ) diff --git a/library/version_features.c b/library/version_features.c -index e866e67..3184bc2 100644 +index e866e67..7798b27 100644 --- a/library/version_features.c +++ b/library/version_features.c @@ -264,6 +264,9 @@ static const char *features[] = { @@ -555,8 +932,103 @@ index e866e67..3184bc2 100644 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED", #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +@@ -423,6 +426,9 @@ static const char *features[] = { + #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + "MBEDTLS_X509_RSASSA_PSS_SUPPORT", + #endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ "MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT", ++#endif /* MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT */ + #if defined(MBEDTLS_ZLIB_SUPPORT) + "MBEDTLS_ZLIB_SUPPORT", + #endif /* MBEDTLS_ZLIB_SUPPORT */ +diff --git a/library/x509.c b/library/x509.c +index fad390d..0bc5367 100644 +--- a/library/x509.c ++++ b/library/x509.c +@@ -1005,6 +1005,10 @@ int mbedtls_x509_self_test( int verbose ) + uint32_t flags; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; ++#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ++ mbedtls_x509_crt directorynamecert; ++ char buf[2048]; ++#endif + + if( verbose != 0 ) + mbedtls_printf( " X.509 certificate load: " ); +@@ -1045,11 +1049,45 @@ int mbedtls_x509_self_test( int verbose ) + return( ret ); + } + ++#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ++ if( verbose != 0 ) ++ mbedtls_printf( "passed\n X.509 subject alt name verify: " ); ++ ++ mbedtls_x509_crt_init( &directorynamecert ); ++ ++ ret = mbedtls_x509_crt_parse( &directorynamecert, (const unsigned char *) mbedtls_test_srv_directoryname_ec_crt, ++ mbedtls_test_srv_directoryname_ec_crt_len ); ++ ++ if( ret != 0 ) ++ { ++ if( verbose != 0 ) ++ mbedtls_printf( "failed\n" ); ++ ++ return( ret ); ++ } ++ ++ if( verbose != 0 ) ++ mbedtls_printf( "passed\n X.509 directoryName parsing: " ); ++ ++ ret = mbedtls_x509_crt_info( buf, sizeof( buf ), "", &directorynamecert ); ++ if ( ret < 0 ) ++ { ++ if ( verbose != 0 ) ++ mbedtls_printf( "failed\n" ); ++ ++ return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); ++ } ++ ++#endif ++ + if( verbose != 0 ) +- mbedtls_printf( "passed\n\n"); ++ mbedtls_printf( "passed\n\n" ); + + mbedtls_x509_crt_free( &cacert ); + mbedtls_x509_crt_free( &clicert ); ++#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ++ mbedtls_x509_crt_free( &directorynamecert ); ++#endif + + return( 0 ); + #else +diff --git a/library/x509_create.c b/library/x509_create.c +index df20ec8..5faec78 100644 +--- a/library/x509_create.c ++++ b/library/x509_create.c +@@ -231,15 +231,15 @@ static int x509_write_name( unsigned char **p, unsigned char *start, + } + + int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, +- mbedtls_asn1_named_data *first ) ++ const mbedtls_asn1_named_data *first ) + { + int ret; + size_t len = 0; +- mbedtls_asn1_named_data *cur = first; ++ const mbedtls_asn1_named_data *cur = first; + + while( cur != NULL ) + { +- MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, (char *) cur->oid.p, ++ MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, (const char *) cur->oid.p, + cur->oid.len, + cur->val.p, cur->val.len ) ); + cur = cur->next; diff --git a/library/x509_crt.c b/library/x509_crt.c -index 60e14f9..67cedde 100644 +index 60e14f9..037efae 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -62,6 +62,7 @@ @@ -567,7 +1039,99 @@ index 60e14f9..67cedde 100644 #else #include #endif -@@ -1108,6 +1109,7 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) +@@ -438,17 +439,31 @@ static int x509_get_ext_key_usage( unsigned char **p, + * nameAssigner [0] DirectoryString OPTIONAL, + * partyName [1] DirectoryString } + * +- * NOTE: we only parse and use dNSName at this point. ++ * NOTE: If MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT is not defined, we only parse and use dNSName. ++ * If it is defined, we parse and use all supported types, which are currently dNSName and directoryName. + */ ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++static int x509_get_subject_alt_name( unsigned char **p, ++ const unsigned char *end, ++ mbedtls_x509_general_names *subject_alt_name ) ++ ++#else + static int x509_get_subject_alt_name( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *subject_alt_name ) ++#endif + { + int ret; + size_t len, tag_len; +- mbedtls_asn1_buf *buf; + unsigned char tag; ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ mbedtls_x509_general_names *cur = subject_alt_name; ++ mbedtls_x509_general_name general_name; ++ size_t name_len; ++#else ++ mbedtls_asn1_buf *buf; + mbedtls_asn1_sequence *cur = subject_alt_name; ++#endif + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, +@@ -474,6 +489,49 @@ static int x509_get_subject_alt_name( unsigned char **p, + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ memset( &general_name, 0, sizeof( general_name ) ); ++ switch ( tag ) ++ { ++ case ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ): /* dNSName */ ++ general_name.name_type = MBEDTLS_X509_GENERALNAME_DNSNAME; ++ general_name.dns_name.tag = tag; ++ general_name.dns_name.p = *p; ++ general_name.dns_name.len = tag_len; ++ *p += tag_len; ++ break; ++ case ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 4 ): /* directoryName */ ++ general_name.name_type = MBEDTLS_X509_GENERALNAME_DIRECTORYNAME; ++ if( ( ret = mbedtls_asn1_get_tag( p, end, &name_len, ++ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) ++ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); ++ general_name.directory_name = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); ++ if ( general_name.directory_name == NULL ) ++ return( MBEDTLS_ERR_X509_ALLOC_FAILED ); ++ if( ( ret = mbedtls_x509_get_name( p, *p + name_len, general_name.directory_name ) ) != 0 ) ++ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); ++ break; ++ default: ++ *p += tag_len; ++ continue; ++ } ++ ++ if( cur->general_name.name_type != 0 ) ++ { ++ if( cur->next != NULL ) ++ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); ++ ++ cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_general_names ) ); ++ ++ if( cur->next == NULL ) ++ return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ++ MBEDTLS_ERR_ASN1_ALLOC_FAILED ); ++ ++ cur = cur->next; ++ } ++ ++ memcpy( &cur->general_name, &general_name, sizeof( general_name ) ); ++#else + /* Skip everything but DNS name */ + if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) + { +@@ -501,6 +559,7 @@ static int x509_get_subject_alt_name( unsigned char **p, + buf->p = *p; + buf->len = tag_len; + *p += buf->len; ++#endif + } + + /* Set final sequence entry's next pointer to NULL */ +@@ -1108,6 +1167,7 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) char filename[MAX_PATH]; char *p; size_t len = strlen( path ); @@ -575,7 +1139,7 @@ index 60e14f9..67cedde 100644 WIN32_FIND_DATAW file_data; HANDLE hFind; -@@ -1122,7 +1124,10 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) +@@ -1122,7 +1182,10 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) p = filename + len; filename[len++] = '*'; @@ -587,7 +1151,7 @@ index 60e14f9..67cedde 100644 MAX_PATH - 3 ); if( w_ret == 0 ) return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); -@@ -1139,8 +1144,11 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) +@@ -1139,8 +1202,11 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) continue; @@ -600,3 +1164,1110 @@ index 60e14f9..67cedde 100644 p, (int) len - 1, NULL, NULL ); if( w_ret == 0 ) +@@ -1219,6 +1285,98 @@ cleanup: + } + #endif /* MBEDTLS_FS_IO */ + ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++static const char x509_directory_name_label[] = "directoryName=("; ++static const char x509_directory_name_epilogue[] = ")"; ++ ++/* Length of label constant excluding terminating null. */ ++#define LABEL_LEN( label ) ( sizeof ( label ) - 1 ) ++ ++static int x509_info_subject_alt_name( char **buf, size_t *size, ++ const mbedtls_x509_general_names *subject_alt_name ) ++{ ++ int ret; ++ size_t i; ++ size_t n = *size; ++ char *p = *buf; ++ const mbedtls_x509_general_names *cur = subject_alt_name; ++ const char *sep = ""; ++ size_t sep_len = 0; ++ ++ while( cur != NULL ) ++ { ++ switch ( cur->general_name.name_type ) ++ { ++ case MBEDTLS_X509_GENERALNAME_DNSNAME: ++ i = cur->general_name.dns_name.len + sep_len; ++ ++ if( i >= n ) ++ { ++ *p = '\0'; ++ return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); ++ } ++ ++ n -= i; ++ for( i = 0; i < sep_len; i++ ) ++ *p++ = sep[i]; ++ for( i = 0; i < cur->general_name.dns_name.len; i++ ) ++ *p++ = cur->general_name.dns_name.p[i]; ++ ++ break; ++ ++ case MBEDTLS_X509_GENERALNAME_DIRECTORYNAME: ++ i = sep_len + LABEL_LEN( x509_directory_name_label ); ++ if( i >= n ) ++ { ++ *p = '\0'; ++ return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); ++ } ++ ++ n -= i; ++ for( i = 0; i < sep_len; i++ ) ++ *p++ = sep[i]; ++ for( i = 0; i < LABEL_LEN( x509_directory_name_label ); i++ ) ++ *p++ = x509_directory_name_label[i]; ++ ++ ret = mbedtls_x509_dn_gets( p, n, cur->general_name.directory_name ); ++ if( ret < 0 || ( (size_t) ret ) >= n ) ++ { ++ *p = '\0'; ++ return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); ++ } ++ ++ n -= ret; ++ p += ret; ++ ++ i = LABEL_LEN( x509_directory_name_epilogue ); ++ ++ if( i >= n ) ++ { ++ *p = '\0'; ++ return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); ++ } ++ ++ n -= i; ++ for( i = 0; i < LABEL_LEN( x509_directory_name_epilogue ); i++ ) ++ *p++ = x509_directory_name_epilogue[i]; ++ ++ break; ++ } ++ ++ sep = ", "; ++ sep_len = 2; ++ ++ cur = cur->next; ++ } ++ ++ *p = '\0'; ++ ++ *size = n; ++ *buf = p; ++ ++ return( 0 ); ++} ++#else + static int x509_info_subject_alt_name( char **buf, size_t *size, + const mbedtls_x509_sequence *subject_alt_name ) + { +@@ -1256,6 +1414,7 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, + + return( 0 ); + } ++#endif + + #define PRINT_ITEM(i) \ + { \ +@@ -2188,7 +2347,11 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + int pathlen = 0, selfsigned = 0; + mbedtls_x509_crt *parent; + mbedtls_x509_name *name; ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ mbedtls_x509_general_names *cur = NULL; ++#else + mbedtls_x509_sequence *cur = NULL; ++#endif + mbedtls_pk_type_t pk_type; + + if( profile == NULL ) +@@ -2207,6 +2370,22 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + + while( cur != NULL ) + { ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ /* Only consider dNSName subject alternative names for this check; ignore other types. */ ++ if ( cur->general_name.name_type == MBEDTLS_X509_GENERALNAME_DNSNAME ) ++ { ++ if ( cur->general_name.dns_name.len == cn_len && ++ x509_memcasecmp( cn, cur->general_name.dns_name.p, cn_len ) == 0 ) ++ break; ++ ++ if ( cur->general_name.dns_name.len > 2 && ++ memcmp( cur->general_name.dns_name.p, "*.", 2 ) == 0 && ++ x509_check_wildcard( cn, &cur->general_name.dns_name ) == 0 ) ++ { ++ break; ++ } ++ } ++#else + if( cur->buf.len == cn_len && + x509_memcasecmp( cn, cur->buf.p, cn_len ) == 0 ) + break; +@@ -2217,6 +2396,7 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + { + break; + } ++#endif + + cur = cur->next; + } +@@ -2318,6 +2498,10 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) + mbedtls_x509_crt *cert_prv; + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ mbedtls_x509_general_names *san_cur; ++ mbedtls_x509_general_names *san_prv; ++#endif + mbedtls_x509_sequence *seq_cur; + mbedtls_x509_sequence *seq_prv; + +@@ -2359,6 +2543,38 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) + mbedtls_free( seq_prv ); + } + ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ if ( cert_cur->subject_alt_names.general_name.name_type == MBEDTLS_X509_GENERALNAME_DIRECTORYNAME ) ++ { ++ name_cur = cert_cur->subject_alt_names.general_name.directory_name; ++ while ( name_cur != NULL ) ++ { ++ name_prv = name_cur; ++ name_cur = name_cur->next; ++ mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); ++ mbedtls_free( name_prv ); ++ } ++ } ++ san_cur = cert_cur->subject_alt_names.next; ++ while ( san_cur != NULL ) ++ { ++ san_prv = san_cur; ++ san_cur = san_cur->next; ++ if ( san_prv->general_name.name_type == MBEDTLS_X509_GENERALNAME_DIRECTORYNAME ) ++ { ++ name_cur = san_prv->general_name.directory_name; ++ while ( name_cur != NULL ) ++ { ++ name_prv = name_cur; ++ name_cur = name_cur->next; ++ mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); ++ mbedtls_free( name_prv ); ++ } ++ } ++ mbedtls_zeroize( san_prv, sizeof( mbedtls_x509_general_names )); ++ mbedtls_free( san_prv ); ++ } ++#else + seq_cur = cert_cur->subject_alt_names.next; + while( seq_cur != NULL ) + { +@@ -2367,6 +2583,7 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) + mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } ++#endif + + if( cert_cur->raw.p != NULL ) + { +diff --git a/library/x509write_crt.c b/library/x509write_crt.c +index d1d9a22..55f194d 100644 +--- a/library/x509write_crt.c ++++ b/library/x509write_crt.c +@@ -263,6 +263,63 @@ int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, + return( 0 ); + } + ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++static int x509write_crt_set_subject_alt_name( unsigned char **c, unsigned char *buf, ++ const mbedtls_x509_general_name *name ) ++{ ++ int ret; ++ size_t len = 0; ++ ++ switch ( name->name_type ) ++ { ++ case MBEDTLS_X509_GENERALNAME_DNSNAME: ++ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( c, buf, name->dns_name.p, name->dns_name.len ) ); ++ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( c, buf, name->dns_name.len ) ); ++ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( c, buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ); ++ break; ++ ++ case MBEDTLS_X509_GENERALNAME_DIRECTORYNAME: ++ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( c, buf, name->directory_name ) ); ++ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( c, buf, len ) ); ++ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( c, buf, ++ MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 4 ) ); ++ break; ++ ++ default: ++ return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); ++ } ++ ++ return( (int)len ); ++} ++ ++int mbedtls_x509write_crt_set_subject_alt_names( mbedtls_x509write_cert *ctx, ++ const mbedtls_x509_general_names *names ) ++{ ++ int ret; ++ unsigned char buf[2048]; ++ unsigned char *c = buf + sizeof( buf ); ++ size_t len = 0; ++ const mbedtls_x509_general_names *cur; ++ ++ for ( cur = names; cur != NULL; cur = cur->next ) ++ { ++ MBEDTLS_ASN1_CHK_ADD( len, x509write_crt_set_subject_alt_name( &c, buf, &cur->general_name ) ); ++ } ++ ++ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); ++ MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); ++ ++ ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_SUBJECT_ALT_NAME, ++ MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_ALT_NAME ), ++ 0, c, len ); ++ ++ if( ret != 0 ) ++ return( ret ); ++ ++ return( 0 ); ++} ++#endif /* MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT */ ++ + static int x509_write_time( unsigned char **p, unsigned char *start, + const char *time, size_t size ) + { +diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c +index a1d71e1..b334656 100644 +--- a/programs/ssl/ssl_client2.c ++++ b/programs/ssl/ssl_client2.c +@@ -58,6 +58,7 @@ int main( void ) + #include "mbedtls/error.h" + #include "mbedtls/debug.h" + #include "mbedtls/timing.h" ++#include "mbedtls/oid.h" + + #include + #include +@@ -103,6 +104,8 @@ int main( void ) + #define DFL_FALLBACK -1 + #define DFL_EXTENDED_MS -1 + #define DFL_ETM -1 ++#define DFL_EKU_CLIENT "" ++#define DFL_EKU_SERVER "" + + #define GET_REQUEST "GET %s HTTP/1.0\r\nExtra-header: " + #define GET_REQUEST_END "\r\n\r\n" +@@ -222,6 +225,14 @@ int main( void ) + #define USAGE_ECJPAKE "" + #endif + ++#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) ++#define USAGE_EKU \ ++ " eku=%%s-%%s default: client-server\n" \ ++ " options for each: server, client, codesign\n" ++#else ++#define USAGE_EKU "" ++#endif ++ + #define USAGE \ + "\n usage: ssl_client2 param=<>...\n" \ + "\n acceptable parameters:\n" \ +@@ -261,6 +272,7 @@ int main( void ) + USAGE_ETM \ + USAGE_RECSPLIT \ + USAGE_DHMLEN \ ++ USAGE_EKU \ + "\n" \ + " arc4=%%d default: (library default: 0)\n" \ + " min_version=%%s default: (library default: tls1)\n" \ +@@ -317,6 +329,10 @@ struct options + int fallback; /* is this a fallback connection? */ + int extended_ms; /* negotiate extended master secret? */ + int etm; /* negotiate encrypt then mac? */ ++ const char *eku_cli; /* EKU to check for in client cert */ ++ size_t eku_cli_len; /* length of eku_cli */ ++ const char *eku_srv; /* EKU to check for in server cert */ ++ size_t eku_srv_len; /* length of eku_srv */ + } opt; + + static void my_debug( void *ctx, int level, +@@ -507,6 +523,10 @@ int main( int argc, char *argv[] ) + opt.fallback = DFL_FALLBACK; + opt.extended_ms = DFL_EXTENDED_MS; + opt.etm = DFL_ETM; ++ opt.eku_cli = DFL_EKU_CLIENT; ++ opt.eku_cli_len = MBEDTLS_OID_SIZE( DFL_EKU_CLIENT ); ++ opt.eku_srv = DFL_EKU_SERVER; ++ opt.eku_srv_len = MBEDTLS_OID_SIZE( DFL_EKU_SERVER ); + + for( i = 1; i < argc; i++ ) + { +@@ -797,6 +817,47 @@ int main( int argc, char *argv[] ) + if( opt.dhmlen < 0 ) + goto usage; + } ++ else if ( strcmp(p, "eku") == 0 ) ++ { ++ if ( ( p = strchr( q, '-' ) ) == NULL ) ++ goto usage; ++ *p++ = '\0'; ++ if ( strcmp( q, "server" ) == 0 ) ++ { ++ opt.eku_cli = MBEDTLS_OID_SERVER_AUTH; ++ opt.eku_cli_len = MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH); ++ } ++ else if ( strcmp( q, "client" ) == 0 ) ++ { ++ opt.eku_cli = MBEDTLS_OID_CLIENT_AUTH; ++ opt.eku_cli_len = MBEDTLS_OID_SIZE(MBEDTLS_OID_CLIENT_AUTH); ++ } ++ else if ( strcmp( q, "codesign" ) == 0 ) ++ { ++ opt.eku_cli = MBEDTLS_OID_CODE_SIGNING; ++ opt.eku_cli_len = MBEDTLS_OID_SIZE(MBEDTLS_OID_CODE_SIGNING); ++ } ++ else ++ goto usage; ++ ++ if ( strcmp( p, "server" ) == 0 ) ++ { ++ opt.eku_srv = MBEDTLS_OID_SERVER_AUTH; ++ opt.eku_srv_len = MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH); ++ } ++ else if ( strcmp( p, "client" ) == 0 ) ++ { ++ opt.eku_srv = MBEDTLS_OID_CLIENT_AUTH; ++ opt.eku_srv_len = MBEDTLS_OID_SIZE(MBEDTLS_OID_CLIENT_AUTH); ++ } ++ else if ( strcmp( p, "codesign" ) == 0 ) ++ { ++ opt.eku_srv = MBEDTLS_OID_CODE_SIGNING; ++ opt.eku_srv_len = MBEDTLS_OID_SIZE(MBEDTLS_OID_CODE_SIGNING); ++ } ++ else ++ goto usage; ++ } + else + goto usage; + } +@@ -1088,6 +1149,19 @@ int main( int argc, char *argv[] ) + goto exit; + } + ++#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) ++ if ( opt.eku_cli_len > 0 && opt.eku_srv_len > 0 ) ++ { ++ if( ( ret = mbedtls_ssl_conf_ekus( &conf, ++ opt.eku_cli, opt.eku_cli_len, ++ opt.eku_srv, opt.eku_srv_len ) ) != 0 ) ++ { ++ mbedtls_printf( " failed\n ! mbedtls_ssl_config_ekus returned -0x%x\n\n", -ret ); ++ goto exit; ++ } ++ } ++#endif ++ + #if defined(MBEDTLS_X509_CRT_PARSE_C) + if( opt.debug_level > 0 ) + mbedtls_ssl_conf_verify( &conf, my_verify, NULL ); +diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c +index 18bda59..e65576b 100644 +--- a/programs/ssl/ssl_server2.c ++++ b/programs/ssl/ssl_server2.c +@@ -59,6 +59,7 @@ int main( void ) + #include "mbedtls/error.h" + #include "mbedtls/debug.h" + #include "mbedtls/timing.h" ++#include "mbedtls/oid.h" + + #include + #include +@@ -136,6 +137,8 @@ int main( void ) + #define DFL_BADMAC_LIMIT -1 + #define DFL_EXTENDED_MS -1 + #define DFL_ETM -1 ++#define DFL_EKU_CLIENT "" ++#define DFL_EKU_SERVER "" + + #define LONG_RESPONSE "

01-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ + "02-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ +@@ -304,6 +307,14 @@ int main( void ) + #define USAGE_ECJPAKE "" + #endif + ++#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) ++#define USAGE_EKU \ ++ " eku=%%s-%%s default: client-server\n" \ ++ " options for each: server, client, codesign\n" ++#else ++#define USAGE_EKU "" ++#endif ++ + #define USAGE \ + "\n usage: ssl_server2 param=<>...\n" \ + "\n acceptable parameters:\n" \ +@@ -338,6 +349,7 @@ int main( void ) + USAGE_ALPN \ + USAGE_EMS \ + USAGE_ETM \ ++ USAGE_EKU \ + "\n" \ + " arc4=%%d default: (library default: 0)\n" \ + " min_version=%%s default: (library default: tls1)\n" \ +@@ -400,6 +412,10 @@ struct options + uint32_t hs_to_min; /* Initial value of DTLS handshake timer */ + uint32_t hs_to_max; /* Max value of DTLS handshake timer */ + int badmac_limit; /* Limit of records with bad MAC */ ++ const char *eku_cli; /* EKU to check for in client cert */ ++ size_t eku_cli_len; /* length of eku_cli */ ++ const char *eku_srv; /* EKU to check for in server cert */ ++ size_t eku_srv_len; /* length of eku_srv */ + } opt; + + static void my_debug( void *ctx, int level, +@@ -943,6 +959,10 @@ int main( int argc, char *argv[] ) + opt.badmac_limit = DFL_BADMAC_LIMIT; + opt.extended_ms = DFL_EXTENDED_MS; + opt.etm = DFL_ETM; ++ opt.eku_cli = DFL_EKU_CLIENT; ++ opt.eku_cli_len = MBEDTLS_OID_SIZE( DFL_EKU_CLIENT ); ++ opt.eku_srv = DFL_EKU_SERVER; ++ opt.eku_srv_len = MBEDTLS_OID_SIZE( DFL_EKU_SERVER ); + + for( i = 1; i < argc; i++ ) + { +@@ -1232,6 +1252,47 @@ int main( int argc, char *argv[] ) + { + opt.sni = q; + } ++ else if( strcmp( p, "eku" ) == 0 ) ++ { ++ if( ( p = strchr( q, '-' ) ) == NULL ) ++ goto usage; ++ *p++ = '\0'; ++ if( strcmp( q, "server" ) == 0 ) ++ { ++ opt.eku_cli = MBEDTLS_OID_SERVER_AUTH; ++ opt.eku_cli_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_SERVER_AUTH ); ++ } ++ else if( strcmp( q, "client" ) == 0 ) ++ { ++ opt.eku_cli = MBEDTLS_OID_CLIENT_AUTH; ++ opt.eku_cli_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_CLIENT_AUTH ); ++ } ++ else if( strcmp( q, "codesign" ) == 0 ) ++ { ++ opt.eku_cli = MBEDTLS_OID_CODE_SIGNING; ++ opt.eku_cli_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_CODE_SIGNING ); ++ } ++ else ++ goto usage; ++ ++ if( strcmp( p, "server" ) == 0 ) ++ { ++ opt.eku_srv = MBEDTLS_OID_SERVER_AUTH; ++ opt.eku_srv_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_SERVER_AUTH ); ++ } ++ else if( strcmp( p, "client" ) == 0 ) ++ { ++ opt.eku_srv = MBEDTLS_OID_CLIENT_AUTH; ++ opt.eku_srv_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_CLIENT_AUTH ); ++ } ++ else if( strcmp( p, "codesign" ) == 0 ) ++ { ++ opt.eku_srv = MBEDTLS_OID_CODE_SIGNING; ++ opt.eku_srv_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_CODE_SIGNING ); ++ } ++ else ++ goto usage; ++ } + else + goto usage; + } +@@ -1608,6 +1669,20 @@ int main( int argc, char *argv[] ) + goto exit; + } + ++#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) ++ if ( opt.eku_cli_len > 0 && opt.eku_srv_len > 0 ) ++ { ++ if( ( ret = mbedtls_ssl_conf_ekus( &conf, ++ opt.eku_cli, opt.eku_cli_len, ++ opt.eku_srv, opt.eku_srv_len ) ) != 0 ) ++ { ++ mbedtls_printf( " failed\n ! mbedtls_ssl_config_ekus returned -0x%x\n\n", -ret ); ++ goto exit; ++ } ++ } ++#endif ++ ++ + if( opt.auth_mode != DFL_AUTH_MODE ) + mbedtls_ssl_conf_authmode( &conf, opt.auth_mode ); + +diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c +index 66e5f1d..1405e71 100644 +--- a/programs/x509/cert_write.c ++++ b/programs/x509/cert_write.c +@@ -66,6 +66,16 @@ int main( void ) + #define USAGE_CSR "" + #endif /* MBEDTLS_X509_CSR_PARSE_C */ + ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++#define USAGE_SUBJ_ALT_NAME \ ++ " subj_alt_name=%%s default: (empty)\n" \ ++ " Comma-separated-list of values:\n" \ ++ " dns_name=%%s\n" \ ++ " directory_name=(OU=%%s;CN=%%s;...)\n" ++#else ++#define USAGE_SUBJ_ALT_NAME "" ++#endif /* MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT */ ++ + #define DFL_ISSUER_CRT "" + #define DFL_REQUEST_FILE "" + #define DFL_SUBJECT_KEY "subject.key" +@@ -127,6 +137,7 @@ int main( void ) + " ssl_ca\n" \ + " email_ca\n" \ + " object_signing_ca\n" \ ++ USAGE_SUBJ_ALT_NAME \ + "\n" + + /* +@@ -151,6 +162,9 @@ struct options + int max_pathlen; /* maximum CA path length */ + unsigned char key_usage; /* key usage flags */ + unsigned char ns_cert_type; /* NS cert type */ ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ mbedtls_x509_general_names subj_alt_names; /* Subject alternative names */ ++#endif + } opt; + + int write_certificate( mbedtls_x509write_cert *crt, const char *output_file, +@@ -182,6 +196,58 @@ int write_certificate( mbedtls_x509write_cert *crt, const char *output_file, + return( 0 ); + } + ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++static int add_subj_alt_name( mbedtls_x509_general_names **cur, const mbedtls_x509_general_name *add ) ++{ ++ mbedtls_x509_general_names *new_cur = *cur; ++ ++ if ( new_cur->general_name.name_type != 0 ) ++ { ++ if (new_cur->next != NULL) ++ return( -1 ); ++ ++ new_cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_general_names ) ); ++ ++ if (new_cur->next == NULL) ++ return( -1 ); ++ ++ new_cur = new_cur->next; ++ } ++ ++ memcpy( &new_cur->general_name, add, sizeof( mbedtls_x509_general_name ) ); ++ ++ *cur = new_cur; ++ ++ return( 0 ); ++} ++ ++static void subj_alt_names_free( mbedtls_x509_general_names *names ) ++{ ++ mbedtls_x509_general_names *cur = names; ++ mbedtls_x509_general_names *prv; ++ ++ while ( cur != NULL ) ++ { ++ prv = cur; ++ cur = cur->next; ++ ++ if ( prv->general_name.name_type == MBEDTLS_X509_GENERALNAME_DIRECTORYNAME ) ++ { ++ mbedtls_asn1_free_named_data_list( &prv->general_name.directory_name ); ++ } ++ ++ /* ++ * The first node is part of the opt struct and not heap allocated, so don't free it. ++ * Every other loop, free the node. ++ */ ++ if ( prv != names ) ++ { ++ mbedtls_free( prv ); ++ } ++ } ++} ++#endif ++ + int main( int argc, char *argv[] ) + { + int ret = 0; +@@ -202,6 +268,10 @@ int main( int argc, char *argv[] ) + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + const char *pers = "crt example app"; ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ mbedtls_x509_general_names *name_cur = &opt.subj_alt_names; ++ mbedtls_x509_general_name name_tmp; ++#endif + + /* + * Set to sane values +@@ -243,6 +313,9 @@ int main( int argc, char *argv[] ) + opt.max_pathlen = DFL_MAX_PATHLEN; + opt.key_usage = DFL_KEY_USAGE; + opt.ns_cert_type = DFL_NS_CERT_TYPE; ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ memset( &opt.subj_alt_names, 0, sizeof( opt.subj_alt_names ) ); ++#endif + + for( i = 1; i < argc; i++ ) + { +@@ -358,6 +431,86 @@ int main( int argc, char *argv[] ) + q = r; + } + } ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ else if( strcmp( p, "subj_alt_name" ) == 0 ) ++ { ++ while( q != NULL ) ++ { ++ char *s; ++ ++ if( ( r = strchr( q, ',' ) ) != NULL ) ++ *r++ = '\0'; ++ ++ if( ( s = strchr( q, '=' ) ) == NULL ) ++ goto usage; ++ ++ *s++ = '\0'; ++ ++ if( strcmp( q, "dns_name" ) == 0 ) ++ { ++ name_tmp.name_type = MBEDTLS_X509_GENERALNAME_DNSNAME; ++ name_tmp.dns_name.len = strlen( s ); ++ name_tmp.dns_name.p = (unsigned char *)s; ++ /* tag field doesn't need to be set for writing. */ ++ } ++ else if( strcmp( q, "directory_name" ) == 0 ) ++ { ++ char *rp, *tmp; ++ ++ if ( *s != '(' ) ++ goto usage; ++ ++ if ( ( rp = strchr( s + 1, ')' ) ) == NULL ) ++ goto usage; ++ ++ /* ++ * Replace semicolons in the parenthesized list with commas and temporarily ++ * terminate with null so we can use mbedtls_x509_string_to_names, call it, ++ * and then change them back so the commas don't interfere with later parsing. ++ */ ++ ++ for ( tmp = s + 1; tmp < rp; tmp++ ) ++ { ++ if ( *tmp == ';' ) ++ { ++ *tmp = ','; ++ } ++ } ++ ++ *rp = '\0'; ++ ++ name_tmp.name_type = MBEDTLS_X509_GENERALNAME_DIRECTORYNAME; ++ name_tmp.directory_name = NULL; ++ ret = mbedtls_x509_string_to_names( &name_tmp.directory_name, s + 1 ); ++ ++ if ( ret < 0 ) ++ { ++ mbedtls_strerror( ret, buf, 1024 ); ++ mbedtls_printf( " failed\n ! mbedtls_x509_string_to_names returned %d - %s\n", ret, buf ); ++ goto exit; ++ } ++ ++ for ( tmp = s + 1; tmp < rp; tmp++ ) ++ { ++ if ( *tmp == ',' ) ++ { ++ *tmp = ';'; ++ } ++ } ++ ++ *rp = ')'; ++ ++ } ++ else ++ goto usage; ++ ++ if ( add_subj_alt_name( &name_cur, &name_tmp ) != 0 ) ++ goto exit; ++ ++ q = r; ++ } ++ } ++#endif /* MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT */ + else + goto usage; + } +@@ -632,6 +785,24 @@ int main( int argc, char *argv[] ) + mbedtls_printf( " ok\n" ); + } + ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ if ( opt.subj_alt_names.general_name.name_type ) ++ { ++ mbedtls_printf( " . Adding the Subject Alternative Name extension ..." ); ++ fflush( stdout ); ++ ++ ret = mbedtls_x509write_crt_set_subject_alt_names( &crt, &opt.subj_alt_names ); ++ if ( ret != 0 ) ++ { ++ mbedtls_strerror( ret, buf, 1024 ); ++ mbedtls_printf( " failed\n ! mbedtls_x509write_crt_set_subject_alt_names returned -0x%02x - %s\n\n", -ret, buf ); ++ goto exit; ++ } ++ ++ mbedtls_printf( " ok\n" ); ++ } ++#endif ++ + /* + * 1.2. Writing the request + */ +@@ -649,6 +820,9 @@ int main( int argc, char *argv[] ) + mbedtls_printf( " ok\n" ); + + exit: ++#if defined(MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT) ++ subj_alt_names_free( &opt.subj_alt_names ); ++#endif + mbedtls_x509write_crt_free( &crt ); + mbedtls_pk_free( &loaded_subject_key ); + mbedtls_pk_free( &loaded_issuer_key ); +diff --git a/tests/data_files/server1-bothnames.crt b/tests/data_files/server1-bothnames.crt +new file mode 100644 +index 0000000..b7e1f40 +--- /dev/null ++++ b/tests/data_files/server1-bothnames.crt +@@ -0,0 +1,22 @@ ++-----BEGIN CERTIFICATE----- ++MIIDoTCCAomgAwIBAgIBATANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER ++MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN ++MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G ++A1UEChMIUG9sYXJTU0wxGjAYBgNVBAMTEVBvbGFyU1NMIFNlcnZlciAxMIIBIjAN ++BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJlLhVhXom/ ++uOhFkNvuiBZS0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA0INq1UFD ++d185fAkER4KwVzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMPQPhtgSVf ++CrFTxjB+FTms+Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZvq1lLGTr ++lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w ++bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB ++o4GuMIGrMAkGA1UdEwQCMAAwHQYDVR0OBBYEFB901j8pwXR0RTsFEiw9qL1DWQKm ++MB8GA1UdIwQYMBaAFLRa5KWz3tJS9rnVppUP6z68x/3/MF4GA1UdEQRXMFWkPzA9 ++MQswCQYDVQQGEwJOTDERMA8GA1UEChMIUG9sYXJTU0wxGzAZBgNVBAMTElBvbGFy ++U1NMIFNlcnZlciAxQYISb3RoZXIucG9sYXJzc2wub3JnMA0GCSqGSIb3DQEBCwUA ++A4IBAQCUqTN1WjWPMNpflyDTOEq+DEbNgj83ghhB6cCxHCGNT12CpBvQDh4bj5QC ++c77x8kN5fwy+HO1QIwHhBtjLC0IUfKvJUaTbwvIDH1NotrxSg/ft3HG/ijbTrX9/ ++kxDXDcHkOlNX4Y5cJnU7UBm81n7WInGvGqperXTIDgW5CEkQp2ErtxvSZkNtYe82 ++0DwVIQwjbF5hxFxQPGEzM1AANMyzOYKNtg6S7ElbtU4NQqvcBNr3vaG5ipMrkf2u ++kfJZAs+bPo+UyuFBCRGmOMgOAUrK4WvvxtqKFZDdty+pyTiR25x55Upfum7jxeBt ++Nnu2TUYcY472fXbZA5Y7/gGnmmRe ++-----END CERTIFICATE----- +diff --git a/tests/data_files/server1-directoryname.crt b/tests/data_files/server1-directoryname.crt +new file mode 100644 +index 0000000..b220230 +--- /dev/null ++++ b/tests/data_files/server1-directoryname.crt +@@ -0,0 +1,22 @@ ++-----BEGIN CERTIFICATE----- ++MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER ++MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN ++MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G ++A1UEChMIUG9sYXJTU0wxGjAYBgNVBAMTEVBvbGFyU1NMIFNlcnZlciAxMIIBIjAN ++BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJlLhVhXom/ ++uOhFkNvuiBZS0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA0INq1UFD ++d185fAkER4KwVzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMPQPhtgSVf ++CrFTxjB+FTms+Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZvq1lLGTr ++lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w ++bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB ++o4GaMIGXMAkGA1UdEwQCMAAwHQYDVR0OBBYEFB901j8pwXR0RTsFEiw9qL1DWQKm ++MB8GA1UdIwQYMBaAFLRa5KWz3tJS9rnVppUP6z68x/3/MEoGA1UdEQRDMEGkPzA9 ++MQswCQYDVQQGEwJOTDERMA8GA1UEChMIUG9sYXJTU0wxGzAZBgNVBAMTElBvbGFy ++U1NMIFNlcnZlciAxQTANBgkqhkiG9w0BAQsFAAOCAQEAYb6K1UU+6eUdfMD/vayr ++36VEOFd2SA2AxBgj2GKAB7IyKgT6bZTo6SyfJWtvWlp7Ofjc9nQ2iObNRqN1499t ++DmAb3IM9yXuG00GVVg5brC3RtX1w4KJci2z+R2FX+HPAJW5E2rlU7OIm0FfF2aV6 ++0qhHeJSCwi8DkS6U6dQW3vmFXf4sEVtyRkY5Zh3pEcSb3mNpvxNdq1Ro8TRmOGHe ++HrHAWxgBTeUJ0Dv/TNn39FNyvzwvWDFFxhwgs4+43N7FuSM6XUA86mkwLAsrjfWx ++fKNjq7fpJX2dS08ISV/RismU6RGt/TW4PXrtvEIfy1+kaMDSt+ffz1C1cuSen7xz ++6w== ++-----END CERTIFICATE----- +diff --git a/tests/data_files/server1-dnsname.crt b/tests/data_files/server1-dnsname.crt +new file mode 100644 +index 0000000..f3bad52 +--- /dev/null ++++ b/tests/data_files/server1-dnsname.crt +@@ -0,0 +1,21 @@ ++-----BEGIN CERTIFICATE----- ++MIIDXjCCAkagAwIBAgIBATANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER ++MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN ++MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G ++A1UEChMIUG9sYXJTU0wxGjAYBgNVBAMTEVBvbGFyU1NMIFNlcnZlciAxMIIBIjAN ++BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJlLhVhXom/ ++uOhFkNvuiBZS0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA0INq1UFD ++d185fAkER4KwVzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMPQPhtgSVf ++CrFTxjB+FTms+Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZvq1lLGTr ++lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w ++bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB ++o2wwajAJBgNVHRMEAjAAMB0GA1UdDgQWBBQfdNY/KcF0dEU7BRIsPai9Q1kCpjAf ++BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zAdBgNVHREEFjAUghJvdGhl ++ci5wb2xhcnNzbC5vcmcwDQYJKoZIhvcNAQELBQADggEBAFTQDT3BP8qKss7yVjZM ++8RkFF9GuqgCYPWyyuixzxYU5OJzzo/g5ZQ37wfcOMIUA7Ygs0Pv/L0n5PzncJqwO ++mJpQRghbI4yp2qVsKpdx+SVTS9aDm/madjREbSzk/tXVskINbuaWQ/azKbB6MReu ++XXgcw/iROpKJl+WCVr0cy6EAWPd3QBNLYyoAKpMQT2HXfQT/AhEZJINSYrkJeHCt ++BgTGq8tvXE2OtcjTcmp+KIpkXA6A0laRx5up1xET9wDrdll5AEhXSXDzIEOwIBhJ ++3cExQNdWbO6JdjBi5Qaoq9o7ItQOFSTM6PvRC3MYRwN+WhFdb+4Kmvd5oIArRaHo ++MEM= ++-----END CERTIFICATE----- +diff --git a/tests/data_files/server11-directoryname.crt b/tests/data_files/server11-directoryname.crt +new file mode 100644 +index 0000000..d9e0a16 +--- /dev/null ++++ b/tests/data_files/server11-directoryname.crt +@@ -0,0 +1,10 @@ ++-----BEGIN CERTIFICATE----- ++MIIBVzCB/qADAgECAgkAkWvgYjFeWV0wCgYIKoZIzj0EAwIwEzERMA8GA1UEAwwI ++VGVzdENlcnQwHhcNMTYxMjEzMjMwNDM3WhcNMzAwODIyMjMwNDM3WjATMREwDwYD ++VQQDDAhUZXN0Q2VydDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOkrKfbStoGN ++oOUTet2ryyRul++FE++6vpEup83bHywiOO1a4JtDgzNJcjj8/uAKsECYQrI1T4Y/ ++rpnYu8ff9VGjOzA5MDcGA1UdEQQwMC6kLDAqMRYwFAYDVQQLDA1OYW1lIEFzc2ln ++bmVyMRAwDgYDVQQDDAdNeSBSb2xlMAoGCCqGSM49BAMCA0gAMEUCIGdd/GGuoOXJ ++8Ipl3hy69gb35MmkwEQKuYrud+Qs5XfFAiEAsmEOP4KFZadL23XJfMfGuPn2MDLr ++G9lDDpiediVxGO0= ++-----END CERTIFICATE----- +diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh +index 57155b8..7e754bb 100755 +--- a/tests/ssl-opt.sh ++++ b/tests/ssl-opt.sh +@@ -2526,6 +2526,16 @@ run_test "extKeyUsage cli: codeSign -> fail" \ + -c "Processing of the Certificate handshake message failed" \ + -C "Ciphersuite is TLS-" + ++run_test "extKeyUsage cli: codeSign(requested) -> OK " \ ++ "$O_SRV -key data_files/server5.key \ ++ -cert data_files/server5.eku-cs.crt" \ ++ "$P_CLI debug_level=1 eku=client-codesign" \ ++ 0 \ ++ -C "bad certificate (usage extensions)" \ ++ -C "Processing of the Certificate handshake message failed" \ ++ -c "Ciphersuite is TLS-" ++ ++ + # Tests for extendedKeyUsage, part 3: server-side checking of client cert + + run_test "extKeyUsage cli-auth: clientAuth -> OK" \ +@@ -2568,6 +2578,14 @@ run_test "extKeyUsage cli-auth: codeSign -> fail (hard)" \ + -s "bad certificate (usage extensions)" \ + -s "Processing of the Certificate handshake message failed" + ++run_test "extKeyUsage cli-auth: codeSign(requested) -> OK" \ ++ "$P_SRV debug_level=1 auth_mode=required eku=codesign-server" \ ++ "$O_CLI -key data_files/server5.key \ ++ -cert data_files/server5.eku-cs.crt" \ ++ 0 \ ++ -S "bad certificate (usage extensions)" \ ++ -S "Processing of the Certificate handshake message failed" ++ + # Tests for DHM parameters loading + + run_test "DHM parameters: reference" \ +diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data +index c829823..30fff78 100644 +--- a/tests/suites/test_suite_x509parse.data ++++ b/tests/suites/test_suite_x509parse.data +@@ -122,6 +122,22 @@ X509 certificate v1 with extension + depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3:MBEDTLS_SHA1_C + x509_cert_info:"data_files/cert_v1_with_ext.crt":"cert. version \: 1\nserial number \: BD\:ED\:44\:C7\:D2\:3E\:C2\:A4\nissuer name \: C=XX, ST=XX, L=XX, O=XX, OU=XX, emailAddress=admin@identity-check.org, CN=identity-check.org\nsubject name \: C=XX, ST=XX, L=XX, O=XX, OU=XX, emailAddress=admin@identity-check.org, CN=identity-check.org\nissued on \: 2013-07-04 16\:17\:02\nexpires on \: 2014-07-04 16\:17\:02\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nsubject alt name \: identity-check.org, www.identity-check.org\n" + ++X509 Certificate information EC directoryName subjectAltName ++depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT ++x509_cert_info:"data_files/server11-directoryname.crt":"cert. version \: 3\nserial number \: 91\:6B\:E0\:62\:31\:5E\:59\:5D\nissuer name \: CN=TestCert\nsubject name \: CN=TestCert\nissued on \: 2016-12-13 23\:04\:37\nexpires on \: 2030-08-22 23\:04\:37\nsigned using \: ECDSA with SHA256\nEC key size \: 256 bits\nsubject alt name \: directoryName=(OU=Name Assigner, CN=My Role)\n" ++ ++X509 Certificate information dNSName subjectAltName ++depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C:MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT ++x509_cert_info:"data_files/server1-dnsname.crt":"cert. version \: 3\nserial number \: 01\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued on \: 2011-02-12 14\:44\:06\nexpires on \: 2021-02-12 14\:44\:06\nsigned using \: RSA with SHA-256\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name \: other.polarssl.org\n" ++ ++X509 Certificate information directoryName subjectAltName ++depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C:MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT ++x509_cert_info:"data_files/server1-directoryname.crt":"cert. version \: 3\nserial number \: 01\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued on \: 2011-02-12 14\:44\:06\nexpires on \: 2021-02-12 14\:44\:06\nsigned using \: RSA with SHA-256\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name \: directoryName=(C=NL, O=PolarSSL, CN=PolarSSL Server 1A)\n" ++ ++X509 Certificate information dNSName+directoryName subjectAltName ++depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C:MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT ++x509_cert_info:"data_files/server1-bothnames.crt":"cert. version \: 3\nserial number \: 01\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued on \: 2011-02-12 14\:44\:06\nexpires on \: 2021-02-12 14\:44\:06\nsigned using \: RSA with SHA-256\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name \: directoryName=(C=NL, O=PolarSSL, CN=PolarSSL Server 1A), other.polarssl.org\n" ++ + X509 CRL information #1 + depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_SHA1_C + mbedtls_x509_crl_info:"data_files/crl_expired.pem":"CRL version \: 1\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nthis update \: 2011-02-20 10\:24\:19\nnext update \: 2011-02-20 11\:24\:19\nRevoked certificates\:\nserial number\: 01 revocation date\: 2011-02-12 14\:44\:07\nserial number\: 03 revocation date\: 2011-02-12 14\:44\:07\nsigned using \: RSA with SHA1\n" +diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data +index d4d2a98..57c2ad2 100644 +--- a/tests/suites/test_suite_x509write.data ++++ b/tests/suites/test_suite_x509write.data +@@ -58,6 +58,18 @@ Certificate write check Server1 SHA1, version 1 + depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C + x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_CRT_VERSION_1:"data_files/server1.v1.crt" + ++Certificate write check Server1 SHA256 with dNSName ++depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C:MBEDTLS_SHA256_C:MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT ++x509_crt_subj_alt_name_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA256:0:0:-1:1:"data_files/server1-dnsname.crt" ++ ++Certificate write check Server1 SHA256 with directoryName ++depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C:MBEDTLS_SHA256_C:MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT ++x509_crt_subj_alt_name_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA256:0:0:-1:2:"data_files/server1-directoryname.crt" ++ ++Certificate write check Server1 SHA256 with dNSName and directoryName ++depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C:MBEDTLS_SHA256_C:MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT ++x509_crt_subj_alt_name_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA256:0:0:-1:3:"data_files/server1-bothnames.crt" ++ + X509 String to Names #1 + mbedtls_x509_string_to_names:"C=NL,O=Offspark\, Inc., OU=PolarSSL":"C=NL, O=Offspark, Inc., OU=PolarSSL":0 + +diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function +index 89be31f..184ac2c 100644 +--- a/tests/suites/test_suite_x509write.function ++++ b/tests/suites/test_suite_x509write.function +@@ -157,6 +157,131 @@ exit: + } + /* END_CASE */ + ++/* BEGIN_CASE depends_on:MBEDTLS_PEM_WRITE_C:MBEDTLS_X509_CRT_WRITE_C:MBEDTLS_SHA1_C:MBEDTLS_X509_EXPANDED_SUBJECT_ALT_NAME_SUPPORT */ ++void x509_crt_subj_alt_name_check( char *subject_key_file, char *subject_pwd, ++ char *subject_name, char *issuer_key_file, ++ char *issuer_pwd, char *issuer_name, ++ char *serial_str, char *not_before, char *not_after, ++ int md_type, int key_usage, int cert_type, int ver, int subj_alt_names_type, ++ char *cert_check_file ) ++{ ++ mbedtls_pk_context subject_key, issuer_key; ++ mbedtls_x509write_cert crt; ++ unsigned char buf[4096]; ++ unsigned char check_buf[5000]; ++ mbedtls_mpi serial; ++ int ret; ++ size_t olen = 0, pem_len = 0; ++ int der_len = -1; ++ FILE *f; ++ rnd_pseudo_info rnd_info; ++ ++ memset( &rnd_info, 0x2a, sizeof( rnd_pseudo_info ) ); ++ mbedtls_mpi_init( &serial ); ++ mbedtls_pk_init( &subject_key ); ++ mbedtls_pk_init( &issuer_key ); ++ ++ TEST_ASSERT( mbedtls_pk_parse_keyfile( &subject_key, subject_key_file, ++ subject_pwd ) == 0 ); ++ TEST_ASSERT( mbedtls_pk_parse_keyfile( &issuer_key, issuer_key_file, ++ issuer_pwd ) == 0 ); ++ TEST_ASSERT( mbedtls_mpi_read_string( &serial, 10, serial_str ) == 0 ); ++ ++ mbedtls_x509write_crt_init( &crt ); ++ if( ver != -1 ) ++ mbedtls_x509write_crt_set_version( &crt, ver ); ++ TEST_ASSERT( mbedtls_x509write_crt_set_serial( &crt, &serial ) == 0 ); ++ TEST_ASSERT( mbedtls_x509write_crt_set_validity( &crt, not_before, ++ not_after ) == 0 ); ++ mbedtls_x509write_crt_set_md_alg( &crt, md_type ); ++ TEST_ASSERT( mbedtls_x509write_crt_set_issuer_name( &crt, issuer_name ) == 0 ); ++ TEST_ASSERT( mbedtls_x509write_crt_set_subject_name( &crt, subject_name ) == 0 ); ++ mbedtls_x509write_crt_set_subject_key( &crt, &subject_key ); ++ mbedtls_x509write_crt_set_issuer_key( &crt, &issuer_key ); ++ ++ if( crt.version >= MBEDTLS_X509_CRT_VERSION_3 ) ++ { ++ TEST_ASSERT( mbedtls_x509write_crt_set_basic_constraints( &crt, 0, 0 ) == 0 ); ++ TEST_ASSERT( mbedtls_x509write_crt_set_subject_key_identifier( &crt ) == 0 ); ++ TEST_ASSERT( mbedtls_x509write_crt_set_authority_key_identifier( &crt ) == 0 ); ++ if( key_usage != 0 ) ++ TEST_ASSERT( mbedtls_x509write_crt_set_key_usage( &crt, key_usage ) == 0 ); ++ if( cert_type != 0 ) ++ TEST_ASSERT( mbedtls_x509write_crt_set_ns_cert_type( &crt, cert_type ) == 0 ); ++ if( subj_alt_names_type != 0 ) ++ { ++ mbedtls_x509_general_names dns_name, directory_name; ++ mbedtls_x509_general_names *first = NULL; ++ ++ memset( &dns_name, 0, sizeof( dns_name ) ); ++ memset( &directory_name, 0, sizeof( directory_name ) ); ++ ++ if ( ( subj_alt_names_type & 1 ) == 1 ) ++ { ++ dns_name.general_name.name_type = MBEDTLS_X509_GENERALNAME_DNSNAME; ++ /* Nothing will try to modify the memory pointed to by p, so this cast is safe. */ ++ dns_name.general_name.dns_name.p = (unsigned char *) "other.polarssl.org"; ++ dns_name.general_name.dns_name.len = strlen( (const char *) dns_name.general_name.dns_name.p ); ++ first = &dns_name; ++ } ++ ++ if ( ( subj_alt_names_type & 2 ) == 2 ) ++ { ++ directory_name.general_name.name_type = MBEDTLS_X509_GENERALNAME_DIRECTORYNAME; ++ TEST_ASSERT( mbedtls_x509_string_to_names( &directory_name.general_name.directory_name, "C=NL,O=PolarSSL,CN=PolarSSL Server 1A" ) == 0 ); ++ if ( first == NULL ) ++ { ++ first = &directory_name; ++ } ++ else ++ { ++ first->next = &directory_name; ++ } ++ } ++ ++ TEST_ASSERT( mbedtls_x509write_crt_set_subject_alt_names( &crt, first ) == 0 ); ++ ++ if ( ( subj_alt_names_type & 2 ) == 2 ) ++ { ++ mbedtls_asn1_free_named_data_list( &directory_name.general_name.directory_name ); ++ } ++ } ++ } ++ ++ ret = mbedtls_x509write_crt_pem( &crt, buf, sizeof(buf), ++ rnd_pseudo_rand, &rnd_info ); ++ TEST_ASSERT( ret == 0 ); ++ ++ pem_len = strlen( (char *) buf ); ++ ++ f = fopen( cert_check_file, "r" ); ++ TEST_ASSERT( f != NULL ); ++ olen = fread( check_buf, 1, sizeof(check_buf), f ); ++ fclose( f ); ++ TEST_ASSERT( olen < sizeof(check_buf) ); ++ ++ TEST_ASSERT( olen >= pem_len - 1 ); ++ TEST_ASSERT( memcmp( buf, check_buf, pem_len - 1 ) == 0 ); ++ ++ der_len = mbedtls_x509write_crt_der( &crt, buf, sizeof( buf ), ++ rnd_pseudo_rand, &rnd_info ); ++ TEST_ASSERT( der_len >= 0 ); ++ ++ if( der_len == 0 ) ++ goto exit; ++ ++ ret = mbedtls_x509write_crt_der( &crt, buf, (size_t)( der_len - 1 ), ++ rnd_pseudo_rand, &rnd_info ); ++ TEST_ASSERT( ret == MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); ++ ++exit: ++ mbedtls_x509write_crt_free( &crt ); ++ mbedtls_pk_free( &issuer_key ); ++ mbedtls_pk_free( &subject_key ); ++ mbedtls_mpi_free( &serial ); ++} ++/* END_CASE */ ++ + /* BEGIN_CASE depends_on:MBEDTLS_X509_CREATE_C:MBEDTLS_X509_USE_C */ + void mbedtls_x509_string_to_names( char *name, char *parsed_name, int result ) + { -- 2.7.4