diff --git a/.gitignore b/.gitignore index fee2a31cd..1142e0348 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,15 @@ massif-* # CMake generates *.dir/ folders for in-tree builds (used by MSVC projects), ignore all of those: *.dir/ + +# Generated documentation +/apidoc + +# Common developer files +/GPATH +/GSYMS +/GRTAGS +/GTAGS +/TAGS +/tags +.gdbinit diff --git a/ChangeLog b/ChangeLog index 8db021591..ebcde96cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ mbed TLS ChangeLog (Sorted per branch, date) += mbed TLS 2.7.x feature branch released xxxx-xx-xx + +Features + * Add support for opaque keys in the pk module. Applications can define + opaque key engines to perform operations using keys stored in an + external cryptographic module. + * Support opaque private keys in TLS. + = mbed TLS 2.7.0 branch released 2018-02-03 Security diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index aa23d67f9..489770856 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -34,6 +34,11 @@ #include "ecp.h" #include "md.h" +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + /* * RFC-4492 page 20: * @@ -51,8 +56,40 @@ #if MBEDTLS_ECP_MAX_BYTES > 124 #error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN" #endif + +/** + * \brief Maximum ECDSA signature size for a given curve bit size + * + * \param bits Curve size in bits + * \return Maximum signature size in bytes + * + * \note This macro returns a compile-time constant if its argument + * is one. It may evaluate its argument multiple times; if + * this is a problem, call the function + * mbedtls_ecdsa_max_sig_len instead. + */ +#define MBEDTLS_ECDSA_MAX_SIG_LEN( bits ) \ + ( /*T,L of SEQUENCE*/ ( ( bits ) >= 61 * 8 ? 3 : 2 ) + \ + /*T,L of r,s*/ 2 * ( ( ( bits ) >= 127 * 8 ? 3 : 2 ) + \ + /*V of r,s*/ ( ( bits ) + 8 ) / 8 ) ) + +/** + * \brief Maximum ECDSA signature size for a given curve bit size + * + * \param bits Curve size in bits + * \return Maximum signature size in bytes + * + * \note If you need a compile-time constant, call the macro + * MBEDTLS_ECDSA_MAX_SIG_LEN instead. + */ +static inline size_t mbedtls_ecdsa_max_sig_len( size_t bits ) +{ + return( MBEDTLS_ECDSA_MAX_SIG_LEN( bits ) ); +} + /** The maximal size of an ECDSA signature in Bytes. */ -#define MBEDTLS_ECDSA_MAX_LEN ( 3 + 2 * ( 3 + MBEDTLS_ECP_MAX_BYTES ) ) +#define MBEDTLS_ECDSA_MAX_LEN \ + ( MBEDTLS_ECDSA_MAX_SIG_LEN( 8 * MBEDTLS_ECP_MAX_BYTES ) ) /** * \brief The ECDSA context structure. @@ -65,7 +102,10 @@ extern "C" { /** * \brief This function computes the ECDSA signature of a - * previously-hashed message. + * previously-hashed message. The signature is in + * ASN.1 SEQUENCE format, as described in Standards + * for Efficient Cryptography Group (SECG): SEC1 Elliptic + * Curve Cryptography, section C.5. * * \note The deterministic version is usually preferred. * @@ -178,10 +218,13 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, * \param f_rng The RNG function. * \param p_rng The RNG parameter. * - * \note The \p sig buffer must be at least twice as large as the - * size of the curve used, plus 9. For example, 73 Bytes if - * a 256-bit curve is used. A buffer length of - * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * \note The signature \p sig is expected to in be ASN.1 SEQUENCE + * format, as described in Standards for Efficient + * Cryptography Group (SECG): SEC1 Elliptic Curve + * Cryptography, section C.5. + * + * \note A \p sig buffer length of #MBEDTLS_ECDSA_MAX_LEN is + * always safe. * * \note If the bitlength of the message hash is larger than the * bitlength of the group order, then the hash is truncated as @@ -255,6 +298,35 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, #endif /* MBEDTLS_DEPRECATED_REMOVED */ #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ +/** + * \brief Convert an ECDSA signature from number pair format to ASN.1 + * + * \param r First number of the signature + * \param s Second number of the signature + * \param sig Buffer that will hold the signature + * \param slen Length of the signature written + * \param ssize Size of the sig buffer + * + * \note The size of the buffer \c ssize should be at least + * `MBEDTLS_ECDSA_MAX_SIG_LEN(grp->pbits)` bytes long if the + * signature was produced from curve \c grp, otherwise + * this function may fail with the error + * MBEDTLS_ERR_ASN1_BUF_TOO_SMALL. + * The output ASN.1 SEQUENCE format is as follows: + * Ecdsa-Sig-Value ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } + * This format is expected by \c mbedtls_ecdsa_verify. + * + * \return 0 if successful, + * or a MBEDTLS_ERR_MPI_XXX or MBEDTLS_ERR_ASN1_XXX error code + * + */ +int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, + unsigned char *sig, size_t *slen, + size_t ssize ); + /** * \brief This function reads and verifies an ECDSA signature. * diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index b00ba4da8..9e2755f5a 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -503,6 +503,59 @@ int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **bu int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, unsigned char *buf, size_t blen ); +#if defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) +/** + * \brief Maximum size of the output of mbedtls_ecp_ansi_write_group + * + * \note The maximum size of the OID of a supported group + 2 for + * tag and length. Maximum size 30 is based on the length of + * the OID for primeCurves 10-38 over GF(p) defined by the + * CDC Group, as they seem to have the longest OID out of + * curves in use. + */ +#define MBEDTLS_ECP_GRP_OID_MAX_SIZE ( 30 + 2 ) + +/** + * \brief Write the ANSI X9.62/RFC5480 OID ECParameters of a group + * + * The output is the group's OID wrapped as ASN.1. + * + * \param grp ECP group used + * \param p Buffer to write to + * \param size Buffer size + * \param olen Number of bytes written to \c buf + * \return 0 on success + * or \c MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * or \c MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, + unsigned char *p, size_t size, + size_t *olen ); + +/** + * \brief Export a point in ANSI X9.62/RFC5480 ECPoint + * + * The output is the point wrapped as an ASN.1 octet string + * as defined in X9.62 and RFC 5480. + * + * \param ec ECP public key or key pair + * \param format Point format, should be a MBEDTLS_ECP_PF_XXX macro + * \param p Buffer to write to + * \param size Buffer size + * \param olen Number of bytes written to \c buf on success, + * unspecified on failure. + * + * \return 0 on success + * or \c MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * or \c MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or \c MBEDTLS_ERR_ASN1_BUF_TOO_SMALL + */ +int mbedtls_ecp_ansi_write_point( const mbedtls_ecp_keypair *ec, + int format, + unsigned char *p, + size_t size, size_t *olen ); +#endif /* defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) */ + /** * \brief Multiplication by an integer: R = m * P * (Not thread-safe to use same group in multiple threads) diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h index 8b4d3a875..5d3dcace8 100644 --- a/include/mbedtls/error.h +++ b/include/mbedtls/error.h @@ -84,7 +84,7 @@ * X509 2 20 * PKCS5 2 4 (Started from top) * DHM 3 11 - * PK 3 15 (Started from top) + * PK 3 18 (Started from top) * RSA 4 11 * ECP 4 9 (Started from top) * MD 5 5 diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h index bf2ef5ece..396bcdd44 100644 --- a/include/mbedtls/oid.h +++ b/include/mbedtls/oid.h @@ -283,6 +283,8 @@ /* * ECParameters namedCurve identifiers, from RFC 5480, RFC 5639, and SEC2 + * When adding new OID's, please update MBEDTLS_ECP_GRP_OID_MAX_SIZE + * in ecp.h */ /* secp192r1 OBJECT IDENTIFIER ::= { diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index 1059bdaa5..0e923779f 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -1,10 +1,10 @@ /** * \file pk.h * - * \brief Public Key abstraction layer + * \brief Public Key cryptography abstraction layer */ /* - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -50,11 +50,14 @@ #define inline __inline #endif +/** \name Error codes */ +/**@{*/ + #define MBEDTLS_ERR_PK_ALLOC_FAILED -0x3F80 /**< Memory allocation failed. */ -#define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key */ +#define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key. */ #define MBEDTLS_ERR_PK_BAD_INPUT_DATA -0x3E80 /**< Bad input parameters to function. */ #define MBEDTLS_ERR_PK_FILE_IO_ERROR -0x3E00 /**< Read/write of file failed. */ -#define MBEDTLS_ERR_PK_KEY_INVALID_VERSION -0x3D80 /**< Unsupported key version */ +#define MBEDTLS_ERR_PK_KEY_INVALID_VERSION -0x3D80 /**< Unsupported key version. */ #define MBEDTLS_ERR_PK_KEY_INVALID_FORMAT -0x3D00 /**< Invalid key tag or value. */ #define MBEDTLS_ERR_PK_UNKNOWN_PK_ALG -0x3C80 /**< Key algorithm is unsupported (only RSA and EC are supported). */ #define MBEDTLS_ERR_PK_PASSWORD_REQUIRED -0x3C00 /**< Private key password can't be empty. */ @@ -65,22 +68,34 @@ #define MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE -0x3980 /**< Unavailable feature, e.g. RSA disabled for RSA key. */ #define MBEDTLS_ERR_PK_SIG_LEN_MISMATCH -0x3900 /**< The signature is valid but its length is less than expected. */ #define MBEDTLS_ERR_PK_HW_ACCEL_FAILED -0x3880 /**< PK hardware accelerator failed. */ +#define MBEDTLS_ERR_PK_INVALID_SIGNATURE -0x3800 /**< Invalid signature. */ +#define MBEDTLS_ERR_PK_BUFFER_TOO_SMALL -0x3780 /**< Output buffer too small. */ +#define MBEDTLS_ERR_PK_NOT_PERMITTED -0x3700 /**< Operation not permitted. */ + +/**@}*/ #ifdef __cplusplus extern "C" { #endif +/** \name Asymmetric cryptography operation contexts */ +/**@{*/ + /** - * \brief Public key types - */ + * \brief Asymmetric operation context types + * + * \note An opaque key may be an RSA or ECC key or a key of an + * unrecognized type. Call \c mbedtls_pk_can_do() to check + * whether a key is of a recognized type. */ typedef enum { - MBEDTLS_PK_NONE=0, - MBEDTLS_PK_RSA, - MBEDTLS_PK_ECKEY, - MBEDTLS_PK_ECKEY_DH, - MBEDTLS_PK_ECDSA, - MBEDTLS_PK_RSA_ALT, - MBEDTLS_PK_RSASSA_PSS, + MBEDTLS_PK_NONE=0, /**< Unused context object. */ + MBEDTLS_PK_RSA, /**< RSA key pair (normal software implementation) with PKCS#1 v1.5 or PSS context. */ + MBEDTLS_PK_ECKEY, /**< Generic ECC key pair. */ + MBEDTLS_PK_ECKEY_DH, /**< ECC key pair restricted to key exchanges. */ + MBEDTLS_PK_ECDSA, /**< ECC key pair restricted to signature/verification. */ + MBEDTLS_PK_RSA_ALT, /**< RSA (alternative implementation). */ + MBEDTLS_PK_RSASSA_PSS, /**< RSA key pair; same context as MBEDTLS_PK_RSA, but used to represent keys with the algorithm identifier id-RSASSA-PSS. */ + MBEDTLS_PK_OPAQUE, /**< Opaque key pair (cryptographic material held in an external module). */ } mbedtls_pk_type_t; /** @@ -118,29 +133,95 @@ typedef struct #define MBEDTLS_PK_DEBUG_MAX_ITEMS 3 /** - * \brief Public key information and operations + * \brief Key pair information and operations */ typedef struct mbedtls_pk_info_t mbedtls_pk_info_t; /** - * \brief Public key container + * \brief Context structure for public-key cryptographic operations. + * + * \note This structure contains all the information needed for + * performing a public-key cryptography operation. Depending + * on the operation and the cryptographic algorithm it can + * represent either the public key or a pair of matching + * public and private keys. Also it may contain other + * implementation specific data. */ typedef struct { - const mbedtls_pk_info_t * pk_info; /**< Public key informations */ - void * pk_ctx; /**< Underlying public key context */ + const mbedtls_pk_info_t * pk_info; /**< Algorithm information */ + void * pk_ctx; /**< Underlying key pair context */ } mbedtls_pk_context; +/** + * \brief Get the key type name of a PK context. + * + * \param ctx Context to use + * + * \return Type name on success, or "invalid PK" + */ +const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the key type of a PK context. + * + * \param ctx Context to use + * + * \return Type on success, or MBEDTLS_PK_NONE + * + * \note This function returns the type of the key pair object. The + * type encodes the representation of the object as well as + * the operations that it can be used for. To test whether + * the object represents a key of a recognized type such + * as RSA or ECDSA, call \c mbedtls_pk_can_do(). + */ +mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the representation type associated with a given type + * + * \param type Any key type + * \return A canonical representative among the types with the + * same key representation. This is \c MBEDTLS_PK_RSA + * for RSA keys using the built-in software engine and + * MBEDTLS_PK_ECKEY for EC keys using the built-in + * software engine. Note that for keys of type + * \c MBEDTLS_PK_OPAQUE, the type does not specify the + * representation. + */ +static inline mbedtls_pk_type_t mbedtls_pk_representation_type( mbedtls_pk_type_t type ) +{ + switch( type ) + { + case MBEDTLS_PK_RSA: + case MBEDTLS_PK_RSASSA_PSS: + return( MBEDTLS_PK_RSA ); + case MBEDTLS_PK_ECKEY: + case MBEDTLS_PK_ECKEY_DH: + case MBEDTLS_PK_ECDSA: + return( MBEDTLS_PK_ECKEY ); + default: + return( type ); + } +} + #if defined(MBEDTLS_RSA_C) /** * Quick access to an RSA context inside a PK context. * - * \warning You must make sure the PK context actually holds an RSA context - * before using this function! + * \warning You must either make sure the PK context actually holds a + * transparent RSA context by checking + * \c mbedtls_pk_representation_type( mbedtls_pk_get_type( &pk ) ) before using + * this function, or check that the return value is not NULL before using it. */ static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) { - return( (mbedtls_rsa_context *) (pk).pk_ctx ); + mbedtls_pk_type_t type = + mbedtls_pk_representation_type( mbedtls_pk_get_type( &pk ) ); + if( type == MBEDTLS_PK_RSA ) + return( (mbedtls_rsa_context *)( pk.pk_ctx ) ); + else + return( NULL ); } #endif /* MBEDTLS_RSA_C */ @@ -148,12 +229,19 @@ static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) /** * Quick access to an EC context inside a PK context. * - * \warning You must make sure the PK context actually holds an EC context - * before using this function! + * \warning You must either make sure the PK context actually holds a + * transparent RSA context by checking + * \c mbedtls_pk_representation_type( mbedtls_pk_get_type( &pk ) ) before using + * this function, or check that the return value is not NULL before using it. */ static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk ) { - return( (mbedtls_ecp_keypair *) (pk).pk_ctx ); + mbedtls_pk_type_t type = + mbedtls_pk_representation_type( mbedtls_pk_get_type( &pk ) ); + if( type == MBEDTLS_PK_ECKEY ) + return( (mbedtls_ecp_keypair *)( pk.pk_ctx ) ); + else + return( NULL ); } #endif /* MBEDTLS_ECP_C */ @@ -172,10 +260,14 @@ typedef size_t (*mbedtls_pk_rsa_alt_key_len_func)( void *ctx ); #endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ /** - * \brief Return information associated with the given PK type + * \brief Return default information associated with the given PK type * * \param pk_type PK type to search for. * + * \note This function returns NULL if pk_type indicates an opaque + * key, since the type does not provide enough information to + * build an opaque key. + * * \return The PK info associated with the type or NULL if not found. */ const mbedtls_pk_info_t *mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ); @@ -201,7 +293,17 @@ void mbedtls_pk_free( mbedtls_pk_context *ctx ); * MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input, * MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure. * - * \note For contexts holding an RSA-alt key, use + * \note Engines that implement opaque keys may offer an + * alternative setup function that take engine-dependent + * parameters. If the documentation of the engine lists such a + * function, call it instead of mbedtls_pk_setup. A standard + * way of providing such function is by first calling the + * generic mbedtls_pk_setup function (in particular taking + * care of context allocation through ctx_alloc) and + * afterwards proceeding to initialize the + * implementation-specific context structure. + * + * \note For contexts holding an RSA-alt key pair, use * \c mbedtls_pk_setup_rsa_alt() instead. */ int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ); @@ -211,7 +313,7 @@ int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ); * \brief Initialize an RSA-alt context * * \param ctx Context to initialize. Must be empty (type NONE). - * \param key RSA key pointer + * \param key RSA key pair pointer * \param decrypt_func Decryption function * \param sign_func Signing function * \param key_len_func Function returning key length in bytes @@ -240,6 +342,11 @@ size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ); * \brief Get the length in bytes of the underlying key * \param ctx Context to use * + * \note This returns the minimum number of bytes required to + * store the part of the key that defines its size (modulus + * for RSA, coordinate for ECC). The way the key is stored + * in the context may have a different size. + * * \return Key length in bytes, or 0 on error */ static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx ) @@ -248,13 +355,24 @@ static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx ) } /** - * \brief Tell if a context can do the operation given by type + * \brief Tell if a context can do the operations given by type + * + * \note This function can be used to identify the type of key + * (e.g. RSA vs ECC), and a superset of permitted + * operations. It is possible that this function returns + * true but some operations are not allowed. For example + * this function always returns true if ctx is an RSA + * context and type is MBEDTLS_PK_RSA, but the key may + * be restricted to any subset of operations among signature, + * verification, encryption and decryption. To determine + * which operations a key allow, attempt the operation and + * check the return status. * * \param ctx Context to test * \param type Target type * - * \return 0 if context can't do the operations, - * 1 otherwise. + * \return 1 if context can do the operations, + * 0 otherwise. */ int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ); @@ -271,7 +389,7 @@ int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ); * \return 0 on success (signature is valid), * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if the signature is * valid but its actual length is less than sig_len, - * or a specific error code. + * or a type-specific error code. * * \note For RSA keys, the default padding type is PKCS#1 v1.5. * Use \c mbedtls_pk_verify_ext( MBEDTLS_PK_RSASSA_PSS, ... ) @@ -304,7 +422,7 @@ int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, * used for this type of signatures, * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if the signature is * valid but its actual length is less than sig_len, - * or a specific error code. + * or a type-specific error code. * * \note If hash_len is 0, then the length associated with md_alg * is used instead, or an error returned if it is invalid. @@ -328,11 +446,18 @@ int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, * \param hash Hash of the message to sign * \param hash_len Hash length or 0 (see notes) * \param sig Place to write the signature - * \param sig_len Number of bytes written + * \param sig_len Actual length in bytes of the created signature * \param f_rng RNG function * \param p_rng RNG parameter * - * \return 0 on success, or a specific error code. + * \return 0 on success, or a type-specific error code. + * + * \note The signature buffer \c sig must be of appropriate size + * which can be calculated with + * \c mbedtls_pk_get_signature_size. + * Depending on the algorithm, the value returned in + * \c sig_len may be less or equal to the value returned by + * \c mbedtls_pk_get_signature_size. * * \note For RSA keys, the default padding type is PKCS#1 v1.5. * There is no interface in the PK module to make RSASSA-PSS @@ -349,6 +474,16 @@ int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, unsigned char *sig, size_t *sig_len, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); +/** + * \brief Provide an upper bound for the size of a signature made + * with this key. + * + * \param ctx PK context to use + * + * \return Maximum size in bytes of a signature made with this key. + */ +size_t mbedtls_pk_get_signature_size( const mbedtls_pk_context *ctx ); + /** * \brief Decrypt message (including padding if relevant). * @@ -363,7 +498,7 @@ int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, * * \note For RSA keys, the default padding type is PKCS#1 v1.5. * - * \return 0 on success, or a specific error code. + * \return 0 on success, or a type-specific error code. */ int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, const unsigned char *input, size_t ilen, @@ -384,7 +519,7 @@ int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, * * \note For RSA keys, the default padding type is PKCS#1 v1.5. * - * \return 0 on success, or a specific error code. + * \return 0 on success, or a type-specific error code. */ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, const unsigned char *input, size_t ilen, @@ -397,7 +532,19 @@ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, * \param pub Context holding a public key. * \param prv Context holding a private (and public) key. * - * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + * \return * 0 on success. + * * MBEDTLS_ERR_PK_BAD_INPUT_DATA if one of the contexts + * is ill-formed. + * * MBEDTLS_ERR_PK_TYPE_MISMATCH if the contexts cannot + * represent keys of the same type. + * * MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE if it is impossible + * to determine whether the keys match. This can only happen + * if \c prv is an opaque key. + * * Or a type-specific error code. + * + * \note Opaque key types may omit implementing this function + * by providing a NULL pointer in the mbedtls_pk_info_t structure. + * Currently, an opaque \c pub never matches a transparent \c prv. */ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); @@ -407,27 +554,16 @@ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_conte * \param ctx Context to use * \param items Place to write debug items * - * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + * \return * 0 on success. + * * MBEDTLS_ERR_PK_BAD_INPUT_DATA if the context is ill-formed. + * * MBEDTLS_ERR_PK_TYPE_MISMATCH if the context does not + * support exporting debug information. + * * Or a type-specific error code. */ int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ); -/** - * \brief Access the type name - * - * \param ctx Context to use - * - * \return Type name on success, or "invalid PK" - */ -const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); +/**@}*/ -/** - * \brief Get the key type - * - * \param ctx Context to use - * - * \return Type on success, or MBEDTLS_PK_NONE - */ -mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); #if defined(MBEDTLS_PK_PARSE_C) /** \ingroup pk_module */ @@ -513,7 +649,12 @@ int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) #endif /* MBEDTLS_FS_IO */ #endif /* MBEDTLS_PK_PARSE_C */ + + #if defined(MBEDTLS_PK_WRITE_C) +/** \name Key pair serialization */ +/**@{*/ + /** * \brief Write a private key to a PKCS#1 or SEC1 DER structure * Note: data is written at the end of the buffer! Use the @@ -567,11 +708,13 @@ int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *ctx, unsigned char *buf, si */ int mbedtls_pk_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); #endif /* MBEDTLS_PEM_WRITE_C */ +/**@}*/ #endif /* MBEDTLS_PK_WRITE_C */ -/* - * WARNING: Low-level functions. You probably do not want to use these unless - * you are certain you do ;) +/** \name Low-level functions */ +/**@{*/ +/** + * \warning You probably do not want to use these unless you are certain you do ;) */ #if defined(MBEDTLS_PK_PARSE_C) @@ -611,6 +754,8 @@ int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ); #endif +/**@}*/ + #ifdef __cplusplus } #endif diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h new file mode 100644 index 000000000..89752cea9 --- /dev/null +++ b/include/mbedtls/pk_info.h @@ -0,0 +1,338 @@ +/** + * \file pk_info.h + * + * \brief Public Key cryptography abstraction layer: engine interface + * + * This file defines the interface which public-key cryptography engines + * (PK engines) must implement. A PK engine defines how a public-private + * key pair is represented and how to perform cryptographic operations + * with it. Mbed TLS contains built-in PK engines implemented either + * purely in software or with hardware acceleration support, depending + * on the target platform. In addition, it is possible to define custom + * opaque key engines that forward operation requests to cryptographic + * modules outside Mbed TLS, such as external cryptoprocessors or general + * PKCS#11 tokens. + */ +/* + * Copyright (C) 2006-2018, 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_PK_INFO_H +#define MBEDTLS_PK_INFO_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "pk.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Methods that opaque key pair objects must implement. + * + * Engines that interface with external cryptographic processors must + * implement this interface. It allows using different engines for each key. + * Platform-specific hardware accelerators that can be used for all keys of + * a given type should not use this interface, but rather provide an + * alternative implementation of the respective cryptographic module - for + * example to use an RSA accelerator you can define MBEDTLS_RSA_ALT, and + * provide your own implementation of the RSA module. + * + * \warning: If you are using the PK interface to perform operations on + * keys, call the functions in pk.h. The interface in this file should only + * be used by implementers of opaque key engines. + * + * An engine for asymmetric cryptography must implement the interface + * described in this structure. The interface for the engine may be + * exposed in one of two ways: + * + * - Declare the mbedtls_pk_info_t structure and instruct users to call + * mbedtls_pk_setup with that structure. + * - Keep the mbedtls_pk_info_t structure hidden and declare a function + * to call instead of mbedtls_pk_setup. This function should have an + * interface of the form + * 'int mbedtls_pk_setup_myengine(mbedtls_pk_context *, ...)' + * where the extra parameters depend on the engine, e.g. handles to keys + * stored in an external cryptographic module. + * + * Unless otherwise indicated, functions returning int must return an + * Mbed TLS status code, either 0 for success or a negative value to indicate + * an error. It is recommended to use the MBEDTLS_ERR_PK_XXX error codes + * defined in pk.h. + * + * Some methods are optional; this is clearly indicated in their description. + * If a method is optional, then an opaque key implementation may put NULL + * in the corresponding field. The corresponding function in pk.h will + * return #MBEDTLS_ERR_PK_TYPE_MISMATCH in this case. + * + * + * \warning: Do not declare this structure directly! It may be extended in + * future versions of Mbed TLS. Call the macro + * MBEDTLS_PK_OPAQUE_INFO_1() instead. + * This macro is guaranteed to take parameters with the same type + * and semantics as previous versions and fill any new field of the + * structure with sensible values. + */ +struct mbedtls_pk_info_t +{ + /** Key pair type. + * + * mbedtls_pk_get_type() returns this value. + * + * For transparent keys, this contains an indication of supported + * algorithms. For opaque keys, this is #MBEDTLS_PK_OPAQUE. */ + mbedtls_pk_type_t type; + + /** Type name. + * + * mbedtls_pk_get_name() returns this value. It must be a + * null-terminated string. + * + * For transparent keys, this reflects the key type. For opaque keys, + * this reflects the cryptographic module driver. */ + const char *name; + + /** Get key size in bits. + * + * mbedtls_pk_get_bitlen() returns this value. + * + * This function cannot fail. */ + size_t (*get_bitlen)( const void *ctx ); + + /** Tell if the context implements the algorithm specified by + * the provided type (e.g. ECKEY can do ECDSA). + * + * mbedtls_pk_can_do() calls this function. + * + * This function is only based on the key type. It does not take any + * usage restrictions into account. */ + int (*can_do)( const void * ctx, mbedtls_pk_type_t type ); + + /** Upper bound of the signature length + * + * mbedtls_pk_get_signature_size() returns this value. + * + * In case of an error, or an unsupported key type, 0 should be returned. + * + * Opaque implementations may omit this method if they do not support + * signing. */ + size_t (*signature_size_func)( const void *ctx ); + + /** Verify signature + * + * mbedtls_pk_verify() calls this function. + * + * Opaque implementations may omit this method if they do not support + * signature verification. */ + int (*verify_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + + /** Make signature + * + * mbedtls_pk_sign() calls this function. + * + * Assumes that the buffer \c sig has room for + * \c signature_size_func(ctx) bytes. + * + * The arguments \c f_rng and \c p_rng are provided in case the + * algorithm requires randomization. Implementations are not + * required to use it if they have their own random source. If \c + * f_rng is null, the implementation should operate if it can, and + * return #MBEDTLS_ERR_PK_BAD_INPUT_DATA otherwise. + * + * Opaque implementations may omit this method if they do not support + * signing. If this method is provided, so must be + * \ref mbedtls_pk_info_t.signature_size_func. */ + int (*sign_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Decrypt message + * + * mbedtls_pk_decrypt() calls this function. + * + * The arguments \c f_rng and \c p_rng are provided in case the + * algorithm requires randomization. Implementations are not + * required to use it if they have their own random source. If \c + * f_rng is null, the implementation should operate if it can, and + * return #MBEDTLS_ERR_PK_BAD_INPUT_DATA otherwise. + * + * Opaque implementations may omit this method if they do not support + * decryption. */ + int (*decrypt_func)( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Encrypt message + * + * mbedtls_pk_decrypt() calls this function. + * + * The arguments \c f_rng and \c p_rng are provided in case the + * algorithm requires randomization. Implementations are not + * required to use it if they have their own random source. If \c + * f_rng is null, the implementation should operate if it can, and + * return #MBEDTLS_ERR_PK_BAD_INPUT_DATA otherwise. + * + * Opaque implementations may omit this method if they do not support + * encryption. */ + int (*encrypt_func)( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Check public-private key pair + * + * mbedtls_pk_check_pair() calls this function on the private key pair + * object \c prv. The other argument \c pub may be of any type, but it + * is guaranteed to be initialized. The implementation is allowed to do + * a probabilistic and computationally expensive check. + * + * If \c prv is an RSA key and \c pub is a transparent RSA key + * (i.e. \c pub has the type #MBEDTLS_PK_RSA or #MBEDTLS_PK_RSASSA_PSS), + * then \c check_pair_func must return 0 if the public key is + * mathematically equivalent to the public part of \c prv, and + * #MBEDTLS_ERR_RSA_KEY_CHECK_FAILED otherwise. + * + * If \c pub is an ECC key and \c pub is a transparent ECC key that can + * be used for ECDSA (i.e. \c pub has the type #MBEDTLS_PK_ECKEY or + * #MBEDTLS_PK_ECDSA), then \c check_pair_func must return 0 if the public + * key is mathematically equivalent to the public part of \c prv, and + * #MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise. + * + * If \c pub is a transparent key (key of type #MBEDTLS_PK_RSA, + * #MBEDTLS_PK_RSASSA_PSS, #MBEDTLS_PK_ECKEY or #MBEDTLS_PK_ECDSA) whose + * type does not match the semantic type of \c prv (RSA, ECC or other), + * then \c check_pair_func must return #MBEDTLS_ERR_PK_TYPE_MISMATCH. + * + * If \c pub and \c prv are opaque keys from the same engines (i.e. their + * pk_info fields are equal), then \c check_pair_func must return 0, + * #MBEDTLS_ERR_PK_TYPE_MISMATCH, or #MBEDTLS_ERR_RSA_KEY_CHECK_FAILED + * or #MBEDTLS_ERR_ECP_BAD_INPUT_DATA as in the case of transparent keys. + * + * If \c pub is an opaque key which is not from the same engine as \c prv, + * then \c check_pair_func may either return a semantically correct status + * as in the case of transparent keys, or it may return + * #MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE. + * + * Alternatively, \c check_pair_func may return another PK, RSA or ECP + * error code if applicable. */ + int (*check_pair_func)( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); + + /** Allocate a new context + * + * mbedtls_pk_setup() calls this function. + * + * If this function returns NULL, the allocation is considered to + * have failed and the object remains uninitialized. + * + * Opaque implementations may omit this method. In this case, + * mbedtls_pk_setup() will set the \c pk_ctx field of the + * mbedtls_pk_context object to NULL, and it is up to an engine-specific + * setup function to initialize the \c pk_ctx field. This is useful if + * the size of the memory depends on extra parameters passed to the + * engine-specific setup function. */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context + * + * mbedtls_pk_free() calls this function. It must free the data allocated + * by \c ctx_alloc_func as well as any other resource that belongs to + * the object. */ + void (*ctx_free_func)( void *ctx ); + + /** Interface with the debug module + * + * mbedtls_pk_debug() calls this function. + * + * Opaque implementations may omit this method. */ + void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); + +}; + +/** + * \brief Initializer for opaque key engines + * + * Methods that opaque key pair objects must implement. + * + * The value of this macro is a suitable initializer for an object of type + * mbedtls_pk_info_t. It is guaranteed to remain so in future versions of the + * library, even if the type mbedtls_pk_info_t changes. + * + * This macro is suitable for static initializers provided that all of its + * parameters are constant. + * + * \param name For transparent keys, this reflects the key type. For opaque + * keys, this reflects the cryptographic module driver. + * \param get_bitlen \ref mbedtls_pk_info_t.get_bitlen method + * \param can_do \ref mbedtls_pk_info_t.can_do method + * \param signature_size_func \ref mbedtls_pk_info_t.signature_size_func method + * \param verify_func \ref mbedtls_pk_info_t.verify_func method + * \param sign_func \ref mbedtls_pk_info_t.sign_func method + * \param decrypt_func \ref mbedtls_pk_info_t.decrypt_func method + * \param encrypt_func \ref mbedtls_pk_info_t.encrypt_func method + * \param check_pair_func \ref mbedtls_pk_info_t.check_pair_func method + * \param ctx_alloc_func \ref mbedtls_pk_info_t.ctx_alloc_func method + * \param ctx_free_func \ref mbedtls_pk_info_t.ctx_free_func method + * \param debug_func \ref mbedtls_pk_info_t.debug_func method + * + * \return Initializer for an object of type mbedtls_pk_info_t with the + * specified field values */ +#define MBEDTLS_PK_OPAQUE_INFO_1( \ + name \ + , get_bitlen \ + , can_do \ + , signature_size_func \ + , verify_func \ + , sign_func \ + , decrypt_func \ + , encrypt_func \ + , check_pair_func \ + , ctx_alloc_func \ + , ctx_free_func \ + , debug_func \ + ) \ + { \ + MBEDTLS_PK_OPAQUE \ + , name \ + , get_bitlen \ + , can_do \ + , signature_size_func \ + , verify_func \ + , sign_func \ + , decrypt_func \ + , encrypt_func \ + , check_pair_func \ + , ctx_alloc_func \ + , ctx_free_func \ + , debug_func \ + } + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PK_INFO_H */ diff --git a/include/mbedtls/pk_internal.h b/include/mbedtls/pk_internal.h index 3dae0fc5b..42d6bc0b6 100644 --- a/include/mbedtls/pk_internal.h +++ b/include/mbedtls/pk_internal.h @@ -1,10 +1,17 @@ /** * \file pk_internal.h * - * \brief Public Key abstraction layer: wrapper functions + * \brief Public Key cryptography abstraction layer: internal definitions + * + * This file contains built-in types for handling natively supported key types + * using the interface defined in pk_info.h. + * + * \warning This file contains internal definitions for the library. + * The interfaces in this file may change in future versions of the + * library without notice. */ /* - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -22,8 +29,8 @@ * This file is part of mbed TLS (https://tls.mbed.org) */ -#ifndef MBEDTLS_PK_WRAP_H -#define MBEDTLS_PK_WRAP_H +#ifndef MBEDTLS_PK_INTERNAL_H +#define MBEDTLS_PK_INTERNAL_H #if !defined(MBEDTLS_CONFIG_FILE) #include "config.h" @@ -33,57 +40,6 @@ #include "pk.h" -struct mbedtls_pk_info_t -{ - /** Public key type */ - mbedtls_pk_type_t type; - - /** Type name */ - const char *name; - - /** Get key size in bits */ - size_t (*get_bitlen)( const void * ); - - /** Tell if the context implements this type (e.g. ECKEY can do ECDSA) */ - int (*can_do)( mbedtls_pk_type_t type ); - - /** Verify signature */ - int (*verify_func)( void *ctx, mbedtls_md_type_t md_alg, - const unsigned char *hash, size_t hash_len, - const unsigned char *sig, size_t sig_len ); - - /** Make signature */ - int (*sign_func)( void *ctx, mbedtls_md_type_t md_alg, - const unsigned char *hash, size_t hash_len, - unsigned char *sig, size_t *sig_len, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ); - - /** Decrypt message */ - int (*decrypt_func)( void *ctx, const unsigned char *input, size_t ilen, - unsigned char *output, size_t *olen, size_t osize, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ); - - /** Encrypt message */ - int (*encrypt_func)( void *ctx, const unsigned char *input, size_t ilen, - unsigned char *output, size_t *olen, size_t osize, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ); - - /** Check public-private key pair */ - int (*check_pair_func)( const void *pub, const void *prv ); - - /** Allocate a new context */ - void * (*ctx_alloc_func)( void ); - - /** Free the given context */ - void (*ctx_free_func)( void *ctx ); - - /** Interface with the debug module */ - void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); - -}; #if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) /* Container for RSA-alt */ typedef struct @@ -112,4 +68,4 @@ extern const mbedtls_pk_info_t mbedtls_ecdsa_info; extern const mbedtls_pk_info_t mbedtls_rsa_alt_info; #endif -#endif /* MBEDTLS_PK_WRAP_H */ +#endif /* MBEDTLS_PK_INTERNAL_H */ diff --git a/library/ecdsa.c b/library/ecdsa.c index 826fefe5c..ed4268dde 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -287,31 +287,48 @@ cleanup: #endif /* MBEDTLS_ECDSA_VERIFY_ALT */ /* - * Convert a signature (given by context) to ASN.1 + * Convert a signature (given by context) to ASN.1. + * This function is for internal use only. Upon an error, it may leave + * the signature buffer partially written. */ -static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, - unsigned char *sig, size_t *slen ) +static int internal_ecdsa_signature_to_asn1( const mbedtls_mpi *r, + const mbedtls_mpi *s, unsigned char *sig, + size_t *slen, size_t ssize ) { int ret; - unsigned char buf[MBEDTLS_ECDSA_MAX_LEN]; - unsigned char *p = buf + sizeof( buf ); + unsigned char *p = sig + ssize; size_t len = 0; - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, s ) ); - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, r ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, sig, s ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, sig, r ) ); - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, buf, len ) ); - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, buf, + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, sig, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, sig, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); - memcpy( sig, p, len ); + memmove( sig, p, len ); + memset( sig + len, 0, ssize - len ); *slen = len; return( 0 ); } /* - * Compute and write signature + * Convert a signature from number pair format to ASN.1. + * Zeroize the buffer on error. + */ +int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, + unsigned char *sig, size_t *slen, size_t ssize ) +{ + int ret = internal_ecdsa_signature_to_asn1( r, s, sig, slen, ssize ); + if( ret != 0 ) + memset( sig, 0, ssize ); + return( ret ); +} + +/* + * Compute and write signature. This function assumes that sig is large enough. + * Refer to MBEDTLS_ECDSA_MAX_SIG_LEN for the signature size. */ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hlen, @@ -321,6 +338,7 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t { int ret; mbedtls_mpi r, s; + const size_t ssize = MBEDTLS_ECDSA_MAX_SIG_LEN( ctx->grp.pbits ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s ); @@ -338,7 +356,7 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t hash, hlen, f_rng, p_rng ) ); #endif - MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); + MBEDTLS_MPI_CHK( mbedtls_ecdsa_signature_to_asn1( &r, &s, sig, slen, ssize ) ); cleanup: mbedtls_mpi_free( &r ); diff --git a/library/ecp.c b/library/ecp.c index b41baef27..c88a40e6c 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -51,6 +51,11 @@ #include "mbedtls/ecp.h" #include "mbedtls/threading.h" +#if defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" +#endif + #include #if !defined(MBEDTLS_ECP_ALT) @@ -2059,6 +2064,62 @@ cleanup: return( ret ); } +#if defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) +int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, + unsigned char *p, + size_t size, size_t *olen ) +{ + const char *oid; + unsigned char *q; + size_t oid_length; + int ret; + + *olen = 0; + ret = mbedtls_oid_get_oid_by_ec_grp( grp->id, &oid, &oid_length ); + if( ret != 0 ) + return( ret ); + // Output is a TLV with len(T)=1, len(L)=1, V=OID + if( size < 2 + oid_length ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + q = p + 2 + oid_length; + MBEDTLS_ASN1_CHK_ADD( *olen, mbedtls_asn1_write_oid( &q, p, oid, + oid_length ) ); + if ( p != q ) + return ( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + return ( 0 ); +} + +int mbedtls_ecp_ansi_write_point( const mbedtls_ecp_keypair *ec, + int format, + unsigned char *p, + size_t size, size_t *olen ) +{ + unsigned char *q; + size_t tl_max_size = 3; /* room for the OCTET_STRING tag and length */ + int ret; + + if( size < tl_max_size ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + q = p + tl_max_size; + ret = mbedtls_ecp_point_write_binary( &ec->grp, &ec->Q, + format, + olen, q, size - tl_max_size ); + if( ret < 0 ) + return( ret ); + ret = mbedtls_asn1_write_len( &q, p, *olen ); + if( ret < 0 ) + return( ret ); + ret = mbedtls_asn1_write_tag( &q, p, MBEDTLS_ASN1_OCTET_STRING ); + if( ret < 0 ) + return( ret ); + *olen += tl_max_size - ( q - p ); + if( q != p ) + memmove( p, q, *olen ); + return( 0 ); +} +#endif /* defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) */ + #if defined(MBEDTLS_SELF_TEST) /* diff --git a/library/error.c b/library/error.c index 0292480ae..a86daac59 100644 --- a/library/error.c +++ b/library/error.c @@ -336,6 +336,12 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "PK - The signature is valid but its length is less than expected" ); if( use_ret == -(MBEDTLS_ERR_PK_HW_ACCEL_FAILED) ) mbedtls_snprintf( buf, buflen, "PK - PK hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_PK_INVALID_SIGNATURE) ) + mbedtls_snprintf( buf, buflen, "PK - Invalid signature" ); + if( use_ret == -(MBEDTLS_ERR_PK_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "PK - Output buffer too small" ); + if( use_ret == -(MBEDTLS_ERR_PK_NOT_PERMITTED) ) + mbedtls_snprintf( buf, buflen, "PK - Operation not permitted" ); #endif /* MBEDTLS_PK_C */ #if defined(MBEDTLS_PKCS12_C) diff --git a/library/pk.c b/library/pk.c index b52c73fbc..ac9635cb7 100644 --- a/library/pk.c +++ b/library/pk.c @@ -28,6 +28,7 @@ #if defined(MBEDTLS_PK_C) #include "mbedtls/pk.h" #include "mbedtls/pk_internal.h" +#include "mbedtls/pk_info.h" #if defined(MBEDTLS_RSA_C) #include "mbedtls/rsa.h" @@ -93,6 +94,7 @@ const mbedtls_pk_info_t * mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ) return( &mbedtls_ecdsa_info ); #endif /* MBEDTLS_PK_RSA_ALT omitted on purpose */ + /* MBEDTLS_PK_OPAQUE omitted on purpose: they can't be built by parsing */ default: return( NULL ); } @@ -106,8 +108,11 @@ int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ) if( ctx == NULL || info == NULL || ctx->pk_info != NULL ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); - if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) - return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + if( info->ctx_alloc_func != NULL ) + { + if( ( ctx->pk_ctx = info->ctx_alloc_func( ) ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + } ctx->pk_info = info; @@ -154,7 +159,7 @@ int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ) if( ctx == NULL || ctx->pk_info == NULL ) return( 0 ); - return( ctx->pk_info->can_do( type ) ); + return( ctx->pk_info->can_do( ctx->pk_ctx, type ) ); } /* @@ -311,24 +316,27 @@ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ) { if( pub == NULL || pub->pk_info == NULL || - prv == NULL || prv->pk_info == NULL || - prv->pk_info->check_pair_func == NULL ) + prv == NULL || prv->pk_info == NULL ) { return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); } - if( prv->pk_info->type == MBEDTLS_PK_RSA_ALT ) + if( pub->pk_info == prv->pk_info && pub->pk_ctx == prv->pk_ctx ) + return( 0 ); + + if( prv->pk_info->check_pair_func == NULL ) { - if( pub->pk_info->type != MBEDTLS_PK_RSA ) - return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); - } - else - { - if( pub->pk_info != prv->pk_info ) - return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } - return( prv->pk_info->check_pair_func( pub->pk_ctx, prv->pk_ctx ) ); + if( prv->pk_info->type != MBEDTLS_PK_OPAQUE && + prv->pk_info->type != MBEDTLS_PK_RSA_ALT ) + { + if( pub->pk_info != prv->pk_info ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } + + return( prv->pk_info->check_pair_func( pub, prv ) ); } /* @@ -342,6 +350,20 @@ size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ) return( ctx->pk_info->get_bitlen( ctx->pk_ctx ) ); } +/* + * Maximum signature size + */ +size_t mbedtls_pk_get_signature_size( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->signature_size_func == NULL ) + return( 0 ); + + return( ctx->pk_info->signature_size_func( ctx->pk_ctx ) ); +} + /* * Export debug information */ @@ -369,7 +391,9 @@ const char *mbedtls_pk_get_name( const mbedtls_pk_context *ctx ) } /* - * Access the PK type + * Access the PK type. + * For an opaque key pair object, this does not give any information on the + * underlying cryptographic material. */ mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ) { diff --git a/library/pk_wrap.c b/library/pk_wrap.c index a4bb35fc8..238881e61 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -26,6 +26,7 @@ #endif #if defined(MBEDTLS_PK_C) +#include "mbedtls/pk_info.h" #include "mbedtls/pk_internal.h" /* Even if RSA not activated, for the sake of RSA-alt */ @@ -60,8 +61,9 @@ static void mbedtls_zeroize( void *v, size_t n ) { #endif #if defined(MBEDTLS_RSA_C) -static int rsa_can_do( mbedtls_pk_type_t type ) +static int rsa_can_do( const void *ctx, mbedtls_pk_type_t type ) { + (void) ctx; return( type == MBEDTLS_PK_RSA || type == MBEDTLS_PK_RSASSA_PSS ); } @@ -117,6 +119,12 @@ static int rsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, md_alg, (unsigned int) hash_len, hash, sig ) ); } +static size_t rsa_signature_size( const void *ctx_arg ) +{ + const mbedtls_rsa_context *ctx = ctx_arg; + return( ctx->len ); +} + static int rsa_decrypt_wrap( void *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, size_t osize, @@ -146,10 +154,10 @@ static int rsa_encrypt_wrap( void *ctx, ilen, input, output ) ); } -static int rsa_check_pair_wrap( const void *pub, const void *prv ) +static int rsa_check_pair_wrap( const mbedtls_pk_context *pub, + const mbedtls_pk_context *prv ) { - return( mbedtls_rsa_check_pub_priv( (const mbedtls_rsa_context *) pub, - (const mbedtls_rsa_context *) prv ) ); + return( mbedtls_rsa_check_pub_priv( pub->pk_ctx, prv->pk_ctx ) ); } static void *rsa_alloc_wrap( void ) @@ -186,6 +194,7 @@ const mbedtls_pk_info_t mbedtls_rsa_info = { "RSA", rsa_get_bitlen, rsa_can_do, + rsa_signature_size, rsa_verify_wrap, rsa_sign_wrap, rsa_decrypt_wrap, @@ -201,8 +210,9 @@ const mbedtls_pk_info_t mbedtls_rsa_info = { /* * Generic EC key */ -static int eckey_can_do( mbedtls_pk_type_t type ) +static int eckey_can_do( const void *ctx, mbedtls_pk_type_t type ) { + (void) ctx; return( type == MBEDTLS_PK_ECKEY || type == MBEDTLS_PK_ECKEY_DH || type == MBEDTLS_PK_ECDSA ); @@ -260,12 +270,18 @@ static int eckey_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, return( ret ); } +static size_t ecdsa_signature_size( const void *ctx_arg ) +{ + const mbedtls_ecp_keypair *ctx = ctx_arg; + return( MBEDTLS_ECDSA_MAX_SIG_LEN( ctx->grp.pbits ) ); +} + #endif /* MBEDTLS_ECDSA_C */ -static int eckey_check_pair( const void *pub, const void *prv ) +static int eckey_check_pair( const mbedtls_pk_context *pub, + const mbedtls_pk_context *prv ) { - return( mbedtls_ecp_check_pub_priv( (const mbedtls_ecp_keypair *) pub, - (const mbedtls_ecp_keypair *) prv ) ); + return( mbedtls_ecp_check_pub_priv( pub->pk_ctx, prv->pk_ctx ) ); } static void *eckey_alloc_wrap( void ) @@ -297,11 +313,13 @@ const mbedtls_pk_info_t mbedtls_eckey_info = { eckey_get_bitlen, eckey_can_do, #if defined(MBEDTLS_ECDSA_C) + ecdsa_signature_size, eckey_verify_wrap, eckey_sign_wrap, #else NULL, NULL, + NULL, #endif NULL, NULL, @@ -314,8 +332,9 @@ const mbedtls_pk_info_t mbedtls_eckey_info = { /* * EC key restricted to ECDH */ -static int eckeydh_can_do( mbedtls_pk_type_t type ) +static int eckeydh_can_do( const void *ctx, mbedtls_pk_type_t type ) { + (void) ctx; return( type == MBEDTLS_PK_ECKEY || type == MBEDTLS_PK_ECKEY_DH ); } @@ -329,6 +348,7 @@ const mbedtls_pk_info_t mbedtls_eckeydh_info = { NULL, NULL, NULL, + NULL, eckey_check_pair, eckey_alloc_wrap, /* Same underlying key structure */ eckey_free_wrap, /* Same underlying key structure */ @@ -337,8 +357,9 @@ const mbedtls_pk_info_t mbedtls_eckeydh_info = { #endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_ECDSA_C) -static int ecdsa_can_do( mbedtls_pk_type_t type ) +static int ecdsa_can_do( const void *ctx, mbedtls_pk_type_t type ) { + (void) ctx; return( type == MBEDTLS_PK_ECDSA ); } @@ -388,6 +409,7 @@ const mbedtls_pk_info_t mbedtls_ecdsa_info = { "ECDSA", eckey_get_bitlen, /* Compatible key structures */ ecdsa_can_do, + ecdsa_signature_size, ecdsa_verify_wrap, ecdsa_sign_wrap, NULL, @@ -404,8 +426,9 @@ const mbedtls_pk_info_t mbedtls_ecdsa_info = { * Support for alternative RSA-private implementations */ -static int rsa_alt_can_do( mbedtls_pk_type_t type ) +static int rsa_alt_can_do( const void *ctx, mbedtls_pk_type_t type ) { + (void) ctx; return( type == MBEDTLS_PK_RSA ); } @@ -434,6 +457,13 @@ static int rsa_alt_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, md_alg, (unsigned int) hash_len, hash, sig ) ); } +static size_t rsa_alt_signature_size( const void *ctx ) +{ + const mbedtls_rsa_alt_context *rsa_alt = (const mbedtls_rsa_alt_context *) ctx; + + return( rsa_alt->key_len_func( rsa_alt->key ) ); +} + static int rsa_alt_decrypt_wrap( void *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, size_t osize, @@ -452,26 +482,30 @@ static int rsa_alt_decrypt_wrap( void *ctx, } #if defined(MBEDTLS_RSA_C) -static int rsa_alt_check_pair( const void *pub, const void *prv ) +static int rsa_alt_check_pair( const mbedtls_pk_context *pub, + const mbedtls_pk_context *prv ) { unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; unsigned char hash[32]; size_t sig_len = 0; int ret; - if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub ) ) + if( pub->pk_info->type != MBEDTLS_PK_RSA ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + if( rsa_alt_get_bitlen( prv->pk_ctx ) != rsa_get_bitlen( pub->pk_ctx ) ) return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); memset( hash, 0x2a, sizeof( hash ) ); - if( ( ret = rsa_alt_sign_wrap( (void *) prv, MBEDTLS_MD_NONE, + if( ( ret = rsa_alt_sign_wrap( (void *) prv->pk_ctx, MBEDTLS_MD_NONE, hash, sizeof( hash ), sig, &sig_len, NULL, NULL ) ) != 0 ) { return( ret ); } - if( rsa_verify_wrap( (void *) pub, MBEDTLS_MD_NONE, + if( rsa_verify_wrap( pub->pk_ctx, MBEDTLS_MD_NONE, hash, sizeof( hash ), sig, sig_len ) != 0 ) { return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); @@ -502,6 +536,7 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = { "RSA-alt", rsa_alt_get_bitlen, rsa_alt_can_do, + rsa_alt_signature_size, NULL, rsa_alt_sign_wrap, rsa_alt_decrypt_wrap, diff --git a/library/ssl_srv.c b/library/ssl_srv.c index aca4235e6..a2acf99a3 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -739,7 +739,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_ECDSA_C) if( pk_alg == MBEDTLS_PK_ECDSA && - ssl_check_key_curve( cur->key, ssl->handshake->curves ) != 0 ) + ssl_check_key_curve( &cur->cert->pk, ssl->handshake->curves ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) ); continue; diff --git a/tests/scripts/generate_code.pl b/tests/scripts/generate_code.pl index e489a0055..4c24c7c09 100755 --- a/tests/scripts/generate_code.pl +++ b/tests/scripts/generate_code.pl @@ -111,12 +111,7 @@ my @test_cases_lines = split/^/, ; my $test_cases; my $index = 2; for my $line (@test_cases_lines) { - if ($line =~ /^\/\* BEGIN_SUITE_HELPERS .*\*\//) - { - $line = $line."#line $index \"$test_case_file\"\n"; - } - - if ($line =~ /^\/\* BEGIN_CASE .*\*\//) + if ($line =~ /^\/\* BEGIN_.*\*\//) { $line = $line."#line $index \"$test_case_file\"\n"; } diff --git a/tests/suites/test_suite_ecdsa.function b/tests/suites/test_suite_ecdsa.function index b73095388..8a96c024b 100644 --- a/tests/suites/test_suite_ecdsa.function +++ b/tests/suites/test_suite_ecdsa.function @@ -142,7 +142,7 @@ void ecdsa_write_read_random( int id ) rnd_pseudo_info rnd_info; unsigned char hash[32]; unsigned char sig[200]; - size_t sig_len, i; + size_t sig_len, max_sig_len, i; mbedtls_ecdsa_init( &ctx ); memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) ); @@ -162,8 +162,10 @@ void ecdsa_write_read_random( int id ) TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ), sig, sig_len ) == 0 ); - /* check we didn't write past the announced length */ - for( i = sig_len; i < sizeof( sig ); i++ ) + /* check we didn't write past the maximum length */ + max_sig_len = MBEDTLS_ECDSA_MAX_SIG_LEN( ctx.grp.pbits ); + TEST_ASSERT( sig_len <= max_sig_len ); + for( i = max_sig_len; i < sizeof( sig ); i++ ) TEST_ASSERT( sig[i] == 0x2a ); /* try verification with invalid length */ diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index a43e7d75d..c165d1889 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -30,6 +30,26 @@ ECP curve info #8 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED mbedtls_ecp_curve_info:MBEDTLS_ECP_DP_SECP192R1:19:192:"secp192r1" +ECP write ECParameters OID secp192r1 +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED +ecp_ansi_write_group:MBEDTLS_ECP_DP_SECP192R1:"06082a8648ce3d030101" + +ECP write ECParameters OID secp521r1 +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_ECP_DP_SECP521R1_ENABLED +ecp_ansi_write_group:MBEDTLS_ECP_DP_SECP521R1:"06052b81040023" + +ECP write ECParameters OID brainpoolP512r1 +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_ECP_DP_BP512R1_ENABLED +ecp_ansi_write_group:MBEDTLS_ECP_DP_BP512R1:"06092b240303020801010d" + +ECP write ECPoint octet string (uncompressed) +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED +ecp_ansi_write_point:"data_files/ec_pub.der":MBEDTLS_ECP_PF_UNCOMPRESSED:"043104bc797db3ae7f08ec3d496b4fb411b3f620a558a501e0222d08cfe0dc8aec8b1a7bf24be92951cc5ba1bebb2474909ae0" + +ECP write ECPoint octet string (compressed) +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED +ecp_ansi_write_point:"data_files/ec_pub.der":MBEDTLS_ECP_PF_COMPRESSED:"041902bc797db3ae7f08ec3d496b4fb411b3f620a558a501e0222d" + ECP check pubkey Montgomery #1 (too big) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED ecp_check_pub:MBEDTLS_ECP_DP_CURVE25519:"010000000000000000000000000000000000000000000000000000000000000000":"0":"1":MBEDTLS_ERR_ECP_INVALID_KEY diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 99780c0de..feab0f7de 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1,5 +1,6 @@ /* BEGIN_HEADER */ #include "mbedtls/ecp.h" +#include "mbedtls/pk.h" #define ECP_PF_UNKNOWN -1 /* END_HEADER */ @@ -412,6 +413,70 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C */ +void ecp_ansi_write_group( int id, char *hex ) +{ + mbedtls_ecp_group grp; + unsigned char good[MBEDTLS_ECP_GRP_OID_MAX_SIZE]; + unsigned char tested[MBEDTLS_ECP_GRP_OID_MAX_SIZE]; + size_t good_len = unhexify( good, hex ); + size_t received_len = 0; + int ret = 0; + mbedtls_ecp_group_init( &grp ); + TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 ); + + /* Positive test */ + ret = mbedtls_ecp_ansi_write_group( &grp, tested, sizeof( tested ), + &received_len ); + TEST_ASSERT( ret == 0 && good_len == (unsigned) received_len ); + TEST_ASSERT( memcmp( good, tested, good_len ) == 0 ); + + /* Buffer too small */ + TEST_ASSERT( mbedtls_ecp_ansi_write_group( &grp, tested, good_len - 1, + &received_len ) == + MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + +exit: + mbedtls_ecp_group_free( &grp ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_PK_PARSE_C:MBEDTLS_FS_IO */ +void ecp_ansi_write_point( char *key_file, int format, char *good_hex ) +{ + unsigned char good_buf[1000]; + unsigned char tested_buf[1000]; + size_t good_len = unhexify( good_buf, good_hex ); + size_t received_len = 0; + mbedtls_pk_context pk; + int ret = -1; + mbedtls_pk_init( &pk ); + TEST_ASSERT( mbedtls_pk_parse_public_keyfile( &pk, key_file ) == 0 ); + + /* Positive test */ + ret = mbedtls_ecp_ansi_write_point( mbedtls_pk_ec( pk ), format, + tested_buf, sizeof( tested_buf ), + &received_len ); + TEST_ASSERT( ret == 0 && good_len == (unsigned) received_len ); + TEST_ASSERT( memcmp( good_buf, tested_buf, good_len ) == 0 ); + + /* Buffer too small */ + TEST_ASSERT( mbedtls_ecp_ansi_write_point( mbedtls_pk_ec( pk ), format, + tested_buf, good_len - 1, + &received_len ) == + MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + +exit: + if( ret >= 0 ) + { + unsigned char out[999] = {0}; + hexify( out, tested_buf, ret ); + printf( "== %s ==\n", out ); + } + mbedtls_pk_free( &pk ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mbedtls_ecp_check_privkey( int id, char *key_hex, int ret ) { diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data index cfb4281be..657fdf210 100644 --- a/tests/suites/test_suite_pk.data +++ b/tests/suites/test_suite_pk.data @@ -153,3 +153,20 @@ mbedtls_pk_check_pair:"data_files/ec_256_pub.pem":"data_files/server1.key":MBEDT RSA hash_len overflow (size_t vs unsigned int) depends_on:MBEDTLS_RSA_C:MBEDTLS_HAVE_INT64 pk_rsa_overflow: + +PK opaque mock +depends_on:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C +pk_opaque_mock: + +PK opaque with failed allocation +depends_on:MBEDTLS_RSA_C +pk_opaque_fail_allocation: + +PK opaque minimal +depends_on:MBEDTLS_RSA_C +pk_opaque_minimal: + +#PK opaque wrapper (RSA) +#depends_on:MBEDTLS_RSA_C +#pk_opaque_wrapper: +# diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index e84783667..c190b12ab 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -1,5 +1,8 @@ /* BEGIN_HEADER */ +#include + #include "mbedtls/pk.h" +#include "mbedtls/pk_info.h" /* For error codes */ #include "mbedtls/ecp.h" @@ -39,14 +42,15 @@ static int pk_genkey( mbedtls_pk_context *pk ) } #if defined(MBEDTLS_RSA_C) -int mbedtls_rsa_decrypt_func( void *ctx, int mode, size_t *olen, + +static int mbedtls_rsa_decrypt_func( void *ctx, int mode, size_t *olen, const unsigned char *input, unsigned char *output, size_t output_max_len ) { return( mbedtls_rsa_pkcs1_decrypt( (mbedtls_rsa_context *) ctx, NULL, NULL, mode, olen, input, output, output_max_len ) ); } -int mbedtls_rsa_sign_func( void *ctx, +static int mbedtls_rsa_sign_func( void *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig ) @@ -54,11 +58,270 @@ int mbedtls_rsa_sign_func( void *ctx, return( mbedtls_rsa_pkcs1_sign( (mbedtls_rsa_context *) ctx, f_rng, p_rng, mode, md_alg, hashlen, hash, sig ) ); } -size_t mbedtls_rsa_key_len_func( void *ctx ) +static size_t mbedtls_rsa_key_len_func( void *ctx ) { return( ((const mbedtls_rsa_context *) ctx)->len ); } + +/* Prepare a raw RSA context with a small random key. */ +static void pk_rsa_prepare( mbedtls_rsa_context *raw ) +{ + mbedtls_rsa_init( raw, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE ); +#if defined(MBEDTLS_GENPRIME) + mbedtls_rsa_gen_key( raw, rnd_std_rand, NULL, RSA_KEY_SIZE, 3 ); +#endif +} + +/* Test the RSA context tested_ctx by comparing its operation with a + generic RSA context which is initialized with the key in raw. */ +static void pk_rsa_match( mbedtls_rsa_context *raw, + mbedtls_pk_context *tested_ctx, + int sign_ret, int verify_ret, + int encrypt_ret, int decrypt_ret, + int debug_ret ) +{ + mbedtls_pk_context basic_ctx; + mbedtls_pk_debug_item dbg_items[10]; + unsigned char hash[50], sig[1000]; + unsigned char msg[50], ciph[1000], test[1000]; + size_t sig_len, ciph_len, test_len; + + memset( hash, 0x2a, sizeof( hash ) ); + memset( sig, 0, sizeof( sig ) ); + memset( msg, 0x2a, sizeof( msg ) ); + memset( ciph, 0, sizeof( ciph ) ); + memset( test, 0, sizeof( test ) ); + + /* Initialize basic PK RSA context with raw key */ + mbedtls_pk_init( &basic_ctx ); + TEST_ASSERT( mbedtls_pk_setup( &basic_ctx, + mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == 0 ); + TEST_ASSERT( mbedtls_rsa_copy( mbedtls_pk_rsa( basic_ctx ), raw ) == 0 ); + + /* Test administrative functions */ + TEST_ASSERT( mbedtls_pk_can_do( tested_ctx, MBEDTLS_PK_RSA ) ); + TEST_ASSERT( mbedtls_pk_get_bitlen( tested_ctx ) == RSA_KEY_SIZE ); + TEST_ASSERT( mbedtls_pk_get_len( tested_ctx ) == RSA_KEY_LEN ); + TEST_ASSERT( mbedtls_pk_get_signature_size( tested_ctx ) == RSA_KEY_LEN ); + + /* Test signature */ + TEST_ASSERT( mbedtls_pk_sign( tested_ctx, MBEDTLS_MD_NONE, hash, sizeof( hash ), + sig, &sig_len, rnd_std_rand, NULL ) == sign_ret ); + if( sign_ret == 0 ) + { +#if defined(MBEDTLS_HAVE_INT64) + TEST_ASSERT( mbedtls_pk_sign( tested_ctx, MBEDTLS_MD_NONE, hash, (size_t)-1, + NULL, NULL, rnd_std_rand, NULL ) == + MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* MBEDTLS_HAVE_INT64 */ + TEST_ASSERT( sig_len == RSA_KEY_LEN ); + TEST_ASSERT( mbedtls_pk_verify( &basic_ctx, MBEDTLS_MD_NONE, + hash, sizeof( hash ), sig, sig_len ) == 0 ); + } + + /* Test verification */ + TEST_ASSERT( mbedtls_pk_sign( &basic_ctx, MBEDTLS_MD_NONE, hash, sizeof( hash ), + sig, &sig_len, rnd_std_rand, NULL ) == 0 ); + TEST_ASSERT( mbedtls_pk_verify( tested_ctx, MBEDTLS_MD_NONE, + hash, sizeof( hash ), sig, sig_len ) == verify_ret ); + if( verify_ret == 0 ) + { + TEST_ASSERT( mbedtls_pk_verify( tested_ctx, MBEDTLS_MD_NONE, + hash, sizeof( hash ), sig, sig_len - 1 ) == MBEDTLS_ERR_RSA_VERIFY_FAILED ); + sig[sig_len-1] ^= 1; + TEST_ASSERT( mbedtls_pk_verify( tested_ctx, MBEDTLS_MD_NONE, + hash, sizeof( hash ), sig, sig_len ) == MBEDTLS_ERR_RSA_INVALID_PADDING ); + } + + /* Test encryption */ + TEST_ASSERT( mbedtls_pk_encrypt( tested_ctx, msg, sizeof( msg ), + ciph, &ciph_len, sizeof( ciph ), + rnd_std_rand, NULL ) == encrypt_ret ); + if( encrypt_ret == 0 ) + { + TEST_ASSERT( mbedtls_pk_decrypt( &basic_ctx, ciph, ciph_len, + test, &test_len, sizeof( test ), + rnd_std_rand, NULL ) == 0 ); + TEST_ASSERT( test_len == sizeof( msg ) ); + TEST_ASSERT( memcmp( test, msg, test_len ) == 0 ); + } + + /* Test decryption */ + TEST_ASSERT( mbedtls_pk_encrypt( &basic_ctx, msg, sizeof( msg ), + ciph, &ciph_len, sizeof( ciph ), + rnd_std_rand, NULL ) == 0 ); + TEST_ASSERT( mbedtls_pk_decrypt( tested_ctx, ciph, ciph_len, + test, &test_len, sizeof( test ), + rnd_std_rand, NULL ) == decrypt_ret ); + if( decrypt_ret == 0 ) + { + TEST_ASSERT( test_len == sizeof( msg ) ); + TEST_ASSERT( memcmp( test, msg, test_len ) == 0 ); + } + + /* Test debug */ + TEST_ASSERT( mbedtls_pk_debug( tested_ctx, dbg_items ) == debug_ret ); + +exit: + mbedtls_pk_free( &basic_ctx ); +} + +#define OPAQUE_MOCK_CAN_DO MBEDTLS_PK_RSA +#define OPAQUE_MOCK_BITLEN 'b' +#define OPAQUE_MOCK_MD_ALG MBEDTLS_MD_SHA256 +#define OPAQUE_MOCK_SIGNATURE_SIZE 4 +#define OPAQUE_MOCK_GOOD_SIGNATURE "good" +static const unsigned char opaque_mock_hash[8] = "HASHhash"; +static const unsigned char opaque_mock_reference_input[10] = "INPUTinput"; +static const unsigned char opaque_mock_reference_encrypted[12] = "C:JOQVUjoqvu"; +static const unsigned char opaque_mock_reference_decrypted[12] = "P:HMOTShmots"; +static char opaque_mock_fake_ctx = 'c'; +static mbedtls_pk_debug_item opaque_mock_pk_debug_item; +static int opaque_mock_debug_called_correctly = 0; +static int opaque_mock_free_called_correctly = 0; + +static size_t opaque_mock_get_bitlen( const void *ctx ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + return( OPAQUE_MOCK_BITLEN ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_can_do( const void *ctx, + mbedtls_pk_type_t type ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + return( type == OPAQUE_MOCK_CAN_DO ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_verify_func( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + TEST_ASSERT( md_alg == OPAQUE_MOCK_MD_ALG ); + TEST_ASSERT( hash_len == sizeof( opaque_mock_hash ) ); + TEST_ASSERT( hash == opaque_mock_hash ); + if( sig_len != OPAQUE_MOCK_SIGNATURE_SIZE ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + if( memcmp( sig, OPAQUE_MOCK_GOOD_SIGNATURE, OPAQUE_MOCK_SIGNATURE_SIZE ) ) + return( MBEDTLS_ERR_PK_INVALID_SIGNATURE ); + return( 0 ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_sign_func( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + TEST_ASSERT( md_alg == OPAQUE_MOCK_MD_ALG ); + TEST_ASSERT( hash_len == sizeof( opaque_mock_hash ) ); + TEST_ASSERT( hash == opaque_mock_hash ); + memcpy( sig, OPAQUE_MOCK_GOOD_SIGNATURE, OPAQUE_MOCK_SIGNATURE_SIZE ); + *sig_len = OPAQUE_MOCK_SIGNATURE_SIZE; + (void) f_rng; + (void) p_rng; + return( 0 ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_decrypt_func( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + TEST_ASSERT( ilen == sizeof( opaque_mock_reference_input ) ); + TEST_ASSERT( !memcmp( input, opaque_mock_reference_input, + sizeof( opaque_mock_reference_input ) ) ); + if( osize < sizeof( opaque_mock_reference_decrypted ) ) + return( MBEDTLS_ERR_PK_BUFFER_TOO_SMALL ); + *olen = sizeof( opaque_mock_reference_decrypted ); + memcpy( output, opaque_mock_reference_decrypted, sizeof( opaque_mock_reference_decrypted ) ); + (void) f_rng; + (void) p_rng; + return( 0 ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_encrypt_func( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + TEST_ASSERT( ilen == sizeof( opaque_mock_reference_input ) ); + TEST_ASSERT( !memcmp( input, opaque_mock_reference_input, + sizeof( opaque_mock_reference_input ) ) ); + if( osize < sizeof( opaque_mock_reference_encrypted ) ) + return( MBEDTLS_ERR_PK_BUFFER_TOO_SMALL ); + *olen = sizeof( opaque_mock_reference_encrypted ); + memcpy( output, opaque_mock_reference_encrypted, sizeof( opaque_mock_reference_encrypted ) ); + (void) f_rng; + (void) p_rng; + return( 0 ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_check_pair_func( const mbedtls_pk_context *pub, + const mbedtls_pk_context *prv ) +{ + TEST_ASSERT( prv->pk_ctx == &opaque_mock_fake_ctx ); + if( mbedtls_pk_get_type( pub ) != MBEDTLS_PK_RSA ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + return( 0 ); +exit: + return( INT_MIN ); +} + +static void *opaque_mock_ctx_alloc_func( void ) +{ + return( &opaque_mock_fake_ctx ); +} +static void *opaque_mock_ctx_alloc_fail( void ) +{ + return( NULL ); +} + +static void opaque_mock_ctx_free_func( void *ctx ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + opaque_mock_free_called_correctly = 1; +exit: + return; +} + +static void opaque_mock_debug_func( const void *ctx, + mbedtls_pk_debug_item *items ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + TEST_ASSERT( items == &opaque_mock_pk_debug_item ); + opaque_mock_debug_called_correctly = 1; +exit: + return; +} + +static size_t opaque_mock_signature_size_func( const void *ctx ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + return( OPAQUE_MOCK_SIGNATURE_SIZE ); +exit: + return( -1 ); +} + + #endif /* MBEDTLS_RSA_C */ + /* END_HEADER */ /* BEGIN_DEPENDENCIES @@ -262,17 +525,19 @@ void pk_sign_verify( int type, int sign_ret, int verify_ret ) mbedtls_pk_init( &pk ); - memset( hash, 0x2a, sizeof hash ); - memset( sig, 0, sizeof sig ); + memset( hash, 0x2a, sizeof( hash ) ); + memset( sig, 0, sizeof( sig ) ); TEST_ASSERT( mbedtls_pk_setup( &pk, mbedtls_pk_info_from_type( type ) ) == 0 ); TEST_ASSERT( pk_genkey( &pk ) == 0 ); - TEST_ASSERT( mbedtls_pk_sign( &pk, MBEDTLS_MD_SHA256, hash, sizeof hash, + TEST_ASSERT( mbedtls_pk_sign( &pk, MBEDTLS_MD_SHA256, hash, sizeof( hash ), sig, &sig_len, rnd_std_rand, NULL ) == sign_ret ); + if( sign_ret == 0 ) + TEST_ASSERT( sig_len <= mbedtls_pk_get_signature_size( &pk ) ); TEST_ASSERT( mbedtls_pk_verify( &pk, MBEDTLS_MD_SHA256, - hash, sizeof hash, sig, sig_len ) == verify_ret ); + hash, sizeof( hash ), sig, sig_len ) == verify_ret ); exit: mbedtls_pk_free( &pk ); @@ -449,74 +714,287 @@ void pk_rsa_alt( ) * Test it against the public operations (encrypt, verify) of a * corresponding rsa context. */ + mbedtls_pk_context alt; mbedtls_rsa_context raw; - mbedtls_pk_context rsa, alt; - mbedtls_pk_debug_item dbg_items[10]; - unsigned char hash[50], sig[1000]; - unsigned char msg[50], ciph[1000], test[1000]; - size_t sig_len, ciph_len, test_len; - int ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; - mbedtls_rsa_init( &raw, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE ); - mbedtls_pk_init( &rsa ); mbedtls_pk_init( &alt ); + /* Generate an RSA key to use in both contexts */ + pk_rsa_prepare( &raw ); - memset( hash, 0x2a, sizeof hash ); - memset( sig, 0, sizeof sig ); - memset( msg, 0x2a, sizeof msg ); - memset( ciph, 0, sizeof ciph ); - memset( test, 0, sizeof test ); - - /* Initiliaze PK RSA context with random key */ - TEST_ASSERT( mbedtls_pk_setup( &rsa, - mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == 0 ); - TEST_ASSERT( pk_genkey( &rsa ) == 0 ); - - /* Extract key to the raw rsa context */ - TEST_ASSERT( mbedtls_rsa_copy( &raw, mbedtls_pk_rsa( rsa ) ) == 0 ); - - /* Initialize PK RSA_ALT context */ + /* Set up the alt context with the generated key */ + mbedtls_pk_init( &alt ); TEST_ASSERT( mbedtls_pk_setup_rsa_alt( &alt, (void *) &raw, - mbedtls_rsa_decrypt_func, mbedtls_rsa_sign_func, mbedtls_rsa_key_len_func ) == 0 ); + mbedtls_rsa_decrypt_func, + mbedtls_rsa_sign_func, + mbedtls_rsa_key_len_func ) == 0 ); - /* Test administrative functions */ - TEST_ASSERT( mbedtls_pk_can_do( &alt, MBEDTLS_PK_RSA ) ); - TEST_ASSERT( mbedtls_pk_get_bitlen( &alt ) == RSA_KEY_SIZE ); - TEST_ASSERT( mbedtls_pk_get_len( &alt ) == RSA_KEY_LEN ); + /* Check the metadata in the alt context */ TEST_ASSERT( mbedtls_pk_get_type( &alt ) == MBEDTLS_PK_RSA_ALT ); TEST_ASSERT( strcmp( mbedtls_pk_get_name( &alt ), "RSA-alt" ) == 0 ); - /* Test signature */ - TEST_ASSERT( mbedtls_pk_sign( &alt, MBEDTLS_MD_NONE, hash, sizeof hash, - sig, &sig_len, rnd_std_rand, NULL ) == 0 ); -#if defined(MBEDTLS_HAVE_INT64) - TEST_ASSERT( mbedtls_pk_sign( &alt, MBEDTLS_MD_NONE, hash, (size_t)-1, - NULL, NULL, rnd_std_rand, NULL ) == - MBEDTLS_ERR_PK_BAD_INPUT_DATA ); -#endif /* MBEDTLS_HAVE_INT64 */ - TEST_ASSERT( sig_len == RSA_KEY_LEN ); - TEST_ASSERT( mbedtls_pk_verify( &rsa, MBEDTLS_MD_NONE, - hash, sizeof hash, sig, sig_len ) == 0 ); - - /* Test decrypt */ - TEST_ASSERT( mbedtls_pk_encrypt( &rsa, msg, sizeof msg, - ciph, &ciph_len, sizeof ciph, - rnd_std_rand, NULL ) == 0 ); - TEST_ASSERT( mbedtls_pk_decrypt( &alt, ciph, ciph_len, - test, &test_len, sizeof test, - rnd_std_rand, NULL ) == 0 ); - TEST_ASSERT( test_len == sizeof msg ); - TEST_ASSERT( memcmp( test, msg, test_len ) == 0 ); - - /* Test forbidden operations */ - TEST_ASSERT( mbedtls_pk_encrypt( &alt, msg, sizeof msg, - ciph, &ciph_len, sizeof ciph, - rnd_std_rand, NULL ) == ret ); - TEST_ASSERT( mbedtls_pk_verify( &alt, MBEDTLS_MD_NONE, - hash, sizeof hash, sig, sig_len ) == ret ); - TEST_ASSERT( mbedtls_pk_debug( &alt, dbg_items ) == ret ); + /* Exercise the alt context */ + pk_rsa_match( &raw, &alt, + 0, MBEDTLS_ERR_PK_TYPE_MISMATCH, + MBEDTLS_ERR_PK_TYPE_MISMATCH, 0, + MBEDTLS_ERR_PK_TYPE_MISMATCH ); exit: mbedtls_rsa_free( &raw ); - mbedtls_pk_free( &rsa ); mbedtls_pk_free( &alt ); + mbedtls_pk_free( &alt ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C */ +void pk_opaque_mock( ) +{ + mbedtls_pk_info_t info = + MBEDTLS_PK_OPAQUE_INFO_1( + "mock" + , opaque_mock_get_bitlen + , opaque_mock_can_do + , opaque_mock_signature_size_func + , opaque_mock_verify_func + , opaque_mock_sign_func + , opaque_mock_decrypt_func + , opaque_mock_encrypt_func + , opaque_mock_check_pair_func + , opaque_mock_ctx_alloc_func + , opaque_mock_ctx_free_func + , opaque_mock_debug_func + ); + mbedtls_pk_context ctx; + unsigned char sig[OPAQUE_MOCK_SIGNATURE_SIZE] = OPAQUE_MOCK_GOOD_SIGNATURE; + unsigned char input[sizeof( opaque_mock_reference_input )]; + unsigned char output[sizeof( opaque_mock_reference_decrypted )] = "garbage"; + size_t len; + + mbedtls_pk_init( &ctx ); + TEST_ASSERT( mbedtls_pk_setup( &ctx, &info ) == 0 ); + + TEST_ASSERT( mbedtls_pk_get_type( &ctx ) == MBEDTLS_PK_OPAQUE ); + TEST_ASSERT( mbedtls_pk_get_name( &ctx ) == info.name ); + TEST_ASSERT( mbedtls_pk_get_bitlen( &ctx ) == OPAQUE_MOCK_BITLEN ); + TEST_ASSERT( mbedtls_pk_can_do( &ctx, OPAQUE_MOCK_CAN_DO ) == 1 ); + TEST_ASSERT( mbedtls_pk_can_do( &ctx, OPAQUE_MOCK_CAN_DO ^ 1 ) == 0 ); + TEST_ASSERT( mbedtls_pk_get_signature_size( &ctx ) == OPAQUE_MOCK_SIGNATURE_SIZE ); + + TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, + opaque_mock_hash, sizeof( opaque_mock_hash ), + sig, OPAQUE_MOCK_SIGNATURE_SIZE ) == 0 ); + TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, + opaque_mock_hash, sizeof( opaque_mock_hash ), + sig, OPAQUE_MOCK_SIGNATURE_SIZE - 1 ) == + MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + sig[0] ^= 1; + TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, + opaque_mock_hash, sizeof( opaque_mock_hash ), + sig, OPAQUE_MOCK_SIGNATURE_SIZE ) == + MBEDTLS_ERR_PK_INVALID_SIGNATURE ); + len = -42; + TEST_ASSERT( mbedtls_pk_sign( &ctx, OPAQUE_MOCK_MD_ALG, + opaque_mock_hash, sizeof( opaque_mock_hash ), + sig, &len, NULL, NULL ) == 0 ); + TEST_ASSERT( len == OPAQUE_MOCK_SIGNATURE_SIZE ); + + memcpy( input, opaque_mock_reference_input, + sizeof( opaque_mock_reference_input ) ); + len = -42; + TEST_ASSERT( mbedtls_pk_encrypt( &ctx, input, sizeof( input ), + output, &len, + sizeof( opaque_mock_reference_encrypted ), + NULL, NULL ) == 0); + TEST_ASSERT( memcmp( input, opaque_mock_reference_input, + sizeof( opaque_mock_reference_input ) ) == 0 ); + TEST_ASSERT( len == sizeof( opaque_mock_reference_encrypted ) ); + TEST_ASSERT( memcmp( output, opaque_mock_reference_encrypted, + sizeof( opaque_mock_reference_encrypted ) ) == 0 ); + len = -42; + TEST_ASSERT( mbedtls_pk_decrypt( &ctx, input, sizeof( input ), + output, &len, + sizeof( opaque_mock_reference_decrypted ), + NULL, NULL ) == 0); + TEST_ASSERT( memcmp( input, opaque_mock_reference_input, + sizeof( opaque_mock_reference_input ) ) == 0 ); + TEST_ASSERT( len == sizeof( opaque_mock_reference_decrypted ) ); + TEST_ASSERT( memcmp( output, opaque_mock_reference_decrypted, + sizeof( opaque_mock_reference_decrypted ) ) == 0 ); + + TEST_ASSERT( mbedtls_pk_check_pair( NULL, &ctx ) == + MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + TEST_ASSERT( mbedtls_pk_check_pair( &ctx, &ctx ) == 0 ); + { + mbedtls_pk_context pub; + mbedtls_pk_init( &pub ); + TEST_ASSERT( mbedtls_pk_check_pair( &pub, &ctx ) == + MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + TEST_ASSERT( mbedtls_pk_setup( &pub, + mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == 0 ); + TEST_ASSERT( mbedtls_pk_check_pair( &pub, &ctx ) == 0 ); + mbedtls_pk_free( &pub ); + + TEST_ASSERT( mbedtls_pk_setup( &pub, + mbedtls_pk_info_from_type( MBEDTLS_PK_ECDSA ) ) == 0 ); + TEST_ASSERT( mbedtls_pk_check_pair( &pub, &ctx ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH ); + mbedtls_pk_free( &pub ); +} + + opaque_mock_debug_called_correctly = 0; + TEST_ASSERT( mbedtls_pk_debug( &ctx, &opaque_mock_pk_debug_item ) == 0 ); + TEST_ASSERT( opaque_mock_debug_called_correctly ); + + opaque_mock_free_called_correctly = 0; + mbedtls_pk_free( &ctx ); + TEST_ASSERT( opaque_mock_free_called_correctly ); + return; + +exit: + mbedtls_pk_free( &ctx ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_RSA_C */ +void pk_opaque_minimal( ) +{ + mbedtls_pk_info_t info = + MBEDTLS_PK_OPAQUE_INFO_1( + "mock" + , opaque_mock_get_bitlen + , opaque_mock_can_do + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , opaque_mock_ctx_free_func + , NULL + ); + mbedtls_pk_context ctx; + + mbedtls_pk_init( &ctx ); + TEST_ASSERT( mbedtls_pk_setup( &ctx, &info ) == 0 ); + ctx.pk_ctx = &opaque_mock_fake_ctx; + + TEST_ASSERT( mbedtls_pk_get_type( &ctx ) == MBEDTLS_PK_OPAQUE ); + TEST_ASSERT( mbedtls_pk_get_name( &ctx ) == info.name ); + TEST_ASSERT( mbedtls_pk_get_bitlen( &ctx ) == OPAQUE_MOCK_BITLEN ); + TEST_ASSERT( mbedtls_pk_can_do( &ctx, OPAQUE_MOCK_CAN_DO ) == 1 ); + TEST_ASSERT( mbedtls_pk_can_do( &ctx, OPAQUE_MOCK_CAN_DO ^ 1 ) == 0 ); + TEST_ASSERT( mbedtls_pk_get_signature_size( &ctx ) == 0 ); + + TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, + NULL, 0, NULL, 0 ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH ); + TEST_ASSERT( mbedtls_pk_sign( &ctx, OPAQUE_MOCK_MD_ALG, NULL, 0, + NULL, NULL, NULL, NULL ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH ); + TEST_ASSERT( mbedtls_pk_encrypt( &ctx, NULL, 0, + NULL, NULL, 0, NULL, NULL ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH); + TEST_ASSERT( mbedtls_pk_decrypt( &ctx, NULL, 0, + NULL, NULL, 0, NULL, NULL ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH); + + TEST_ASSERT( mbedtls_pk_check_pair( NULL, &ctx ) == + MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + TEST_ASSERT( mbedtls_pk_check_pair( &ctx, &ctx ) == 0 ); + { + mbedtls_pk_context pub; + mbedtls_pk_init( &pub ); + TEST_ASSERT( mbedtls_pk_setup( &pub, + mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == 0 ); + TEST_ASSERT( mbedtls_pk_check_pair( &pub, &ctx ) == + MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + mbedtls_pk_free( &pub ); +} + + TEST_ASSERT( mbedtls_pk_debug( &ctx, &opaque_mock_pk_debug_item ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + opaque_mock_free_called_correctly = 0; + mbedtls_pk_free( &ctx ); + TEST_ASSERT( opaque_mock_free_called_correctly ); + return; + +exit: + mbedtls_pk_free( &ctx ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_RSA_C */ +void pk_opaque_fail_allocation( ) +{ + mbedtls_pk_info_t info = + MBEDTLS_PK_OPAQUE_INFO_1( + "mock" + , opaque_mock_get_bitlen + , opaque_mock_can_do + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , opaque_mock_ctx_alloc_fail + , NULL + , NULL + ); + mbedtls_pk_context ctx; + mbedtls_pk_init( &ctx ); + TEST_ASSERT( mbedtls_pk_setup( &ctx, &info ) == + MBEDTLS_ERR_PK_ALLOC_FAILED ); + TEST_ASSERT( ctx.pk_info == NULL ); + TEST_ASSERT( ctx.pk_ctx == NULL ); +exit: + mbedtls_pk_free( &ctx ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_RSA_C:MBEDTLS_PK_RSA_ALT_SUPPORT */ +void pk_opaque_wrapper( ) +{ + /* Test an opaque context that's a wrapper around the usual RSA + implementation against an independent raw RSA context. */ + mbedtls_pk_context opaque; + mbedtls_rsa_context raw; + const mbedtls_pk_info_t *mbedtls_rsa_info = + mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); + mbedtls_pk_info_t pk_rsa_opaque_info = + MBEDTLS_PK_OPAQUE_INFO_1( + "RSA-opaque-wrapper" + , mbedtls_rsa_info->get_bitlen + , mbedtls_rsa_info->can_do + , mbedtls_rsa_info->signature_size_func + , mbedtls_rsa_info->verify_func + , mbedtls_rsa_info->sign_func + , mbedtls_rsa_info->decrypt_func + , mbedtls_rsa_info->encrypt_func + , NULL // we don't test check_pair here + , mbedtls_rsa_info->ctx_alloc_func + , mbedtls_rsa_info->ctx_free_func + , mbedtls_rsa_info->debug_func + ); + + /* Generate an RSA key to use in both contexts */ + pk_rsa_prepare( &raw ); + + /* Set up the opaque context with the generated key */ + mbedtls_pk_init( &opaque ); + TEST_ASSERT( mbedtls_pk_setup( &opaque, &pk_rsa_opaque_info ) == 0 ); + mbedtls_rsa_copy( opaque.pk_ctx, &raw ); + + /* Check the metadata in the opaque context */ + TEST_ASSERT( mbedtls_pk_get_type( &opaque ) == MBEDTLS_PK_OPAQUE ); + TEST_ASSERT( strcmp( mbedtls_pk_get_name( &opaque ), + "RSA-opaque-wrapper" ) == 0 ); + + /* Exercise the opaque context */ + pk_rsa_match( &raw, &opaque, 0, 0, 0, 0, 0 ); + +exit: + mbedtls_rsa_free( &raw ); + mbedtls_pk_free( &opaque ); } /* END_CASE */ diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index f13f83cc1..1a55eaaa3 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -191,6 +191,7 @@ +