From: Lukasz Pawelczyk Date: Tue, 12 Apr 2016 11:42:52 +0000 (+0200) Subject: Sign/verify initial implementation. Examples to follow. X-Git-Tag: accepted/tizen/common/20160810.161523~201 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5e2949b23829e35ab7d24e7d5589cb4663ae6835;p=platform%2Fcore%2Fsecurity%2Fyaca.git Sign/verify initial implementation. Examples to follow. Change-Id: I31205fdbb897011b2cf5cbff02acbae396e95205 --- diff --git a/api/yaca/error.h b/api/yaca/error.h index e8d11ed..1e5ee16 100644 --- a/api/yaca/error.h +++ b/api/yaca/error.h @@ -33,7 +33,7 @@ extern "C" { enum __yaca_error_code { YACA_ERROR_INVALID_ARGUMENT = -1, - YACA_ERROR_NOT_IMPLEMENTED= -2, + YACA_ERROR_NOT_IMPLEMENTED = -2, YACA_ERROR_OPENSSL_FAILURE = -3, YACA_ERROR_NOT_SUPPORTED = -4, YACA_ERROR_TOO_BIG_ARGUMENT = -5, diff --git a/src/sign.c b/src/sign.c index 2f37c0f..aee4c8c 100644 --- a/src/sign.c +++ b/src/sign.c @@ -18,52 +18,389 @@ #include -#include -#include +#include #include #include #include "internal.h" +/* Operation type saved in context to recognize what + * type of operation is performed and how to perform it. +*/ +enum sign_op_type { + OP_SIGN = 0, + OP_VERIFY_SYMMETRIC = 1, + OP_VERIFY_ASYMMETRIC = 2 +}; + +struct yaca_sign_ctx_s +{ + struct yaca_ctx_s ctx; + + EVP_MD_CTX *mdctx; + enum sign_op_type op_type; +}; + +static struct yaca_sign_ctx_s *get_sign_ctx(const yaca_ctx_h ctx) +{ + if (ctx == YACA_CTX_NULL) + return NULL; + + switch (ctx->type) + { + case YACA_CTX_SIGN: + return (struct yaca_sign_ctx_s *)ctx; + default: + return NULL; + } +} + +static int get_sign_output_length(const yaca_ctx_h ctx, size_t input_len) +{ + struct yaca_sign_ctx_s *c = get_sign_ctx(ctx); + + if (c == NULL || c->mdctx == NULL || c->mdctx->pctx == NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(c->mdctx->pctx); + if (pkey == NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + size_t len = EVP_PKEY_size(pkey); + if (len <= 0) + return YACA_ERROR_INVALID_ARGUMENT; + + return len; +} + +static void destroy_sign_context(yaca_ctx_h ctx) +{ + struct yaca_sign_ctx_s *c = get_sign_ctx(ctx); + + if (c == NULL) + return; + + EVP_MD_CTX_destroy(c->mdctx); + c->mdctx = NULL; +} + +static int create_sign_pkey(const yaca_key_h key, EVP_PKEY **pkey) +{ + const struct yaca_key_simple_s *simple_key = key_get_simple(key); + const struct yaca_key_evp_s *evp_key = key_get_evp(key); + + if (pkey == NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + if (simple_key != NULL) + { + *pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, + NULL, + (unsigned char *)simple_key->d, + simple_key->bits / 8); + if (*pkey == NULL) + return YACA_ERROR_OPENSSL_FAILURE; + + return 0; + } + + if (evp_key != NULL) + { + *pkey = evp_key->evp; + /* Add a reference so we can free it afterwards anyway */ + CRYPTO_add(&(*pkey)->references, 1, CRYPTO_LOCK_EVP_PKEY); + + return 0; + } + + return YACA_ERROR_INVALID_ARGUMENT; +} + +/* TODO: error checking? + * should DES and IV keys be rejected by us or silently let them work? + */ API int yaca_sign_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo, const yaca_key_h key) { - return YACA_ERROR_NOT_IMPLEMENTED; + struct yaca_sign_ctx_s *nc = NULL; + EVP_PKEY *pkey; + const EVP_MD *md; + int ret; + + if (ctx == NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + ret = create_sign_pkey(key, &pkey); + if (ret != 0) + return ret; + + // TODO: use zalloc when available + nc = yaca_malloc(sizeof(struct yaca_sign_ctx_s)); + if (nc == NULL) { + ret = YACA_ERROR_OUT_OF_MEMORY; + goto free_key; + } + + nc->ctx.type = YACA_CTX_SIGN; + nc->ctx.ctx_destroy = destroy_sign_context; + nc->ctx.get_output_length = get_sign_output_length; + + switch (key->type) + { + case YACA_KEY_TYPE_SYMMETRIC: + case YACA_KEY_TYPE_RSA_PRIV: + nc->op_type = OP_SIGN; + break; + case YACA_KEY_TYPE_DSA_PRIV: + case YACA_KEY_TYPE_ECDSA_PRIV: + ret = YACA_ERROR_NOT_IMPLEMENTED; + goto free_ctx; + default: + ret = YACA_ERROR_INVALID_ARGUMENT; + goto free_ctx; + } + + ret = digest_get_algorithm(algo, &md); + if (ret != 0) + goto free_ctx; + + nc->mdctx = EVP_MD_CTX_create(); + if (nc->mdctx == NULL) { + ret = YACA_ERROR_OPENSSL_FAILURE; + goto free_ctx; + } + + ret = EVP_DigestSignInit(nc->mdctx, NULL, md, NULL, pkey); + if (ret == -2) { + ret = YACA_ERROR_NOT_SUPPORTED; + goto ctx; + } + if (ret != 1) { + ret = YACA_ERROR_OPENSSL_FAILURE; + goto ctx; + } + + *ctx = (yaca_ctx_h)nc; + + ret = 0; + +ctx: + if (ret != 0) + EVP_MD_CTX_destroy(nc->mdctx); +free_ctx: + if (ret != 0) + yaca_free(nc); +free_key: + EVP_PKEY_free(pkey); + + return ret; } API int yaca_sign_update(yaca_ctx_h ctx, const char *data, size_t data_len) { - return YACA_ERROR_NOT_IMPLEMENTED; + struct yaca_sign_ctx_s *c = get_sign_ctx(ctx); + int ret; + + if (c == NULL || c->op_type != OP_SIGN || + data == NULL || data_len == 0) + return YACA_ERROR_INVALID_ARGUMENT; + + ret = EVP_DigestSignUpdate(c->mdctx, data, data_len); + if (ret == -2) + return YACA_ERROR_NOT_SUPPORTED; + if (ret != 1) + return YACA_ERROR_OPENSSL_FAILURE; + + return 0; } API int yaca_sign_final(yaca_ctx_h ctx, char *mac, size_t *mac_len) { - return YACA_ERROR_NOT_IMPLEMENTED; + 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) + return YACA_ERROR_INVALID_ARGUMENT; + + ret = EVP_DigestSignFinal(c->mdctx, (unsigned char *)mac, mac_len); + if (ret == -2) + return YACA_ERROR_NOT_SUPPORTED; + if (ret != 1) + return YACA_ERROR_OPENSSL_FAILURE; + + return 0; } API int yaca_verify_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo, const yaca_key_h key) { - return YACA_ERROR_NOT_IMPLEMENTED; + struct yaca_sign_ctx_s *nc = NULL; + EVP_PKEY *pkey; + const EVP_MD *md; + int ret; + + if (ctx == NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + ret = create_sign_pkey(key, &pkey); + if (ret != 0) + return ret; + + // TODO: use zalloc when available + nc = yaca_malloc(sizeof(struct yaca_sign_ctx_s)); + if (nc == NULL) { + ret = YACA_ERROR_OUT_OF_MEMORY; + goto free_key; + } + + nc->ctx.type = YACA_CTX_SIGN; + nc->ctx.ctx_destroy = destroy_sign_context; + nc->ctx.get_output_length = NULL; + + switch (key->type) + { + case YACA_KEY_TYPE_SYMMETRIC: + nc->op_type = OP_VERIFY_SYMMETRIC; + break; + case YACA_KEY_TYPE_RSA_PUB: + nc->op_type = OP_VERIFY_ASYMMETRIC; + break; + case YACA_KEY_TYPE_DSA_PUB: + case YACA_KEY_TYPE_ECDSA_PUB: + ret = YACA_ERROR_NOT_IMPLEMENTED; + goto free_ctx; + default: + ret = YACA_ERROR_INVALID_ARGUMENT; + goto free_ctx; + } + + ret = digest_get_algorithm(algo, &md); + if (ret < 0) + goto free_ctx; + + nc->mdctx = EVP_MD_CTX_create(); + if (nc->mdctx == NULL) { + ret = YACA_ERROR_OPENSSL_FAILURE; + goto free_ctx; + } + + switch (nc->op_type) + { + case OP_VERIFY_SYMMETRIC: + ret = EVP_DigestSignInit(nc->mdctx, NULL, md, NULL, pkey); + break; + case OP_VERIFY_ASYMMETRIC: + ret = EVP_DigestVerifyInit(nc->mdctx, NULL, md, NULL, pkey); + break; + default: + ret = YACA_ERROR_INVALID_ARGUMENT; + goto ctx; + } + + if (ret == -2) { + ret = YACA_ERROR_NOT_SUPPORTED; + goto ctx; + } + if (ret != 1) { + ret = YACA_ERROR_OPENSSL_FAILURE; + goto ctx; + } + + *ctx = (yaca_ctx_h)nc; + + ret = 0; + +ctx: + if (ret != 0) + EVP_MD_CTX_destroy(nc->mdctx); +free_ctx: + if (ret != 0) + yaca_free(nc); +free_key: + EVP_PKEY_free(pkey); + + return ret; } API int yaca_verify_update(yaca_ctx_h ctx, const char *data, size_t data_len) { - return YACA_ERROR_NOT_IMPLEMENTED; + struct yaca_sign_ctx_s *c = get_sign_ctx(ctx); + int ret; + + if (c == NULL || data == NULL || data_len == 0) + return YACA_ERROR_INVALID_ARGUMENT; + + switch (c->op_type) + { + case OP_VERIFY_SYMMETRIC: + ret = EVP_DigestSignUpdate(c->mdctx, data, data_len); + break; + case OP_VERIFY_ASYMMETRIC: + ret = EVP_DigestVerifyUpdate(c->mdctx, data, data_len); + break; + default: + return YACA_ERROR_INVALID_ARGUMENT; + } + + if (ret == -2) + return YACA_ERROR_NOT_SUPPORTED; + if (ret != 1) + return YACA_ERROR_OPENSSL_FAILURE; + + return 0; } API int yaca_verify_final(yaca_ctx_h ctx, const char *mac, size_t mac_len) { - return YACA_ERROR_NOT_IMPLEMENTED; + struct yaca_sign_ctx_s *c = get_sign_ctx(ctx); + char mac_cmp[mac_len]; + size_t mac_cmp_len = mac_len; + int ret; + + if (c == NULL || mac == NULL || mac_len == 0) + return YACA_ERROR_INVALID_ARGUMENT; + + switch (c->op_type) + { + case OP_VERIFY_SYMMETRIC: + ret = EVP_DigestSignFinal(c->mdctx, + (unsigned char *)mac_cmp, + &mac_cmp_len); + if (ret == -2) + return YACA_ERROR_NOT_SUPPORTED; + if (ret != 1) + return YACA_ERROR_OPENSSL_FAILURE; + + if (mac_len != mac_cmp_len || + CRYPTO_memcmp(mac, mac_cmp, mac_len) != 0) + return YACA_ERROR_SIGNATURE_INVALID; + + return 0; + case OP_VERIFY_ASYMMETRIC: + ret = EVP_DigestVerifyFinal(c->mdctx, + (unsigned char *)mac, + mac_len); + if (ret == 0) + return YACA_ERROR_SIGNATURE_INVALID; + if (ret == -2) + return YACA_ERROR_NOT_SUPPORTED; + if (ret != 1) + return YACA_ERROR_OPENSSL_FAILURE; + + return 0; + default: + return YACA_ERROR_INVALID_ARGUMENT; + } }