From 6d708b68bad86163b9b1393b52bc6e3747adfe6c Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Mon, 13 Jun 2016 16:29:43 +0200 Subject: [PATCH 01/16] Make sure library errors are not treated as fatal Openssl defines a bit flag ERR_R_FATAL = 64 which may be used with common error reasons (ERR_R_...). However, it's possible that library specific error reasons (>99) have the bit set as well. ERR_FATAL_ERROR macro doesn't check it. Check added. Change-Id: I92b8b1011d0d22b84ec7e43f53bc60431cfe17fd --- src/debug.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/debug.c b/src/debug.c index 3778fc9..66ece0e 100644 --- a/src/debug.c +++ b/src/debug.c @@ -35,6 +35,7 @@ // TODO any better idea than to use __thread? static __thread yaca_error_cb error_cb = NULL; static bool error_strings_loaded = false; +static const int GENERIC_REASON_MAX = 99; API void yaca_debug_set_error_cb(yaca_error_cb fn) { @@ -133,8 +134,9 @@ int error_handle(const char *file, int line, const char *function) } /* fatal errors */ - if (ret == YACA_ERROR_NONE && ERR_FATAL_ERROR(err) > 0) { - switch (ERR_GET_REASON(err)) { + int reason = ERR_GET_REASON(err); + if (ret == YACA_ERROR_NONE && reason <= GENERIC_REASON_MAX && ERR_FATAL_ERROR(err) > 0) { + switch (reason) { case ERR_R_MALLOC_FAILURE: ret = YACA_ERROR_OUT_OF_MEMORY; break; -- 2.7.4 From fb6985a9cde6c0af3b33068ac79dc99125ecacab Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Wed, 15 Jun 2016 10:18:12 +0200 Subject: [PATCH 02/16] ACR: Describe yaca_key_bit_length_e values Change-Id: Id51e3f99f9ece8279c338896d66020687ec4fb65 --- api/yaca/yaca_types.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/api/yaca/yaca_types.h b/api/yaca/yaca_types.h index 60c82f9..2d5edc9 100644 --- a/api/yaca/yaca_types.h +++ b/api/yaca/yaca_types.h @@ -109,21 +109,37 @@ typedef enum { * @since_tizen 3.0 */ typedef enum { + /** 24 bits */ YACA_KEY_LENGTH_IV_UNSAFE_24BIT = 24, + /** 64 bits */ YACA_KEY_LENGTH_IV_64BIT = 64, + /** 128 bits */ YACA_KEY_LENGTH_IV_128BIT = 128, + /** 256 bits */ YACA_KEY_LENGTH_IV_256BIT = 256, + /** 8 bits */ YACA_KEY_LENGTH_UNSAFE_8BIT = 8, + /** 40 bits */ YACA_KEY_LENGTH_UNSAFE_40BIT = 40, + /** 64 bits */ YACA_KEY_LENGTH_UNSAFE_64BIT = 64, + /** 80 bits */ YACA_KEY_LENGTH_UNSAFE_80BIT = 80, + /** 128 bits */ YACA_KEY_LENGTH_UNSAFE_128BIT = 128, + /** 192 bits */ YACA_KEY_LENGTH_192BIT = 192, + /** 256 bits */ YACA_KEY_LENGTH_256BIT = 256, + /** 512 bits */ YACA_KEY_LENGTH_512BIT = 512, + /** 1024 bits */ YACA_KEY_LENGTH_1024BIT = 1024, + /** 2048 bits */ YACA_KEY_LENGTH_2048BIT = 2048, + /** 3072 bits */ YACA_KEY_LENGTH_3072BIT = 3072, + /** 4096 bits */ YACA_KEY_LENGTH_4096BIT = 4096 } yaca_key_bit_length_e; -- 2.7.4 From f2b88dbd1879cc6dde334a759d696178e5147532 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Wed, 15 Jun 2016 17:32:31 +0200 Subject: [PATCH 03/16] Make sure output length argument is not NULL Change-Id: I2ed584063314213efba934b282f603ce49f69899 --- src/crypto.c | 2 +- src/digest.c | 2 ++ src/encrypt.c | 2 ++ src/sign.c | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/crypto.c b/src/crypto.c index 6acdc2a..40f6a99 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -291,7 +291,7 @@ API int yaca_context_destroy(yaca_context_h ctx) API int yaca_context_get_output_length(const yaca_context_h ctx, size_t input_len, size_t *output_len) { - if (ctx == YACA_CONTEXT_NULL) + if (ctx == YACA_CONTEXT_NULL || output_len == NULL) return YACA_ERROR_INVALID_PARAMETER; return ctx->get_output_length(ctx, input_len, output_len); diff --git a/src/digest.c b/src/digest.c index 235a0a2..64b88f4 100644 --- a/src/digest.c +++ b/src/digest.c @@ -54,6 +54,8 @@ static int get_digest_output_length(const yaca_context_h ctx, UNUSED size_t input_len, size_t *output_len) { + assert(output_len != NULL); + struct yaca_digest_ctx_s *c = get_digest_ctx(ctx); if (c == NULL) diff --git a/src/encrypt.c b/src/encrypt.c index 7a01f33..5942e2e 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -59,6 +59,8 @@ void destroy_encrypt_context(const yaca_context_h ctx) int get_encrypt_output_length(const yaca_context_h ctx, size_t input_len, size_t *output_len) { + assert(output_len != NULL); + struct yaca_encrypt_context_s *nc = get_encrypt_context(ctx); int block_size; diff --git a/src/sign.c b/src/sign.c index 7be2005..98543e0 100644 --- a/src/sign.c +++ b/src/sign.c @@ -67,6 +67,8 @@ static int get_sign_output_length(const yaca_context_h ctx, UNUSED size_t input_len, size_t *output_len) { + assert(output_len != NULL); + struct yaca_sign_ctx_s *c = get_sign_ctx(ctx); if (c == NULL) -- 2.7.4 From a8cbf719688ff0c8de6d4f3ad647bb6ef63159f1 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Thu, 16 Jun 2016 11:46:08 +0200 Subject: [PATCH 04/16] Do not segfault on contexts without get_output_length (e.g. verify) Change-Id: I0541f8f685b5d02370e67cabf3ea89f5794f0ee5 --- src/crypto.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/crypto.c b/src/crypto.c index 40f6a99..e4c1f29 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -291,7 +291,8 @@ API int yaca_context_destroy(yaca_context_h ctx) API int yaca_context_get_output_length(const yaca_context_h ctx, size_t input_len, size_t *output_len) { - if (ctx == YACA_CONTEXT_NULL || output_len == NULL) + if (ctx == YACA_CONTEXT_NULL || output_len == NULL || + ctx->get_output_length == NULL) return YACA_ERROR_INVALID_PARAMETER; return ctx->get_output_length(ctx, input_len, output_len); -- 2.7.4 From b4888d60c1b69205db39cd46485e158ccb1b49b3 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Thu, 16 Jun 2016 12:55:25 +0200 Subject: [PATCH 05/16] For get_output_length in digest and sign require input_len == 0 Change-Id: If195121b6c56fcd91c6d88d469d213b13b88dcc9 --- api/yaca/yaca_crypto.h | 2 +- src/digest.c | 4 ++-- src/sign.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/yaca/yaca_crypto.h b/api/yaca/yaca_crypto.h index b9d9899..d95a7c2 100644 --- a/api/yaca/yaca_crypto.h +++ b/api/yaca/yaca_crypto.h @@ -259,7 +259,7 @@ int yaca_context_destroy(yaca_context_h ctx); * * @remarks This function can be used to learn the required size of the output buffer * for a single operation (eg. *_update or *_finalize). In case the operation - * has no input (eg. *_finalize), the value of @b input_len should be set to 0. + * has no input (eg. *_finalize), the value of @b input_len has to be set to 0. * * @param[in] ctx Previously initialized crypto context * @param[in] input_len Length of the input data to be processed diff --git a/src/digest.c b/src/digest.c index 64b88f4..b003e97 100644 --- a/src/digest.c +++ b/src/digest.c @@ -51,14 +51,14 @@ static struct yaca_digest_ctx_s *get_digest_ctx(const yaca_context_h ctx) } static int get_digest_output_length(const yaca_context_h ctx, - UNUSED size_t input_len, + size_t input_len, size_t *output_len) { assert(output_len != NULL); struct yaca_digest_ctx_s *c = get_digest_ctx(ctx); - if (c == NULL) + if (c == NULL || input_len != 0) return YACA_ERROR_INVALID_PARAMETER; int md_size = EVP_MD_CTX_size(c->mdctx); diff --git a/src/sign.c b/src/sign.c index 98543e0..5dd261c 100644 --- a/src/sign.c +++ b/src/sign.c @@ -64,14 +64,14 @@ static struct yaca_sign_ctx_s *get_sign_ctx(const yaca_context_h ctx) } static int get_sign_output_length(const yaca_context_h ctx, - UNUSED size_t input_len, + size_t input_len, size_t *output_len) { assert(output_len != NULL); struct yaca_sign_ctx_s *c = get_sign_ctx(ctx); - if (c == NULL) + if (c == NULL || input_len != 0) return YACA_ERROR_INVALID_PARAMETER; assert(c->mdctx != NULL); -- 2.7.4 From c834530d31eb232eda6d38363b7d4a8544e5ef54 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Thu, 16 Jun 2016 12:41:02 +0200 Subject: [PATCH 06/16] Make digest context reusable after finish Change-Id: Iecb125820264470a25fe42e0449c991d7ad3c5bc --- src/digest.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/digest.c b/src/digest.c index b003e97..6062a2b 100644 --- a/src/digest.c +++ b/src/digest.c @@ -204,6 +204,14 @@ API int yaca_digest_finalize(yaca_context_h ctx, char *digest, size_t *digest_le return ret; } + /* Make it reusable */ + ret = c->mdctx->digest->init(c->mdctx); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + return ret; + } + *digest_len = len; return YACA_ERROR_NONE; -- 2.7.4 From d23ceada62bc8cc1d4a3e76100f0101bff37078f Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Fri, 17 Jun 2016 12:48:23 +0200 Subject: [PATCH 07/16] ACR: Modify remarks related to pointer/handle cleanup Change-Id: Id2e9136a8d896ff8036a9aa5096b617454b5c609 --- api/yaca/yaca_crypto.h | 20 ++++++++++++++------ api/yaca/yaca_digest.h | 4 +++- api/yaca/yaca_encrypt.h | 8 ++++++-- api/yaca/yaca_key.h | 16 ++++++++++++---- api/yaca/yaca_seal.h | 14 ++++++++++---- api/yaca/yaca_sign.h | 16 ++++++++++++---- api/yaca/yaca_simple.h | 18 ++++++++++++------ 7 files changed, 69 insertions(+), 27 deletions(-) diff --git a/api/yaca/yaca_crypto.h b/api/yaca/yaca_crypto.h index d95a7c2..17ad90b 100644 --- a/api/yaca/yaca_crypto.h +++ b/api/yaca/yaca_crypto.h @@ -78,6 +78,8 @@ int yaca_cleanup(void); * * @since_tizen 3.0 * + * @remarks The @a memory should be freed using yaca_free() + * * @param[in] size Size of the allocation (bytes) * @param[out] memory Allocated memory * @@ -97,6 +99,8 @@ int yaca_malloc(size_t size, void **memory); * * @since_tizen 3.0 * + * @remarks The @a memory should be freed using yaca_free() + * * @param[in] size Size of the allocation (bytes) * @param[out] memory Allocated memory * @@ -116,11 +120,13 @@ int yaca_zalloc(size_t size, void **memory); * * @since_tizen 3.0 * - * @remarks In case of failure the function doesn't free the memory pointed by @b memory. + * @remarks In case of failure the function doesn't free the memory pointed by @a memory. * - * @remarks If @b *memory is NULL then the call is equivalent to yaca_malloc(). + * @remarks If @a *memory is NULL then the call is equivalent to yaca_malloc(). * - * @remarks If the function fails the contents of @b memory will be left unchanged. + * @remarks If the function fails the contents of @a memory will be left unchanged. + * + * @remarks The @a memory should be freed using yaca_free() * * @param[in] size Size of the new allocation (bytes) * @param[in,out] memory Memory to be reallocated @@ -154,7 +160,7 @@ int yaca_realloc(size_t size, void **memory); int yaca_free(void *memory); /** - * @brief Safely compares first @b len bytes of two buffers. + * @brief Safely compares first @a len bytes of two buffers. * * @since_tizen 3.0 * @@ -214,9 +220,11 @@ int yaca_context_set_property(yaca_context_h ctx, * * @since_tizen 3.0 * + * @remarks The @a value should be freed using yaca_free() + * * @param[in] ctx Previously initialized crypto context * @param[in] property Property to be read - * @param[out] value Copy of the property value (must be freed with yaca_free()) + * @param[out] value Copy of the property value * @param[out] value_len Length of the property value will be returned here * * @return #YACA_ERROR_NONE on success, negative on error @@ -259,7 +267,7 @@ int yaca_context_destroy(yaca_context_h ctx); * * @remarks This function can be used to learn the required size of the output buffer * for a single operation (eg. *_update or *_finalize). In case the operation - * has no input (eg. *_finalize), the value of @b input_len has to be set to 0. + * has no input (eg. *_finalize), the value of @a input_len has to be set to 0. * * @param[in] ctx Previously initialized crypto context * @param[in] input_len Length of the input data to be processed diff --git a/api/yaca/yaca_digest.h b/api/yaca/yaca_digest.h index 622928b..6a66a6f 100644 --- a/api/yaca/yaca_digest.h +++ b/api/yaca/yaca_digest.h @@ -43,7 +43,9 @@ extern "C" { * * @since_tizen 3.0 * - * @param[out] ctx Newly created context (must be freed with yaca_context_destroy()) + * @remarks The @a ctx should be released using yaca_context_destroy() + * + * @param[out] ctx Newly created context * @param[in] algo Digest algorithm that will be used * * @return #YACA_ERROR_NONE on success, negative on error diff --git a/api/yaca/yaca_encrypt.h b/api/yaca/yaca_encrypt.h index c87d048..d2425d4 100644 --- a/api/yaca/yaca_encrypt.h +++ b/api/yaca/yaca_encrypt.h @@ -68,7 +68,9 @@ int yaca_encrypt_get_iv_bit_length(yaca_encrypt_algorithm_e algo, * * @since_tizen 3.0 * - * @param[out] ctx Newly created context (must be freed with yaca_context_destroy()) + * @remarks The @a ctx should be released using yaca_context_destroy() + * + * @param[out] ctx Newly created context * @param[in] algo Encryption algorithm that will be used * @param[in] bcm Chaining mode that will be used * @param[in] sym_key Symmetric key that will be used @@ -152,7 +154,9 @@ int yaca_encrypt_finalize(yaca_context_h ctx, * * @since_tizen 3.0 * - * @param[out] ctx Newly created context (must be freed with yaca_context_destroy()) + * @remarks The @a ctx should be released using yaca_context_destroy() + * + * @param[out] ctx Newly created context * @param[in] algo Encryption algorithm that was used to encrypt the data * @param[in] bcm Chaining mode that was used to encrypt the data * @param[in] sym_key Symmetric key that was used to encrypt the data diff --git a/api/yaca/yaca_key.h b/api/yaca/yaca_key.h index 5f0aa1b..4ad7ff4 100644 --- a/api/yaca/yaca_key.h +++ b/api/yaca/yaca_key.h @@ -95,11 +95,13 @@ int yaca_key_get_bit_length(const yaca_key_h key, size_t *key_bit_len); * used. If it's not known if the key is encrypted one should pass NULL as * password and check for the #YACA_ERROR_INVALID_PASSWORD return code. * + * @remarks The @a key should be released using yaca_key_destroy() + * * @param[in] key_type Type of the key * @param[in] password null terminated password for the key (can be NULL) * @param[in] data Blob containing the key * @param[in] data_len Size of the blob - * @param[out] key Returned key (must be freed with yaca_key_destroy()) + * @param[out] key Returned key * * @return #YACA_ERROR_NONE on success, negative on error * @retval #YACA_ERROR_NONE Successful @@ -183,9 +185,11 @@ int yaca_key_export(const yaca_key_h key, * - RSA: length >= 256bits * - DSA: length >= 512bits, multiple of 64 * + * @remarks The @a key should be released using yaca_key_destroy() + * * @param[in] key_type Type of the key to be generated * @param[in] key_bit_len Length of the key (in bits) to be generated - * @param[out] key Newly generated key (must be freed with yaca_key_destroy()) + * @param[out] key Newly generated key * * @return #YACA_ERROR_NONE on success, negative on error * @retval #YACA_ERROR_NONE Successful @@ -207,8 +211,10 @@ int yaca_key_generate(yaca_key_type_e key_type, * * @since_tizen 3.0 * + * @remarks The @a pub_key should be released using yaca_key_destroy() + * * @param[in] prv_key Private key to extract the public one from - * @param[out] pub_key Extracted public key (must be freed with yaca_key_destroy()) + * @param[out] pub_key Extracted public key * * @return #YACA_ERROR_NONE on success, negative on error * @retval #YACA_ERROR_NONE Successful @@ -252,13 +258,15 @@ int yaca_key_destroy(yaca_key_h key); * * @since_tizen 3.0 * + * @remarks The @a key should be released using yaca_key_destroy() + * * @param[in] password User password as a NULL-terminated string * @param[in] salt Salt, should be a non-empty string * @param[in] salt_len Length of the salt * @param[in] iterations Number of iterations * @param[in] algo Digest algorithm that should be used in key generation * @param[in] key_bit_len Length of a key (in bits) to be generated - * @param[out] key Newly generated key (must be freed with yaca_key_destroy()) + * @param[out] key Newly generated key * * @return #YACA_ERROR_NONE on success, negative on error * @retval #YACA_ERROR_NONE Successful diff --git a/api/yaca/yaca_seal.h b/api/yaca/yaca_seal.h index 2171130..72d090e 100644 --- a/api/yaca/yaca_seal.h +++ b/api/yaca/yaca_seal.h @@ -49,18 +49,22 @@ extern "C" { * so can be ONLY used with yaca_open_initialize(). It can be exported, * but after import it can be ONLY used with yaca_open_initialize() as well. * + * @remarks The @a ctx should be released using yaca_context_destroy() + * + * @remarks The @a sym_key should be released using yaca_key_destroy() + * + * @remarks The @a iv should be released using yaca_key_destroy() + * * @since_tizen 3.0 * - * @param[out] ctx Newly created context (must be freed with yaca_context_destroy()) + * @param[out] ctx Newly created context * @param[in] pub_key Public key of the peer that will receive the encrypted data * @param[in] algo Symmetric algorithm that will be used * @param[in] bcm Block chaining mode for the symmetric algorithm * @param[in] sym_key_bit_len Symmetric key length (in bits) that will be generated * @param[out] sym_key Generated symmetric key that will be used, * it is encrypted with peer's public key - * (must be freed with yaca_key_destroy()) * @param[out] iv Generated initialization vector that will be used - * (must be freed with yaca_key_destroy()) * * @return #YACA_ERROR_NONE on success, negative on error * @retval #YACA_ERROR_NONE Successful @@ -145,7 +149,9 @@ int yaca_seal_finalize(yaca_context_h ctx, * * @since_tizen 3.0 * - * @param[out] ctx Newly created context (must be freed by yaca_context_destroy()) + * @remarks The @a ctx should be released using yaca_context_destroy() + * + * @param[out] ctx Newly created context * @param[in] prv_key Private key, part of the pair that was used for the encryption * @param[in] algo Symmetric algorithm that was used for the encryption * @param[in] bcm Block chaining mode for the symmetric algorithm diff --git a/api/yaca/yaca_sign.h b/api/yaca/yaca_sign.h index 2d9206f..a5267d8 100644 --- a/api/yaca/yaca_sign.h +++ b/api/yaca/yaca_sign.h @@ -46,7 +46,9 @@ extern "C" { * @remarks For verification use yaca_verify_initialize(), yaca_verify_update() and * yaca_verify_finalize() functions with matching public key. * - * @param[out] ctx Newly created context (must be freed with yaca_context_destroy()) + * @remarks The @a ctx should be released using yaca_context_destroy() + * + * @param[out] ctx Newly created context * @param[in] algo Digest algorithm that will be used * @param[in] key Private key that will be used, algorithm is deduced based * on key type, supported key types: @@ -81,7 +83,9 @@ int yaca_sign_initialize(yaca_context_h *ctx, * @remarks For verification, calculate message HMAC and compare with received MAC using * yaca_memcmp(). * - * @param[out] ctx Newly created context (must be freed with yaca_context_destroy()) + * @remarks The @a ctx should be released using yaca_context_destroy() + * + * @param[out] ctx Newly created context * @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, @@ -113,7 +117,9 @@ int yaca_sign_initialize_hmac(yaca_context_h *ctx, * @remarks For verification, calculate message CMAC and compare with received MAC using * yaca_memcmp(). * - * @param[out] ctx Newly created context (must be freed with yaca_context_destroy()) + * @remarks The @a ctx should be released using yaca_context_destroy() + * + * @param[out] ctx Newly created context * @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, @@ -194,7 +200,9 @@ int yaca_sign_finalize(yaca_context_h ctx, * * @since_tizen 3.0 * - * @param[out] ctx Newly created context (must be freed with yaca_context_destroy()) + * @remarks The @a ctx should be released using yaca_context_destroy() + * + * @param[out] ctx Newly created context * @param[in] algo Digest algorithm that will be used * @param[in] key Public key that will be used, algorithm is deduced based on * key type, supported key types: diff --git a/api/yaca/yaca_simple.h b/api/yaca/yaca_simple.h index 5dd2b13..86f2f88 100644 --- a/api/yaca/yaca_simple.h +++ b/api/yaca/yaca_simple.h @@ -50,11 +50,12 @@ extern "C" { * * @since_tizen 3.0 * + * @remarks The @a digest should be freed using yaca_free() + * * @param[in] algo Digest algorithm (select #YACA_DIGEST_SHA256 if unsure) * @param[in] data Data from which the digest is to be calculated * @param[in] data_len Length of the data * @param[out] digest Message digest, will be allocated by the library - * (should be freed with yaca_free()) * @param[out] digest_len Length of message digest (depends on algorithm) * * @return #YACA_ERROR_NONE on success, negative on error @@ -78,6 +79,8 @@ int yaca_simple_calculate_digest(yaca_digest_algorithm_e algo, * * @since_tizen 3.0 * + * @remarks The @a ciphertext should be freed using yaca_free() + * * @param[in] algo Encryption algorithm (select #YACA_ENCRYPT_AES if unsure) * @param[in] bcm Chaining mode (select #YACA_BCM_CBC if unsure) * @param[in] sym_key Symmetric encryption key (see key.h for key generation functions) @@ -85,7 +88,6 @@ int yaca_simple_calculate_digest(yaca_digest_algorithm_e algo, * @param[in] plaintext Plaintext to be encrypted * @param[in] plaintext_len Length of the plaintext * @param[out] ciphertext Encrypted data, will be allocated by the library - * (should be freed with yaca_free()) * @param[out] ciphertext_len Length of the encrypted data (may be larger than decrypted) * * @return #YACA_ERROR_NONE on success, negative on error @@ -114,6 +116,8 @@ int yaca_simple_encrypt(yaca_encrypt_algorithm_e algo, * * @since_tizen 3.0 * + * @remarks The @a plaintext should be freed using yaca_free() + * * @param[in] algo Decryption algorithm that was used to encrypt the data * @param[in] bcm Chaining mode that was used to encrypt the data * @param[in] sym_key Symmetric encryption key that was used to encrypt the data @@ -121,7 +125,6 @@ int yaca_simple_encrypt(yaca_encrypt_algorithm_e algo, * @param[in] ciphertext Ciphertext to be decrypted * @param[in] ciphertext_len Length of ciphertext * @param[out] plaintext Decrypted data, will be allocated by the library - * (should be freed with yaca_free()) * @param[out] plaintext_len Length of the decrypted data * * @return #YACA_ERROR_NONE on success, negative on error @@ -150,6 +153,8 @@ int yaca_simple_decrypt(yaca_encrypt_algorithm_e algo, * * @since_tizen 3.0 * + * @remarks The @a signature should be freed using yaca_free() + * * @param[in] algo Digest algorithm that will be used * @param[in] key Private key that will be used, algorithm is * deduced based on key type, supported key types: @@ -158,7 +163,6 @@ int yaca_simple_decrypt(yaca_encrypt_algorithm_e algo, * @param[in] data Data to be signed * @param[in] data_len Length of the data * @param[out] signature Message signature, will be allocated by the - * library (should be freed with yaca_free()) * @param[out] signature_len Length of the signature * * @return #YACA_ERROR_NONE on success, negative on error @@ -222,6 +226,8 @@ int yaca_simple_verify_signature(yaca_digest_algorithm_e algo, * @remarks For verification, calculate message HMAC and compare with received MAC using * yaca_memcmp(). * + * @remarks The @a mac should be freed using yaca_free() + * * @param[in] algo Digest algorithm that will be used * @param[in] key Key that will be used, supported key types: * - #YACA_KEY_TYPE_SYMMETRIC, @@ -229,7 +235,6 @@ int yaca_simple_verify_signature(yaca_digest_algorithm_e algo, * @param[in] data Data to calculate HMAC from * @param[in] data_len Length of the data * @param[out] mac MAC, will be allocated by the library - * (should be freed with yaca_free()) * @param[out] mac_len Length of the MAC * * @return #YACA_ERROR_NONE on success, negative on error @@ -259,6 +264,8 @@ int yaca_simple_calculate_hmac(yaca_digest_algorithm_e algo, * @remarks For verification, calculate message CMAC and compare with received MAC using * yaca_memcmp(). * + * @remarks The @a mac should be freed using yaca_free() + * * @param[in] algo Encryption algorithm that will be used * @param[in] key Key that will be used, supported key types: * - #YACA_KEY_TYPE_SYMMETRIC, @@ -266,7 +273,6 @@ int yaca_simple_calculate_hmac(yaca_digest_algorithm_e algo, * @param[in] data Data to calculate CMAC from * @param[in] data_len Length of the data * @param[out] mac MAC, will be allocated by the library - * (should be freed with yaca_free()) * @param[out] mac_len Length of the MAC * * @return #YACA_ERROR_NONE on success, negative on error -- 2.7.4 From 6095acfb01f7082a08cedb8268588dcdf22c5dc0 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Tue, 21 Jun 2016 16:18:41 +0200 Subject: [PATCH 08/16] Allow empty input for yaca_simple_caclulate_digest Change-Id: Ibaed61aec9e5370c4521139629a9ac108a6aa3ca --- api/yaca/yaca_simple.h | 4 ++-- src/simple.c | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/api/yaca/yaca_simple.h b/api/yaca/yaca_simple.h index 86f2f88..ecd532a 100644 --- a/api/yaca/yaca_simple.h +++ b/api/yaca/yaca_simple.h @@ -54,13 +54,13 @@ extern "C" { * * @param[in] algo Digest algorithm (select #YACA_DIGEST_SHA256 if unsure) * @param[in] data Data from which the digest is to be calculated - * @param[in] data_len Length of the data + * @param[in] data_len Length of the data. Can be 0. * @param[out] digest Message digest, will be allocated by the library * @param[out] digest_len Length of message digest (depends on algorithm) * * @return #YACA_ERROR_NONE on success, negative on error * @retval #YACA_ERROR_NONE Successful - * @retval #YACA_ERROR_INVALID_PARAMETER Required parameters have incorrect values (NULL, 0 + * @retval #YACA_ERROR_INVALID_PARAMETER Required parameters have incorrect values (NULL, * invalid algo) * @retval #YACA_ERROR_OUT_OF_MEMORY Out of memory error * @retval #YACA_ERROR_INTERNAL Internal error diff --git a/src/simple.c b/src/simple.c index a17f78e..a621281 100644 --- a/src/simple.c +++ b/src/simple.c @@ -44,16 +44,18 @@ API int yaca_simple_calculate_digest(yaca_digest_algorithm_e algo, char *ldigest = NULL; size_t ldigest_len; - if (data == NULL || data_len == 0 || digest == NULL || digest_len == NULL) + if ((data == NULL && data_len > 0) || digest == NULL || digest_len == NULL) return YACA_ERROR_INVALID_PARAMETER; ret = yaca_digest_initialize(&ctx, algo); if (ret != YACA_ERROR_NONE) return ret; - ret = yaca_digest_update(ctx, data, data_len); - if (ret != YACA_ERROR_NONE) - goto exit; + if (data_len > 0) { + ret = yaca_digest_update(ctx, data, data_len); + if (ret != YACA_ERROR_NONE) + goto exit; + } ret = yaca_context_get_output_length(ctx, 0, &ldigest_len); if (ret != YACA_ERROR_NONE) -- 2.7.4 From 938fa5992203c5a409eeed89eef00147cb52ac71 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Tue, 21 Jun 2016 15:14:13 +0200 Subject: [PATCH 09/16] Update digest API description -Add empty message digest remark -Add context reuse remark Change-Id: I255dc403f3f82d4359e56e632607b4d93e811b2f --- api/yaca/yaca_digest.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/api/yaca/yaca_digest.h b/api/yaca/yaca_digest.h index 6a66a6f..f45f25b 100644 --- a/api/yaca/yaca_digest.h +++ b/api/yaca/yaca_digest.h @@ -87,6 +87,13 @@ int yaca_digest_update(yaca_context_h ctx, const char *data, size_t data_len); * * @since_tizen 3.0 * + * @remarks After returning from this function the context is ready to be reused for another + * message digest calculation. There's no need to initialize it again with + * yaca_digest_initialize(). + * + * @remarks Skipping yaca_digest_update() and calling only yaca_digest_finalize() will produce an + * empty message digest. + * * @param[in,out] ctx A valid digest context * @param[out] digest Buffer for the message digest * (must be allocated by client, see yaca_context_get_output_length()) -- 2.7.4 From 9262a1fc34d3efbb4602af5269e3ec12b121c04d Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 21 Jun 2016 15:57:21 +0200 Subject: [PATCH 10/16] Make sure there are no OpenSSL errors logged for key_import() autodetect Change-Id: I850db9d0316bbd5883797195c8358e6aef91297c --- src/debug.c | 1 + src/key.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/debug.c b/src/debug.c index 66ece0e..6babb5f 100644 --- a/src/debug.c +++ b/src/debug.c @@ -125,6 +125,7 @@ int error_handle(const char *file, int line, const char *function) case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED): case ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_READ_BIO, PEM_R_NO_START_LINE): case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG): + case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA): ret = YACA_ERROR_INVALID_PARAMETER; break; case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_BAD_DECRYPT): diff --git a/src/key.c b/src/key.c index 3a70534..a368488 100644 --- a/src/key.c +++ b/src/key.c @@ -301,9 +301,11 @@ int import_evp(yaca_key_h *key, X509 *x509 = PEM_read_bio_X509(src, NULL, cb, (void*)password); if (ERROR_HANDLE() == YACA_ERROR_INVALID_PASSWORD) wrong_pass = true; - if (x509 != NULL) + if (x509 != NULL) { pkey = X509_get_pubkey(x509); - X509_free(x509); + X509_free(x509); + ERROR_CLEAR(); + } private = false; } } -- 2.7.4 From 285b3432bf25b440abf3fc2e6f086266d5b8ffda Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Thu, 23 Jun 2016 14:15:36 +0200 Subject: [PATCH 11/16] Enforce NULL data for empty digest input Change-Id: I7fbd82b9aea2c9c2b712d72e09ac014d2dcf6a2f --- src/simple.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/simple.c b/src/simple.c index a621281..f8f5537 100644 --- a/src/simple.c +++ b/src/simple.c @@ -44,7 +44,8 @@ API int yaca_simple_calculate_digest(yaca_digest_algorithm_e algo, char *ldigest = NULL; size_t ldigest_len; - if ((data == NULL && data_len > 0) || digest == NULL || digest_len == NULL) + if ((data == NULL && data_len > 0) || (data != NULL && data_len == 0) || + digest == NULL || digest_len == NULL) return YACA_ERROR_INVALID_PARAMETER; ret = yaca_digest_initialize(&ctx, algo); -- 2.7.4 From f7315c8ef73915ea64a86f91371724d65257cb5b Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 28 Jun 2016 11:33:57 +0200 Subject: [PATCH 12/16] Drop reusability of digest context Adding reusability to sign/encrypt contexts proved to be too difficult and prone to errors for the feature to be worth altogether. Change-Id: I5aaf1db54c482950cb00079e488433c35b5e1b1b --- api/yaca/yaca_digest.h | 4 ---- src/digest.c | 8 -------- 2 files changed, 12 deletions(-) diff --git a/api/yaca/yaca_digest.h b/api/yaca/yaca_digest.h index f45f25b..0aac56c 100644 --- a/api/yaca/yaca_digest.h +++ b/api/yaca/yaca_digest.h @@ -87,10 +87,6 @@ int yaca_digest_update(yaca_context_h ctx, const char *data, size_t data_len); * * @since_tizen 3.0 * - * @remarks After returning from this function the context is ready to be reused for another - * message digest calculation. There's no need to initialize it again with - * yaca_digest_initialize(). - * * @remarks Skipping yaca_digest_update() and calling only yaca_digest_finalize() will produce an * empty message digest. * diff --git a/src/digest.c b/src/digest.c index 6062a2b..b003e97 100644 --- a/src/digest.c +++ b/src/digest.c @@ -204,14 +204,6 @@ API int yaca_digest_finalize(yaca_context_h ctx, char *digest, size_t *digest_le return ret; } - /* Make it reusable */ - ret = c->mdctx->digest->init(c->mdctx); - if (ret != 1) { - ret = YACA_ERROR_INTERNAL; - ERROR_DUMP(ret); - return ret; - } - *digest_len = len; return YACA_ERROR_NONE; -- 2.7.4 From 87db6df29c3dd37d75cb3d059944a701b4c7f588 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 29 Jun 2016 13:43:09 +0200 Subject: [PATCH 13/16] Handle invalid params properly for simple sign/verify/cmac/hmac Change-Id: I86f0c4d3d1e7766b064fdba3822432569db1283c --- src/simple.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/simple.c b/src/simple.c index f8f5537..f1ee20a 100644 --- a/src/simple.c +++ b/src/simple.c @@ -242,9 +242,11 @@ static int sign(const yaca_context_h ctx, const char *data, size_t data_len, assert(signature != NULL); assert(signature_len != NULL); - ret = yaca_sign_update(ctx, data, data_len); - if (ret != YACA_ERROR_NONE) - return ret; + if (data_len > 0) { + ret = yaca_sign_update(ctx, data, data_len); + if (ret != YACA_ERROR_NONE) + return ret; + } ret = yaca_context_get_output_length(ctx, 0, signature_len); if (ret != YACA_ERROR_NONE) @@ -275,6 +277,10 @@ API int yaca_simple_calculate_signature(yaca_digest_algorithm_e algo, int ret; yaca_context_h ctx = YACA_CONTEXT_NULL; + if ((data == NULL && data_len > 0) || (data != NULL && data_len == 0) || + signature == NULL || signature_len == NULL) + return YACA_ERROR_INVALID_PARAMETER; + ret = yaca_sign_initialize(&ctx, algo, key); if (ret != YACA_ERROR_NONE) return ret; @@ -296,13 +302,19 @@ API int yaca_simple_verify_signature(yaca_digest_algorithm_e algo, int ret; yaca_context_h ctx = YACA_CONTEXT_NULL; + if ((data == NULL && data_len > 0) || (data != NULL && data_len == 0) || + signature == NULL || signature_len == 0) + return YACA_ERROR_INVALID_PARAMETER; + ret = yaca_verify_initialize(&ctx, algo, key); if (ret != YACA_ERROR_NONE) return ret; - ret = yaca_verify_update(ctx, data, data_len); - if (ret != YACA_ERROR_NONE) - goto exit; + if (data_len > 0) { + ret = yaca_verify_update(ctx, data, data_len); + if (ret != YACA_ERROR_NONE) + goto exit; + } ret = yaca_verify_finalize(ctx, signature, signature_len); @@ -322,6 +334,10 @@ API int yaca_simple_calculate_hmac(yaca_digest_algorithm_e algo, int ret; yaca_context_h ctx = YACA_CONTEXT_NULL; + if ((data == NULL && data_len > 0) || (data != NULL && data_len == 0) || + mac == NULL || mac_len == NULL) + return YACA_ERROR_INVALID_PARAMETER; + ret = yaca_sign_initialize_hmac(&ctx, algo, key); if (ret != YACA_ERROR_NONE) return ret; @@ -343,6 +359,10 @@ API int yaca_simple_calculate_cmac(yaca_encrypt_algorithm_e algo, int ret; yaca_context_h ctx = YACA_CONTEXT_NULL; + if ((data == NULL && data_len > 0) || (data != NULL && data_len == 0) || + mac == NULL || mac_len == NULL) + return YACA_ERROR_INVALID_PARAMETER; + ret = yaca_sign_initialize_cmac(&ctx, algo, key); if (ret != YACA_ERROR_NONE) return ret; -- 2.7.4 From 58f6edf6b2707d54b27aa60ff12e921559e6a97a Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Fri, 1 Jul 2016 18:41:25 +0200 Subject: [PATCH 14/16] Missing const in write_file() Change-Id: I31ee04a3643fb85627e533807d6780a86f24447c --- examples/misc.c | 2 +- examples/misc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/misc.c b/examples/misc.c index 693044d..fe3711f 100644 --- a/examples/misc.c +++ b/examples/misc.c @@ -50,7 +50,7 @@ void debug_func(const char *buf) puts(buf); } -int write_file(const char *path, char *data, size_t data_len) +int write_file(const char *path, const char *data, size_t data_len) { size_t written = 0; FILE *f; diff --git a/examples/misc.h b/examples/misc.h index 843aba2..bf8a8e0 100644 --- a/examples/misc.h +++ b/examples/misc.h @@ -30,7 +30,7 @@ void dump_hex(const char *buf, size_t dump_size, const char *fmt, ...); void debug_func(const char *buf); -int write_file(const char *path, char *data, size_t data_len); +int write_file(const char *path, const char *data, size_t data_len); int read_file(const char *path, char **data, size_t *data_len); -- 2.7.4 From 840b872095e3c856ee8987f6cbc7d52796c3cbc9 Mon Sep 17 00:00:00 2001 From: Mateusz Forc Date: Mon, 4 Jul 2016 16:54:19 +0200 Subject: [PATCH 15/16] Changed return type to void Changed yaca_free, yaca_key_destroy, yaca_context_destroy ret type: int->void and respectievely doxygen comments Change-Id: Idfe8e1a17574c66990d81e95c3caed3799595b3f --- api/yaca/yaca_crypto.h | 10 ++-------- api/yaca/yaca_key.h | 5 +---- src/crypto.c | 8 ++------ src/key.c | 4 +--- 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/api/yaca/yaca_crypto.h b/api/yaca/yaca_crypto.h index 17ad90b..baf0315 100644 --- a/api/yaca/yaca_crypto.h +++ b/api/yaca/yaca_crypto.h @@ -150,14 +150,11 @@ int yaca_realloc(size_t size, void **memory); * * @param[in] memory Pointer to the memory to be freed * - * @return #YACA_ERROR_NONE on success - * @retval #YACA_ERROR_NONE Successful - * * @see yaca_malloc() * @see yaca_zalloc() * @see yaca_realloc() */ -int yaca_free(void *memory); +void yaca_free(void *memory); /** * @brief Safely compares first @a len bytes of two buffers. @@ -251,13 +248,10 @@ int yaca_context_get_property(const yaca_context_h ctx, * * @param[in,out] ctx Crypto context * - * @return #YACA_ERROR_NONE on success - * @retval #YACA_ERROR_NONE Successful - * * @see #yaca_context_h * */ -int yaca_context_destroy(yaca_context_h ctx); +void yaca_context_destroy(yaca_context_h ctx); /** * @brief Returns the output length for a given algorithm. Can only be called diff --git a/api/yaca/yaca_key.h b/api/yaca/yaca_key.h index 4ad7ff4..75fb2ca 100644 --- a/api/yaca/yaca_key.h +++ b/api/yaca/yaca_key.h @@ -235,14 +235,11 @@ int yaca_key_extract_public(const yaca_key_h prv_key, yaca_key_h *pub_key); * * @param[in,out] key Key to be freed * - * @return #YACA_ERROR_NONE on success - * @retval #YACA_ERROR_NONE Successful - * * @see yaca_key_import() * @see yaca_key_export() * @see yaca_key_generate() */ -int yaca_key_destroy(yaca_key_h key); +void yaca_key_destroy(yaca_key_h key); /**@}*/ diff --git a/src/crypto.c b/src/crypto.c index e4c1f29..158bcf8 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -235,11 +235,9 @@ API int yaca_realloc(size_t size, void **memory) return YACA_ERROR_NONE; } -API int yaca_free(void *memory) +API void yaca_free(void *memory) { OPENSSL_free(memory); - - return YACA_ERROR_NONE; } API int yaca_randomize_bytes(char *data, size_t data_len) @@ -277,15 +275,13 @@ API int yaca_context_get_property(const yaca_context_h ctx, yaca_property_e prop return ctx->get_param(ctx, property, value, value_len); } -API int yaca_context_destroy(yaca_context_h ctx) +API void yaca_context_destroy(yaca_context_h ctx) { if (ctx != YACA_CONTEXT_NULL) { assert(ctx->ctx_destroy != NULL); ctx->ctx_destroy(ctx); yaca_free(ctx); } - - return YACA_ERROR_NONE; } API int yaca_context_get_output_length(const yaca_context_h ctx, diff --git a/src/key.c b/src/key.c index a368488..2511437 100644 --- a/src/key.c +++ b/src/key.c @@ -1186,7 +1186,7 @@ exit: return ret; } -API int yaca_key_destroy(yaca_key_h key) +API void yaca_key_destroy(yaca_key_h key) { struct yaca_key_simple_s *simple_key = key_get_simple(key); struct yaca_key_evp_s *evp_key = key_get_evp(key); @@ -1198,8 +1198,6 @@ API int yaca_key_destroy(yaca_key_h key) EVP_PKEY_free(evp_key->evp); yaca_free(evp_key); } - - return YACA_ERROR_NONE; } API int yaca_key_derive_pbkdf2(const char *password, -- 2.7.4 From 15d4e181e6f671604ba2a8fe4678ec70e3c79a38 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Thu, 30 Jun 2016 16:32:22 +0200 Subject: [PATCH 16/16] Reworked password handling for import/export - Always use callback. - Return INVALID_PASSWORD for combinations that do support password, it was not required for import but was given in params. - Return INVALID_PARAM for combinations that do not support password while it was given in params. For both, import and export. - PKCS8 always requires a password. - Added few special cases to differentiate INV_PARAM and INV_PASSWORD. Change-Id: I171e89125600151e33178eadc3df6b6004987f3c --- api/yaca/yaca_key.h | 22 ++++++++--- examples/key_password.c | 22 ++++++----- src/debug.c | 28 ++++++++++++- src/key.c | 103 +++++++++++++++++++++++++++++++----------------- todo.txt | 3 +- 5 files changed, 125 insertions(+), 53 deletions(-) diff --git a/api/yaca/yaca_key.h b/api/yaca/yaca_key.h index 75fb2ca..89801ba 100644 --- a/api/yaca/yaca_key.h +++ b/api/yaca/yaca_key.h @@ -95,6 +95,11 @@ int yaca_key_get_bit_length(const yaca_key_h key, size_t *key_bit_len); * used. If it's not known if the key is encrypted one should pass NULL as * password and check for the #YACA_ERROR_INVALID_PASSWORD return code. * + * @remarks If the imported key will be detected as a format that does not support + * encryption and password was passed #YACA_ERROR_INVALID_PARAMETER will + * be returned. For a list of keys and formats that do support encryption + * see yaca_key_export() documentation. + * * @remarks The @a key should be released using yaca_key_destroy() * * @param[in] key_type Type of the key @@ -132,7 +137,7 @@ int yaca_key_import(yaca_key_type_e key_type, * @remarks For key formats two values are allowed: * - #YACA_KEY_FORMAT_DEFAULT: this is the only option possible in case of symmetric * keys (or IV), for asymmetric keys it will choose PKCS#1 - * for RSA and SSLeay for DSA. + * for RSA keys and SSLeay for DSA keys. * - #YACA_KEY_FORMAT_PKCS8: this will only work for private asymmetric keys. * * @remarks The following file formats are supported: @@ -141,11 +146,18 @@ int yaca_key_import(yaca_key_type_e key_type, * - #YACA_KEY_FILE_FORMAT_PEM: used only for asymmetric, PEM file format * - #YACA_KEY_FILE_FORMAT_DER: used only for asymmetric, DER file format * - * @remarks If no password is provided the exported key will be unencrypted. Only private - * RSA/DSA exported as PEM can be encrypted. + * @remarks Encryption is supported and optional for RSA/DSA private keys in the + * #YACA_KEY_FORMAT_DEFAULT with #YACA_KEY_FILE_FORMAT_PEM format. If no password is + * provided the exported key will be unencrypted. The encryption algorithm used + * in this case is AES-256-CBC. + * + * @remarks Encryption is obligatory for #YACA_KEY_FORMAT_PKCS8 format (for both, PEM and DER + * file formats). If no password is provided the #YACA_ERROR_INVALID_PARAMETER will + * be returned. The encryption algorithm used in this case is PBE with DES-CBC. * - * @remarks TODO:document the default encryption algorithm (AES256 for FORMAT_DEFAULT, - * unknown yet for the FORMAT_PKCS8). + * @remakrs Encryption is not supported for the symmetric and public keys in all their + * supported formats. If a password is provided in such case the + * #YACA_ERROR_INVALID_PARAMETER will be returned. * * @param[in] key Key to be exported * @param[in] key_fmt Format of the key diff --git a/examples/key_password.c b/examples/key_password.c index ef40fa2..724e472 100644 --- a/examples/key_password.c +++ b/examples/key_password.c @@ -25,7 +25,8 @@ #include "misc.h" #include "../src/debug.h" -void example_password(const yaca_key_h key, yaca_key_format_e key_fmt) +void example_password(const yaca_key_h key, yaca_key_format_e key_fmt, + yaca_key_file_format_e key_file_fmt) { char *k = NULL; size_t kl; @@ -37,7 +38,9 @@ void example_password(const yaca_key_h key, yaca_key_format_e key_fmt) if (ret != YACA_ERROR_NONE) goto exit; - ret = yaca_key_export(key, key_fmt, YACA_KEY_FILE_FORMAT_PEM, password, &k, &kl); + ret = yaca_key_export(key, key_fmt, key_file_fmt, password, &k, &kl); + if (ret == YACA_ERROR_INVALID_PARAMETER) + printf("invalid parameter, probably a missing password for PKCS8\n"); if (ret != YACA_ERROR_NONE) goto exit; @@ -53,9 +56,6 @@ void example_password(const yaca_key_h key, yaca_key_format_e key_fmt) ret = yaca_key_import(YACA_KEY_TYPE_RSA_PRIV, password, k, kl, &lkey); if (ret == YACA_ERROR_INVALID_PASSWORD) printf("invalid password\n"); - - yaca_free(password); - password = NULL; } if (ret != YACA_ERROR_NONE) @@ -64,7 +64,7 @@ void example_password(const yaca_key_h key, yaca_key_format_e key_fmt) yaca_free(k); k = NULL; - ret = yaca_key_export(lkey, key_fmt, YACA_KEY_FILE_FORMAT_PEM, NULL, &k, &kl); + ret = yaca_key_export(lkey, key_fmt, YACA_KEY_FILE_FORMAT_PEM, password, &k, &kl); if (ret != YACA_ERROR_NONE) goto exit; @@ -91,10 +91,12 @@ int main() if (ret != YACA_ERROR_NONE) goto exit; - printf("Default format:\n"); - example_password(key, YACA_KEY_FORMAT_DEFAULT); - printf("\nPKCS8 format:\n"); - example_password(key, YACA_KEY_FORMAT_PKCS8); + printf("Default format with PEM:\n"); + example_password(key, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM); + printf("\nPKCS8 format with PEM:\n"); + example_password(key, YACA_KEY_FORMAT_PKCS8, YACA_KEY_FILE_FORMAT_PEM); + printf("\nPKCS8 format with DER:\n"); + example_password(key, YACA_KEY_FORMAT_PKCS8, YACA_KEY_FILE_FORMAT_DER); exit: yaca_key_destroy(key); diff --git a/src/debug.c b/src/debug.c index 6babb5f..f510ef3 100644 --- a/src/debug.c +++ b/src/debug.c @@ -26,6 +26,8 @@ #include #include +#include +#include #include @@ -124,12 +126,36 @@ int error_handle(const char *file, int line, const char *function) case ERR_PACK(ERR_LIB_RSA, RSA_F_PKEY_RSA_CTRL, RSA_R_INVALID_KEYBITS): case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED): case ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_READ_BIO, PEM_R_NO_START_LINE): - case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG): case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA): ret = YACA_ERROR_INVALID_PARAMETER; break; + case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_GET_OBJECT, ASN1_R_TOO_LONG): + case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_GET_OBJECT, ASN1_R_HEADER_TOO_LONG): + case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG): + { + bool found_crypto_error = false; + + while ((err = ERR_get_error()) != 0) + if (err == ERR_PACK(ERR_LIB_PKCS12, PKCS12_F_PKCS12_ITEM_DECRYPT_D2I, PKCS12_R_DECODE_ERROR) || + err == ERR_PACK(ERR_LIB_PKCS12, PKCS12_F_PKCS12_PBE_CRYPT, PKCS12_R_PKCS12_CIPHERFINAL_ERROR) || + err == ERR_PACK(ERR_LIB_DSA, DSA_F_OLD_DSA_PRIV_DECODE, ERR_R_DSA_LIB) || + err == ERR_PACK(ERR_LIB_RSA, RSA_F_OLD_RSA_PRIV_DECODE, ERR_R_RSA_LIB)) { + found_crypto_error = true; + break; + } + + if (found_crypto_error) + ret = YACA_ERROR_INVALID_PASSWORD; + else + ret = YACA_ERROR_INVALID_PARAMETER; + + break; + } case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_BAD_DECRYPT): case ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_DO_HEADER, PEM_R_BAD_DECRYPT): + case ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_DO_HEADER, PEM_R_BAD_PASSWORD_READ): + case ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_READ_BIO_PRIVATEKEY, PEM_R_BAD_PASSWORD_READ): + case ERR_PACK(ERR_LIB_PEM, PEM_F_D2I_PKCS8PRIVATEKEY_BIO, PEM_R_BAD_PASSWORD_READ): ret = YACA_ERROR_INVALID_PASSWORD; break; } diff --git a/src/key.c b/src/key.c index 2511437..1a02ce5 100644 --- a/src/key.c +++ b/src/key.c @@ -39,16 +39,32 @@ #include "internal.h" -/* This callback only exists to block the default OpenSSL one and - * allow us to check for a proper error code when the key is encrypted - */ -int password_dummy_cb(char *buf, UNUSED int size, UNUSED int rwflag, UNUSED void *u) +struct openssl_password_data { + bool password_requested; + const char *password; +}; + +int openssl_password_cb(char *buf, int size, UNUSED int rwflag, void *u) { - const char empty[] = ""; + struct openssl_password_data *cb_data = u; + + if (cb_data->password == NULL) + return 0; - memcpy(buf, empty, sizeof(empty)); + size_t pass_len = strlen(cb_data->password); - return sizeof(empty); + if (pass_len > INT_MAX || (int)pass_len > size) + return 0; + + memcpy(buf, cb_data->password, pass_len); + cb_data->password_requested = true; + + return pass_len; +} + +int openssl_password_cb_error(UNUSED char *buf, UNUSED int size, UNUSED int rwflag, UNUSED void *u) +{ + return 0; } int base64_decode_length(const char *data, size_t data_len, size_t *len) @@ -251,9 +267,10 @@ int import_evp(yaca_key_h *key, int ret; BIO *src = NULL; EVP_PKEY *pkey = NULL; - bool wrong_pass = false; - pem_password_cb *cb = NULL; + pem_password_cb *cb = openssl_password_cb; + struct openssl_password_data cb_data = {false, password}; bool private; + bool password_supported; yaca_key_type_e type; struct yaca_key_evp_s *nk = NULL; @@ -274,74 +291,79 @@ int import_evp(yaca_key_h *key, return YACA_ERROR_INTERNAL; } - /* Block the default OpenSSL password callback */ - if (password == NULL) - cb = password_dummy_cb; - /* Possible PEM */ if (strncmp("----", data, 4) == 0) { - if (pkey == NULL && !wrong_pass) { + if (pkey == NULL) { BIO_reset(src); - pkey = PEM_read_bio_PrivateKey(src, NULL, cb, (void*)password); + pkey = PEM_read_bio_PrivateKey(src, NULL, cb, (void*)&cb_data); if (ERROR_HANDLE() == YACA_ERROR_INVALID_PASSWORD) - wrong_pass = true; + return YACA_ERROR_INVALID_PASSWORD; private = true; + password_supported = true; } - if (pkey == NULL && !wrong_pass) { + if (pkey == NULL) { BIO_reset(src); - pkey = PEM_read_bio_PUBKEY(src, NULL, cb, (void*)password); - if (ERROR_HANDLE() == YACA_ERROR_INVALID_PASSWORD) - wrong_pass = true; + pkey = PEM_read_bio_PUBKEY(src, NULL, openssl_password_cb_error, NULL); + ERROR_CLEAR(); private = false; + password_supported = false; } - if (pkey == NULL && !wrong_pass) { + if (pkey == NULL) { BIO_reset(src); - X509 *x509 = PEM_read_bio_X509(src, NULL, cb, (void*)password); - if (ERROR_HANDLE() == YACA_ERROR_INVALID_PASSWORD) - wrong_pass = true; + X509 *x509 = PEM_read_bio_X509(src, NULL, openssl_password_cb_error, NULL); if (x509 != NULL) { pkey = X509_get_pubkey(x509); X509_free(x509); - ERROR_CLEAR(); } + ERROR_CLEAR(); private = false; + password_supported = false; } } /* Possible DER */ else { - if (pkey == NULL && !wrong_pass) { + if (pkey == NULL) { BIO_reset(src); - pkey = d2i_PKCS8PrivateKey_bio(src, NULL, cb, (void*)password); + pkey = d2i_PKCS8PrivateKey_bio(src, NULL, cb, (void*)&cb_data); if (ERROR_HANDLE() == YACA_ERROR_INVALID_PASSWORD) - wrong_pass = true; + return YACA_ERROR_INVALID_PASSWORD; private = true; + password_supported = true; } - if (pkey == NULL && !wrong_pass) { + if (pkey == NULL) { BIO_reset(src); pkey = d2i_PrivateKey_bio(src, NULL); ERROR_CLEAR(); private = true; + password_supported = false; } - if (pkey == NULL && !wrong_pass) { + if (pkey == NULL) { BIO_reset(src); pkey = d2i_PUBKEY_bio(src, NULL); ERROR_CLEAR(); private = false; + password_supported = false; } } BIO_free(src); - if (wrong_pass) - return YACA_ERROR_INVALID_PASSWORD; - if (pkey == NULL) return YACA_ERROR_INVALID_PARAMETER; + /* password was given, but it was not required to perform import */ + if (password != NULL && !cb_data.password_requested) { + if (password_supported) + ret = YACA_ERROR_INVALID_PASSWORD; + else + ret = YACA_ERROR_INVALID_PARAMETER; + goto exit; + } + switch (EVP_PKEY_type(pkey->type)) { case EVP_PKEY_RSA: type = private ? YACA_KEY_TYPE_RSA_PRIV : YACA_KEY_TYPE_RSA_PUB; @@ -503,6 +525,8 @@ int export_evp_default_bio(struct yaca_key_evp_s *evp_key, case YACA_KEY_TYPE_RSA_PUB: case YACA_KEY_TYPE_DSA_PUB: + if (password != NULL) + return YACA_ERROR_INVALID_PARAMETER; ret = PEM_write_bio_PUBKEY(mem, evp_key->evp); break; @@ -521,15 +545,21 @@ int export_evp_default_bio(struct yaca_key_evp_s *evp_key, switch (evp_key->key.type) { case YACA_KEY_TYPE_RSA_PRIV: + if (password != NULL) + return YACA_ERROR_INVALID_PARAMETER; ret = i2d_RSAPrivateKey_bio(mem, EVP_PKEY_get0(evp_key->evp)); break; case YACA_KEY_TYPE_DSA_PRIV: + if (password != NULL) + return YACA_ERROR_INVALID_PARAMETER; ret = i2d_DSAPrivateKey_bio(mem, EVP_PKEY_get0(evp_key->evp)); break; case YACA_KEY_TYPE_RSA_PUB: case YACA_KEY_TYPE_DSA_PUB: + if (password != NULL) + return YACA_ERROR_INVALID_PARAMETER; ret = i2d_PUBKEY_bio(mem, evp_key->evp); break; @@ -567,10 +597,11 @@ int export_evp_pkcs8_bio(struct yaca_key_evp_s *evp_key, assert(mem != NULL); int ret; - int nid = -1; + int nid = NID_pbeWithMD5AndDES_CBC; - if (password != NULL) - nid = NID_pbeWithMD5AndDES_CBC; + /* PKCS8 export requires a password */ + if (password == NULL) + return YACA_ERROR_INVALID_PARAMETER; switch (key_file_fmt) { diff --git a/todo.txt b/todo.txt index e2ef626..c33b5d7 100644 --- a/todo.txt +++ b/todo.txt @@ -7,4 +7,5 @@ Global: - yaca_key_wrap(), yaca_key_unwrap() - We need a way to import keys encrypted with hw (or other) keys. New function like yaca_key_load or sth? -- Add extended description and examples in documentation. \ No newline at end of file +- Add extended description and examples in documentation. +- Check PKCS8 with PKCS5 2.0 (EVP cipher instead of PBE) -- 2.7.4