From 04e0b98b70502efc859928d0704627bb7f59e768 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 20 Apr 2016 16:35:44 +0200 Subject: [PATCH 01/16] API changes around key_import and key_export key_import will autodetect key_format and key_file_format. Only the expected key_type is required. key_export needs to have key_format and key_file_format explicitly given (obviously). It will get the key_type from the key. Change-Id: I6a8e04c886f6acd95dc124918606fbad992108c2 --- api/yaca/key.h | 45 +++++++++++++++++++++++++++++++++++---------- examples/encrypt_aes_gcm.c | 2 +- examples/key_exchange.c | 5 ++--- examples/test.c | 2 +- src/key.c | 8 ++++---- 5 files changed, 43 insertions(+), 19 deletions(-) diff --git a/api/yaca/key.h b/api/yaca/key.h index dd1dbe8..3a829d5 100644 --- a/api/yaca/key.h +++ b/api/yaca/key.h @@ -53,19 +53,29 @@ extern "C" { int yaca_key_get_bits(const yaca_key_h key); /** - * @brief yaca_key_import Imports a key from the arbitrary format. + * @brief yaca_key_import Imports a key. * - * @param[out] key Returned key (must be freed with yaca_key_free()). - * @param[in] key_file_fmt Format of the key file. - * @param[in] key_type Type of the key. - * @param[in] data Blob containing the key. - * @param[in] data_len Size of the blob. + * This function imports a key trying to match it to the key_type specified. + * It should autodetect both, key format and file format. + * + * For symmetric, IV and DES keys RAW binary format and BASE64 encoded + * binary format are supported. + * For asymmetric keys PEM and DER file formats are supported. + * + * Asymmetric keys can be in PKCS#1 or SSleay key formats (for RSA and + * DSA respectively). Asymmetric private keys can also be in PKCS#8 + * format. Additionally it is possible to import public RSA key from + * X509 certificate. + * + * @param[out] key Returned key (must be freed with yaca_key_free()). + * @param[in] key_type Type of the key. + * @param[in] data Blob containing the key. + * @param[in] data_len Size of the blob. * * @return 0 on success, negative on error. - * @see #yaca_key_fmt_e, #yaca_key_type_e, yaca_key_export(), yaca_key_free() + * @see #yaca_key_type_e, yaca_key_export(), yaca_key_free() */ int yaca_key_import(yaca_key_h *key, - yaca_key_file_fmt_e key_file_fmt, yaca_key_type_e key_type, const char *data, size_t data_len); @@ -73,16 +83,31 @@ int yaca_key_import(yaca_key_h *key, /** * @brief yaca_key_export Exports a key to arbitrary format. Export may fail if key is HW-based. * + * This function exports the key to an arbitrary key format and key file format. + * + * 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. + * - #YACA_KEY_FORMAT_PKCS8: this will only work for private asymmetric keys. + * + * The following file formats are supported: + * - #YACA_KEY_FILE_FORMAT_RAW: used only for symmetric, raw binary format + * - #YACA_KEY_FILE_FORMAT_BASE64: used only for symmetric, BASE64 encoded binary form + * - #YACA_KEY_FILE_FORMAT_PEM: used only for asymmetric, PEM file format + * - #YACA_KEY_FILE_FORMAT_DER: used only for asymmetric, DER file format + * * @param[in] key Key to be exported. - * @param[in] key_file_fmt Format of the key. + * @param[in] key_fmt Format of the key. + * @param[in] key_file_fmt Format of the key file. * @param[out] data Data, allocated by the library, containing exported key * (must be freed with yaca_free()). * @param[out] data_len Size of the output data. * * @return 0 on success, negative on error. - * @see #yaca_key_fmt_e, yaca_key_import(), yaca_key_free() + * @see #yaca_key_fmt_e, #yaca_key_file_fmt_e, yaca_key_import(), yaca_key_free() */ int yaca_key_export(const yaca_key_h key, + yaca_key_fmt_e key_fmt, yaca_key_file_fmt_e key_file_fmt, char **data, size_t *data_len); diff --git a/examples/encrypt_aes_gcm.c b/examples/encrypt_aes_gcm.c index 17c51ff..9bc60fe 100644 --- a/examples/encrypt_aes_gcm.c +++ b/examples/encrypt_aes_gcm.c @@ -71,7 +71,7 @@ void encrypt_decrypt_aes_gcm(void) goto clean; // generate and export aad? - ret = yaca_key_export(aad_key, YACA_KEY_FILE_FORMAT_RAW, &aad, &aad_len); + ret = yaca_key_export(aad_key, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_RAW, &aad, &aad_len); if (ret < 0) goto clean; diff --git a/examples/key_exchange.c b/examples/key_exchange.c index edbcd5d..9192679 100644 --- a/examples/key_exchange.c +++ b/examples/key_exchange.c @@ -67,8 +67,7 @@ void key_exchange_dh(void) if (1 != fread(buffer, size, 1, fp)) goto clean; - ret = yaca_key_import(&peer_key, - YACA_KEY_FILE_FORMAT_RAW, YACA_KEY_TYPE_DH_PUB, + ret = yaca_key_import(&peer_key, YACA_KEY_TYPE_DH_PUB, buffer, size); if (ret < 0) goto clean; @@ -124,7 +123,7 @@ void key_exchange_ecdh(void) if (1 != fread(buffer, size, 1, fp)) goto clean; - ret = yaca_key_import(&peer_key, YACA_KEY_FILE_FORMAT_RAW, YACA_KEY_TYPE_ECDH_PUB, buffer, size); + ret = yaca_key_import(&peer_key, YACA_KEY_TYPE_ECDH_PUB, buffer, size); if (ret < 0) goto clean; diff --git a/examples/test.c b/examples/test.c index a26148a..6f1bdf4 100644 --- a/examples/test.c +++ b/examples/test.c @@ -45,7 +45,7 @@ int main(int argc, char* argv[]) printf("done (%d)\n", ret); printf("Exporting key using CryptoAPI.. "); - ret = yaca_key_export(key, YACA_KEY_FILE_FORMAT_RAW, &k, &kl); + ret = yaca_key_export(key, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_RAW, &k, &kl); if (ret < 0) return ret; printf("done (%d)\n", ret); diff --git a/src/key.c b/src/key.c index eacaccd..1aba0d3 100644 --- a/src/key.c +++ b/src/key.c @@ -123,7 +123,6 @@ API int yaca_key_get_bits(const yaca_key_h key) } API int yaca_key_import(yaca_key_h *key, - yaca_key_file_fmt_e key_file_fmt, yaca_key_type_e key_type, const char *data, size_t data_len) @@ -131,9 +130,6 @@ API int yaca_key_import(yaca_key_h *key, if (key == NULL || data == NULL || data_len == 0) return YACA_ERROR_INVALID_ARGUMENT; - if (key_file_fmt != YACA_KEY_FILE_FORMAT_RAW) - return YACA_ERROR_NOT_IMPLEMENTED; - if (key_type == YACA_KEY_TYPE_SYMMETRIC) { struct yaca_key_simple_s *nk = NULL; @@ -164,6 +160,7 @@ API int yaca_key_import(yaca_key_h *key, } API int yaca_key_export(const yaca_key_h key, + yaca_key_fmt_e key_fmt, yaca_key_file_fmt_e key_file_fmt, char **data, size_t *data_len) @@ -175,6 +172,9 @@ API int yaca_key_export(const yaca_key_h key, if (data == NULL || data_len == NULL) return YACA_ERROR_INVALID_ARGUMENT; + if (key_fmt != YACA_KEY_FORMAT_DEFAULT) + return YACA_ERROR_NOT_IMPLEMENTED; + if (key_file_fmt != YACA_KEY_FILE_FORMAT_RAW) return YACA_ERROR_NOT_IMPLEMENTED; -- 2.7.4 From 782ce7f8fe5088539326dd9d92df30b9f6b03ded Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Thu, 28 Apr 2016 13:39:06 +0200 Subject: [PATCH 02/16] Small fixes in key.c Check for key length (non zero and dividable by 8). Asymmetric keys in the current state are INVALID_ARGUMENT. Change-Id: Ic7dd64fa86a485f11e52b83b2b82f710c4d55c80 --- src/key.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/src/key.c b/src/key.c index 1aba0d3..4006f5f 100644 --- a/src/key.c +++ b/src/key.c @@ -36,7 +36,7 @@ static inline void simple_key_sanity_check(const struct yaca_key_simple_s *key) { - assert(key->bits); + assert(key->bits != 0); assert(key->bits % 8 == 0); } @@ -206,7 +206,7 @@ API int yaca_key_gen(yaca_key_h *sym_key, struct yaca_key_simple_s *nk = NULL; size_t key_byte_len = key_bits / 8; - if (sym_key == NULL) + if (sym_key == NULL || key_bits % 8 != 0) return YACA_ERROR_INVALID_ARGUMENT; switch(key_type) @@ -215,21 +215,6 @@ API int yaca_key_gen(yaca_key_h *sym_key, case YACA_KEY_TYPE_IV: break; case YACA_KEY_TYPE_DES: - case YACA_KEY_TYPE_RSA_PUB: /* RSA public key */ - case YACA_KEY_TYPE_RSA_PRIV: /* RSA private key */ - case YACA_KEY_TYPE_DSA_PUB: /* DSA public key */ - case YACA_KEY_TYPE_DSA_PRIV: /* DSA private key */ - case YACA_KEY_TYPE_DH_PUB: /* DH public key */ - case YACA_KEY_TYPE_DH_PRIV: /* DH private key */ - case YACA_KEY_TYPE_ECDSA_PUB: /* ECDSA public key */ - case YACA_KEY_TYPE_ECDSA_PRIV: /* ECDSA private key */ - case YACA_KEY_TYPE_ECDH_PUB: /* ECDH public key */ - case YACA_KEY_TYPE_ECDH_PRIV: /* ECDH private key */ - case YACA_KEY_TYPE_PAIR_RSA: /* Pair of RSA keys */ - case YACA_KEY_TYPE_PAIR_DSA: /* Pair of DSA keys */ - case YACA_KEY_TYPE_PAIR_DH: /* Pair of DH keys */ - case YACA_KEY_TYPE_PAIR_ECDSA: /* Pair of ECDSA keys */ - case YACA_KEY_TYPE_PAIR_ECDH: /* Pair of ECDH keys */ return YACA_ERROR_NOT_IMPLEMENTED; default: return YACA_ERROR_INVALID_ARGUMENT; @@ -418,16 +403,16 @@ API int yaca_key_derive_pbkdf2(const char *password, iter == 0 || key_bits == 0 || key == NULL) return YACA_ERROR_INVALID_ARGUMENT; - ret = digest_get_algorithm(algo, &md); - if (ret < 0) - return ret; - if (key_bits % 8) /* Key length must be multiple of 8-bits */ return YACA_ERROR_INVALID_ARGUMENT; if (key_byte_len > SIZE_MAX - sizeof(struct yaca_key_simple_s)) return YACA_ERROR_TOO_BIG_ARGUMENT; + ret = digest_get_algorithm(algo, &md); + if (ret < 0) + return ret; + nk = yaca_zalloc(sizeof(struct yaca_key_simple_s) + key_byte_len); if (nk == NULL) return YACA_ERROR_OUT_OF_MEMORY; -- 2.7.4 From f3cea1e67d96b68b600f4869009cf076a88fde7c Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Thu, 28 Apr 2016 13:55:04 +0200 Subject: [PATCH 03/16] Some TODOs added for things noticed Change-Id: I8683a77c3e50dea327cb5c10973d1fe310765470 --- api/yaca/types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/api/yaca/types.h b/api/yaca/types.h index 5478a46..c467121 100644 --- a/api/yaca/types.h +++ b/api/yaca/types.h @@ -84,6 +84,7 @@ typedef enum { YACA_KEY_TYPE_ECDSA_PUB, /**< Elliptic Curve Digital Signature Algorithm public key */ YACA_KEY_TYPE_ECDSA_PRIV, /**< Elliptic Curve Digital Signature Algorithm private key */ + // TODO: ECDH might not exist as a separate key type, remove? YACA_KEY_TYPE_ECDH_PUB, /**< Elliptic Curve Diffie-Hellman public key */ YACA_KEY_TYPE_ECDH_PRIV, /**< Elliptic Curve Diffie-Hellman private key */ -- 2.7.4 From f64a279a8f0470812194f0a2515192c81d81bab8 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Mon, 25 Apr 2016 18:33:26 +0200 Subject: [PATCH 04/16] yaca_key_export() implementation for YACA_KEY_FORMAT_DEFAULT Change-Id: I946b1f862dd7f75d93372cea00deb6487ae35fb7 --- src/key.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 231 insertions(+), 17 deletions(-) diff --git a/src/key.c b/src/key.c index 4006f5f..8373a4c 100644 --- a/src/key.c +++ b/src/key.c @@ -31,6 +31,8 @@ #include #include +#include +#include #include "internal.h" @@ -60,6 +62,219 @@ static inline void key_sanity_check(const yaca_key_h key) } #endif +int export_simple_raw(struct yaca_key_simple_s *simple_key, + char **data, + size_t *data_len) +{ + assert(simple_key != NULL); + assert(data != NULL); + assert(data_len != NULL); + + size_t key_len = simple_key->bits / 8; + + *data = yaca_malloc(key_len); + if (*data == NULL) { + ERROR_DUMP(YACA_ERROR_OUT_OF_MEMORY); + return YACA_ERROR_OUT_OF_MEMORY; + } + + memcpy(*data, simple_key->d, key_len); + *data_len = key_len; + + return 0; +} + +int export_simple_base64(struct yaca_key_simple_s *simple_key, + char **data, + size_t *data_len) +{ + assert(simple_key != NULL); + assert(data != NULL); + assert(data_len != NULL); + + int ret; + size_t key_len = simple_key->bits / 8; + BIO *b64; + BIO *mem; + char *bio_data; + long bio_data_len; + + b64 = BIO_new(BIO_f_base64()); + if (b64 == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + return ret; + } + + mem = BIO_new(BIO_s_mem()); + if (mem == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + + BIO_push(b64, mem); + + ret = BIO_write(b64, simple_key->d, key_len); + if (ret <= 0 || (unsigned)ret != key_len) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + + ret = BIO_flush(b64); + if (ret <= 0) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + + bio_data_len = BIO_get_mem_data(mem, &bio_data); + if (bio_data_len <= 0) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + + *data = yaca_malloc(bio_data_len); + if (*data == NULL) { + ret = YACA_ERROR_OUT_OF_MEMORY; + ERROR_DUMP(ret); + goto free_bio; + } + + memcpy(*data, bio_data, bio_data_len); + *data_len = bio_data_len; + ret = 0; + +free_bio: + BIO_free_all(b64); + + return ret; +} + +int export_evp(struct yaca_key_evp_s *evp_key, + yaca_key_file_fmt_e key_file_fmt, + char **data, + size_t *data_len) +{ + assert(evp_key != NULL); + assert(data != NULL); + assert(data_len != NULL); + + int ret = 0; + BIO *mem; + char *bio_data; + long bio_data_len; + + mem = BIO_new(BIO_s_mem()); + if (mem == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + return ret; + } + + switch (key_file_fmt) { + + case YACA_KEY_FILE_FORMAT_PEM: + switch (evp_key->key.type) { + + case YACA_KEY_TYPE_RSA_PRIV: + case YACA_KEY_TYPE_DSA_PRIV: + ret = PEM_write_bio_PrivateKey(mem, evp_key->evp, NULL, NULL, 0, NULL, NULL); + break; + + case YACA_KEY_TYPE_RSA_PUB: + case YACA_KEY_TYPE_DSA_PUB: + ret = PEM_write_bio_PUBKEY(mem, evp_key->evp); + break; + + case YACA_KEY_TYPE_DH_PRIV: + case YACA_KEY_TYPE_DH_PUB: + case YACA_KEY_TYPE_ECDSA_PRIV: + case YACA_KEY_TYPE_ECDSA_PUB: + case YACA_KEY_TYPE_ECDH_PRIV: + case YACA_KEY_TYPE_ECDH_PUB: + ret = YACA_ERROR_NOT_IMPLEMENTED; + goto free_bio; + + default: + ret = YACA_ERROR_INVALID_ARGUMENT; + goto free_bio; + } + + break; + + case YACA_KEY_FILE_FORMAT_DER: + switch (evp_key->key.type) { + + case YACA_KEY_TYPE_RSA_PRIV: + case YACA_KEY_TYPE_DSA_PRIV: + ret = i2d_PrivateKey_bio(mem, evp_key->evp); + break; + + case YACA_KEY_TYPE_RSA_PUB: + case YACA_KEY_TYPE_DSA_PUB: + ret = i2d_PUBKEY_bio(mem, evp_key->evp); + break; + + case YACA_KEY_TYPE_DH_PRIV: + case YACA_KEY_TYPE_DH_PUB: + case YACA_KEY_TYPE_ECDSA_PRIV: + case YACA_KEY_TYPE_ECDSA_PUB: + case YACA_KEY_TYPE_ECDH_PRIV: + case YACA_KEY_TYPE_ECDH_PUB: + ret = YACA_ERROR_NOT_IMPLEMENTED; + goto free_bio; + + default: + ret = YACA_ERROR_INVALID_ARGUMENT; + goto free_bio; + } + + break; + + default: + ret = YACA_ERROR_INVALID_ARGUMENT; + goto free_bio; + } + + if (ret <= 0) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + + ret = BIO_flush(mem); + if (ret <= 0) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + + bio_data_len = BIO_get_mem_data(mem, &bio_data); + if (bio_data_len <= 0) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + + *data = yaca_malloc(bio_data_len); + if (*data == NULL) { + ret = YACA_ERROR_OUT_OF_MEMORY; + ERROR_DUMP(ret); + goto free_bio; + } + + memcpy(*data, bio_data, bio_data_len); + *data_len = bio_data_len; + ret = 0; + +free_bio: + BIO_free_all(mem); + return ret; +} + struct yaca_key_simple_s *key_get_simple(const yaca_key_h key) { if (key == YACA_KEY_NULL) @@ -165,35 +380,34 @@ API int yaca_key_export(const yaca_key_h key, char **data, size_t *data_len) { - size_t byte_len; struct yaca_key_simple_s *simple_key = key_get_simple(key); struct yaca_key_evp_s *evp_key = key_get_evp(key); if (data == NULL || data_len == NULL) return YACA_ERROR_INVALID_ARGUMENT; - if (key_fmt != YACA_KEY_FORMAT_DEFAULT) - return YACA_ERROR_NOT_IMPLEMENTED; - - if (key_file_fmt != YACA_KEY_FILE_FORMAT_RAW) - return YACA_ERROR_NOT_IMPLEMENTED; - - if (simple_key != NULL) { + if (simple_key != NULL) simple_key_sanity_check(simple_key); - byte_len = simple_key->bits / 8; - *data = yaca_malloc(byte_len); - memcpy(*data, simple_key->d, byte_len); - *data_len = byte_len; + if (evp_key != NULL) + evp_key_sanity_check(evp_key); + + if (key_fmt == YACA_KEY_FORMAT_DEFAULT && + key_file_fmt == YACA_KEY_FILE_FORMAT_RAW && + simple_key != NULL) + return export_simple_raw(simple_key, data, data_len); - return 0; - } + if (key_fmt == YACA_KEY_FORMAT_DEFAULT && + key_file_fmt == YACA_KEY_FILE_FORMAT_BASE64 && + simple_key != NULL) + return export_simple_base64(simple_key, data, data_len); - if (evp_key != NULL) { - evp_key_sanity_check(evp_key); + if (key_fmt == YACA_KEY_FORMAT_DEFAULT && + evp_key != NULL) + return export_evp(evp_key, key_file_fmt, data, data_len); + if (key_fmt == YACA_KEY_FORMAT_PKCS8) return YACA_ERROR_NOT_IMPLEMENTED; - } return YACA_ERROR_INVALID_ARGUMENT; } -- 2.7.4 From d978aca4ccfbfe374bcd55784fbfad730a88fdb4 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Thu, 28 Apr 2016 18:30:29 +0200 Subject: [PATCH 05/16] yaca_key_import() basic implementation (symmetrical and RSA) Change-Id: I8a90a06326fabbbd8b013452c1d0797635451464 --- src/key.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 291 insertions(+), 25 deletions(-) diff --git a/src/key.c b/src/key.c index 8373a4c..d6d95c4 100644 --- a/src/key.c +++ b/src/key.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -62,6 +63,277 @@ static inline void key_sanity_check(const yaca_key_h key) } #endif +int base64_decode_length(const char *data, size_t data_len, size_t *len) +{ + assert(data != NULL); + assert(data_len != 0); + assert(len != NULL); + + size_t padded = 0; + size_t tmp_len = data_len; + + if (data_len % 4 != 0) + return YACA_ERROR_INVALID_ARGUMENT; + + if (data[tmp_len - 1] == '=') { + padded = 1; + if (data[tmp_len - 2] == '=') + padded = 2; + } + + *len = data_len / 4 * 3 - padded; + return 0; +} + +#define TMP_BUF_LEN 512 + +int base64_decode(const char *data, size_t data_len, BIO **output) +{ + assert(data != NULL); + assert(data_len != 0); + assert(output != NULL); + + int ret; + BIO *b64 = NULL; + BIO *src = NULL; + BIO *dst = NULL; + char tmpbuf[TMP_BUF_LEN]; + size_t b64_len; + char *out; + long out_len; + + /* This is because of BIO_new_mem_buf() having its length param typed int */ + if (data_len > INT_MAX) + return YACA_ERROR_TOO_BIG_ARGUMENT; + + /* First phase of correctness checking, calculate expected output length */ + ret = base64_decode_length(data, data_len, &b64_len); + if (ret != 0) + return ret; + + b64 = BIO_new(BIO_f_base64()); + if (b64 == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + return ret; + } + + src = BIO_new_mem_buf(data, data_len); + if (src == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + + BIO_push(b64, src); + + dst = BIO_new(BIO_s_mem()); + if (dst == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + /* Try to decode */ + for(;;) { + ret = BIO_read(b64, tmpbuf, TMP_BUF_LEN); + if (ret < 0) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + + if (ret == 0) + break; + + if (BIO_write(dst, tmpbuf, ret) != ret) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + } + + BIO_flush(dst); + + /* Check wether the length of the decoded data is what we expected */ + out_len = BIO_get_mem_data(dst, &out); + if (out_len < 0) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } + if ((size_t)out_len != b64_len) { + ret = YACA_ERROR_INVALID_ARGUMENT; + goto free_bio; + } + + *output = dst; + dst = NULL; + ret = 0; + +free_bio: + BIO_free_all(b64); + BIO_free_all(dst); + + return ret; +} + +int import_simple(yaca_key_h *key, + yaca_key_type_e key_type, + const char *data, + size_t data_len) +{ + assert(key != NULL); + assert(data != NULL); + assert(data_len != 0); + + int ret; + BIO *decoded = NULL; + const char *key_data; + size_t key_data_len; + struct yaca_key_simple_s *nk = NULL; + + ret = base64_decode(data, data_len, &decoded); + if (ret == 0) { + /* Conversion successfull, get the BASE64 */ + long len = BIO_get_mem_data(decoded, &key_data); + if (len <= 0 || key_data == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + return ret; + } + key_data_len = len; + } else if (ret == YACA_ERROR_INVALID_ARGUMENT) { + /* This was not BASE64 or it was corrupted, treat as RAW */ + key_data_len = data_len; + key_data = data; + } else { + /* Some other, possibly unrecoverable error, give up */ + return ret; + } + + if (key_data_len > SIZE_MAX - sizeof(struct yaca_key_simple_s)) { + ret = YACA_ERROR_TOO_BIG_ARGUMENT; + goto out; + } + + nk = yaca_zalloc(sizeof(struct yaca_key_simple_s) + key_data_len); + if (nk == NULL) { + ret = YACA_ERROR_OUT_OF_MEMORY; + goto out; + } + + memcpy(nk->d, key_data, key_data_len); + nk->bits = key_data_len * 8; + nk->key.type = key_type; + + *key = (yaca_key_h)nk; + ret = 0; + +out: + BIO_free_all(decoded); + return ret; +} + +int import_evp(yaca_key_h *key, + yaca_key_type_e key_type, + const char *data, + size_t data_len) +{ + assert(key != NULL); + assert(data != NULL); + assert(data_len != 0); + + BIO *src = NULL; + EVP_PKEY *pkey = NULL; + bool private; + yaca_key_type_e type; + struct yaca_key_evp_s *nk = NULL; + + /* Neither PEM nor DER will ever be shorter then 4 bytes (12 seems + * to be minimum for DER, much more for PEM). This is just to make + * sure we have at least 4 bytes for strncmp() below. + */ + if (data_len < 4) + return YACA_ERROR_INVALID_ARGUMENT; + + /* This is because of BIO_new_mem_buf() having its length param typed int */ + if (data_len > INT_MAX) + return YACA_ERROR_TOO_BIG_ARGUMENT; + + src = BIO_new_mem_buf(data, data_len); + if (src == NULL) { + ERROR_DUMP(YACA_ERROR_INTERNAL); + return YACA_ERROR_INTERNAL; + } + + /* Possible PEM */ + if (strncmp("----", data, 4) == 0) { + if (pkey == NULL) { + BIO_reset(src); + pkey = PEM_read_bio_PrivateKey(src, NULL, NULL, NULL); + private = true; + } + + if (pkey == NULL) { + BIO_reset(src); + pkey = PEM_read_bio_PUBKEY(src, NULL, NULL, NULL); + private = false; + } + } + /* Possible DER */ + else { + if (pkey == NULL) { + BIO_reset(src); + pkey = d2i_PrivateKey_bio(src, NULL); + private = true; + } + + if (pkey == NULL) { + BIO_reset(src); + pkey = d2i_PUBKEY_bio(src, NULL); + private = false; + } + } + + BIO_free(src); + + if (pkey == NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + switch (EVP_PKEY_type(pkey->type)) { + case EVP_PKEY_RSA: + type = private ? YACA_KEY_TYPE_RSA_PRIV : YACA_KEY_TYPE_RSA_PUB; + break; + + case EVP_PKEY_DSA: + type = private ? YACA_KEY_TYPE_DSA_PRIV : YACA_KEY_TYPE_DSA_PUB; + break; + + case EVP_PKEY_EC: + type = private ? YACA_KEY_TYPE_ECDSA_PRIV : YACA_KEY_TYPE_ECDSA_PUB; + break; + + default: + return YACA_ERROR_INVALID_ARGUMENT; + } + + if (type != key_type) + return YACA_ERROR_INVALID_ARGUMENT; + + nk = yaca_zalloc(sizeof(struct yaca_key_evp_s)); + if (nk == NULL) + return YACA_ERROR_OUT_OF_MEMORY; + + nk->evp = pkey; + *key = (yaca_key_h)nk; + (*key)->type = type; + + return 0; +} + int export_simple_raw(struct yaca_key_simple_s *simple_key, char **data, size_t *data_len) @@ -114,6 +386,7 @@ int export_simple_base64(struct yaca_key_simple_s *simple_key, } BIO_push(b64, mem); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); ret = BIO_write(b64, simple_key->d, key_len); if (ret <= 0 || (unsigned)ret != key_len) { @@ -345,32 +618,25 @@ API int yaca_key_import(yaca_key_h *key, if (key == NULL || data == NULL || data_len == 0) return YACA_ERROR_INVALID_ARGUMENT; - if (key_type == YACA_KEY_TYPE_SYMMETRIC) { - struct yaca_key_simple_s *nk = NULL; - - if (data_len > SIZE_MAX - sizeof(struct yaca_key_simple_s)) - return YACA_ERROR_TOO_BIG_ARGUMENT; - - nk = yaca_zalloc(sizeof(struct yaca_key_simple_s) + data_len); - if (nk == NULL) - return YACA_ERROR_OUT_OF_MEMORY; - - memcpy(nk->d, data, data_len); /* TODO: CRYPTO_/EVP_... */ - nk->bits = data_len * 8; - nk->key.type = key_type; - - *key = (yaca_key_h)nk; - return 0; - } - - if (key_type == YACA_KEY_TYPE_DES) { - // TODO: ... - return YACA_ERROR_NOT_IMPLEMENTED; - } - - /* if (...) */ { - // TODO: all the other key types + switch (key_type) { + case YACA_KEY_TYPE_SYMMETRIC: + case YACA_KEY_TYPE_IV: + return import_simple(key, key_type, data, data_len); + case YACA_KEY_TYPE_RSA_PUB: + case YACA_KEY_TYPE_RSA_PRIV: + return import_evp(key, key_type, data, data_len); + case YACA_KEY_TYPE_DES: + case YACA_KEY_TYPE_DSA_PUB: + case YACA_KEY_TYPE_DSA_PRIV: + case YACA_KEY_TYPE_DH_PUB: + case YACA_KEY_TYPE_DH_PRIV: + case YACA_KEY_TYPE_ECDSA_PUB: + case YACA_KEY_TYPE_ECDSA_PRIV: + case YACA_KEY_TYPE_ECDH_PUB: + case YACA_KEY_TYPE_ECDH_PRIV: return YACA_ERROR_NOT_IMPLEMENTED; + default: + return YACA_ERROR_INVALID_ARGUMENT; } } -- 2.7.4 From 477f87afb5ee0d5f3f74a42ae2c15872108b8bb5 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 26 Apr 2016 15:04:30 +0200 Subject: [PATCH 06/16] key_import/key_export example Change-Id: Ia638fdc60c88684163dc6afe3aa3e83d65684950 --- examples/CMakeLists.txt | 1 + examples/key_import_export.c | 231 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 examples/key_import_export.c diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9048331..fe238d2 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -50,6 +50,7 @@ BUILD_EXAMPLE("yaca-example-encrypt-gcm" encrypt_aes_gcm.c) BUILD_EXAMPLE("yaca-example-sign" sign.c) BUILD_EXAMPLE("yaca-example-key-exchange" key_exchange.c) BUILD_EXAMPLE("yaca-example-test" test.c) +BUILD_EXAMPLE("yaca-example-key-impexp" key_import_export.c) INSTALL(FILES ${COMMON_SOURCES} DESTINATION ${EXAMPLES_DIR}) diff --git a/examples/key_import_export.c b/examples/key_import_export.c new file mode 100644 index 0000000..fba4664 --- /dev/null +++ b/examples/key_import_export.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Krzysztof Jackiewicz + * + * 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 + */ + +/** + * @file key_import_export.c + * @brief + */ + +#include + +#include "misc.h" + +#include +#include +#include +#include +#include + +void key_import_export_sym(yaca_key_h sym) +{ + int ret; + + char *raw = NULL; + size_t raw_len; + char *b64= NULL; + size_t b64_len; + + yaca_key_h raw_imported = YACA_KEY_NULL; + yaca_key_h b64_imported = YACA_KEY_NULL; + + + ret = yaca_key_export(sym, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_BASE64, &b64, &b64_len); + if (ret != 0) + return; + ret = yaca_key_import(&b64_imported, YACA_KEY_TYPE_SYMMETRIC, b64, b64_len); + if (ret != 0) + goto free; + + printf("\n\t***** BASE64 exported key: *****\n%*s\n", (int)b64_len, b64); + yaca_free(b64); + b64 = NULL; + + ret = yaca_key_export(b64_imported, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_BASE64, &b64, &b64_len); + if (ret != 0) + goto free; + + printf("\t***** BASE64 imported key: *****\n%*s\n", (int)b64_len, b64); + + + ret = yaca_key_export(sym, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_RAW, &raw, &raw_len); + if (ret != 0) + goto free; + ret = yaca_key_import(&raw_imported, YACA_KEY_TYPE_SYMMETRIC, raw, raw_len); + if (ret != 0) + goto free; + + dump_hex(raw, raw_len, "\n\t***** RAW exported key: *****"); + yaca_free(raw); + raw = NULL; + + ret = yaca_key_export(raw_imported, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_RAW, &raw, &raw_len); + if (ret != 0) + goto free; + + dump_hex(raw, raw_len, "\t***** RAW imported key: *****"); + +free: + yaca_key_free(raw_imported); + yaca_key_free(b64_imported); + yaca_free(raw); + yaca_free(b64); +} + +void key_import_export_rsa(yaca_key_h priv, yaca_key_h pub) +{ + int ret; + + char *pem_prv = NULL; + size_t pem_prv_len; + char *der_prv = NULL; + size_t der_prv_len; + + char *pem_pub = NULL; + size_t pem_pub_len; + char *der_pub = NULL; + size_t der_pub_len; + + yaca_key_h pem_prv_imported = YACA_KEY_NULL; + yaca_key_h der_prv_imported = YACA_KEY_NULL; + yaca_key_h pem_pub_imported = YACA_KEY_NULL; + yaca_key_h der_pub_imported = YACA_KEY_NULL; + + + /* PEM private */ + + ret = yaca_key_export(priv, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM, &pem_prv, &pem_prv_len); + if (ret != 0) + return; + ret = yaca_key_import(&pem_prv_imported, YACA_KEY_TYPE_RSA_PRIV, pem_prv, pem_prv_len); + if (ret != 0) + goto free; + + printf("\n\t***** PEM exported private key: *****\n%*s", (int)pem_prv_len, pem_prv); + yaca_free(pem_prv); + pem_prv = NULL; + + ret = yaca_key_export(pem_prv_imported, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM, &pem_prv, &pem_prv_len); + if (ret != 0) + goto free; + + printf("\t***** PEM imported private key: *****\n%*s", (int)pem_prv_len, pem_prv); + + + /* DER private */ + + ret = yaca_key_export(priv, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_DER, &der_prv, &der_prv_len); + if (ret != 0) + goto free; + ret = yaca_key_import(&der_prv_imported, YACA_KEY_TYPE_RSA_PRIV, der_prv, der_prv_len); + if (ret != 0) + goto free; + + dump_hex(der_prv, der_prv_len, "\n\t***** DER exported private key: *****"); + yaca_free(der_prv); + der_prv = NULL; + + ret = yaca_key_export(der_prv_imported, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_DER, &der_prv, &der_prv_len); + if (ret != 0) + goto free; + + dump_hex(der_prv, der_prv_len, "\t***** DER imported private key: *****"); + + + /* PEM public */ + + ret = yaca_key_export(pub, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM, &pem_pub, &pem_pub_len); + if (ret != 0) + goto free; + ret = yaca_key_import(&pem_pub_imported, YACA_KEY_TYPE_RSA_PUB, pem_pub, pem_pub_len); + if (ret != 0) + goto free; + + printf("\n\t***** PEM exported public key: *****\n%*s", (int)pem_pub_len, pem_pub); + yaca_free(pem_pub); + pem_pub = NULL; + + ret = yaca_key_export(pem_pub_imported, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM, &pem_pub, &pem_pub_len); + if (ret != 0) + goto free; + + printf("\t***** PEM imported public key: *****\n%*s", (int)pem_pub_len, pem_pub); + + + /* DER public */ + + ret = yaca_key_export(pub, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_DER, &der_pub, &der_pub_len); + if (ret != 0) + goto free; + ret = yaca_key_import(&der_pub_imported, YACA_KEY_TYPE_RSA_PUB, der_pub, der_pub_len); + if (ret != 0) + goto free; + + dump_hex(der_pub, der_pub_len, "\n\t***** DER exported public key: *****"); + yaca_free(der_pub); + der_pub = NULL; + + ret = yaca_key_export(der_pub_imported, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_DER, &der_pub, &der_pub_len); + if (ret != 0) + goto free; + + dump_hex(der_pub, der_pub_len, "\t***** DER imported public key: *****"); + +free: + yaca_key_free(der_pub_imported); + yaca_key_free(pem_pub_imported); + yaca_key_free(der_prv_imported); + yaca_key_free(pem_prv_imported); + yaca_free(der_pub); + yaca_free(pem_pub); + yaca_free(der_prv); + yaca_free(pem_prv); +} + +int main() +{ + yaca_key_h sym; + yaca_key_h rsa_priv; + yaca_key_h rsa_pub; + int ret; + + ret = yaca_init(); + if (ret != 0) + return ret; + + yaca_error_set_debug_func(debug_func); + + ret = yaca_key_gen(&sym, YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_1024BIT); + if (ret != 0) + goto exit; + + ret = yaca_key_gen_pair(&rsa_priv, &rsa_pub, YACA_KEY_TYPE_PAIR_RSA, YACA_KEY_1024BIT); + if (ret != 0) + goto free_sym; + + key_import_export_sym(sym); + key_import_export_rsa(rsa_priv, rsa_pub); + + yaca_key_free(rsa_priv); + yaca_key_free(rsa_pub); +free_sym: + yaca_key_free(sym); +exit: + yaca_exit(); + + return ret; +} -- 2.7.4 From 3b7c99c08bd52ae2d1dcfa3b2d1c53ec3b782268 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Thu, 5 May 2016 11:45:46 +0200 Subject: [PATCH 07/16] Make yaca GCC 5 compatibile GCC 5 issues a warning for __FUNCTION__. Use __func__ instead. Change-Id: I3d37621c8384e4f229140bfc3af8c92f81058ff5 --- src/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal.h b/src/internal.h index 5bff4f1..119728f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -101,6 +101,6 @@ struct yaca_key_simple_s *key_get_simple(const yaca_key_h key); struct yaca_key_evp_s *key_get_evp(const yaca_key_h key); void error_dump(const char *file, int line, const char *function, int code); -#define ERROR_DUMP(code) error_dump(__FILE__, __LINE__, __FUNCTION__, (code)) +#define ERROR_DUMP(code) error_dump(__FILE__, __LINE__, __func__, (code)) #endif -- 2.7.4 From 4d45f43effc56dc4d826400ebdd042fb2796297a Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Fri, 6 May 2016 15:14:22 +0200 Subject: [PATCH 08/16] Remove YACA_ERROR_NOT_SUPPORTED Change-Id: I3f6b9cf907fc4fb4e0dd6dd84452f1448e223e65 --- api/yaca/error.h | 7 +++--- src/crypto.c | 23 ++++++------------- src/sign.c | 68 ++++++++++++++++++-------------------------------------- 3 files changed, 32 insertions(+), 66 deletions(-) diff --git a/api/yaca/error.h b/api/yaca/error.h index eaca621..944d8a3 100644 --- a/api/yaca/error.h +++ b/api/yaca/error.h @@ -41,10 +41,9 @@ enum __yaca_error_code { YACA_ERROR_INVALID_ARGUMENT = -1, YACA_ERROR_NOT_IMPLEMENTED = -2, YACA_ERROR_INTERNAL = -3, - YACA_ERROR_NOT_SUPPORTED = -4, - YACA_ERROR_TOO_BIG_ARGUMENT = -5, - YACA_ERROR_OUT_OF_MEMORY = -6, - YACA_ERROR_SIGNATURE_INVALID = -7 + YACA_ERROR_TOO_BIG_ARGUMENT = -4, + YACA_ERROR_OUT_OF_MEMORY = -5, + YACA_ERROR_SIGNATURE_INVALID = -6 }; // TODO disable debug function in release? diff --git a/src/crypto.c b/src/crypto.c index 734dba5..650bdcf 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -84,39 +84,30 @@ API int yaca_rand_bytes(char *data, size_t data_len) return YACA_ERROR_INVALID_ARGUMENT; ret = RAND_bytes((unsigned char *)data, data_len); - if (ret == 1) - return 0; - - if (ret == -1) - ret = YACA_ERROR_NOT_SUPPORTED; - else + if (ret != 1) { ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + return ret; + } - ERROR_DUMP(ret); - return ret; + return 0; } API int yaca_ctx_set_param(yaca_ctx_h ctx, yaca_ex_param_e param, const void *value, size_t value_len) { - if (ctx == YACA_CTX_NULL) + if (ctx == YACA_CTX_NULL || ctx->set_param == NULL) return YACA_ERROR_INVALID_ARGUMENT; - if (ctx->set_param == NULL) - return YACA_ERROR_NOT_SUPPORTED; - return ctx->set_param(ctx, param, value, value_len); } API int yaca_ctx_get_param(const yaca_ctx_h ctx, yaca_ex_param_e param, void **value, size_t *value_len) { - if (ctx == YACA_CTX_NULL) + if (ctx == YACA_CTX_NULL || ctx->get_param == NULL) return YACA_ERROR_INVALID_ARGUMENT; - if (ctx->get_param == NULL) - return YACA_ERROR_NOT_SUPPORTED; - return ctx->get_param(ctx, param, value, value_len); } diff --git a/src/sign.c b/src/sign.c index 0c789bc..24fe7ac 100644 --- a/src/sign.c +++ b/src/sign.c @@ -180,11 +180,6 @@ API int yaca_sign_init(yaca_ctx_h *ctx, } ret = EVP_DigestSignInit(nc->mdctx, NULL, md, NULL, pkey); - if (ret == -2) { - ret = YACA_ERROR_NOT_SUPPORTED; - ERROR_DUMP(ret); - goto ctx; - } if (ret != 1) { ret = YACA_ERROR_INTERNAL; ERROR_DUMP(ret); @@ -219,16 +214,13 @@ API int yaca_sign_update(yaca_ctx_h ctx, return YACA_ERROR_INVALID_ARGUMENT; ret = EVP_DigestSignUpdate(c->mdctx, data, data_len); - if (ret == 1) - return 0; - - if (ret == -2) - ret = YACA_ERROR_NOT_SUPPORTED; - else + if (ret != 1) { ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + return ret; + } - ERROR_DUMP(ret); - return ret; + return 0; } API int yaca_sign_final(yaca_ctx_h ctx, @@ -243,16 +235,13 @@ API int yaca_sign_final(yaca_ctx_h ctx, return YACA_ERROR_INVALID_ARGUMENT; ret = EVP_DigestSignFinal(c->mdctx, (unsigned char *)mac, mac_len); - if(ret == 1) - return 0; - - if (ret == -2) - ret = YACA_ERROR_NOT_SUPPORTED; - else + if(ret != 1) { ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + return ret; + } - ERROR_DUMP(ret); - return ret; + return 0; } API int yaca_verify_init(yaca_ctx_h *ctx, @@ -323,11 +312,6 @@ API int yaca_verify_init(yaca_ctx_h *ctx, goto ctx; } - if (ret == -2) { - ret = YACA_ERROR_NOT_SUPPORTED; - ERROR_DUMP(ret); - goto ctx; - } if (ret != 1) { ret = YACA_ERROR_INTERNAL; ERROR_DUMP(ret); @@ -372,16 +356,13 @@ API int yaca_verify_update(yaca_ctx_h ctx, return YACA_ERROR_INVALID_ARGUMENT; } - if (ret == 1) - return 0; - - if (ret == -2) - ret = YACA_ERROR_NOT_SUPPORTED; - else + if (ret != 1) { ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + return ret; + } - ERROR_DUMP(ret); - return ret; + return 0; } API int yaca_verify_final(yaca_ctx_h ctx, @@ -402,19 +383,16 @@ API int yaca_verify_final(yaca_ctx_h ctx, ret = EVP_DigestSignFinal(c->mdctx, (unsigned char *)mac_cmp, &mac_cmp_len); - if (ret == 1) { - if (mac_len != mac_cmp_len || CRYPTO_memcmp(mac, mac_cmp, mac_len) != 0) - return YACA_ERROR_SIGNATURE_INVALID; - return 0; + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + return ret; } - if (ret == -2) - ret = YACA_ERROR_NOT_SUPPORTED; - else - ret = YACA_ERROR_INTERNAL; + if (mac_len != mac_cmp_len || CRYPTO_memcmp(mac, mac_cmp, mac_len) != 0) + return YACA_ERROR_SIGNATURE_INVALID; - ERROR_DUMP(ret); - return ret; + return 0; case OP_VERIFY_ASYMMETRIC: ret = EVP_DigestVerifyFinal(c->mdctx, (unsigned char *)mac, @@ -424,8 +402,6 @@ API int yaca_verify_final(yaca_ctx_h ctx, if (ret == 0) ret = YACA_ERROR_SIGNATURE_INVALID; - else if (ret == -2) - ret = YACA_ERROR_NOT_SUPPORTED; else ret = YACA_ERROR_INTERNAL; -- 2.7.4 From 6d0a0767ece8013d89d38431fd56c6a88072f00d Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Mon, 9 May 2016 15:55:29 +0200 Subject: [PATCH 09/16] write_file()/read_file() functions added They are not used now, but they are very helpful for debugging and they will be used in future examples. Change-Id: Ia3cee5a67013543096cef45b04b649ce5faaf9e8 --- examples/misc.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ examples/misc.h | 4 +++ 2 files changed, 88 insertions(+) diff --git a/examples/misc.c b/examples/misc.c index bd951e9..b3a8fdc 100644 --- a/examples/misc.c +++ b/examples/misc.c @@ -1,5 +1,8 @@ #include #include +#include + +#include #include #include "misc.h" @@ -19,3 +22,84 @@ void debug_func(const char* buf) { puts(buf); } + +int write_file(const char *path, char *data, size_t data_len) +{ + size_t written = 0; + FILE *f; + + f = fopen(path, "w"); + if (f == NULL) + return -1; + + while (written != data_len) { + int ret = fwrite(data + written, 1, data_len - written, f); + + if (ferror(f) != 0) { + fclose(f); + return -1; + } + + written += ret; + } + + fclose(f); + return 0; +} + +#define BUF_SIZE 512 + +int read_file(const char *path, char **data, size_t *data_len) +{ + int ret; + char tmp[BUF_SIZE]; + char *buf = NULL; + size_t buf_len; + FILE *f; + + f = fopen(path, "r"); + if (f == NULL) + return -1; + + for(;;) { + size_t read = fread(tmp, 1, BUF_SIZE, f); + + if (read > 0) { + if (buf == NULL) { + buf = yaca_malloc(read); + if (buf == NULL) { + ret = -1; + break; + } + buf_len = 0; + } else { + char *new_buf = yaca_realloc(buf, buf_len + read); + if (new_buf == NULL) { + ret = -1; + break; + } + buf = new_buf; + } + + memcpy(buf + buf_len, tmp, read); + buf_len += read; + } + + if (ferror(f) != 0) { + ret = -1; + break; + } + + if (feof(f)) { + *data = buf; + *data_len = buf_len; + buf = NULL; + ret = 0; + break; + } + } + + fclose(f); + free(buf); + return ret; +} diff --git a/examples/misc.h b/examples/misc.h index a4436f5..7d89758 100644 --- a/examples/misc.h +++ b/examples/misc.h @@ -37,4 +37,8 @@ void dump_hex(const char *buf, void debug_func(const char* buf); +int write_file(const char *path, char *data, size_t data_len); + +int read_file(const char *path, char **data, size_t *data_len); + #endif /* MISC_H */ -- 2.7.4 From 32bc85cef8ae6e6dd60bcc742d252210008fc188 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 11 May 2016 12:19:41 +0200 Subject: [PATCH 10/16] Incorporate sanity checks into key_get_* functions Change-Id: I2d13b621b202c6c5800b745fe5b9f48d5a88aac8 --- src/key.c | 57 +++++++++++++++++++-------------------------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/src/key.c b/src/key.c index d6d95c4..a8fb8ff 100644 --- a/src/key.c +++ b/src/key.c @@ -37,31 +37,6 @@ #include "internal.h" -static inline void simple_key_sanity_check(const struct yaca_key_simple_s *key) -{ - assert(key->bits != 0); - assert(key->bits % 8 == 0); -} - -// TODO: do we need a sanity check sanity for Evp keys? -static inline void evp_key_sanity_check(const struct yaca_key_evp_s *key) -{ -} - -// TODO: do we need this variant? or the two above are enough? -#if 0 -static inline void key_sanity_check(const yaca_key_h key) -{ - 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 (simple_key != NULL) - simple_key_sanity_check(simple_key); - - if (evp_key != NULL) - evp_key_sanity_check(evp_key); -} -#endif int base64_decode_length(const char *data, size_t data_len, size_t *len) { @@ -550,6 +525,8 @@ free_bio: struct yaca_key_simple_s *key_get_simple(const yaca_key_h key) { + struct yaca_key_simple_s *k; + if (key == YACA_KEY_NULL) return NULL; @@ -558,7 +535,14 @@ struct yaca_key_simple_s *key_get_simple(const yaca_key_h key) case YACA_KEY_TYPE_SYMMETRIC: case YACA_KEY_TYPE_DES: case YACA_KEY_TYPE_IV: - return (struct yaca_key_simple_s *)key; + k = (struct yaca_key_simple_s *)key; + + /* sanity check */ + assert(k->bits != 0); + assert(k->bits % 8 == 0); + assert(k->d != NULL); + + return k; default: return NULL; } @@ -566,6 +550,8 @@ struct yaca_key_simple_s *key_get_simple(const yaca_key_h key) struct yaca_key_evp_s *key_get_evp(const yaca_key_h key) { + struct yaca_key_evp_s *k; + if (key == YACA_KEY_NULL) return NULL; @@ -575,7 +561,12 @@ struct yaca_key_evp_s *key_get_evp(const yaca_key_h key) case YACA_KEY_TYPE_RSA_PRIV: case YACA_KEY_TYPE_DSA_PUB: case YACA_KEY_TYPE_DSA_PRIV: - return (struct yaca_key_evp_s *)key; + k = (struct yaca_key_evp_s *)key; + + /* sanity check */ + assert(k->evp != NULL); + + return k; default: return NULL; } @@ -586,16 +577,12 @@ API int yaca_key_get_bits(const yaca_key_h key) 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 (simple_key != NULL) { - simple_key_sanity_check(simple_key); + if (simple_key != NULL) return simple_key->bits; - } if (evp_key != NULL) { int ret; - evp_key_sanity_check(evp_key); - // TODO: handle ECC keys when they're implemented ret = EVP_PKEY_bits(evp_key->evp); if (ret <= 0) { @@ -652,12 +639,6 @@ API int yaca_key_export(const yaca_key_h key, if (data == NULL || data_len == NULL) return YACA_ERROR_INVALID_ARGUMENT; - if (simple_key != NULL) - simple_key_sanity_check(simple_key); - - if (evp_key != NULL) - evp_key_sanity_check(evp_key); - if (key_fmt == YACA_KEY_FORMAT_DEFAULT && key_file_fmt == YACA_KEY_FILE_FORMAT_RAW && simple_key != NULL) -- 2.7.4 From 2758c7949bf6208e94e180565fabde70d795eb01 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Mon, 2 May 2016 13:50:46 +0200 Subject: [PATCH 11/16] yaca_key_extract_public() public function The idea is to remove yaca_key_gen_pair() and always generate using yaca_key_gen(). The latter will always generate private keys for asymmetric types. Public key will be extracted (if needed) using the function implemented here. This approach has an advantage that we can extract public keys for private keys imported from external sources. Previously this was impossible. Change-Id: I081c81eb37ed3267518aac21a9bf36063ef0e901 --- api/yaca/key.h | 11 ++++++++++ src/key.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/api/yaca/key.h b/api/yaca/key.h index 3a829d5..c7e3727 100644 --- a/api/yaca/key.h +++ b/api/yaca/key.h @@ -127,6 +127,17 @@ int yaca_key_gen(yaca_key_h *sym_key, size_t key_bits); /** + * @brief yaca_key_extract_public Extracts public key from a private one. + * + * @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_free()). + * + * @return 0 on success, negative on error. + * @see yaca_key_gen(), yaca_key_import(), yaca_key_free() + */ +int yaca_key_extract_public(const yaca_key_h prv_key, yaca_key_h *pub_key); + +/** * @brief yaca_key_gen_pair Generates a new key pair. * * @param[out] prv_key Newly generated private key (must be freed with yaca_key_free()). diff --git a/src/key.c b/src/key.c index a8fb8ff..5c0d43c 100644 --- a/src/key.c +++ b/src/key.c @@ -704,6 +704,73 @@ err: return ret; } +API int yaca_key_extract_public(const yaca_key_h prv_key, yaca_key_h *pub_key) +{ + int ret; + struct yaca_key_evp_s *evp_key = key_get_evp(prv_key); + struct yaca_key_evp_s *nk = NULL; + RSA *rsa_pub = NULL; + + if (prv_key == YACA_KEY_NULL || evp_key == NULL || pub_key == NULL) + return YACA_ERROR_INVALID_ARGUMENT; + + nk = yaca_zalloc(sizeof(struct yaca_key_evp_s)); + if (nk == NULL) + return YACA_ERROR_OUT_OF_MEMORY; + + nk->evp = EVP_PKEY_new(); + if (nk->evp == NULL) { + ret = YACA_ERROR_OUT_OF_MEMORY; + ERROR_DUMP(ret); + goto free_key; + } + + switch(prv_key->type) + { + case YACA_KEY_TYPE_RSA_PRIV: + assert(EVP_PKEY_type(evp_key->evp->type) == EVP_PKEY_RSA); + + rsa_pub = RSAPublicKey_dup(EVP_PKEY_get0(evp_key->evp)); + if (rsa_pub == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_evp; + } + + ret = EVP_PKEY_assign_RSA(nk->evp, rsa_pub); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_rsa; + } + + *pub_key = (yaca_key_h)nk; + (*pub_key)->type = YACA_KEY_TYPE_RSA_PUB; + + return 0; + + case YACA_KEY_TYPE_DSA_PRIV: + case YACA_KEY_TYPE_ECDSA_PRIV: + ret = YACA_ERROR_NOT_IMPLEMENTED; + goto free_evp; + + default: + ret = YACA_ERROR_INVALID_ARGUMENT; + goto free_evp; + } + + return YACA_ERROR_INVALID_ARGUMENT; + +free_rsa: + RSA_free(rsa_pub); +free_evp: + EVP_PKEY_free(nk->evp); +free_key: + yaca_free(nk); + + return ret; +} + API int yaca_key_gen_pair(yaca_key_h *prv_key, yaca_key_h *pub_key, yaca_key_type_e key_type, -- 2.7.4 From 44822be1342157167807fa3602de469071411095 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Mon, 2 May 2016 17:48:47 +0200 Subject: [PATCH 12/16] Make it possible to generate private keys with yaca_key_gen() Change-Id: I7d4928ab27dad85cd52f3cff60ff9a9e61ae261f --- api/yaca/key.h | 8 ++-- src/key.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 115 insertions(+), 29 deletions(-) diff --git a/api/yaca/key.h b/api/yaca/key.h index c7e3727..e1126a6 100644 --- a/api/yaca/key.h +++ b/api/yaca/key.h @@ -113,16 +113,18 @@ int yaca_key_export(const yaca_key_h key, size_t *data_len); /** - * @brief yaca_key_gen Generates a secure symmetric key (or an initialization vector). + * @brief yaca_key_gen Generates a secure key (or an initialization vector). * - * @param[out] sym_key Newly generated key (must be freed with yaca_key_free()). + * This function is used to generate symmetric and private asymmetric keys. + * + * @param[out] key Newly generated key (must be freed with yaca_key_free()). * @param[in] key_type Type of the key to be generated. * @param[in] key_bits Length of the key (in bits) to be generated. * * @return 0 on success, negative on error. * @see #yaca_key_type_e, #yaca_key_bits_e, yaca_key_gen_pair(), yaca_key_free() */ -int yaca_key_gen(yaca_key_h *sym_key, +int yaca_key_gen(yaca_key_h *key, yaca_key_type_e key_type, size_t key_bits); diff --git a/src/key.c b/src/key.c index 5c0d43c..2ba3fe9 100644 --- a/src/key.c +++ b/src/key.c @@ -523,6 +523,88 @@ free_bio: return ret; } +int gen_simple(struct yaca_key_simple_s **out, size_t key_bits) +{ + assert(out != NULL); + + int ret; + struct yaca_key_simple_s *nk; + size_t key_byte_len = key_bits / 8; + + if (key_byte_len > SIZE_MAX - sizeof(struct yaca_key_simple_s)) + return YACA_ERROR_TOO_BIG_ARGUMENT; + + nk = yaca_zalloc(sizeof(struct yaca_key_simple_s) + key_byte_len); + if (nk == NULL) + return YACA_ERROR_OUT_OF_MEMORY; + + nk->bits = key_bits; + + ret = yaca_rand_bytes(nk->d, key_byte_len); + if (ret != 0) + return ret; + + *out = nk; + return 0; +} + +int gen_evp_rsa(struct yaca_key_evp_s **out, size_t key_bits) +{ + assert(out != NULL); + assert(key_bits > 0); + assert(key_bits % 8 == 0); + + int ret; + struct yaca_key_evp_s *nk; + EVP_PKEY_CTX *ctx; + EVP_PKEY *pkey = NULL; + + nk = yaca_zalloc(sizeof(struct yaca_key_evp_s)); + if (nk == NULL) + return YACA_ERROR_OUT_OF_MEMORY; + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + if (ctx == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_nk; + } + + ret = EVP_PKEY_keygen_init(ctx); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_ctx; + } + + ret = EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, key_bits); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_ctx; + } + + ret = EVP_PKEY_keygen(ctx, &pkey); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_ctx; + } + + nk->evp = pkey; + + *out = nk; + nk = NULL; + ret = 0; + +free_ctx: + EVP_PKEY_CTX_free(ctx); +free_nk: + yaca_free(nk); + + return ret; +} + struct yaca_key_simple_s *key_get_simple(const yaca_key_h key) { struct yaca_key_simple_s *k; @@ -659,49 +741,51 @@ API int yaca_key_export(const yaca_key_h key, return YACA_ERROR_INVALID_ARGUMENT; } -API int yaca_key_gen(yaca_key_h *sym_key, +// TODO: this NEEDS random number generator initialized +// there is some other TODO elsewhere about it +API int yaca_key_gen(yaca_key_h *key, yaca_key_type_e key_type, size_t key_bits) { int ret; - struct yaca_key_simple_s *nk = NULL; - size_t key_byte_len = key_bits / 8; + struct yaca_key_simple_s *nk_simple = NULL; + struct yaca_key_evp_s *nk_evp = NULL; - if (sym_key == NULL || key_bits % 8 != 0) + if (key == NULL || key_bits == 0 || key_bits % 8 != 0) return YACA_ERROR_INVALID_ARGUMENT; switch(key_type) { case YACA_KEY_TYPE_SYMMETRIC: case YACA_KEY_TYPE_IV: - break; - case YACA_KEY_TYPE_DES: - return YACA_ERROR_NOT_IMPLEMENTED; - default: - return YACA_ERROR_INVALID_ARGUMENT; - } - - if (key_byte_len > SIZE_MAX - sizeof(struct yaca_key_simple_s)) - return YACA_ERROR_TOO_BIG_ARGUMENT; + ret = gen_simple(&nk_simple, key_bits); + if (ret != 0) + return ret; - nk = yaca_zalloc(sizeof(struct yaca_key_simple_s) + key_byte_len); - if (nk == NULL) - return YACA_ERROR_OUT_OF_MEMORY; + nk_simple->key.type = key_type; - nk->bits = key_bits; - nk->key.type = key_type; + *key = (yaca_key_h)nk_simple; + return 0; - ret = yaca_rand_bytes(nk->d, key_byte_len); - if (ret != 0) - goto err; + case YACA_KEY_TYPE_RSA_PRIV: + ret = gen_evp_rsa(&nk_evp, key_bits); + if (ret != 0) + return ret; - *sym_key = (yaca_key_h)nk; + nk_evp->key.type = key_type; - return 0; + *key = (yaca_key_h)nk_evp; + return 0; -err: - yaca_free(nk); - return ret; + case YACA_KEY_TYPE_DES: + case YACA_KEY_TYPE_DSA_PRIV: + case YACA_KEY_TYPE_DH_PRIV: + case YACA_KEY_TYPE_ECDSA_PRIV: + case YACA_KEY_TYPE_ECDH_PRIV: + return YACA_ERROR_NOT_IMPLEMENTED; + default: + return YACA_ERROR_INVALID_ARGUMENT; + } } API int yaca_key_extract_public(const yaca_key_h prv_key, yaca_key_h *pub_key) -- 2.7.4 From c74009102692e8ef59f70de4c49917efbd387c16 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 4 May 2016 13:36:27 +0200 Subject: [PATCH 13/16] Removal of yaca_key_gen_pair() and its enum values You can achieve the same now with yaca_key_gen() and yaca_key_extract_public() if/when the latter is needed. Change-Id: I5f47ed118e283b4d868f000108900f377b1260df --- api/yaca/key.h | 20 +------- api/yaca/types.h | 6 --- examples/key_exchange.c | 14 ++++-- examples/key_import_export.c | 6 ++- examples/seal.c | 10 ++-- examples/sign.c | 5 +- src/key.c | 113 ------------------------------------------- todo.txt | 1 - 8 files changed, 28 insertions(+), 147 deletions(-) diff --git a/api/yaca/key.h b/api/yaca/key.h index e1126a6..0ffc8cf 100644 --- a/api/yaca/key.h +++ b/api/yaca/key.h @@ -122,7 +122,7 @@ int yaca_key_export(const yaca_key_h key, * @param[in] key_bits Length of the key (in bits) to be generated. * * @return 0 on success, negative on error. - * @see #yaca_key_type_e, #yaca_key_bits_e, yaca_key_gen_pair(), yaca_key_free() + * @see #yaca_key_type_e, #yaca_key_bits_e, yaca_key_free() */ int yaca_key_gen(yaca_key_h *key, yaca_key_type_e key_type, @@ -140,27 +140,11 @@ int yaca_key_gen(yaca_key_h *key, int yaca_key_extract_public(const yaca_key_h prv_key, yaca_key_h *pub_key); /** - * @brief yaca_key_gen_pair Generates a new key pair. - * - * @param[out] prv_key Newly generated private key (must be freed with yaca_key_free()). - * @param[out] pub_key Newly generated public key (must be freed with yaca_key_free()). - * @param[in] key_type Type of the key to be generated (must be YACA_KEY_TYPE_PAIR*). - * @param[in] key_bits Length of the key (in bits) to be generated. - * - * @return 0 on success, negative on error. - * @see #yaca_key_type_e, #yaca_key_bits_e, yaca_key_gen(), yaca_key_free() - */ -int yaca_key_gen_pair(yaca_key_h *prv_key, - yaca_key_h *pub_key, - yaca_key_type_e key_type, - size_t key_bits); - -/** * @brief yaca_key_free Frees the key created by the library. * Passing YACA_KEY_NULL is allowed. * * @param key Key to be freed. - * @see yaca_key_import(), yaca_key_export(), yaca_key_gen(), yaca_key_gen_pair() + * @see yaca_key_import(), yaca_key_export(), yaca_key_gen() * */ void yaca_key_free(yaca_key_h key); diff --git a/api/yaca/types.h b/api/yaca/types.h index c467121..ea9b2bd 100644 --- a/api/yaca/types.h +++ b/api/yaca/types.h @@ -87,12 +87,6 @@ typedef enum { // TODO: ECDH might not exist as a separate key type, remove? YACA_KEY_TYPE_ECDH_PUB, /**< Elliptic Curve Diffie-Hellman public key */ YACA_KEY_TYPE_ECDH_PRIV, /**< Elliptic Curve Diffie-Hellman private key */ - - YACA_KEY_TYPE_PAIR_RSA, /**< Pair of RSA keys */ - YACA_KEY_TYPE_PAIR_DSA, /**< Pair of DSA keys */ - YACA_KEY_TYPE_PAIR_DH, /**< Pair of DH keys */ - YACA_KEY_TYPE_PAIR_ECDSA, /**< Pair of ECDSA keys */ - YACA_KEY_TYPE_PAIR_ECDH /**< Pair of ECDH keys */ } yaca_key_type_e; /** diff --git a/examples/key_exchange.c b/examples/key_exchange.c index 9192679..b3e4f05 100644 --- a/examples/key_exchange.c +++ b/examples/key_exchange.c @@ -43,9 +43,11 @@ void key_exchange_dh(void) long size; // generate private, public key - // add KEY_TYPE_PAIR_DH or use KEY_TYPE_PAIR_ECC and proper len? - // imo add KEY_TYPE_PAIR_DH - ret = yaca_key_gen_pair(&private_key, &public_key, YACA_KEY_TYPE_PAIR_DH, YACA_KEY_2048BIT); + ret = yaca_key_gen(&private_key, YACA_KEY_TYPE_DH_PRIV, YACA_KEY_2048BIT); + if (ret < 0) + goto clean; + + ret = yaca_key_extract_public(private_key, &public_key); if (ret < 0) goto clean; @@ -101,7 +103,11 @@ void key_exchange_ecdh(void) long size; // generate private, public key - ret = yaca_key_gen_pair(&private_key, &public_key, YACA_KEY_TYPE_PAIR_ECDH, YACA_KEY_CURVE_P256); + ret = yaca_key_gen(&private_key, YACA_KEY_TYPE_ECDH_PRIV, YACA_KEY_CURVE_P256); + if (ret < 0) + goto clean; + + ret = yaca_key_extract_public(private_key, &public_key); if (ret < 0) goto clean; diff --git a/examples/key_import_export.c b/examples/key_import_export.c index fba4664..02fb4ab 100644 --- a/examples/key_import_export.c +++ b/examples/key_import_export.c @@ -213,7 +213,11 @@ int main() if (ret != 0) goto exit; - ret = yaca_key_gen_pair(&rsa_priv, &rsa_pub, YACA_KEY_TYPE_PAIR_RSA, YACA_KEY_1024BIT); + ret = yaca_key_gen(&rsa_priv, YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_1024BIT); + if (ret != 0) + goto free_sym; + + ret = yaca_key_extract_public(rsa_priv, &rsa_pub); if (ret != 0) goto free_sym; diff --git a/examples/seal.c b/examples/seal.c index a631c91..c75b721 100644 --- a/examples/seal.c +++ b/examples/seal.c @@ -54,13 +54,16 @@ void encrypt_seal(void) printf("Plain data (16 of %zu bytes): %.16s\n", LOREM4096_SIZE, lorem4096); /* Generate key pair */ - if (yaca_key_gen_pair(&key_priv, &key_pub, YACA_KEY_TYPE_PAIR_RSA, YACA_KEY_4096BIT) != 0) + if (yaca_key_gen(&key_priv, YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_4096BIT) != 0) return; + if (yaca_key_extract_public(key_priv, &key_pub) != 0) + goto ex_prvk; + /* Encrypt a.k.a. seal */ { if (yaca_seal_init(&ctx, key_pub, algo, bcm, key_bits, &aes_key, &iv) != 0) - goto ex_pk; + goto ex_pubk; if ((block_len = yaca_get_block_length(ctx)) <= 0) goto ex_ak; @@ -128,8 +131,9 @@ ex_ak: yaca_ctx_free(ctx); yaca_key_free(aes_key); yaca_key_free(iv); -ex_pk: +ex_pubk: yaca_key_free(key_pub); +ex_prvk: yaca_key_free(key_priv); } diff --git a/examples/sign.c b/examples/sign.c index 58b921f..84d5574 100644 --- a/examples/sign.c +++ b/examples/sign.c @@ -46,9 +46,12 @@ void sign_verify_rsa(void) #endif // GENERATE - if (yaca_key_gen_pair(&prv, &pub, YACA_KEY_TYPE_PAIR_RSA, YACA_KEY_4096BIT) != 0) + if (yaca_key_gen(&prv, YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_4096BIT) != 0) return; + if (yaca_key_extract_public(prv, &pub) != 0) + goto finish; + // SIGN if (yaca_sign_init(&ctx, YACA_DIGEST_SHA512, prv) != 0) goto finish; diff --git a/src/key.c b/src/key.c index 2ba3fe9..de2b48e 100644 --- a/src/key.c +++ b/src/key.c @@ -855,119 +855,6 @@ free_key: return ret; } -API int yaca_key_gen_pair(yaca_key_h *prv_key, - yaca_key_h *pub_key, - yaca_key_type_e key_type, - size_t key_bits) -{ - int ret; - struct yaca_key_evp_s *nk_prv = NULL; - struct yaca_key_evp_s *nk_pub = NULL; - RSA *rsa = NULL; - BIGNUM *bne = NULL; - - if (prv_key == NULL || pub_key == NULL) - return YACA_ERROR_INVALID_ARGUMENT; - - if (key_type != YACA_KEY_TYPE_PAIR_RSA) - return YACA_ERROR_NOT_IMPLEMENTED; - - nk_prv = yaca_zalloc(sizeof(struct yaca_key_evp_s)); - if (nk_prv == NULL) - return YACA_ERROR_OUT_OF_MEMORY; - - nk_pub = yaca_zalloc(sizeof(struct yaca_key_evp_s)); - if (nk_pub == NULL) { - ret = YACA_ERROR_OUT_OF_MEMORY; - goto free_prv; - } - - // TODO: this NEEDS random number generator initialized - // there is some other TODO elsewhere about it - - bne = BN_new(); - if (bne == NULL) { - ret = YACA_ERROR_OUT_OF_MEMORY; - ERROR_DUMP(ret); - goto free_pub; - } - - ret = BN_set_word(bne, RSA_F4); - if (ret != 1) { - ret = YACA_ERROR_INTERNAL; - ERROR_DUMP(ret); - goto free_bne; - } - - rsa = RSA_new(); - if (rsa == NULL) { - ret = YACA_ERROR_OUT_OF_MEMORY; - ERROR_DUMP(ret); - goto free_bne; - } - - ret = RSA_generate_key_ex(rsa, key_bits, bne, NULL); - if (ret != 1) { - ret = YACA_ERROR_INTERNAL; - ERROR_DUMP(ret); - goto free_rsa; - } - - nk_prv->evp = EVP_PKEY_new(); - if (nk_prv->evp == NULL) { - ret = YACA_ERROR_OUT_OF_MEMORY; - ERROR_DUMP(ret); - goto free_rsa; - } - - nk_pub->evp = EVP_PKEY_new(); - if (nk_prv->evp == NULL) { - ret = YACA_ERROR_OUT_OF_MEMORY; - ERROR_DUMP(ret); - goto free_evp_prv; - } - - ret = EVP_PKEY_assign_RSA(nk_prv->evp, RSAPrivateKey_dup(rsa)); - if (ret != 1) { - ret = YACA_ERROR_INTERNAL; - ERROR_DUMP(ret); - goto free_evp_pub; - } - - ret = EVP_PKEY_assign_RSA(nk_pub->evp, RSAPublicKey_dup(rsa)); - if (ret != 1) { - ret = YACA_ERROR_INTERNAL; - ERROR_DUMP(ret); - goto free_evp_pub; - } - - *prv_key = (yaca_key_h)nk_prv; - (*prv_key)->type = YACA_KEY_TYPE_RSA_PRIV; - *pub_key = (yaca_key_h)nk_pub; - (*pub_key)->type = YACA_KEY_TYPE_RSA_PUB; - - ret = 0; - -free_evp_pub: - if (ret != 0) - EVP_PKEY_free(nk_pub->evp); -free_evp_prv: - if (ret != 0) - EVP_PKEY_free(nk_prv->evp); -free_rsa: - RSA_free(rsa); -free_bne: - BN_free(bne); -free_pub: - if (ret != 0) - yaca_free(nk_pub); -free_prv: - if (ret != 0) - yaca_free(nk_prv); - - return ret; -} - API void yaca_key_free(yaca_key_h key) { struct yaca_key_simple_s *simple_key = key_get_simple(key); diff --git a/todo.txt b/todo.txt index b2e5846..a13943d 100644 --- a/todo.txt +++ b/todo.txt @@ -2,4 +2,3 @@ Global: - Rethink and possibly add verification of output buffer lengths. In other words check whether the user won't cause a buffer overflow. - Importing/exporting encrypted (passphrased) RSA keys -- What about importing RSA priv and generating PUB from it? -- 2.7.4 From dba9420e3a86166562aa8e3a18cc637b75a361d1 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Fri, 6 May 2016 11:49:23 +0200 Subject: [PATCH 14/16] Add missing example comments Change-Id: Ie67851cf21395a72519ff2d2e79973184572749c --- examples/key_import_export.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/key_import_export.c b/examples/key_import_export.c index 02fb4ab..57b231c 100644 --- a/examples/key_import_export.c +++ b/examples/key_import_export.c @@ -44,6 +44,8 @@ void key_import_export_sym(yaca_key_h sym) yaca_key_h b64_imported = YACA_KEY_NULL; + /* BASE64 */ + ret = yaca_key_export(sym, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_BASE64, &b64, &b64_len); if (ret != 0) return; @@ -62,6 +64,8 @@ void key_import_export_sym(yaca_key_h sym) printf("\t***** BASE64 imported key: *****\n%*s\n", (int)b64_len, b64); + /* RAW */ + ret = yaca_key_export(sym, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_RAW, &raw, &raw_len); if (ret != 0) goto free; -- 2.7.4 From 571478e61b249ae1c9a5c78f2652d164baf75bda Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Fri, 6 May 2016 16:18:53 +0200 Subject: [PATCH 15/16] Add GNU global files to .gitignore Change-Id: I6e7160af73a35b33bdcf76059c3a99be8f29c0db --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 7115d13..3a844ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ build doc/html doc/man +GPATH +GRTAGS +GTAGS -- 2.7.4 From 1dcbbaa65ed769da7b54cdc1fb9ea3068cec3a75 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Fri, 6 May 2016 18:44:56 +0200 Subject: [PATCH 16/16] yaca_key_gen() and yaca_key_extract_public() for DSA There is no dedicated method to extract public key for DSA, only export/import (to temporary memory). As the latter method also works for RSA and I predict it will work for ECDSA I use it exclusively. Change-Id: Idf25df43da571cfb3d67192b5263e4a4c260feeb --- src/key.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 133 insertions(+), 37 deletions(-) diff --git a/src/key.c b/src/key.c index de2b48e..00a26d3 100644 --- a/src/key.c +++ b/src/key.c @@ -605,6 +605,90 @@ free_nk: return ret; } +int gen_evp_dsa(struct yaca_key_evp_s **out, size_t key_bits) +{ + assert(out != NULL); + assert(key_bits > 0); + assert(key_bits % 8 == 0); + + int ret; + struct yaca_key_evp_s *nk; + EVP_PKEY_CTX *pctx; + EVP_PKEY_CTX *kctx; + EVP_PKEY *pkey = NULL; + EVP_PKEY *params = NULL; + + nk = yaca_zalloc(sizeof(struct yaca_key_evp_s)); + if (nk == NULL) + return YACA_ERROR_OUT_OF_MEMORY; + + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL); + if (pctx == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_nk; + } + + ret = EVP_PKEY_paramgen_init(pctx); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_pctx; + } + + ret = EVP_PKEY_CTX_set_dsa_paramgen_bits(pctx, key_bits); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_pctx; + } + + ret = EVP_PKEY_paramgen(pctx, ¶ms); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_pctx; + } + + kctx = EVP_PKEY_CTX_new(params, NULL); + if (kctx == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_params; + } + + ret = EVP_PKEY_keygen_init(kctx); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_kctx; + } + + ret = EVP_PKEY_keygen(kctx, &pkey); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_kctx; + } + + nk->evp = pkey; + + *out = nk; + nk = NULL; + ret = 0; + +free_kctx: + EVP_PKEY_CTX_free(kctx); +free_params: + EVP_PKEY_free(params); +free_pctx: + EVP_PKEY_CTX_free(pctx); +free_nk: + yaca_free(nk); + + return ret; +} + struct yaca_key_simple_s *key_get_simple(const yaca_key_h key) { struct yaca_key_simple_s *k; @@ -777,8 +861,17 @@ API int yaca_key_gen(yaca_key_h *key, *key = (yaca_key_h)nk_evp; return 0; - case YACA_KEY_TYPE_DES: case YACA_KEY_TYPE_DSA_PRIV: + ret = gen_evp_dsa(&nk_evp, key_bits); + if (ret != 0) + return ret; + + nk_evp->key.type = key_type; + + *key = (yaca_key_h)nk_evp; + return 0; + + case YACA_KEY_TYPE_DES: case YACA_KEY_TYPE_DH_PRIV: case YACA_KEY_TYPE_ECDSA_PRIV: case YACA_KEY_TYPE_ECDH_PRIV: @@ -792,8 +885,9 @@ API int yaca_key_extract_public(const yaca_key_h prv_key, yaca_key_h *pub_key) { int ret; struct yaca_key_evp_s *evp_key = key_get_evp(prv_key); - struct yaca_key_evp_s *nk = NULL; - RSA *rsa_pub = NULL; + struct yaca_key_evp_s *nk; + BIO *mem; + EVP_PKEY *pkey; if (prv_key == YACA_KEY_NULL || evp_key == NULL || pub_key == NULL) return YACA_ERROR_INVALID_ARGUMENT; @@ -802,54 +896,56 @@ API int yaca_key_extract_public(const yaca_key_h prv_key, yaca_key_h *pub_key) if (nk == NULL) return YACA_ERROR_OUT_OF_MEMORY; - nk->evp = EVP_PKEY_new(); - if (nk->evp == NULL) { - ret = YACA_ERROR_OUT_OF_MEMORY; + mem = BIO_new(BIO_s_mem()); + if (mem == NULL) { + ret = YACA_ERROR_INTERNAL; ERROR_DUMP(ret); - goto free_key; + goto free_nk; } - switch(prv_key->type) - { - case YACA_KEY_TYPE_RSA_PRIV: - assert(EVP_PKEY_type(evp_key->evp->type) == EVP_PKEY_RSA); - - rsa_pub = RSAPublicKey_dup(EVP_PKEY_get0(evp_key->evp)); - if (rsa_pub == NULL) { - ret = YACA_ERROR_INTERNAL; - ERROR_DUMP(ret); - goto free_evp; - } + ret = i2d_PUBKEY_bio(mem, evp_key->evp); + if (ret != 1) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } - ret = EVP_PKEY_assign_RSA(nk->evp, rsa_pub); - if (ret != 1) { - ret = YACA_ERROR_INTERNAL; - ERROR_DUMP(ret); - goto free_rsa; - } + pkey = d2i_PUBKEY_bio(mem, NULL); + if (pkey == NULL) { + ret = YACA_ERROR_INTERNAL; + ERROR_DUMP(ret); + goto free_bio; + } - *pub_key = (yaca_key_h)nk; - (*pub_key)->type = YACA_KEY_TYPE_RSA_PUB; + BIO_free(mem); + mem = NULL; - return 0; + nk->evp = pkey; + *pub_key = (yaca_key_h)nk; + switch(prv_key->type) + { + case YACA_KEY_TYPE_RSA_PRIV: + (*pub_key)->type = YACA_KEY_TYPE_RSA_PUB; + break; case YACA_KEY_TYPE_DSA_PRIV: + (*pub_key)->type = YACA_KEY_TYPE_DSA_PUB; + break; case YACA_KEY_TYPE_ECDSA_PRIV: - ret = YACA_ERROR_NOT_IMPLEMENTED; - goto free_evp; - + (*pub_key)->type = YACA_KEY_TYPE_ECDSA_PUB; + break; default: ret = YACA_ERROR_INVALID_ARGUMENT; - goto free_evp; + goto free_pkey; } - return YACA_ERROR_INVALID_ARGUMENT; + return 0; -free_rsa: - RSA_free(rsa_pub); -free_evp: - EVP_PKEY_free(nk->evp); -free_key: +free_pkey: + EVP_PKEY_free(pkey); +free_bio: + BIO_free(mem); +free_nk: yaca_free(nk); return ret; -- 2.7.4