Merge remote-tracking branch 'restricted/pr/584' into baremetal-proposed

* restricted/pr/584: (140 commits)
  Remove superfluous new line in x509.c
  Add comment about X.509 name comparison of buffer with itself
  [Fixup] Add missing PK release call in Cert Verify parsing
  Fix guard controlling whether nested acquire calls are allowed
  Add X.509 CRT test for nested calls for CRT frame / PK acquire
  Don't return threading error on release()-without-acquire() calls
  Don't allow nested CRT acquire()-calls if MBEDTLS_X509_ALWAYS_FLUSH
  Make X.509 CRT cache reference counting unconditional
  Remove memory buffer alloc from i386 test in all.sh
  Don't mention pk_sign() in the context of public-key contexts
  Don't use assertion for failures of mbedtls_x509_crt_x_acquire()
  Fix copy pasta in x509_crt.h
  Reference copy-less versions of X.509 CRT frame/PK getters
  x509_crt.c: Add blank line to increase readability
  [FIXUP] Fix bug in ASN.1 traversal of silently ignored tag
  [FIXUP] Fix typo in declaration of mbedtls_x509_memcasecmp()
  Move signature-info extraction out of MBEDTLS_X509_REMOVE_INFO
  Fix certificate validity checking logic to work with !TIME_DATE
  Simplify X.509 CRT version check in UID parsing
  Remove unused variable warning in on-demand X.509 parsing
  ...
This commit is contained in:
Manuel Pégourié-Gonnard 2019-07-03 10:03:45 +02:00
commit 417d2ce076
37 changed files with 3518 additions and 1120 deletions

View file

@ -49,6 +49,13 @@ API Changes
always return NULL, and removes the peer_cert field from the
mbedtls_ssl_session structure which otherwise stores the peer's
certificate.
* Add a new compile-time option `MBEDTLS_X509_ON_DEMAND_PARSING`,
disabled by default, which allows to parse and cache X.509 CRTs
on demand only, at the benefit of lower RAM usage. Enabling
this option breaks the structure API of X.509 in that most
fields of `mbedtls_x509_crt` are removed, but it keeps the
X.509 function API. See the API changes section as well as
the documentation in `config.h` for more information.
Bugfix
* Server's RSA certificate in certs.c was SHA-1 signed. In the default

View file

@ -91,6 +91,8 @@
#define MBEDTLS_X509_CHECK_KEY_USAGE
#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
#define MBEDTLS_X509_REMOVE_INFO
#define MBEDTLS_X509_ON_DEMAND_PARSING
#define MBEDTLS_X509_ALWAYS_FLUSH
#define MBEDTLS_ASN1_PARSE_C
/* X.509 CSR writing */

View file

@ -89,6 +89,18 @@
#define MBEDTLS_ASN1_CONSTRUCTED 0x20
#define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80
/* Slightly smaller way to check if tag is a string tag
* compared to canonical implementation. */
#define MBEDTLS_ASN1_IS_STRING_TAG( tag ) \
( ( tag ) < 32u && ( \
( ( 1u << ( tag ) ) & ( ( 1u << MBEDTLS_ASN1_BMP_STRING ) | \
( 1u << MBEDTLS_ASN1_UTF8_STRING ) | \
( 1u << MBEDTLS_ASN1_T61_STRING ) | \
( 1u << MBEDTLS_ASN1_IA5_STRING ) | \
( 1u << MBEDTLS_ASN1_UNIVERSAL_STRING ) | \
( 1u << MBEDTLS_ASN1_PRINTABLE_STRING ) | \
( 1u << MBEDTLS_ASN1_BIT_STRING ) ) ) != 0 ) )
/*
* Bit masks for each of the components of an ASN.1 tag as specified in
* ITU X.690 (08/2015), section 8.1 "General rules for encoding",
@ -119,6 +131,10 @@
( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \
memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 )
#define MBEDTLS_OID_CMP_RAW(oid_str, oid_buf, oid_buf_len) \
( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf_len) ) || \
memcmp( (oid_str), (oid_buf), (oid_buf_len) ) != 0 )
#ifdef __cplusplus
extern "C" {
#endif
@ -260,20 +276,97 @@ int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end
size_t *len );
/**
* \brief Parses and splits an ASN.1 "SEQUENCE OF <tag>"
* Updated the pointer to immediately behind the full sequence tag.
* \brief Free a heap-allocated linked list presentation of
* an ASN.1 sequence, including the first element.
*
* \param p The position in the ASN.1 data
* \param end End of data
* \param cur First variable in the chain to fill
* \param tag Type of sequence
* \param seq The address of the first sequence component. This may
* be \c NULL, in which case this functions returns
* immediately.
*/
void mbedtls_asn1_sequence_free( mbedtls_asn1_sequence *seq );
/**
* \brief This function parses and splits an ASN.1 "SEQUENCE OF <tag>"
* and updates the source buffer pointer to immediately behind
* the full sequence.
*
* \param p The address of the pointer to the beginning of the
* ASN.1 SEQUENCE OF structure, including ASN.1 tag+length header.
* On success, `*p` is advanced to point to the first byte
* following the parsed ASN.1 sequence.
* \param end The end of the ASN.1 input buffer starting at \p p. This is
* used for bounds checking.
* \param cur The address at which to store the first entry in the parsed
* sequence. Further entries are heap-allocated and referenced
* from \p cur.
* \param tag The common tag of the entries in the ASN.1 sequence.
*
* \note Ownership for the heap-allocated elements \c cur->next,
* \c cur->next->next, ..., is passed to the caller. It
* is hence the caller's responsibility to free them when
* no longer needed, and mbedtls_asn1_sequence_free() can
* be used for that, passing \c cur->next as the \c seq
* argument (or \p cur if \p cur itself was heap-allocated
* by the caller).
*
* \return 0 if successful or a specific ASN.1 error code.
*/
int mbedtls_asn1_get_sequence_of( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_sequence *cur,
int tag);
int tag );
/**
* \brief Traverse an ASN.1 SEQUENCE container and
* call a callback for each entry.
*
* \warning This function is still experimental and may change
* at any time.
*
* \param p The address of the pointer to the beginning of
* the ASN.1 SEQUENCE header. This is updated to
* point to the end of the ASN.1 SEQUENCE container
* on a successful invocation.
* \param end The end of the ASN.1 SEQUENCE container.
* \param tag_must_mask A mask to be applied to the ASN.1 tags found within
* the SEQUENCE before comparing to \p tag_must_value.
* \param tag_must_val The required value of each ASN.1 tag found in the
* SEQUENCE, after masking with \p tag_must_mask.
* Mismatching tags lead to an error.
* For example, a value of \c 0 for both \p tag_must_mask
* and \p tag_must_val means that every tag is allowed,
* while a value of \c 0xFF for \p tag_must_mask means
* that \p tag_must_val is the only allowed tag.
* \param tag_may_mask A mask to be applied to the ASN.1 tags found within
* the SEQUENCE before comparing to \p tag_may_value.
* \param tag_may_val The desired value of each ASN.1 tag found in the
* SEQUENCE, after masking with \p tag_may_mask.
* Mismatching tags will be silently ignored.
* For example, a value of \c 0 for \p tag_may_mask and
* \p tag_may_val means that any tag will be considered,
* while a value of \c 0xFF for \p tag_may_mask means
* that all tags with value different from \p tag_may_val
* will be ignored.
* \param cb The callback to trigger for each component
* in the ASN.1 SEQUENCE. If the callback returns
* a non-zero value, the function stops immediately,
* forwarding the callback's return value.
* \param ctx The context to be passed to the callback \p cb.
*
* \return \c 0 if successful the entire ASN.1 SEQUENCE
* was traversed without parsing or callback errors.
* \return A negative ASN.1 error code on a parsing failure.
* \return A non-zero error code forwarded from the callback
* \p cb in case the latter returns a non-zero value.
*/
int mbedtls_asn1_traverse_sequence_of(
unsigned char **p,
const unsigned char *end,
uint8_t tag_must_mask, uint8_t tag_must_val,
uint8_t tag_may_mask, uint8_t tag_may_val,
int (*cb)( void *ctx, int tag,
unsigned char* start, size_t len ),
void *ctx );
#if defined(MBEDTLS_BIGNUM_C)
/**

View file

@ -1757,6 +1757,54 @@
*/
#define MBEDTLS_VERSION_FEATURES
/**
* \def MBEDTLS_X509_ON_DEMAND_PARSING
*
* Save RAM by reducing mbedtls_x509_crt to a pointer
* to the raw CRT data and parsing CRTs on demand only.
*
* \warning This option changes the API by removing most of
* the structure fields of mbedtls_x509_crt.
*
* \warning This option and its corresponding X.509 API are currently
* under development and may change at any time.
*
* Regardless of whether this option is enabled or not, direct access of
* structure fields of `mbedtls_x509_crt` should be replaced by calls to
* one of the following functions:
* - mbedtls_x509_crt_get_frame(), to obtain a CRT frame giving
* access to several basic CRT fields (such as the CRT version),
* as well as pointers to the raw ASN.1 data of more complex fields
* (such as the issuer).
* - mbedtls_x509_crt_get_pk(), to obtain a public key context
* for the public key contained in the certificate.
* - mbedtls_x509_crt_get_issuer(), to obtain the issuer name.
* - mbedtls_x509_crt_get_subject(), to obtain the subject name.
* - mbedtls_x509_crt_get_subject_alt_names(), to obtain the
* alternative names from the subject alternative names extension.
* - mbedtls_x509_crt_get_ext_key_usage(), to obtain the state of
* the extended key usage extension.
*
* Uncomment this to enable on-demand CRT parsing to save RAM.
*/
//#define MBEDTLS_X509_ON_DEMAND_PARSING
/**
* \def MBEDTLS_X509_ALWAYS_FLUSH
*
* Save RAM by having Mbed TLS always flush caches for parsed X.509
* structures after use: This means, firstly, that caches of X.509
* structures used by an API call are flushed when the call returns,
* but it also encompasses immediate flushing of caches when Mbed TLS uses
* multiple structures in succession, thereby reducing the peak RAM usage.
* Setting this option leads to minimal RAM usage of the X.509 module at
* the cost of performance penalties when using X.509 structures multiple
* times (such as trusted CRTs on systems serving many connections).
*
* Uncomment this to always flush caches for unused X.509 structures.
*/
#define MBEDTLS_X509_ALWAYS_FLUSH
/**
* \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
*

View file

@ -183,6 +183,15 @@ extern "C" {
* \{
*/
/**
* Basic length-value buffer structure
*/
typedef struct mbedtls_x509_buf_raw
{
unsigned char *p; /*!< The address of the first byte in the buffer. */
size_t len; /*!< The number of Bytes in the buffer. */
} mbedtls_x509_buf_raw;
/**
* Type-length-value structure that allows for ASN1 using DER.
*/
@ -269,6 +278,29 @@ int mbedtls_x509_time_is_past( const mbedtls_x509_time *to );
*/
int mbedtls_x509_time_is_future( const mbedtls_x509_time *from );
/**
* \brief Free a dynamic linked list presentation of an X.509 name
* as returned e.g. by mbedtls_x509_crt_get_subject().
*
* \param name The address of the first name component. This may
* be \c NULL, in which case this functions returns
* immediately.
*/
void mbedtls_x509_name_free( mbedtls_x509_name *name );
/**
* \brief Free a dynamic linked list presentation of an X.509 sequence
* as returned e.g. by mbedtls_x509_crt_get_subject_alt_name().
*
* \param seq The address of the first sequence component. This may
* be \c NULL, in which case this functions returns
* immediately.
*/
static inline void mbedtls_x509_sequence_free( mbedtls_x509_sequence *seq )
{
mbedtls_asn1_sequence_free( (mbedtls_asn1_sequence*) seq );
}
#if defined(MBEDTLS_SELF_TEST)
/**
@ -280,49 +312,6 @@ int mbedtls_x509_self_test( int verbose );
#endif /* MBEDTLS_SELF_TEST */
/*
* Internal module functions. You probably do not want to use these unless you
* know you do.
*/
int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end,
mbedtls_x509_name *cur );
int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *alg );
int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *alg, mbedtls_x509_buf *params );
#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params,
mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md,
int *salt_len );
#endif
int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig );
int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params,
mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg,
void **sig_opts );
int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end,
mbedtls_x509_time *t );
int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *serial );
int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *ext, int tag );
#if !defined(MBEDTLS_X509_REMOVE_INFO)
int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid,
mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg,
const void *sig_opts );
#endif
int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name );
int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name );
int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len,
int critical, const unsigned char *val,
size_t val_len );
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 );
int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start,
const char *oid, size_t oid_len,
unsigned char *sig, size_t size );
#define MBEDTLS_X509_SAFE_SNPRINTF \
do { \
if( ret < 0 || (size_t) ret >= n ) \
@ -332,6 +321,18 @@ int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start,
p += (size_t) ret; \
} while( 0 )
#define MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP \
do { \
if( ret < 0 || (size_t) ret >= n ) \
{ \
ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; \
goto cleanup; \
} \
\
n -= (size_t) ret; \
p += (size_t) ret; \
} while( 0 )
#ifdef __cplusplus
}
#endif

View file

@ -75,7 +75,7 @@ typedef struct mbedtls_x509_crl
int version; /**< CRL version (1=v1, 2=v2) */
mbedtls_x509_buf sig_oid; /**< CRL signature type identifier */
mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). */
mbedtls_x509_buf_raw issuer_raw; /**< The raw issuer data (DER). */
mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */

View file

@ -32,6 +32,7 @@
#include "x509.h"
#include "x509_crl.h"
#include "x509_internal.h"
/**
* \addtogroup x509_module
@ -47,14 +48,69 @@ extern "C" {
* \{
*/
typedef struct mbedtls_x509_crt_frame
{
/* Keep these 8-bit fields at the front of the structure to allow them to
* be fetched in a single instruction on Thumb2; putting them at the back
* requires an intermediate address calculation. */
uint8_t version; /**< The X.509 version. (1=v1, 2=v2, 3=v3) */
uint8_t ca_istrue; /**< Optional Basic Constraint extension value:
* 1 if this certificate belongs to a CA, 0 otherwise. */
uint8_t max_pathlen; /**< Optional Basic Constraint extension value:
* The maximum path length to the root certificate.
* Path length is 1 higher than RFC 5280 'meaning', so 1+ */
uint8_t ns_cert_type; /**< Optional Netscape certificate type extension value:
* See the values in x509.h */
mbedtls_md_type_t sig_md; /**< The hash algorithm used to hash CRT before signing. */
mbedtls_pk_type_t sig_pk; /**< The signature algorithm used to sign the CRT hash. */
uint16_t key_usage; /**< Optional key usage extension value: See the values in x509.h */
uint32_t ext_types; /**< Bitfield indicating which extensions are present.
* See the values in x509.h. */
mbedtls_x509_time valid_from; /**< The start time of certificate validity. */
mbedtls_x509_time valid_to; /**< The end time of certificate validity. */
mbedtls_x509_buf_raw raw; /**< The raw certificate data in DER. */
mbedtls_x509_buf_raw tbs; /**< The part of the CRT that is [T]o [B]e [S]igned. */
mbedtls_x509_buf_raw serial; /**< The unique ID for certificate issued by a specific CA. */
mbedtls_x509_buf_raw pubkey_raw; /**< The raw public key data (DER). */
mbedtls_x509_buf_raw issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */
mbedtls_x509_buf_raw issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */
mbedtls_x509_buf_raw subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */
mbedtls_x509_buf_raw subject_raw; /**< The raw subject data (DER). Used for quick comparison. */
mbedtls_x509_buf_raw sig; /**< Signature: hash of the tbs part signed with the private key. */
mbedtls_x509_buf_raw sig_alg; /**< The signature algorithm used for \p sig. */
mbedtls_x509_buf_raw v3_ext; /**< The raw data for the extension list in the certificate.
* Might be useful for manual inspection of extensions that
* Mbed TLS doesn't yet support. */
mbedtls_x509_buf_raw subject_alt_raw; /**< The raw data for the SubjectAlternativeNames extension. */
mbedtls_x509_buf_raw ext_key_usage_raw; /**< The raw data for the ExtendedKeyUsage extension. */
} mbedtls_x509_crt_frame;
/**
* Container for an X.509 certificate. The certificate may be chained.
*/
typedef struct mbedtls_x509_crt
{
int own_buffer; /**< Indicates if \c raw is owned
* by the structure or not. */
mbedtls_x509_buf raw; /**< The raw certificate data (DER). */
* by the structure or not. */
mbedtls_x509_buf raw; /**< The raw certificate data (DER). */
mbedtls_x509_crt_cache *cache; /**< Internal parsing cache. */
struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */
/* Legacy fields */
#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING)
mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */
int version; /**< The X.509 version. (1=v1, 2=v2, 3=v3) */
@ -84,7 +140,7 @@ typedef struct mbedtls_x509_crt
unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */
mbedtls_x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */
mbedtls_x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */
unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values in x509.h */
@ -92,8 +148,7 @@ typedef struct mbedtls_x509_crt
mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */
mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */
void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */
struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */
#endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */
}
mbedtls_x509_crt;
@ -586,6 +641,366 @@ void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx );
*/
void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx );
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
/**
* \brief Request CRT frame giving access to basic CRT fields
* and raw ASN.1 data of complex fields.
*
* \param crt The CRT to use. This must be initialized and set up.
* \param dst The address of the destination frame structure.
* This need not be initialized.
*
* \note ::mbedtls_x509_crt_frame does not contain pointers to
* dynamically allocated memory, and hence need not be freed.
* Users may e.g. allocate an instance of
* ::mbedtls_x509_crt_frame on the stack and call this function
* on it, in which case no allocation/freeing has to be done.
*
* \note You may also use mbedtls_x509_crt_frame_acquire() and
* mbedtls_x509_crt_frame_release() for copy-less variants
* of this function.
*
* \return \c 0 on success. In this case, \p dst is updated
* to hold the frame for the given CRT.
* \return A negative error code on failure.
*/
int mbedtls_x509_crt_get_frame( mbedtls_x509_crt const *crt,
mbedtls_x509_crt_frame *dst );
/**
* \brief Set up a PK context with the public key in a certificate.
*
* \param crt The certificate to use. This must be initialized and set up.
* \param pk The address of the destination PK context to fill.
* This must be initialized via mbedtls_pk_init().
*
* \note You may also use mbedtls_x509_crt_pk_acquire() and
* mbedtls_x509_crt_pk_release() for copy-less variants
* of this function.
*
* \return \c 0 on success. In this case, the user takes ownership
* of the destination PK context, and is responsible for
* calling mbedtls_pk_free() on it once it's no longer needed.
* \return A negative error code on failure.
*/
int mbedtls_x509_crt_get_pk( mbedtls_x509_crt const *crt,
mbedtls_pk_context *pk );
/**
* \brief Request the subject name of a CRT, presented
* as a dynamically allocated linked list.
*
* \param crt The CRT to use. This must be initialized and set up.
* \param subject The address at which to store the address of the
* first entry of the generated linked list holding
* the subject name.
*
* \note Depending on your use case, consider using the raw ASN.1
* describing the subject name instead of the heap-allocated
* linked list generated by this call. The pointers to the
* raw ASN.1 data are part of the CRT frame that can be queried
* via mbedtls_x509_crt_get_frame(), and they can be traversed
* via mbedtls_asn1_traverse_sequence_of().
*
* \return \c 0 on success. In this case, the user takes ownership
* of the name context, and is responsible for freeing it
* through a call to mbedtls_x509_name_free() once it's no
* longer needed.
* \return A negative error code on failure.
*/
int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt,
mbedtls_x509_name **subject );
/**
* \brief Request the subject name of a CRT, presented
* as a dynamically allocated linked list.
*
* \param crt The CRT to use. This must be initialized and set up.
* \param issuer The address at which to store the address of the
* first entry of the generated linked list holding
* the subject name.
*
* \note Depending on your use case, consider using the raw ASN.1
* describing the issuer name instead of the heap-allocated
* linked list generated by this call. The pointers to the
* raw ASN.1 data are part of the CRT frame that can be queried
* via mbedtls_x509_crt_get_frame(), and they can be traversed
* via mbedtls_asn1_traverse_sequence_of().
*
* \return \c 0 on success. In this case, the user takes ownership
* of the name context, and is responsible for freeing it
* through a call to mbedtls_x509_name_free() once it's no
* longer needed.
* \return A negative error code on failure.
*/
int mbedtls_x509_crt_get_issuer( mbedtls_x509_crt const *crt,
mbedtls_x509_name **issuer );
/**
* \brief Request the subject alternative name of a CRT, presented
* as a dynamically allocated linked list.
*
* \param crt The CRT to use. This must be initialized and set up.
* \param subj_alt The address at which to store the address of the
* first component of the subject alternative names list.
*
* \note Depending in your use case, consider using the raw ASN.1
* describing the subject alternative names extension
* instead of the heap-allocated linked list generated by this
* call. The pointers to the raw ASN.1 data are part of the CRT
* frame that can be queried via mbedtls_x509_crt_get_frame(),
* and mbedtls_asn1_traverse_sequence_of() can be used to
* traverse the list of subject alternative names.
*
* \return \c 0 on success. In this case, the user takes ownership
* of the name context, and is responsible for freeing it
* through a call to mbedtls_x509_sequence_free() once it's
* no longer needed.
* \return A negative error code on failure.
*/
int mbedtls_x509_crt_get_subject_alt_names( mbedtls_x509_crt const *crt,
mbedtls_x509_sequence **subj_alt );
/**
* \brief Request the ExtendedKeyUsage extension of a CRT,
* presented as a dynamically allocated linked list.
*
* \param crt The CRT to use. This must be initialized and set up.
* \param ext_key_usage The address at which to store the address of the
* first entry of the ExtendedKeyUsage extension.
*
* \note Depending in your use case, consider using the raw ASN.1
* describing the extended key usage extension instead of
* the heap-allocated linked list generated by this call.
* The pointers to the raw ASN.1 data are part of the CRT
* frame that can be queried via mbedtls_x509_crt_get_frame(),
* and mbedtls_asn1_traverse_sequence_of() can be used to
* traverse the entries in the extended key usage extension.
*
* \return \c 0 on success. In this case, the user takes ownership
* of the name context, and is responsible for freeing it
* through a call to mbedtls_x509_sequence_free() once it's
* no longer needed.
* \return A negative error code on failure.
*/
int mbedtls_x509_crt_get_ext_key_usage( mbedtls_x509_crt const *crt,
mbedtls_x509_sequence **ext_key_usage );
/**
* \brief Flush internal X.509 CRT parsing cache, if present.
*
* \param crt The CRT structure whose cache to flush.
*
* \note Calling this function frequently reduces RAM usage
* at the cost of performance.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt );
/**
* \brief Request temporary read-access to a certificate frame
* for a given certificate.
*
* Once no longer needed, the frame must be released
* through a call to mbedtls_x509_crt_frame_release().
*
* This is a copy-less version of mbedtls_x509_crt_get_frame().
* See there for more information.
*
* \param crt The certificate to use. This must be initialized and set up.
* \param dst The address at which to store the address of a readable
* certificate frame for the input certificate \p crt which the
* caller can use until calling mbedtls_x509_crt_frame_release().
*
* \note The certificate frame `**frame_ptr` returned by this function
* is owned by the X.509 module and must not be freed or modified
* by the caller. The X.509 module guarantees its validity as long
* as \p crt is valid and mbedtls_x509_crt_frame_release() hasn't
* been issued.
*
* \note In a single-threaded application using
* MBEDTLS_X509_ALWAYS_FLUSH, nested calls to this function
* are not allowed and will fail gracefully with
* MBEDTLS_ERR_X509_FATAL_ERROR.
*
* \return \c 0 on success. In this case, `*frame_ptr` is updated
* to hold the address of a frame for the given CRT.
* \return A negative error code on failure.
*/
static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt,
mbedtls_x509_crt_frame const **dst )
{
int ret = 0;
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif /* MBEDTLS_THREADING_C */
#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \
defined(MBEDTLS_THREADING_C)
if( crt->cache->frame_readers == 0 )
#endif
ret = mbedtls_x509_crt_cache_provide_frame( crt );
#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \
defined(MBEDTLS_THREADING_C)
if( crt->cache->frame_readers == MBEDTLS_X509_CACHE_FRAME_READERS_MAX )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
crt->cache->frame_readers++;
#endif
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif /* MBEDTLS_THREADING_C */
*dst = crt->cache->frame;
return( ret );
}
/**
* \brief Release access to a certificate frame acquired
* through a prior call to mbedtls_x509_crt_frame_acquire().
*
* \param crt The certificate for which a certificate frame has
* previously been acquired.
*/
static inline int mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt )
{
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif /* MBEDTLS_THREADING_C */
#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \
defined(MBEDTLS_THREADING_C)
if( crt->cache->frame_readers == 0 )
return( MBEDTLS_ERR_X509_FATAL_ERROR );
crt->cache->frame_readers--;
#endif
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_unlock( &crt->cache->frame_mutex );
#endif /* MBEDTLS_THREADING_C */
#if defined(MBEDTLS_X509_ALWAYS_FLUSH)
(void) mbedtls_x509_crt_flush_cache_frame( crt );
#endif /* MBEDTLS_X509_ALWAYS_FLUSH */
#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) && \
!defined(MBEDTLS_THREADING_C)
((void) crt);
#endif
return( 0 );
}
/**
* \brief Request temporary access to a public key context
* for a given certificate.
*
* Once no longer needed, the frame must be released
* through a call to mbedtls_x509_crt_pk_release().
*
* This is a copy-less version of mbedtls_x509_crt_get_pk().
* See there for more information.
*
* \param crt The certificate to use. This must be initialized and set up.
* \param dst The address at which to store the address of a public key
* context for the public key in the input certificate \p crt.
*
* \warning The public key context `**pk_ptr` returned by this function
* is owned by the X.509 module and must be used by the caller
* in a thread-safe way. In particular, the caller must only
* use the context with functions which are `const` on the input
* context, or those which are known to be thread-safe. The latter
* for example includes mbedtls_pk_verify() for ECC or RSA public
* key contexts.
*
* \note In a single-threaded application using
* MBEDTLS_X509_ALWAYS_FLUSH, nested calls to this function
* are not allowed and will fail gracefully with
* MBEDTLS_ERR_X509_FATAL_ERROR.
*
* \return \c 0 on success. In this case, `*pk_ptr` is updated
* to hold the address of a public key context for the given
* certificate.
* \return A negative error code on failure.
*/
static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt,
mbedtls_pk_context **dst )
{
int ret = 0;
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif /* MBEDTLS_THREADING_C */
#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \
defined(MBEDTLS_THREADING_C)
if( crt->cache->pk_readers == 0 )
#endif
ret = mbedtls_x509_crt_cache_provide_pk( crt );
#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \
defined(MBEDTLS_THREADING_C)
if( crt->cache->pk_readers == MBEDTLS_X509_CACHE_PK_READERS_MAX )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
crt->cache->pk_readers++;
#endif
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif /* MBEDTLS_THREADING_C */
*dst = crt->cache->pk;
return( ret );
}
/**
* \brief Release access to a public key context acquired
* through a prior call to mbedtls_x509_crt_frame_acquire().
*
* \param crt The certificate for which a certificate frame has
* previously been acquired.
*/
static inline int mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt )
{
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif /* MBEDTLS_THREADING_C */
#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \
defined(MBEDTLS_THREADING_C)
if( crt->cache->pk_readers == 0 )
return( MBEDTLS_ERR_X509_FATAL_ERROR );
crt->cache->pk_readers--;
#endif
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_unlock( &crt->cache->pk_mutex );
#endif /* MBEDTLS_THREADING_C */
#if defined(MBEDTLS_X509_ALWAYS_FLUSH)
(void) mbedtls_x509_crt_flush_cache_pk( crt );
#endif /* MBEDTLS_X509_ALWAYS_FLUSH */
#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) && \
!defined(MBEDTLS_THREADING_C)
((void) crt);
#endif
return( 0 );
}
#endif /* MBEDTLS_X509_CRT_PARSE_C */
/* \} name */

View file

@ -0,0 +1,117 @@
/**
* \file x509_internal.h
*
* \brief Internal X.509 functions
*/
/*
* Copyright (C) 2006-2019, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*
*/
#ifndef MBEDTLS_X509_INTERNAL_H
#define MBEDTLS_X509_INTERNAL_H
#include "x509.h"
#include "threading.h"
/* Internal structure used for caching parsed data from an X.509 CRT. */
struct mbedtls_x509_crt;
struct mbedtls_pk_context;
struct mbedtls_x509_crt_frame;
#define MBEDTLS_X509_CACHE_PK_READERS_MAX ((uint32_t) -1)
#define MBEDTLS_X509_CACHE_FRAME_READERS_MAX ((uint32_t) -1)
typedef struct mbedtls_x509_crt_cache
{
#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \
defined(MBEDTLS_THREADING_C)
uint32_t frame_readers;
uint32_t pk_readers;
#endif /* !MBEDTLS_X509_ALWAYS_FLUSH || MBEDTLS_THREADING_C */
#if defined(MBEDTLS_THREADING_C)
mbedtls_threading_mutex_t frame_mutex;
mbedtls_threading_mutex_t pk_mutex;
#endif
mbedtls_x509_buf_raw pk_raw;
struct mbedtls_x509_crt_frame *frame;
struct mbedtls_pk_context *pk;
} mbedtls_x509_crt_cache;
/* Internal X.509 CRT cache handling functions. */
int mbedtls_x509_crt_flush_cache_frame( struct mbedtls_x509_crt const *crt );
int mbedtls_x509_crt_flush_cache_pk( struct mbedtls_x509_crt const *crt );
int mbedtls_x509_crt_cache_provide_frame( struct mbedtls_x509_crt const *crt );
int mbedtls_x509_crt_cache_provide_pk( struct mbedtls_x509_crt const *crt );
/* Uncategorized internal X.509 functions */
int mbedtls_x509_get_name( unsigned char *p, size_t len,
mbedtls_x509_name *cur );
int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *alg );
int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *alg, mbedtls_x509_buf *params );
#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params,
mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md,
int *salt_len );
#endif
int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig );
int mbedtls_x509_get_sig_alg_raw( unsigned char **p, unsigned char const *end,
mbedtls_md_type_t *md_alg,
mbedtls_pk_type_t *pk_alg,
void **sig_opts );
int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params,
mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg,
void **sig_opts );
int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end,
mbedtls_x509_time *t );
int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *serial );
int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a,
mbedtls_x509_buf_raw const *b,
int (*check)( void *ctx,
mbedtls_x509_buf *oid,
mbedtls_x509_buf *val,
int next_merged ),
void *check_ctx );
int mbedtls_x509_memcasecmp( const void *s1, const void *s2,
size_t len1, size_t len2 );
int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end,
mbedtls_x509_buf *ext, int tag );
#if !defined(MBEDTLS_X509_REMOVE_INFO)
int mbedtls_x509_sig_alg_gets( char *buf, size_t size,
mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg,
const void *sig_opts );
#endif
int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name );
int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name );
int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len,
int critical, const unsigned char *val,
size_t val_len );
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 );
int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start,
const char *oid, size_t oid_len,
unsigned char *sig, size_t size );
#endif /* MBEDTLS_X509_INTERNAL_H */

View file

@ -229,6 +229,103 @@ int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end
return( 0 );
}
void mbedtls_asn1_sequence_free( mbedtls_asn1_sequence *seq )
{
while( seq != NULL )
{
mbedtls_asn1_sequence *next = seq->next;
mbedtls_platform_zeroize( seq, sizeof( *seq ) );
mbedtls_free( seq );
seq = next;
}
}
/*
* Traverse an ASN.1 "SEQUENCE OF <tag>"
* and call a callback for each entry found.
*/
int mbedtls_asn1_traverse_sequence_of(
unsigned char **p,
const unsigned char *end,
uint8_t tag_must_mask, uint8_t tag_must_val,
uint8_t tag_may_mask, uint8_t tag_may_val,
int (*cb)( void *ctx, int tag,
unsigned char *start, size_t len ),
void *ctx )
{
int ret;
size_t len;
/* Get main sequence tag */
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
{
return( ret );
}
if( *p + len != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
while( *p < end )
{
unsigned char const tag = *(*p)++;
if( ( tag & tag_must_mask ) != tag_must_val )
return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
if( ( ret = mbedtls_asn1_get_len( p, end, &len ) ) != 0 )
return( ret );
if( ( tag & tag_may_mask ) == tag_may_val )
{
if( cb != NULL )
{
ret = cb( ctx, tag, *p, len );
if( ret != 0 )
return( ret );
}
}
*p += len;
}
return( 0 );
}
typedef struct
{
int tag;
mbedtls_asn1_sequence *cur;
} asn1_get_sequence_of_cb_ctx_t;
static int asn1_get_sequence_of_cb( void *ctx,
int tag,
unsigned char *start,
size_t len )
{
asn1_get_sequence_of_cb_ctx_t *cb_ctx =
(asn1_get_sequence_of_cb_ctx_t *) ctx;
mbedtls_asn1_sequence *cur =
cb_ctx->cur;
if( cur->buf.p != NULL )
{
cur->next =
mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) );
if( cur->next == NULL )
return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
cur = cur->next;
}
cur->buf.p = start;
cur->buf.len = len;
cur->buf.tag = tag;
cb_ctx->cur = cur;
return( 0 );
}
/*
@ -239,49 +336,11 @@ int mbedtls_asn1_get_sequence_of( unsigned char **p,
mbedtls_asn1_sequence *cur,
int tag)
{
int ret;
size_t len;
mbedtls_asn1_buf *buf;
/* Get main sequence tag */
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
return( ret );
if( *p + len != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
while( *p < end )
{
buf = &(cur->buf);
buf->tag = **p;
if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 )
return( ret );
buf->p = *p;
*p += buf->len;
/* Allocate and assign next pointer */
if( *p < end )
{
cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1,
sizeof( mbedtls_asn1_sequence ) );
if( cur->next == NULL )
return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
cur = cur->next;
}
}
/* Set final sequence entry's next pointer to NULL */
cur->next = NULL;
if( *p != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
asn1_get_sequence_of_cb_ctx_t cb_ctx = { tag, cur };
memset( cur, 0, sizeof( mbedtls_asn1_sequence ) );
return( mbedtls_asn1_traverse_sequence_of(
p, end, 0xFF, tag, 0, 0,
asn1_get_sequence_of_cb, &cb_ctx ) );
}
int mbedtls_asn1_get_alg( unsigned char **p,
@ -295,15 +354,12 @@ int mbedtls_asn1_get_alg( unsigned char **p,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
return( ret );
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
alg->tag = **p;
end = *p + len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 )
return( ret );
alg->tag = MBEDTLS_ASN1_OID;
alg->p = *p;
*p += alg->len;

View file

@ -127,7 +127,7 @@ int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs )
if( X->n < nblimbs )
{
if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL ) ) == NULL )
if( ( p = (mbedtls_mpi_uint *)mbedtls_calloc( nblimbs, ciL ) ) == NULL )
return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
if( X->p != NULL )
@ -169,7 +169,7 @@ int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs )
if( i < nblimbs )
i = nblimbs;
if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( i, ciL ) ) == NULL )
if( ( p = (mbedtls_mpi_uint *)mbedtls_calloc( i, ciL ) ) == NULL )
return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
if( X->p != NULL )

View file

@ -331,13 +331,13 @@ int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx,
? MBEDTLS_CHACHAPOLY_ENCRYPT
: MBEDTLS_CHACHAPOLY_DECRYPT;
result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context *) ctx->cipher_ctx,
ctx->iv,
mode );
if ( result != 0 )
return( result );
return( mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
return( mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context *) ctx->cipher_ctx,
ad, ad_len ) );
}
#endif
@ -391,7 +391,7 @@ int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *i
if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 )
{
*olen = ilen;
return( mbedtls_chachapoly_update( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
return( mbedtls_chachapoly_update( (mbedtls_chachapoly_context *) ctx->cipher_ctx,
ilen, input, output ) );
}
#endif
@ -924,7 +924,7 @@ int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx,
if ( tag_len != 16U )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
return( mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
return( mbedtls_chachapoly_finish( (mbedtls_chachapoly_context *) ctx->cipher_ctx,
tag ) );
}
#endif
@ -975,7 +975,7 @@ int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
if ( tag_len != sizeof( check_tag ) )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx,
ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context *) ctx->cipher_ctx,
check_tag );
if ( ret != 0 )
{

View file

@ -1987,7 +1987,7 @@ static int chachapoly_setkey_wrap( void *ctx,
if( key_bitlen != 256U )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if ( 0 != mbedtls_chachapoly_setkey( (mbedtls_chachapoly_context*)ctx, key ) )
if ( 0 != mbedtls_chachapoly_setkey( (mbedtls_chachapoly_context *)ctx, key ) )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
return( 0 );

View file

@ -71,7 +71,7 @@ static inline void debug_send_line( const mbedtls_ssl_context *ssl, int level,
*/
#if defined(MBEDTLS_THREADING_C)
char idstr[20 + DEBUG_BUF_SIZE]; /* 0x + 16 nibbles + ': ' */
mbedtls_snprintf( idstr, sizeof( idstr ), "%p: %s", (void*)ssl, str );
mbedtls_snprintf( idstr, sizeof( idstr ), "%p: %s", (void *)ssl, str );
ssl->conf->f_dbg( ssl->conf->p_dbg, level, file, line, idstr );
#else
ssl->conf->f_dbg( ssl->conf->p_dbg, level, file, line, str );
@ -382,6 +382,8 @@ void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level,
while( crt != NULL )
{
int ret;
mbedtls_pk_context *pk;
char buf[1024];
mbedtls_snprintf( str, sizeof( str ), "%s #%d:\n", text, ++i );
@ -390,7 +392,17 @@ void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level,
mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt );
debug_print_line_by_line( ssl, level, file, line, buf );
debug_print_pk( ssl, level, file, line, "crt->", &crt->pk );
ret = mbedtls_x509_crt_pk_acquire( crt, &pk );
if( ret != 0 )
{
mbedtls_snprintf( str, sizeof( str ),
"mbedtls_x509_crt_pk_acquire() failed with -%#04x\n",
-ret );
debug_send_line( ssl, level, file, line, str );
return;
}
debug_print_pk( ssl, level, file, line, "crt->", pk );
mbedtls_x509_crt_pk_release( crt );
crt = crt->next;
}

View file

@ -72,8 +72,8 @@
#endif
#endif /* _MSC_VER */
#define read(fd,buf,len) recv( fd, (char*)( buf ), (int)( len ), 0 )
#define write(fd,buf,len) send( fd, (char*)( buf ), (int)( len ), 0 )
#define read(fd,buf,len) recv( fd, (char *)( buf ), (int)( len ), 0 )
#define write(fd,buf,len) send( fd, (char *)( buf ), (int)( len ), 0 )
#define close(fd) closesocket(fd)
static int wsa_init_done = 0;

View file

@ -2334,7 +2334,15 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl,
peer_pk = &ssl->handshake->peer_pubkey;
#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( ssl->session_negotiate->peer_cert != NULL )
peer_pk = &ssl->session_negotiate->peer_cert->pk;
{
ret = mbedtls_x509_crt_pk_acquire( ssl->session_negotiate->peer_cert,
&peer_pk );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret );
return( ret );
}
}
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( peer_pk == NULL )
@ -2350,7 +2358,8 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl,
if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_RSA ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate key type mismatch" ) );
return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
ret = MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH;
goto cleanup;
}
if( ( ret = mbedtls_pk_encrypt( peer_pk,
@ -2360,7 +2369,7 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl,
ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_rsa_pkcs1_encrypt", ret );
return( ret );
goto cleanup;
}
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
@ -2373,11 +2382,16 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl,
}
#endif
cleanup:
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/* We don't need the peer's public key anymore. Free it. */
mbedtls_pk_free( peer_pk );
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
return( 0 );
#else
mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert );
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
return( ret );
}
#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED ||
MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */
@ -2463,13 +2477,21 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl )
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
peer_pk = &ssl->session_negotiate->peer_cert->pk;
ret = mbedtls_x509_crt_pk_acquire( ssl->session_negotiate->peer_cert,
&peer_pk );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret );
return( ret );
}
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECKEY ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) );
return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
ret = MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH;
goto cleanup;
}
peer_key = mbedtls_pk_ec( *peer_pk );
@ -2478,21 +2500,26 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl )
MBEDTLS_ECDH_THEIRS ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_get_params" ), ret );
return( ret );
goto cleanup;
}
if( ssl_check_server_ecdh_params( ssl ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server certificate (ECDH curve)" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
goto cleanup;
}
cleanup:
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/* We don't need the peer's public key anymore. Free it,
* so that more RAM is available for upcoming expensive
* operations like ECDHE. */
mbedtls_pk_free( peer_pk );
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#else
mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert );
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
return( ret );
}
@ -2799,7 +2826,14 @@ start_processing:
MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
peer_pk = &ssl->session_negotiate->peer_cert->pk;
ret = mbedtls_x509_crt_pk_acquire( ssl->session_negotiate->peer_cert,
&peer_pk );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret );
return( ret );
}
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
/*
@ -2810,6 +2844,9 @@ start_processing:
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert );
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
}
@ -2831,6 +2868,9 @@ start_processing:
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
#endif
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert );
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
return( ret );
}
@ -2839,7 +2879,9 @@ start_processing:
* so that more RAM is available for upcoming expensive
* operations like ECDHE. */
mbedtls_pk_free( peer_pk );
#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
#else
mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert );
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
}
#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */

View file

@ -791,15 +791,58 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl,
for( cur = list; cur != NULL; cur = cur->next )
{
MBEDTLS_SSL_DEBUG_CRT( 3, "candidate certificate chain, certificate",
cur->cert );
int match = 1;
mbedtls_pk_context *pk;
if( ! mbedtls_pk_can_do( &cur->cert->pk, pk_alg ) )
/* WARNING: With the current X.509 caching architecture, this MUST
* happen outside of the PK acquire/release block, because it moves
* the cached PK context. In a threading-enabled build, this would
* rightfully fail, but lead to a use-after-free otherwise. */
MBEDTLS_SSL_DEBUG_CRT( 3, "candidate certificate chain, certificate",
cur->cert );
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
/* ASYNC_PRIVATE may use a NULL entry for the opaque private key, so
* we have to use the public key context to infer the capabilities
* of the key. */
{
int ret;
ret = mbedtls_x509_crt_pk_acquire( cur->cert, &pk );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret );
return( ret );
}
}
#else
/* Outside of ASYNC_PRIVATE, use private key context directly
* instead of querying for the public key context from the
* certificate, so save a few bytes of code. */
pk = cur->key;
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
if( ! mbedtls_pk_can_do( pk, pk_alg ) )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: key type" ) );
continue;
match = 0;
}
#if defined(MBEDTLS_ECDSA_C)
if( pk_alg == MBEDTLS_PK_ECDSA &&
ssl_check_key_curve( pk, ssl->handshake->curves ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) );
match = 0;
}
#endif
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
mbedtls_x509_crt_pk_release( cur->cert );
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
if( match == 0 )
continue;
/*
* This avoids sending the client a cert it'll reject based on
* keyUsage or other extensions.
@ -816,31 +859,42 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl,
continue;
}
#if defined(MBEDTLS_ECDSA_C)
if( pk_alg == MBEDTLS_PK_ECDSA &&
ssl_check_key_curve( &cur->cert->pk, ssl->handshake->curves ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) );
continue;
}
#endif
#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_1)
/*
* Try to select a SHA-1 certificate for pre-1.2 clients, but still
* present them a SHA-higher cert rather than failing if it's the only
* one we got that satisfies the other conditions.
*/
if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 &&
cur->cert->sig_md != MBEDTLS_MD_SHA1 )
if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 )
{
if( fallback == NULL )
fallback = cur;
mbedtls_md_type_t sig_md;
{
int ret;
mbedtls_x509_crt_frame const *frame;
ret = mbedtls_x509_crt_frame_acquire( cur->cert, &frame );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_frame_acquire", ret );
return( ret );
}
sig_md = frame->sig_md;
mbedtls_x509_crt_frame_release( cur->cert );
}
if( sig_md != MBEDTLS_MD_SHA1 )
{
if( fallback == NULL )
fallback = cur;
MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate not preferred: "
"sha-2 with pre-TLS 1.2 client" ) );
continue;
"sha-2 with pre-TLS 1.2 client" ) );
continue;
}
}
#endif /* MBEDTLS_SSL_PROTO_TLS1 ||
MBEDTLS_SSL_PROTO_TLS1_1 ||
MBEDTLS_SSL_PROTO_SSL3 */
/* If we get there, we got a winner */
break;
@ -2953,26 +3007,38 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
#endif
crt = ssl->conf->ca_chain;
while( crt != NULL && crt->version != 0 )
while( crt != NULL && crt->raw.p != NULL )
{
dn_size = crt->subject_raw.len;
mbedtls_x509_crt_frame const *frame;
ret = mbedtls_x509_crt_frame_acquire( crt, &frame );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_frame_acquire", ret );
return( ret );
}
dn_size = frame->subject_raw.len;
if( end < p ||
(size_t)( end - p ) < dn_size ||
(size_t)( end - p ) < 2 + dn_size )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "skipping CAs: buffer too short" ) );
mbedtls_x509_crt_frame_release( crt );
break;
}
*p++ = (unsigned char)( dn_size >> 8 );
*p++ = (unsigned char)( dn_size );
memcpy( p, crt->subject_raw.p, dn_size );
memcpy( p, frame->subject_raw.p, dn_size );
p += dn_size;
MBEDTLS_SSL_DEBUG_BUF( 3, "requested DN", p - dn_size, dn_size );
total_dn_size += 2 + dn_size;
mbedtls_x509_crt_frame_release( crt );
crt = crt->next;
}
}
@ -3614,9 +3680,8 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl,
size_t peer_pmssize )
{
int ret;
size_t len = (size_t)( end - p ); /* Cast is safe because p <= end. */
mbedtls_pk_context *private_key = mbedtls_ssl_own_key( ssl );
mbedtls_pk_context *public_key = &mbedtls_ssl_own_cert( ssl )->pk;
size_t len = mbedtls_pk_get_len( public_key );
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
/* If we have already started decoding the message and there is an ongoing
@ -3634,12 +3699,17 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl,
*/
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SSL_PROTO_SSL3)
if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 )
#endif /* MBEDTLS_SSL_PROTO_SSL3 */
{
if ( p + 2 > end ) {
if( len < 2 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
}
len -= 2;
if( *p++ != ( ( len >> 8 ) & 0xFF ) ||
*p++ != ( ( len ) & 0xFF ) )
{
@ -3649,12 +3719,6 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl,
}
#endif
if( p + len != end )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
}
/*
* Decrypt the premaster secret
*/
@ -4194,7 +4258,15 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
peer_pk = &ssl->handshake->peer_pubkey;
#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( ssl->session_negotiate->peer_cert != NULL )
peer_pk = &ssl->session_negotiate->peer_cert->pk;
{
ret = mbedtls_x509_crt_pk_acquire( ssl->session_negotiate->peer_cert,
&peer_pk );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret );
return( ret );
}
}
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
if( peer_pk == NULL )
@ -4209,7 +4281,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
if( 0 != ret )
{
MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record" ), ret );
return( ret );
goto exit;
}
ssl->state++;
@ -4219,7 +4291,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE_VERIFY )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY;
goto exit;
}
i = mbedtls_ssl_hs_hdr_len( ssl );
@ -4254,7 +4327,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
if( i + 2 > ssl->in_hslen )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY;
goto exit;
}
/*
@ -4266,7 +4340,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg"
" for verify message" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY;
goto exit;
}
#if !defined(MBEDTLS_MD_SHA1)
@ -4287,7 +4362,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg"
" for verify message" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY;
goto exit;
}
/*
@ -4296,7 +4372,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
if( !mbedtls_pk_can_do( peer_pk, pk_alg ) )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "sig_alg doesn't match cert key" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY;
goto exit;
}
i++;
@ -4311,7 +4388,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
if( i + 2 > ssl->in_hslen )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY;
goto exit;
}
sig_len = ( ssl->in_msg[i] << 8 ) | ssl->in_msg[i+1];
@ -4320,7 +4398,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
if( i + sig_len != ssl->in_hslen )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY;
goto exit;
}
/* Calculate hash and verify signature */
@ -4334,13 +4413,19 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
ssl->in_msg + i, sig_len ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
return( ret );
goto exit;
}
mbedtls_ssl_update_handshake_status( ssl );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate verify" ) );
exit:
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert );
#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
return( ret );
}
#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */

View file

@ -6456,6 +6456,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
void *rs_ctx )
{
int ret = 0;
int verify_ret;
const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
ssl->handshake->ciphersuite_info;
mbedtls_x509_crt *ca_chain;
@ -6480,7 +6481,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
/*
* Main check: verify certificate
*/
ret = mbedtls_x509_crt_verify_restartable(
verify_ret = mbedtls_x509_crt_verify_restartable(
chain,
ca_chain, ca_crl,
ssl->conf->cert_profile,
@ -6488,13 +6489,13 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
&ssl->session_negotiate->verify_result,
ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx );
if( ret != 0 )
if( verify_ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret );
MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", verify_ret );
}
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
if( verify_ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
#endif
@ -6504,29 +6505,40 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
#if defined(MBEDTLS_ECP_C)
{
const mbedtls_pk_context *pk = &chain->pk;
mbedtls_pk_context *pk;
ret = mbedtls_x509_crt_pk_acquire( chain, &pk );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret );
return( ret );
}
/* If certificate uses an EC key, make sure the curve is OK */
if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) &&
mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 )
if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) )
ret = mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id );
mbedtls_x509_crt_pk_release( chain );
if( ret != 0 )
{
ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY;
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) );
if( ret == 0 )
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
if( verify_ret == 0 )
verify_ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
}
}
#endif /* MBEDTLS_ECP_C */
if( mbedtls_ssl_check_cert_usage( chain,
ciphersuite_info,
! ssl->conf->endpoint,
&ssl->session_negotiate->verify_result ) != 0 )
ret = mbedtls_ssl_check_cert_usage( chain,
ciphersuite_info,
! ssl->conf->endpoint,
&ssl->session_negotiate->verify_result );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) );
if( ret == 0 )
ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
if( verify_ret == 0 )
verify_ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
}
/* mbedtls_x509_crt_verify_with_profile is supposed to report a
@ -6536,19 +6548,19 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
* functions, are treated as fatal and lead to a failure of
* ssl_parse_certificate even if verification was optional. */
if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL &&
( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ||
ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) )
( verify_ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ||
verify_ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) )
{
ret = 0;
verify_ret = 0;
}
if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) );
ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED;
verify_ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED;
}
if( ret != 0 )
if( verify_ret != 0 )
{
uint8_t alert;
@ -6593,7 +6605,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
}
#endif /* MBEDTLS_DEBUG_C */
return( ret );
return( verify_ret );
}
#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
@ -6760,8 +6772,8 @@ crt_verify:
crt_len = chain->raw.len;
#endif /* MBEDTLS_SSL_RENEGOTIATION */
pk_start = chain->pk_raw.p;
pk_len = chain->pk_raw.len;
pk_start = chain->cache->pk_raw.p;
pk_len = chain->cache->pk_raw.len;
/* Free the CRT structures before computing
* digest and copying the peer's public key. */

View file

@ -534,6 +534,12 @@ static const char *features[] = {
#if defined(MBEDTLS_VERSION_FEATURES)
"MBEDTLS_VERSION_FEATURES",
#endif /* MBEDTLS_VERSION_FEATURES */
#if defined(MBEDTLS_X509_ON_DEMAND_PARSING)
"MBEDTLS_X509_ON_DEMAND_PARSING",
#endif /* MBEDTLS_X509_ON_DEMAND_PARSING */
#if defined(MBEDTLS_X509_ALWAYS_FLUSH)
"MBEDTLS_X509_ALWAYS_FLUSH",
#endif /* MBEDTLS_X509_ALWAYS_FLUSH */
#if defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3)
"MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3",
#endif /* MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 */

View file

@ -38,6 +38,7 @@
#if defined(MBEDTLS_X509_USE_C)
#include "mbedtls/x509.h"
#include "mbedtls/x509_internal.h"
#include "mbedtls/asn1.h"
#include "mbedtls/oid.h"
@ -347,64 +348,59 @@ int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params,
* AttributeType ::= OBJECT IDENTIFIER
*
* AttributeValue ::= ANY DEFINED BY AttributeType
*
* NOTE: This function returns an ASN.1 low-level error code.
*/
static int x509_get_attr_type_value( unsigned char **p,
const unsigned char *end,
mbedtls_x509_name *cur )
mbedtls_x509_buf *oid,
mbedtls_x509_buf *val )
{
int ret;
size_t len;
mbedtls_x509_buf *oid;
mbedtls_x509_buf *val;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
return( MBEDTLS_ERR_X509_INVALID_NAME + ret );
ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE );
if( ret != 0 )
goto exit;
end = *p + len;
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_X509_INVALID_NAME +
MBEDTLS_ERR_ASN1_OUT_OF_DATA );
oid = &cur->oid;
oid->tag = **p;
if( ( ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID ) ) != 0 )
return( MBEDTLS_ERR_X509_INVALID_NAME + ret );
ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID );
if( ret != 0 )
goto exit;
oid->tag = MBEDTLS_ASN1_OID;
oid->p = *p;
*p += oid->len;
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_X509_INVALID_NAME +
MBEDTLS_ERR_ASN1_OUT_OF_DATA );
if( *p == end )
{
ret = MBEDTLS_ERR_ASN1_OUT_OF_DATA;
goto exit;
}
if( **p != MBEDTLS_ASN1_BMP_STRING && **p != MBEDTLS_ASN1_UTF8_STRING &&
**p != MBEDTLS_ASN1_T61_STRING && **p != MBEDTLS_ASN1_PRINTABLE_STRING &&
**p != MBEDTLS_ASN1_IA5_STRING && **p != MBEDTLS_ASN1_UNIVERSAL_STRING &&
**p != MBEDTLS_ASN1_BIT_STRING )
return( MBEDTLS_ERR_X509_INVALID_NAME +
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
if( !MBEDTLS_ASN1_IS_STRING_TAG( **p ) )
{
ret = MBEDTLS_ERR_ASN1_UNEXPECTED_TAG;
goto exit;
}
val = &cur->val;
val->tag = *(*p)++;
if( ( ret = mbedtls_asn1_get_len( p, end, &val->len ) ) != 0 )
return( MBEDTLS_ERR_X509_INVALID_NAME + ret );
ret = mbedtls_asn1_get_len( p, end, &val->len );
if( ret != 0 )
goto exit;
val->p = *p;
*p += val->len;
if( *p != end )
{
return( MBEDTLS_ERR_X509_INVALID_NAME +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
}
ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
cur->next = NULL;
return( 0 );
exit:
return( ret );
}
/*
@ -429,58 +425,235 @@ static int x509_get_attr_type_value( unsigned char **p,
* For the general case we still use a flat list, but we mark elements of the
* same set so that they are "merged" together in the functions that consume
* this list, eg mbedtls_x509_dn_gets().
*
* NOTE: This function returns an ASN.1 low-level error code.
*/
int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end,
mbedtls_x509_name *cur )
static int x509_set_sequence_iterate( unsigned char **p,
unsigned char const **end_set,
unsigned char const *end,
mbedtls_x509_buf *oid,
mbedtls_x509_buf *val )
{
int ret;
size_t set_len;
const unsigned char *end_set;
/* don't use recursion, we'd risk stack overflow if not optimized */
while( 1 )
if( *p == *end_set )
{
/*
* parse SET
*/
if( ( ret = mbedtls_asn1_get_tag( p, end, &set_len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ) != 0 )
return( MBEDTLS_ERR_X509_INVALID_NAME + ret );
/* Parse next TLV of ASN.1 SET structure. */
ret = mbedtls_asn1_get_tag( p, end, &set_len,
MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SET );
if( ret != 0 )
goto exit;
end_set = *p + set_len;
*end_set = *p + set_len;
}
while( 1 )
/* x509_get_attr_type_value() returns ASN.1 low-level error codes. */
ret = x509_get_attr_type_value( p, *end_set, oid, val );
exit:
return( ret );
}
/*
* Like memcmp, but case-insensitive and always returns -1 if different
*/
int mbedtls_x509_memcasecmp( const void *s1, const void *s2,
size_t len1, size_t len2 )
{
size_t i;
unsigned char diff;
const unsigned char *n1 = s1, *n2 = s2;
if( len1 != len2 )
return( -1 );
for( i = 0; i < len1; i++ )
{
diff = n1[i] ^ n2[i];
if( diff == 0 )
continue;
if( diff == 32 &&
( ( n1[i] >= 'a' && n1[i] <= 'z' ) ||
( n1[i] >= 'A' && n1[i] <= 'Z' ) ) )
{
if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 )
return( ret );
if( *p == end_set )
break;
/* Mark this item as being no the only one in a set */
cur->next_merged = 1;
cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) );
if( cur->next == NULL )
return( MBEDTLS_ERR_X509_ALLOC_FAILED );
cur = cur->next;
continue;
}
/*
* continue until end of SEQUENCE is reached
*/
if( *p == end )
return( 0 );
return( -1 );
}
return( 0 );
}
/*
* Compare two X.509 strings, case-insensitive, and allowing for some encoding
* variations (but not all).
*
* Return 0 if equal, -1 otherwise.
*/
static int x509_string_cmp( const mbedtls_x509_buf *a,
const mbedtls_x509_buf *b )
{
if( a->tag == b->tag &&
a->len == b->len &&
memcmp( a->p, b->p, b->len ) == 0 )
{
return( 0 );
}
if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) &&
( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) &&
mbedtls_x509_memcasecmp( a->p, b->p,
a->len, b->len ) == 0 )
{
return( 0 );
}
return( -1 );
}
/*
* Compare two X.509 Names (aka rdnSequence) given as raw ASN.1 data.
*
* See RFC 5280 section 7.1, though we don't implement the whole algorithm:
* We sometimes return unequal when the full algorithm would return equal,
* but never the other way. (In particular, we don't do Unicode normalisation
* or space folding.)
*
* Further, this function allows to pass a callback to be triggered for every
* pair of well-formed and equal entries in the two input name lists.
*
* Returns:
* - 0 if both sequences are well-formed, present the same X.509 name,
* and the callback (if provided) hasn't returned a non-zero value
* on any of the name components.
* - 1 if a difference was detected in the name components.
* - A non-zero error code if the abort callback returns a non-zero value.
* In this case, the returned error code is the error code from the callback.
* - A negative error code if a parsing error occurred in either
* of the two buffers.
*
* This function can be used to verify that a buffer contains a well-formed
* ASN.1 encoded X.509 name by calling it with equal parameters.
*/
int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a,
mbedtls_x509_buf_raw const *b,
int (*abort_check)( void *ctx,
mbedtls_x509_buf *oid,
mbedtls_x509_buf *val,
int next_merged ),
void *abort_check_ctx )
{
int ret;
size_t idx;
unsigned char *p[2], *end[2], *set[2];
p[0] = a->p;
p[1] = b->p;
end[0] = p[0] + a->len;
end[1] = p[1] + b->len;
for( idx = 0; idx < 2; idx++ )
{
size_t len;
ret = mbedtls_asn1_get_tag( &p[idx], end[idx], &len,
MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE );
if( end[idx] != p[idx] + len )
{
return( MBEDTLS_ERR_X509_INVALID_NAME +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
}
set[idx] = p[idx];
}
while( 1 )
{
int next_merged;
mbedtls_x509_buf oid[2], val[2];
ret = x509_set_sequence_iterate( &p[0], (const unsigned char **) &set[0],
end[0], &oid[0], &val[0] );
if( ret != 0 )
goto exit;
ret = x509_set_sequence_iterate( &p[1], (const unsigned char **) &set[1],
end[1], &oid[1], &val[1] );
if( ret != 0 )
goto exit;
if( oid[0].len != oid[1].len ||
memcmp( oid[0].p, oid[1].p, oid[1].len ) != 0 )
{
return( 1 );
}
if( x509_string_cmp( &val[0], &val[1] ) != 0 )
return( 1 );
next_merged = ( set[0] != p[0] );
if( next_merged != ( set[1] != p[1] ) )
return( 1 );
if( abort_check != NULL )
{
ret = abort_check( abort_check_ctx, &oid[0], &val[0],
next_merged );
if( ret != 0 )
return( ret );
}
if( p[0] == end[0] && p[1] == end[1] )
break;
}
exit:
if( ret < 0 )
ret += MBEDTLS_ERR_X509_INVALID_NAME;
return( ret );
}
static int x509_get_name_cb( void *ctx,
mbedtls_x509_buf *oid,
mbedtls_x509_buf *val,
int next_merged )
{
mbedtls_x509_name **cur_ptr = (mbedtls_x509_name**) ctx;
mbedtls_x509_name *cur = *cur_ptr;
if( cur->oid.p != NULL )
{
cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) );
if( cur->next == NULL )
return( MBEDTLS_ERR_X509_ALLOC_FAILED );
return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
cur = cur->next;
}
cur->oid = *oid;
cur->val = *val;
cur->next_merged = next_merged;
*cur_ptr = cur;
return( 0 );
}
int mbedtls_x509_get_name( unsigned char *p,
size_t len,
mbedtls_x509_name *cur )
{
mbedtls_x509_buf_raw name_buf = { p, len };
memset( cur, 0, sizeof( mbedtls_x509_name ) );
return( mbedtls_x509_name_cmp_raw( &name_buf, &name_buf,
x509_get_name_cb,
&cur ) );
}
static int x509_parse_int( unsigned char **p, size_t n, int *res )
@ -655,6 +828,21 @@ int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x
return( 0 );
}
int mbedtls_x509_get_sig_alg_raw( unsigned char **p, unsigned char const *end,
mbedtls_md_type_t *md_alg,
mbedtls_pk_type_t *pk_alg,
void **sig_opts )
{
int ret;
mbedtls_asn1_buf alg, params;
ret = mbedtls_asn1_get_alg( p, end, &alg, &params );
if( ret != 0 )
return( MBEDTLS_ERR_X509_INVALID_ALG + ret );
return( mbedtls_x509_get_sig_alg( &alg, &params, md_alg,
pk_alg, sig_opts ) );
}
/*
* Get signature algorithm from alg OID and optional parameters
*/
@ -664,9 +852,6 @@ int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x50
{
int ret;
if( *sig_opts != NULL )
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
if( ( ret = mbedtls_oid_get_sig_alg( sig_oid, md_alg, pk_alg ) ) != 0 )
return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + ret );
@ -689,7 +874,10 @@ int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x50
return( ret );
}
*sig_opts = (void *) pss_opts;
if( sig_opts != NULL )
*sig_opts = (void *) pss_opts;
else
mbedtls_free( pss_opts );
}
else
#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */
@ -697,7 +885,10 @@ int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x50
/* Make sure parameters are absent or NULL */
if( ( sig_params->tag != MBEDTLS_ASN1_NULL && sig_params->tag != 0 ) ||
sig_params->len != 0 )
return( MBEDTLS_ERR_X509_INVALID_ALG );
return( MBEDTLS_ERR_X509_INVALID_ALG );
if( sig_opts != NULL )
*sig_opts = NULL;
}
return( 0 );
@ -840,20 +1031,34 @@ int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *se
/*
* Helper for writing signature algorithms
*/
int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid,
mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg,
const void *sig_opts )
int mbedtls_x509_sig_alg_gets( char *buf, size_t size, mbedtls_pk_type_t pk_alg,
mbedtls_md_type_t md_alg, const void *sig_opts )
{
int ret;
char *p = buf;
size_t n = size;
const char *desc = NULL;
mbedtls_x509_buf sig_oid;
mbedtls_md_type_t tmp_md_alg = md_alg;
ret = mbedtls_oid_get_sig_alg_desc( sig_oid, &desc );
if( ret != 0 )
ret = mbedtls_snprintf( p, n, "???" );
else
#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
/* The hash for RSASSA is determined by the algorithm parameters;
* in the OID list, the hash is set to MBEDTLS_MD_NONE. */
if( pk_alg == MBEDTLS_PK_RSASSA_PSS )
tmp_md_alg = MBEDTLS_MD_NONE;
#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */
sig_oid.tag = MBEDTLS_ASN1_OID;
ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, tmp_md_alg,
(const char**) &sig_oid.p,
&sig_oid.len );
if( ret == 0 &&
mbedtls_oid_get_sig_alg_desc( &sig_oid, &desc ) == 0 )
{
ret = mbedtls_snprintf( p, n, "%s", desc );
}
else
ret = mbedtls_snprintf( p, n, "???" );
MBEDTLS_X509_SAFE_SNPRINTF;
#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
@ -1003,6 +1208,17 @@ int mbedtls_x509_time_is_future( const mbedtls_x509_time *from )
}
#endif /* MBEDTLS_HAVE_TIME_DATE */
void mbedtls_x509_name_free( mbedtls_x509_name *name )
{
while( name != NULL )
{
mbedtls_x509_name *next = name->next;
mbedtls_platform_zeroize( name, sizeof( *name ) );
mbedtls_free( name );
name = next;
}
}
#if defined(MBEDTLS_SELF_TEST)
#include "mbedtls/x509_crt.h"

View file

@ -28,6 +28,7 @@
#if defined(MBEDTLS_X509_CREATE_C)
#include "mbedtls/x509.h"
#include "mbedtls/x509_internal.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/oid.h"

View file

@ -38,6 +38,7 @@
#if defined(MBEDTLS_X509_CRL_PARSE_C)
#include "mbedtls/x509_crl.h"
#include "mbedtls/x509_internal.h"
#include "mbedtls/oid.h"
#include "mbedtls/platform_util.h"
@ -428,15 +429,17 @@ int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain,
mbedtls_x509_crl_free( crl );
return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
}
p += len;
crl->issuer_raw.len = p - crl->issuer_raw.p;
if( ( ret = mbedtls_x509_get_name( &p, p + len, &crl->issuer ) ) != 0 )
if( ( ret = mbedtls_x509_get_name( crl->issuer_raw.p,
crl->issuer_raw.len,
&crl->issuer ) ) != 0 )
{
mbedtls_x509_crl_free( crl );
return( ret );
}
crl->issuer_raw.len = p - crl->issuer_raw.p;
/*
* thisUpdate Time
* nextUpdate Time OPTIONAL
@ -690,8 +693,8 @@ int mbedtls_x509_crl_info( char *buf, size_t size, const char *prefix,
ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_sig_alg_gets( p, n, &crl->sig_oid, crl->sig_pk, crl->sig_md,
crl->sig_opts );
ret = mbedtls_x509_sig_alg_gets( p, n, crl->sig_pk,
crl->sig_md, crl->sig_opts );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_snprintf( p, n, "\n" );

File diff suppressed because it is too large Load diff

View file

@ -38,6 +38,7 @@
#if defined(MBEDTLS_X509_CSR_PARSE_C)
#include "mbedtls/x509_csr.h"
#include "mbedtls/x509_internal.h"
#include "mbedtls/oid.h"
#include "mbedtls/platform_util.h"
@ -183,15 +184,17 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr,
mbedtls_x509_csr_free( csr );
return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
}
p += len;
csr->subject_raw.len = p - csr->subject_raw.p;
if( ( ret = mbedtls_x509_get_name( &p, p + len, &csr->subject ) ) != 0 )
if( ( ret = mbedtls_x509_get_name( csr->subject_raw.p,
csr->subject_raw.len,
&csr->subject ) ) != 0 )
{
mbedtls_x509_csr_free( csr );
return( ret );
}
csr->subject_raw.len = p - csr->subject_raw.p;
/*
* subjectPKInfo SubjectPublicKeyInfo
*/
@ -357,8 +360,8 @@ int mbedtls_x509_csr_info( char *buf, size_t size, const char *prefix,
ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_sig_alg_gets( p, n, &csr->sig_oid, csr->sig_pk, csr->sig_md,
csr->sig_opts );
ret = mbedtls_x509_sig_alg_gets( p, n, csr->sig_pk,
csr->sig_md, csr->sig_opts );
MBEDTLS_X509_SAFE_SNPRINTF;
if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON,

View file

@ -34,6 +34,7 @@
#if defined(MBEDTLS_X509_CRT_WRITE_C)
#include "mbedtls/x509_crt.h"
#include "mbedtls/x509_internal.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/sha1.h"

View file

@ -33,6 +33,7 @@
#if defined(MBEDTLS_X509_CSR_WRITE_C)
#include "mbedtls/x509_csr.h"
#include "mbedtls/x509_internal.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/platform_util.h"

View file

@ -1466,6 +1466,22 @@ int query_config( const char *config )
}
#endif /* MBEDTLS_VERSION_FEATURES */
#if defined(MBEDTLS_X509_ON_DEMAND_PARSING)
if( strcmp( "MBEDTLS_X509_ON_DEMAND_PARSING", config ) == 0 )
{
MACRO_EXPANSION_TO_STR( MBEDTLS_X509_ON_DEMAND_PARSING );
return( 0 );
}
#endif /* MBEDTLS_X509_ON_DEMAND_PARSING */
#if defined(MBEDTLS_X509_ALWAYS_FLUSH)
if( strcmp( "MBEDTLS_X509_ALWAYS_FLUSH", config ) == 0 )
{
MACRO_EXPANSION_TO_STR( MBEDTLS_X509_ALWAYS_FLUSH );
return( 0 );
}
#endif /* MBEDTLS_X509_ALWAYS_FLUSH */
#if defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3)
if( strcmp( "MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3", config ) == 0 )
{

View file

@ -1067,6 +1067,7 @@ static int ssl_async_start( mbedtls_ssl_context *ssl,
const unsigned char *input,
size_t input_len )
{
int ret;
ssl_async_key_context_t *config_data =
mbedtls_ssl_conf_get_async_config_data( ssl->conf );
unsigned slot;
@ -1075,9 +1076,17 @@ static int ssl_async_start( mbedtls_ssl_context *ssl,
{
char dn[100];
if( mbedtls_x509_dn_gets( dn, sizeof( dn ), &cert->subject ) > 0 )
mbedtls_x509_name *subject;
ret = mbedtls_x509_crt_get_subject( cert, &subject );
if( ret != 0 )
return( ret );
if( mbedtls_x509_dn_gets( dn, sizeof( dn ), subject ) > 0 )
mbedtls_printf( "Async %s callback: looking for DN=%s\n",
op_name, dn );
mbedtls_x509_name_free( subject );
}
/* Look for a private key that matches the public key in cert.
@ -1086,8 +1095,14 @@ static int ssl_async_start( mbedtls_ssl_context *ssl,
* public key. */
for( slot = 0; slot < config_data->slots_used; slot++ )
{
if( mbedtls_pk_check_pair( &cert->pk,
config_data->slots[slot].pk ) == 0 )
mbedtls_pk_context *pk;
int match;
ret = mbedtls_x509_crt_pk_acquire( cert, &pk );
if( ret != 0 )
return( ret );
match = mbedtls_pk_check_pair( pk, config_data->slots[slot].pk );
mbedtls_x509_crt_pk_release( cert );
if( match == 0 )
break;
}
if( slot == config_data->slots_used )

View file

@ -524,6 +524,8 @@ int main( int argc, char *argv[] )
//
if( !opt.selfsign && strlen( opt.issuer_crt ) )
{
mbedtls_x509_name *subject;
/*
* 1.0.a. Load the certificates
*/
@ -538,8 +540,17 @@ int main( int argc, char *argv[] )
goto exit;
}
ret = mbedtls_x509_crt_get_subject( &issuer_crt, &subject );
if( ret != 0 )
{
mbedtls_strerror( ret, buf, 1024 );
mbedtls_printf( " failed\n ! mbedtls_x509_crt_get_subject "
"returned -0x%04x - %s\n\n", -ret, buf );
goto exit;
}
ret = mbedtls_x509_dn_gets( issuer_name, sizeof(issuer_name),
&issuer_crt.subject );
subject );
if( ret < 0 )
{
mbedtls_strerror( ret, buf, 1024 );
@ -550,6 +561,8 @@ int main( int argc, char *argv[] )
opt.issuer_name = issuer_name;
mbedtls_x509_name_free( subject );
mbedtls_printf( " ok\n" );
}
@ -627,12 +640,24 @@ int main( int argc, char *argv[] )
//
if( strlen( opt.issuer_crt ) )
{
if( mbedtls_pk_check_pair( &issuer_crt.pk, issuer_key ) != 0 )
mbedtls_pk_context pk;
ret = mbedtls_x509_crt_get_pk( &issuer_crt, &pk );
if( ret != 0 )
{
mbedtls_strerror( ret, buf, 1024 );
mbedtls_printf( " failed\n ! mbedtls_x509_crt_get_pk "
"returned -0x%04x - %s\n\n", -ret, buf );
goto exit;
}
if( mbedtls_pk_check_pair( &pk, issuer_key ) != 0 )
{
mbedtls_printf( " failed\n ! issuer_key does not match "
"issuer certificate\n\n" );
goto exit;
}
mbedtls_pk_free( &pk );
}
mbedtls_printf( " ok\n" );

View file

@ -1,3 +1,5 @@
option(LINK_WITH_PTHREAD "Explicitly link mbed TLS library to pthread." OFF)
set(libs
mbedtls
)
@ -10,6 +12,10 @@ if(ENABLE_ZLIB_SUPPORT)
set(libs ${libs} ${ZLIB_LIBRARIES})
endif(ENABLE_ZLIB_SUPPORT)
if(LINK_WITH_PTHREAD)
set(libs ${libs} pthread)
endif(LINK_WITH_PTHREAD)
find_package(Perl)
if(NOT PERL_FOUND)
message(FATAL_ERROR "Cannot build test suites without Perl")

View file

@ -53,11 +53,20 @@ ifdef ZLIB
LOCAL_LDFLAGS += -lz
endif
# Pthread shared library extension
ifdef PTHREAD
LOCAL_LDFLAGS += -lpthread
endif
# A test application is built for each suites/test_suite_*.data file.
# Application name is same as .data file's base name and can be
# constructed by stripping path 'suites/' and extension .data.
APPS = $(basename $(subst suites/,,$(wildcard suites/test_suite_*.data)))
ifndef PTHREAD
APPS := $(filter-out test_suite_x509parse_pthread, $(APPS))
endif
# Construct executable name by adding OS specific suffix $(EXEXT).
BINARIES := $(addsuffix $(EXEXT),$(APPS))
@ -136,4 +145,3 @@ $(EMBEDDED_TESTS): embedded_%: suites/$$(firstword $$(subst ., ,$$*)).function s
-o ./TESTS/mbedtls/$*
generate-target-tests: $(EMBEDDED_TESTS)

View file

@ -728,7 +728,7 @@ component_test_full_cmake_clang () {
msg "build: cmake, full config, clang" # ~ 50s
scripts/config.pl full
scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
CC=clang cmake -D CMAKE_BUILD_TYPE:String=Check -D ENABLE_TESTING=On .
CC=clang cmake -D LINK_WITH_PTHREAD=1 -D CMAKE_BUILD_TYPE:String=Check -D ENABLE_TESTING=On .
make
msg "test: main suites (full config)" # ~ 5s
@ -750,7 +750,7 @@ component_build_deprecated () {
scripts/config.pl set MBEDTLS_DEPRECATED_WARNING
# Build with -O -Wextra to catch a maximum of issues.
make CC=gcc CFLAGS='-O -Werror -Wall -Wextra' lib programs
make CC=gcc CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
make PTHREAD=1 CC=gcc CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
msg "build: make, full config + DEPRECATED_REMOVED, clang -O" # ~ 30s
# No cleanup, just tweak the configuration and rebuild
@ -759,7 +759,7 @@ component_build_deprecated () {
scripts/config.pl set MBEDTLS_DEPRECATED_REMOVED
# Build with -O -Wextra to catch a maximum of issues.
make CC=clang CFLAGS='-O -Werror -Wall -Wextra' lib programs
make CC=clang CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
make PTHREAD=1 CC=clang CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
}
@ -807,7 +807,7 @@ component_test_check_params_without_platform () {
scripts/config.pl unset MBEDTLS_PLATFORM_SNPRINTF_ALT
scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
scripts/config.pl unset MBEDTLS_PLATFORM_C
make CC=gcc CFLAGS='-Werror -O1' all test
make CC=gcc PTHREAD=1 CFLAGS='-Werror -O1' all test
}
component_test_check_params_silent () {
@ -815,7 +815,7 @@ component_test_check_params_silent () {
scripts/config.pl full # includes CHECK_PARAMS
scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
sed -i 's/.*\(#define MBEDTLS_PARAM_FAILED( cond )\).*/\1/' "$CONFIG_H"
make CC=gcc CFLAGS='-Werror -O1' all test
make CC=gcc PTHREAD=1 CFLAGS='-Werror -O1' all test
}
component_test_no_platform () {
@ -837,8 +837,8 @@ component_test_no_platform () {
scripts/config.pl unset MBEDTLS_FS_IO
# Note, _DEFAULT_SOURCE needs to be defined for platforms using glibc version >2.19,
# to re-enable platform integration features otherwise disabled in C99 builds
make CC=gcc CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic -O0 -D_DEFAULT_SOURCE' lib programs
make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' test
make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic -O0 -D_DEFAULT_SOURCE' lib programs
make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -O0' test
}
component_build_no_std_function () {
@ -847,21 +847,21 @@ component_build_no_std_function () {
scripts/config.pl full
scripts/config.pl set MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -O0'
}
component_build_no_ssl_srv () {
msg "build: full config except ssl_srv.c, make, gcc" # ~ 30s
scripts/config.pl full
scripts/config.pl unset MBEDTLS_SSL_SRV_C
make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -O0'
}
component_build_no_ssl_cli () {
msg "build: full config except ssl_cli.c, make, gcc" # ~ 30s
scripts/config.pl full
scripts/config.pl unset MBEDTLS_SSL_CLI_C
make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -O0'
}
component_build_no_sockets () {
@ -871,7 +871,7 @@ component_build_no_sockets () {
scripts/config.pl full
scripts/config.pl unset MBEDTLS_NET_C # getaddrinfo() undeclared, etc.
scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY # uses syscall() on GNU/Linux
make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0 -std=c99 -pedantic' lib
make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -O0 -std=c99 -pedantic' lib
}
component_test_no_max_fragment_length () {
@ -918,6 +918,22 @@ component_test_asan_remove_peer_certificate_no_renego () {
if_build_succeeded tests/compat.sh
}
component_test_asan_on_demand_parsing_remove_peer_cert () {
msg "build: default config, no peer CRT, on-demand CRT parsing (ASan build)"
scripts/config.pl unset MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
scripts/config.pl set MBEDTLS_X509_ON_DEMAND_PARSING
scripts/config.pl set MBEDTLS_THREADING_C
scripts/config.pl set MBEDTLS_THREADING_PTHREAD
CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan -D LINK_WITH_PTHREAD=1 .
make
msg "test: !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE, MBEDTLS_X509_ON_DEMAND_PARSING"
make test
msg "test: ssl-opt.sh, !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE, MBEDTLS_X509_ON_DEMAND_PARSING"
if_build_succeeded tests/ssl-opt.sh
}
component_test_no_max_fragment_length_small_ssl_out_content_len () {
msg "build: no MFL extension, small SSL_OUT_CONTENT_LEN (ASan build)"
scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
@ -1008,7 +1024,10 @@ component_test_m32_o0 () {
# Build once with -O0, to compile out the i386 specific inline assembly
msg "build: i386, make, gcc -O0 (ASan build)" # ~ 30s
scripts/config.pl full
make CC=gcc CFLAGS='-O0 -Werror -Wall -Wextra -m32 -fsanitize=address'
scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE
scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
scripts/config.pl unset MBEDTLS_MEMORY_DEBUG
make CC=gcc PTHREAD=1 CFLAGS='-O0 -Werror -Wall -Wextra -m32 -fsanitize=address'
msg "test: i386, make, gcc -O0 (ASan build)"
make test
@ -1027,7 +1046,7 @@ component_test_m32_o1 () {
scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE
scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
scripts/config.pl unset MBEDTLS_MEMORY_DEBUG
make CC=gcc CFLAGS='-O1 -Werror -Wall -Wextra -m32 -fsanitize=address'
make CC=gcc PTHREAD=1 CFLAGS='-O1 -Werror -Wall -Wextra -m32 -fsanitize=address'
msg "test: i386, make, gcc -O1 (ASan build)"
make test
@ -1042,7 +1061,7 @@ support_test_m32_o1 () {
component_test_mx32 () {
msg "build: 64-bit ILP32, make, gcc" # ~ 30s
scripts/config.pl full
make CC=gcc CFLAGS='-Werror -Wall -Wextra -mx32'
make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -mx32'
msg "test: 64-bit ILP32, make, gcc"
make test

View file

@ -935,6 +935,10 @@ X509 Parse Selftest
depends_on:MBEDTLS_SHA1_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_CERTS_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
x509_selftest:
X509 nested acquire
depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
x509_nested_acquire:"308196308180a0030201008204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d010101050003190030160210ffffffffffffffffffffffffffffffff0202ffff300d06092a864886f70d01010b0500030200ff"
X509 CRT ASN1 (Empty Certificate)
x509parse_crt:"":"":MBEDTLS_ERR_X509_INVALID_FORMAT

View file

@ -4,6 +4,7 @@
#include "mbedtls/x509_crt.h"
#include "mbedtls/x509_crl.h"
#include "mbedtls/x509_csr.h"
#include "mbedtls/x509_internal.h"
#include "mbedtls/pem.h"
#include "mbedtls/oid.h"
#include "mbedtls/base64.h"
@ -142,25 +143,48 @@ int verify_print( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint
verify_print_context *ctx = (verify_print_context *) data;
char *p = ctx->p;
size_t n = ctx->buf + sizeof( ctx->buf ) - ctx->p;
mbedtls_x509_crt_frame const *frame;
mbedtls_x509_name *subject;
((void) flags);
ret = mbedtls_snprintf( p, n, "depth %d - serial ", certificate_depth );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_crt_get_subject( crt, &subject );
if( ret != 0 )
return( ret );
ret = mbedtls_x509_serial_gets( p, n, &crt->serial );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_crt_frame_acquire( crt, &frame );
if( ret != 0 )
return( ret );
ret = mbedtls_snprintf( p, n, "depth %d - serial ", certificate_depth );
MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP;
{
mbedtls_x509_buf serial;
serial.p = frame->serial.p;
serial.len = frame->serial.len;
ret = mbedtls_x509_serial_gets( p, n, &serial );
MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP;
}
ret = mbedtls_snprintf( p, n, " - subject " );
MBEDTLS_X509_SAFE_SNPRINTF;
MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP;
ret = mbedtls_x509_dn_gets( p, n, &crt->subject );
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_x509_dn_gets( p, n, subject );
MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP;
ret = mbedtls_snprintf( p, n, " - flags 0x%08x\n", *flags );
MBEDTLS_X509_SAFE_SNPRINTF;
MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP;
ctx->p = p;
cleanup:
mbedtls_x509_name_free( subject );
mbedtls_x509_crt_frame_release( crt );
if( ret < 0 )
return( ret );
return( 0 );
}
#endif /* MBEDTLS_X509_CRT_PARSE_C */
@ -428,15 +452,19 @@ void mbedtls_x509_dn_gets( char * crt_file, char * entity, char * result_str )
mbedtls_x509_crt crt;
char buf[2000];
int res = 0;
mbedtls_x509_name *subject = NULL, *issuer = NULL;
mbedtls_x509_crt_init( &crt );
memset( buf, 0, 2000 );
TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 );
TEST_ASSERT( mbedtls_x509_crt_get_subject( &crt, &subject ) == 0 );
TEST_ASSERT( mbedtls_x509_crt_get_issuer( &crt, &issuer ) == 0 );
if( strcmp( entity, "subject" ) == 0 )
res = mbedtls_x509_dn_gets( buf, 2000, &crt.subject );
res = mbedtls_x509_dn_gets( buf, 2000, subject );
else if( strcmp( entity, "issuer" ) == 0 )
res = mbedtls_x509_dn_gets( buf, 2000, &crt.issuer );
res = mbedtls_x509_dn_gets( buf, 2000, issuer );
else
TEST_ASSERT( "Unknown entity" == 0 );
@ -446,6 +474,8 @@ void mbedtls_x509_dn_gets( char * crt_file, char * entity, char * result_str )
TEST_ASSERT( strcmp( buf, result_str ) == 0 );
exit:
mbedtls_x509_name_free( issuer );
mbedtls_x509_name_free( subject );
mbedtls_x509_crt_free( &crt );
}
/* END_CASE */
@ -453,16 +483,18 @@ exit:
/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */
void mbedtls_x509_time_is_past( char * crt_file, char * entity, int result )
{
mbedtls_x509_crt crt;
mbedtls_x509_crt crt;
mbedtls_x509_crt_frame frame;
mbedtls_x509_crt_init( &crt );
TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 );
TEST_ASSERT( mbedtls_x509_crt_get_frame( &crt, &frame ) == 0 );
if( strcmp( entity, "valid_from" ) == 0 )
TEST_ASSERT( mbedtls_x509_time_is_past( &crt.valid_from ) == result );
TEST_ASSERT( mbedtls_x509_time_is_past( &frame.valid_from ) == result );
else if( strcmp( entity, "valid_to" ) == 0 )
TEST_ASSERT( mbedtls_x509_time_is_past( &crt.valid_to ) == result );
TEST_ASSERT( mbedtls_x509_time_is_past( &frame.valid_to ) == result );
else
TEST_ASSERT( "Unknown entity" == 0 );
@ -474,16 +506,18 @@ exit:
/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */
void mbedtls_x509_time_is_future( char * crt_file, char * entity, int result )
{
mbedtls_x509_crt crt;
mbedtls_x509_crt crt;
mbedtls_x509_crt_frame frame;
mbedtls_x509_crt_init( &crt );
TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 );
TEST_ASSERT( mbedtls_x509_crt_get_frame( &crt, &frame ) == 0 );
if( strcmp( entity, "valid_from" ) == 0 )
TEST_ASSERT( mbedtls_x509_time_is_future( &crt.valid_from ) == result );
TEST_ASSERT( mbedtls_x509_time_is_future( &frame.valid_from ) == result );
else if( strcmp( entity, "valid_to" ) == 0 )
TEST_ASSERT( mbedtls_x509_time_is_future( &crt.valid_to ) == result );
TEST_ASSERT( mbedtls_x509_time_is_future( &frame.valid_to ) == result );
else
TEST_ASSERT( "Unknown entity" == 0 );
@ -563,6 +597,99 @@ exit:
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_X509_CRT_PARSE_C */
void x509_nested_acquire( data_t * buf )
{
/* This tests exercises the behavior of the library when
* facing nested calls to mbedtls_x509_crt_xxx_acquire().
* This is allowed if !MBEDTLS_X509_ALWAYS_FLUSH or
* MBEDTLS_THREADING_C, but forbidden otherwise. */
mbedtls_x509_crt crt;
mbedtls_x509_crt_init( &crt );
TEST_ASSERT( mbedtls_x509_crt_parse_der( &crt, buf->x, buf->len ) == 0 );
/* Nested aquire for CRT frames */
{
int ret;
mbedtls_x509_crt_frame const *frame1;
mbedtls_x509_crt_frame const *frame2;
/* Perform a (hopefully) innocent acquire-release pair first. */
TEST_ASSERT( mbedtls_x509_crt_frame_acquire( &crt, &frame1 ) == 0 );
TEST_ASSERT( mbedtls_x509_crt_frame_release( &crt ) == 0 );
/* Perform two nested acquire calls. */
TEST_ASSERT( mbedtls_x509_crt_frame_acquire( &crt, &frame1 ) == 0 );
ret = mbedtls_x509_crt_frame_acquire( &crt, &frame2 );
#if defined(MBEDTLS_X509_ALWAYS_FLUSH) && \
!defined(MBEDTLS_THREADING_C)
TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR );
#else
TEST_ASSERT( ret == 0 );
TEST_ASSERT( mbedtls_x509_crt_frame_release( &crt ) == 0 );
#endif
TEST_ASSERT( mbedtls_x509_crt_frame_release( &crt ) == 0 );
ret = mbedtls_x509_crt_frame_release( &crt );
/* In contexts which use resource counting, we expect an
* error on an attempted release() without prior acquire(). */
#if defined(MBEDTLS_X509_ALWAYS_FLUSH) && \
!defined(MBEDTLS_THREADING_C)
TEST_ASSERT( ret == 0 );
#else
TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR );
#endif
}
/* Nested aquire for PK contexts */
{
int ret;
mbedtls_pk_context *pk1;
mbedtls_pk_context *pk2;
/* Perform a (hopefully) innocent acquire-release pair first. */
TEST_ASSERT( mbedtls_x509_crt_pk_acquire( &crt, &pk1 ) == 0 );
TEST_ASSERT( mbedtls_x509_crt_pk_release( &crt ) == 0 );
/* Perform two nested acquire calls. */
TEST_ASSERT( mbedtls_x509_crt_pk_acquire( &crt, &pk1 ) == 0 );
ret = mbedtls_x509_crt_pk_acquire( &crt, &pk2 );
#if defined(MBEDTLS_X509_ALWAYS_FLUSH) && \
!defined(MBEDTLS_THREADING_C)
TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR );
#else
TEST_ASSERT( ret == 0 );
TEST_ASSERT( mbedtls_x509_crt_pk_release( &crt ) == 0 );
#endif
TEST_ASSERT( mbedtls_x509_crt_pk_release( &crt ) == 0 );
ret = mbedtls_x509_crt_pk_release( &crt );
/* In contexts which use resource counting, we expect an
* error on an attempted release() without prior acquire(). */
#if defined(MBEDTLS_X509_ALWAYS_FLUSH) && \
!defined(MBEDTLS_THREADING_C)
TEST_ASSERT( ret == 0 );
#else
TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR );
#endif
}
exit:
mbedtls_x509_crt_free( &crt );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_X509_CRL_PARSE_C:!MBEDTLS_X509_REMOVE_INFO */
void x509parse_crl( data_t * buf, char * result_str, int result )
{

View file

@ -0,0 +1,19 @@
X509 CRT concurrent verification #1 (RSA cert, RSA CA)
depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA1_C
x509_verify_thread:"data_files/server1.crt":"data_files/test-ca.crt":0:0:25:50
X509 CRT concurrent verification #2 (EC cert, RSA CA)
depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA1_C
x509_verify_thread:"data_files/server3.crt":"data_files/test-ca.crt":0:0:25:50
X509 CRT concurrent verification #3 (RSA cert, EC CA)
depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_ECP_DP_SECP384R1_ENABLED
x509_verify_thread:"data_files/server4.crt":"data_files/test-ca2.crt":0:0:25:50
X509 CRT concurrent verification #4 (EC cert, EC CA)
depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED
x509_verify_thread:"data_files/server5.crt":"data_files/test-ca2.crt":0:0:25:50
X509 CRT concurrent verification #5 (RSA cert, RSA CA, RSASSA-PSS)
depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_X509_RSASSA_PSS_SUPPORT:MBEDTLS_SHA1_C
x509_verify_thread:"data_files/server9-with-ca.crt":"data_files/test-ca.crt":0:0:25:50

View file

@ -0,0 +1,125 @@
/* BEGIN_HEADER */
#include "mbedtls/bignum.h"
#include "mbedtls/x509.h"
#include "mbedtls/x509_crt.h"
#include "mbedtls/x509_crl.h"
#include "mbedtls/x509_csr.h"
#include "mbedtls/x509_internal.h"
#include "mbedtls/pem.h"
#include "mbedtls/oid.h"
#include "mbedtls/base64.h"
#include "string.h"
/* Profile for backward compatibility. Allows SHA-1, unlike the default
profile. */
const mbedtls_x509_crt_profile compat_profile =
{
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
0xFFFFFFF, /* Any PK alg */
0xFFFFFFF, /* Any curve */
1024,
};
typedef struct
{
mbedtls_x509_crt *crt;
mbedtls_x509_crt *ca;
uint32_t expected_flags;
unsigned id;
int expected_result;
int iter_total;
int result;
} x509_verify_thread_ctx;
void* x509_verify_thread_worker( void *p )
{
unsigned iter_cnt;
x509_verify_thread_ctx *ctx = (x509_verify_thread_ctx *) p;
for( iter_cnt=0; iter_cnt < (unsigned) ctx->iter_total; iter_cnt++ )
{
uint32_t flags;
int res;
res = mbedtls_x509_crt_verify_with_profile( ctx->crt, ctx->ca,
NULL, &compat_profile,
NULL, &flags, NULL, NULL );
if( res != ctx->expected_result ||
flags != ctx->expected_flags )
{
ctx->result = 1;
pthread_exit( NULL );
}
}
ctx->result = 0;
pthread_exit( NULL );
return( NULL );
}
/* END_HEADER */
/* BEGIN_DEPENDENCIES
* depends_on:MBEDTLS_THREADING_PTHREAD:MBEDTLS_X509_CRT_PARSE_C
* END_DEPENDENCIES
*/
/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */
void x509_verify_thread( char *crt_file, char *ca_file,
int result, int flags_result,
int thread_total,
int iterations_per_thread )
{
x509_verify_thread_ctx *thread_ctx;
pthread_t *threads;
int cur_thread;
mbedtls_x509_crt crt;
mbedtls_x509_crt ca;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
TEST_ASSERT( psa_crypto_init() == 0 );
#endif
mbedtls_x509_crt_init( &crt );
mbedtls_x509_crt_init( &ca );
threads = mbedtls_calloc( thread_total, sizeof( pthread_t ) );
thread_ctx = mbedtls_calloc( thread_total, sizeof( x509_verify_thread_ctx ) );
TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 );
TEST_ASSERT( mbedtls_x509_crt_parse_file( &ca, ca_file ) == 0 );
TEST_ASSERT( threads != NULL );
/* Start all verify threads */
for( cur_thread = 0; cur_thread < thread_total; cur_thread++ )
{
thread_ctx[ cur_thread ].id = (unsigned) cur_thread;
thread_ctx[ cur_thread ].ca = &ca;
thread_ctx[ cur_thread ].crt = &crt;
thread_ctx[ cur_thread ].expected_result = result;
thread_ctx[ cur_thread ].expected_flags = flags_result;
thread_ctx[ cur_thread ].iter_total = iterations_per_thread;
TEST_ASSERT( pthread_create( &threads[ cur_thread ], NULL,
&x509_verify_thread_worker,
&thread_ctx[ cur_thread ] ) == 0 );
}
/* Wait for all threads to complete */
for( cur_thread = 0; cur_thread < thread_total; cur_thread++ )
TEST_ASSERT( pthread_join( threads[ cur_thread ], NULL ) == 0 );
/* Check their results */
for( cur_thread = 0; cur_thread < thread_total; cur_thread++ )
TEST_ASSERT( thread_ctx[ cur_thread ].result == 0 );
exit:
mbedtls_free( threads );
mbedtls_free( thread_ctx );
mbedtls_x509_crt_free( &crt );
mbedtls_x509_crt_free( &ca );
}
/* END_CASE */

View file

@ -2,6 +2,7 @@
#include "mbedtls/bignum.h"
#include "mbedtls/x509_crt.h"
#include "mbedtls/x509_csr.h"
#include "mbedtls/x509_internal.h"
#include "mbedtls/pem.h"
#include "mbedtls/oid.h"
#include "mbedtls/rsa.h"
@ -216,7 +217,7 @@ void mbedtls_x509_string_to_names( char * name, char * parsed_name, int result
)
{
int ret;
size_t len = 0;
size_t len;
mbedtls_asn1_named_data *names = NULL;
mbedtls_x509_name parsed, *parsed_cur, *parsed_prv;
unsigned char buf[1024], out[1024], *c;
@ -234,10 +235,9 @@ void mbedtls_x509_string_to_names( char * name, char * parsed_name, int result
ret = mbedtls_x509_write_names( &c, buf, names );
TEST_ASSERT( ret > 0 );
len = (size_t) ret;
TEST_ASSERT( mbedtls_asn1_get_tag( &c, buf + sizeof( buf ), &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) == 0 );
TEST_ASSERT( mbedtls_x509_get_name( &c, buf + sizeof( buf ), &parsed ) == 0 );
TEST_ASSERT( mbedtls_x509_get_name( c, len, &parsed ) == 0 );
ret = mbedtls_x509_dn_gets( (char *) out, sizeof( out ), &parsed );
TEST_ASSERT( ret > 0 );

View file

@ -223,6 +223,7 @@
<ClInclude Include="..\..\include\mbedtls\x509_crl.h" />
<ClInclude Include="..\..\include\mbedtls\x509_crt.h" />
<ClInclude Include="..\..\include\mbedtls\x509_csr.h" />
<ClInclude Include="..\..\include\mbedtls\x509_internal.h" />
<ClInclude Include="..\..\include\mbedtls\xtea.h" />
</ItemGroup>
<ItemGroup>