From: Krzysztof Jackiewicz Date: Tue, 17 May 2016 09:57:12 +0000 (+0200) Subject: Add separate API function stubs for HMAC/CMAC context initialization. X-Git-Tag: accepted/tizen/common/20160810.161523~139 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5e205eca2631457bbbc1af51323cc28586c81bd8;p=platform%2Fcore%2Fsecurity%2Fyaca.git Add separate API function stubs for HMAC/CMAC context initialization. MACs are symmetric equivalent for asymmetric signatures. For asymmetric signatures the signing algorithm can be easily deduced from the key. This is not the case for MAC's where plain symmetric key tells us nothing about the MAC algorithm we want to use. Considered solutions: 1. Introducing new key types for MACs. Cons: - unclear how to handle plain symmetric keys, - introduces an artificial division in symmetric keys, - new enum values, - CMAC cipher has to be set via ctx params. 2. Deducing MAC algorithm from digest algorithm. Digest->HMAC, no digest->CMAC. Cons: - unclear which algorithm will be used, - adding new MAC algorithm may require a significant API change, - CMAC cipher has to be set via ctx params. 3. Leaving CMAC as a digest algorithm. Cons: - CMAC is not a digest algorithm. It's an equivalent of HMAC, RSA, DSA,...etc, - CMAC can't be used for calculating message digest alone, - CMAC can't be used as a digest algorithm for HMAC - CMAC cipher has to be set via ctx params. 4. Adding new API for CMAC and HMAC context creation. Cons: - 1 new functions per MAC algo for context initalization, - 1 function for signature comparison - low API flexibility This is an initial commit for solution 4. Change-Id: I745854fd7b7d87f2c114475b709566ec512d7bbd --- diff --git a/api/yaca/crypto.h b/api/yaca/crypto.h index 9959df0..76a2897 100644 --- a/api/yaca/crypto.h +++ b/api/yaca/crypto.h @@ -181,6 +181,17 @@ int yaca_get_output_length(const yaca_ctx_h ctx, size_t input_len, size_t *outpu */ #define yaca_get_block_length(ctxa, output_len) yaca_get_output_length((ctxa), 0, (output_len)) +/** + * @brief Safely compares first @b len bytes of two buffers. + * + * @param[in] first Pointer to the first buffer. + * @param[in] second Pointer to the second buffer. + * @param[in] len Length to compare. + * + * @return 0 when buffers are equal otherwise #YACA_ERROR_DATA_MISMATCH + */ +int yaca_memcmp(const void *first, const void *second, size_t len); + /**@}*/ #ifdef __cplusplus diff --git a/api/yaca/error.h b/api/yaca/error.h index 22030dd..8aa150b 100644 --- a/api/yaca/error.h +++ b/api/yaca/error.h @@ -44,7 +44,7 @@ enum __yaca_error_code { YACA_ERROR_INTERNAL = -3, YACA_ERROR_TOO_BIG_ARGUMENT = -4, YACA_ERROR_OUT_OF_MEMORY = -5, - YACA_ERROR_SIGNATURE_INVALID = -6, + YACA_ERROR_DATA_MISMATCH = -6, YACA_ERROR_PASSWORD_INVALID = -7 }; diff --git a/api/yaca/sign.h b/api/yaca/sign.h index f018a31..9dcbe43 100644 --- a/api/yaca/sign.h +++ b/api/yaca/sign.h @@ -41,57 +41,115 @@ extern "C" { */ /** - * @brief Initializes a signature context. + * @brief Initializes a signature context for asymmetric signatures. + * + * For verification use yaca_verify_init(), yaca_verify_update() and + * yaca_verify_final() functions with matching public key. * * @param[out] ctx Newly created context (must be freed with yaca_ctx_free()). * @param[in] algo Digest algorithm that will be used. - * @param[in] key Private or symmetric key that will be used (algorithm is deduced based on key type). + * @param[in] key Private key that will be used. Algorithm is deduced based + * on key type. Supported key types: + * - #YACA_KEY_TYPE_RSA_PRIV, + * - #YACA_KEY_TYPE_DSA_PRIV, + * - #YACA_KEY_TYPE_ECDSA_PRIV. * * @return 0 on success, negative on error. - * @see #yaca_digest_algo_e, yaca_sign_update(), yaca_sign_final() + * @see #yaca_key_type_e, #yaca_digest_algo_e, yaca_sign_update(), + * yaca_sign_final(), yaca_verify_init(), yaca_verify_update(), + * yaca_verify_final() */ int yaca_sign_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo, const yaca_key_h key); /** - * @brief Feeds the data into the digital signature algorithm. + * @brief Initializes a signature context for HMAC. + * + * For verification, calculate message HMAC and compare with received MAC using + * yaca_memcmp(). + * + * @param[out] ctx Newly created context (must be freed with yaca_ctx_free()). + * @param[in] algo Digest algorithm that will be used. + * @param[in] key Symmetric key that will be used. Supported key types: + * - #YACA_KEY_TYPE_SYMMETRIC, + * - #YACA_KEY_TYPE_DES. + * + * @return 0 on success, negative on error. + * @see #yaca_key_type_e, #yaca_digest_algo_e, yaca_sign_update(), + * yaca_sign_final(), yaca_memcmp() + */ +int yaca_sign_hmac_init(yaca_ctx_h *ctx, + yaca_digest_algo_e algo, + const yaca_key_h key); + +/** + * @brief Initializes a signature context for CMAC. * - * @param[in,out] ctx Context created by yaca_sign_init(). + * For verification, calculate message CMAC and compare with received MAC using + * yaca_memcmp(). + * + * @param[out] ctx Newly created context (must be freed with yaca_ctx_free()). + * @param[in] algo Encryption algorithm that will be used. + * @param[in] key Symmetric key that will be used. Supported key types: + * - #YACA_KEY_TYPE_SYMMETRIC, + * - #YACA_KEY_TYPE_DES. + * + * @return 0 on success, negative on error. + * @see #yaca_key_type_e, #yaca_enc_algo_e, yaca_sign_update(), + * yaca_sign_final(), yaca_memcmp() + */ +int yaca_sign_cmac_init(yaca_ctx_h *ctx, + yaca_enc_algo_e algo, + const yaca_key_h key); + +/** + * @brief Feeds the data into the digital signature or MAC algorithm. + * + * @param[in,out] ctx Context created by yaca_sign_init(), + * yaca_sign_hmac_init() or yaca_sign_cmac_init(). * @param[in] data Data to be signed. * @param[in] data_len Length of the data. * * @return 0 on success, negative on error. - * @see yaca_sign_init(), yaca_sign_final() + * @see yaca_sign_init(), yaca_sign_final(), yaca_sign_hmac_init(), + * yaca_sign_cmac_init() */ int yaca_sign_update(yaca_ctx_h ctx, const char *data, size_t data_len); /** - * @brief Calculates the final signature. + * @brief Calculates the final signature or MAC. * - * @param[in,out] ctx A valid sign context. - * @param[out] mac Buffer for the MAC or the signature (must be allocated by client, see - * yaca_get_sign_length()). - * @param[out] mac_len Length of the MAC or the signature, actual number of bytes written will be returned here. + * @param[in,out] ctx A valid sign context. + * @param[out] signature Buffer for the MAC or the signature, + * (must be allocated by client, see yaca_get_sign_length()). + * @param[out] signature_len Length of the MAC or the signature, + * actual number of bytes written will be returned here. * * @return 0 on success, negative on error. - * @see yaca_sign_init(), yaca_sign_update() + * @see yaca_sign_init(), yaca_sign_update(), yaca_sign_hmac_init(), + * yaca_sign_cmac_init() */ int yaca_sign_final(yaca_ctx_h ctx, - char *mac, - size_t *mac_len); + char *signature, + size_t *signature_len); /** - * @brief Initializes a signature verification context. + * @brief Initializes a signature verification context for asymmetric signatures * * @param[out] ctx Newly created context (must be freed with yaca_ctx_free()). * @param[in] algo Digest algorithm that will be used. - * @param[in] key Private or symmetric key that will be used (algorithm is deduced based on key type). + * @param[in] key Public key that will be used. Algorithm is deduced based on + * key type. Supported key types: + * - #YACA_KEY_TYPE_RSA_PUB, + * - #YACA_KEY_TYPE_DSA_PUB, + * - #YACA_KEY_TYPE_ECDSA_PUB. * * @return 0 on success, negative on error. - * @see #yaca_digest_algo_e, yaca_verify_update(), yaca_verify_final() + * @see #yaca_key_type_e, #yaca_digest_algo_e, yaca_verify_update(), + * yaca_verify_final() */ int yaca_verify_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo, @@ -114,16 +172,17 @@ int yaca_verify_update(yaca_ctx_h ctx, /** * @brief Performs the verification. * - * @param[in,out] ctx A valid verify context. - * @param[in] mac Input MAC or signature (returned by yaca_sign_final()). - * @param[in] mac_len Size of the MAC or the signature. + * @param[in,out] ctx A valid verify context. + * @param[in] signature Input signature (returned by yaca_sign_final()). + * @param[in] signature_len Size of the signature. * - * @return 0 on success, negative on error. + * @return 0 on success, YACA_ERROR_DATA_MISMATCH if verification fails, + * negative on error. * @see yaca_verify_init(), yaca_verify_update() */ int yaca_verify_final(yaca_ctx_h ctx, - const char *mac, - size_t mac_len); + const char *signature, + size_t signature_len); /**@}*/ diff --git a/src/crypto.c b/src/crypto.c index df5ba7d..bca42a8 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -127,3 +127,11 @@ API int yaca_get_output_length(const yaca_ctx_h ctx, size_t input_len, size_t *o return ctx->get_output_length(ctx, input_len, output_len); } + +API int yaca_memcmp(const void *first, const void *second, size_t len) +{ + if (CRYPTO_memcmp(first, second, len) == 0) + return 0; + + return YACA_ERROR_DATA_MISMATCH; +} diff --git a/src/sign.c b/src/sign.c index 9573c4c..e47c839 100644 --- a/src/sign.c +++ b/src/sign.c @@ -356,17 +356,17 @@ API int yaca_sign_update(yaca_ctx_h ctx, } API int yaca_sign_final(yaca_ctx_h ctx, - char *mac, - size_t *mac_len) + char *signature, + size_t *signature_len) { struct yaca_sign_ctx_s *c = get_sign_ctx(ctx); int ret; if (c == NULL || c->op_type != OP_SIGN || - mac == NULL || mac_len == NULL || *mac_len == 0) + signature == NULL || signature_len == NULL || *signature_len == 0) return YACA_ERROR_INVALID_ARGUMENT; - ret = EVP_DigestSignFinal(c->mdctx, (unsigned char *)mac, mac_len); + ret = EVP_DigestSignFinal(c->mdctx, (unsigned char *)signature, signature_len); if(ret != 1) { ret = YACA_ERROR_INTERNAL; ERROR_DUMP(ret); @@ -499,15 +499,15 @@ API int yaca_verify_update(yaca_ctx_h ctx, } API int yaca_verify_final(yaca_ctx_h ctx, - const char *mac, - size_t mac_len) + const char *signature, + size_t signature_len) { struct yaca_sign_ctx_s *c = get_sign_ctx(ctx); - char mac_cmp[mac_len]; - size_t mac_cmp_len = mac_len; + char mac_cmp[signature_len]; + size_t mac_cmp_len = signature_len; int ret; - if (c == NULL || mac == NULL || mac_len == 0) + if (c == NULL || signature == NULL || signature_len == 0) return YACA_ERROR_INVALID_ARGUMENT; switch (c->op_type) @@ -522,19 +522,19 @@ API int yaca_verify_final(yaca_ctx_h ctx, return ret; } - if (mac_len != mac_cmp_len || CRYPTO_memcmp(mac, mac_cmp, mac_len) != 0) - return YACA_ERROR_SIGNATURE_INVALID; + if (signature_len != mac_cmp_len || CRYPTO_memcmp(signature, mac_cmp, signature_len) != 0) + return YACA_ERROR_DATA_MISMATCH; return 0; case OP_VERIFY_ASYMMETRIC: ret = EVP_DigestVerifyFinal(c->mdctx, - (unsigned char *)mac, - mac_len); + (unsigned char *)signature, + signature_len); if (ret == 1) return 0; if (ret == 0) - ret = YACA_ERROR_SIGNATURE_INVALID; + ret = YACA_ERROR_DATA_MISMATCH; else ret = YACA_ERROR_INTERNAL;