From f64a279a8f0470812194f0a2515192c81d81bab8 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Mon, 25 Apr 2016 18:33:26 +0200 Subject: [PATCH 01/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 02/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 03/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 04/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 05/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 06/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 07/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 08/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 09/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 10/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 11/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 12/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 13/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 From 82a68c8a8ab4ca140798a192c8086318ae915b00 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Mon, 9 May 2016 12:42:54 +0200 Subject: [PATCH 14/16] yaca_key_import()/yaca_key_export() for DSA It seems that my previous import/export commit was generic enough to handle DSA as well. Only minor change was required to enable DSA. That's why this commit is so short. Change-Id: I0627c10a723b0011dde705d74d290caa36533a9d --- src/key.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/key.c b/src/key.c index 00a26d3..2406350 100644 --- a/src/key.c +++ b/src/key.c @@ -777,10 +777,10 @@ API int yaca_key_import(yaca_key_h *key, 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: + return import_evp(key, key_type, data, data_len); + case YACA_KEY_TYPE_DES: case YACA_KEY_TYPE_DH_PUB: case YACA_KEY_TYPE_DH_PRIV: case YACA_KEY_TYPE_ECDSA_PUB: -- 2.7.4 From d98b1aa22ed766ef6c311efc5940f11a13750d43 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Mon, 9 May 2016 13:20:54 +0200 Subject: [PATCH 15/16] Add DSA to import/export example Improved printing a little. This example can serve partially as a test. It has been written this way as a verification tool as we don't have proper tests yet. Change-Id: Ifbda0f17e2e8fc0b734d34d49668a4a7662c337d --- examples/key_import_export.c | 100 +++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 27 deletions(-) diff --git a/examples/key_import_export.c b/examples/key_import_export.c index 57b231c..6dc18e1 100644 --- a/examples/key_import_export.c +++ b/examples/key_import_export.c @@ -31,7 +31,7 @@ #include #include -void key_import_export_sym(yaca_key_h sym) +int key_import_export_sym(yaca_key_h sym) { int ret; @@ -48,12 +48,12 @@ void key_import_export_sym(yaca_key_h sym) ret = yaca_key_export(sym, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_BASE64, &b64, &b64_len); if (ret != 0) - return; + return ret; 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); + printf("\n\t***** BASE64 exported key: *****\n%.*s\n", (int)b64_len, b64); yaca_free(b64); b64 = NULL; @@ -61,7 +61,7 @@ void key_import_export_sym(yaca_key_h sym) if (ret != 0) goto free; - printf("\t***** BASE64 imported key: *****\n%*s\n", (int)b64_len, b64); + printf("\t***** BASE64 imported key: *****\n%.*s\n", (int)b64_len, b64); /* RAW */ @@ -83,14 +83,20 @@ void key_import_export_sym(yaca_key_h sym) dump_hex(raw, raw_len, "\t***** RAW imported key: *****"); + ret = 0; + free: yaca_key_free(raw_imported); yaca_key_free(b64_imported); yaca_free(raw); yaca_free(b64); + + return ret; } -void key_import_export_rsa(yaca_key_h priv, yaca_key_h pub) +int key_import_export_asym(yaca_key_h priv, yaca_key_h pub, + yaca_key_type_e priv_type, yaca_key_type_e pub_type, + const char *algo) { int ret; @@ -114,12 +120,12 @@ void key_import_export_rsa(yaca_key_h priv, yaca_key_h pub) 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); + return ret; + ret = yaca_key_import(&pem_prv_imported, priv_type, 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); + printf("\n\t***** %s PEM exported private key: *****\n%.*s", algo, (int)pem_prv_len, pem_prv); yaca_free(pem_prv); pem_prv = NULL; @@ -127,7 +133,7 @@ void key_import_export_rsa(yaca_key_h priv, yaca_key_h pub) if (ret != 0) goto free; - printf("\t***** PEM imported private key: *****\n%*s", (int)pem_prv_len, pem_prv); + printf("\t***** %s PEM imported private key: *****\n%.*s", algo, (int)pem_prv_len, pem_prv); /* DER private */ @@ -135,11 +141,11 @@ void key_import_export_rsa(yaca_key_h priv, yaca_key_h pub) 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); + ret = yaca_key_import(&der_prv_imported, priv_type, der_prv, der_prv_len); if (ret != 0) goto free; - dump_hex(der_prv, der_prv_len, "\n\t***** DER exported private key: *****"); + dump_hex(der_prv, der_prv_len, "\n\t***** %s DER exported private key: *****", algo); yaca_free(der_prv); der_prv = NULL; @@ -147,7 +153,7 @@ void key_import_export_rsa(yaca_key_h priv, yaca_key_h pub) if (ret != 0) goto free; - dump_hex(der_prv, der_prv_len, "\t***** DER imported private key: *****"); + dump_hex(der_prv, der_prv_len, "\t***** %s DER imported private key: *****", algo); /* PEM public */ @@ -155,11 +161,11 @@ void key_import_export_rsa(yaca_key_h priv, yaca_key_h pub) 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); + ret = yaca_key_import(&pem_pub_imported, pub_type, 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); + printf("\n\t***** %s PEM exported public key: *****\n%.*s", algo, (int)pem_pub_len, pem_pub); yaca_free(pem_pub); pem_pub = NULL; @@ -167,7 +173,7 @@ void key_import_export_rsa(yaca_key_h priv, yaca_key_h pub) if (ret != 0) goto free; - printf("\t***** PEM imported public key: *****\n%*s", (int)pem_pub_len, pem_pub); + printf("\t***** %s PEM imported public key: *****\n%.*s", algo, (int)pem_pub_len, pem_pub); /* DER public */ @@ -175,11 +181,11 @@ void key_import_export_rsa(yaca_key_h priv, yaca_key_h pub) 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); + ret = yaca_key_import(&der_pub_imported, pub_type, der_pub, der_pub_len); if (ret != 0) goto free; - dump_hex(der_pub, der_pub_len, "\n\t***** DER exported public key: *****"); + dump_hex(der_pub, der_pub_len, "\n\t***** %s DER exported public key: *****", algo); yaca_free(der_pub); der_pub = NULL; @@ -187,7 +193,9 @@ void key_import_export_rsa(yaca_key_h priv, yaca_key_h pub) if (ret != 0) goto free; - dump_hex(der_pub, der_pub_len, "\t***** DER imported public key: *****"); + dump_hex(der_pub, der_pub_len, "\t***** %s DER imported public key: *****", algo); + + ret = 0; free: yaca_key_free(der_pub_imported); @@ -198,13 +206,17 @@ free: yaca_free(pem_pub); yaca_free(der_prv); yaca_free(pem_prv); + + return ret; } int main() { - yaca_key_h sym; - yaca_key_h rsa_priv; - yaca_key_h rsa_pub; + yaca_key_h sym = YACA_KEY_NULL; + yaca_key_h rsa_priv = YACA_KEY_NULL; + yaca_key_h rsa_pub = YACA_KEY_NULL; + yaca_key_h dsa_priv = YACA_KEY_NULL; + yaca_key_h dsa_pub = YACA_KEY_NULL; int ret; ret = yaca_init(); @@ -219,18 +231,52 @@ int main() ret = yaca_key_gen(&rsa_priv, YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_1024BIT); if (ret != 0) - goto free_sym; + goto free; ret = yaca_key_extract_public(rsa_priv, &rsa_pub); if (ret != 0) - goto free_sym; + goto free; - key_import_export_sym(sym); - key_import_export_rsa(rsa_priv, rsa_pub); + ret = yaca_key_gen(&dsa_priv, YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_1024BIT); + if (ret != 0) + goto free; - yaca_key_free(rsa_priv); + ret = yaca_key_extract_public(dsa_priv, &dsa_pub); + if (ret != 0) + goto free; + + printf("\t***************************************\n"); + printf("\t************** SYMMETRIC **************\n"); + printf("\t***************************************\n"); + ret = key_import_export_sym(sym); + if (ret == 0) + printf("\n\t********* SYMMETRIC - success *********\n\n"); + else + printf("\n\t********* SYMMETRIC - failure *********\n\n"); + + printf("\t***************************************\n"); + printf("\t***************** RSA *****************\n"); + printf("\t***************************************\n"); + ret = key_import_export_asym(rsa_priv, rsa_pub, YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_TYPE_RSA_PUB, "RSA"); + if (ret == 0) + printf("\n\t************ RSA - success ************\n\n"); + else + printf("\n\t************ RSA - failure ************\n\n"); + + printf("\t***************************************\n"); + printf("\t***************** DSA *****************\n"); + printf("\t***************************************\n"); + ret = key_import_export_asym(dsa_priv, dsa_pub, YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_TYPE_DSA_PUB, "DSA"); + if (ret == 0) + printf("\n\t************ DSA - success ************\n\n"); + else + printf("\n\t************ DSA - failure ************\n\n"); + +free: + yaca_key_free(dsa_pub); + yaca_key_free(dsa_priv); yaca_key_free(rsa_pub); -free_sym: + yaca_key_free(rsa_priv); yaca_key_free(sym); exit: yaca_exit(); -- 2.7.4 From 3fe61dca1147ecad93699d4d27bc12bc7ece3f65 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Mon, 9 May 2016 13:27:08 +0200 Subject: [PATCH 16/16] DSA sign/verify support The previous implementation was generic enough to handle DSA as well. Change-Id: I0c952e340cae3fabb05aa0e10fa5f0947319e4f8 --- src/sign.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sign.c b/src/sign.c index 24fe7ac..b885cc6 100644 --- a/src/sign.c +++ b/src/sign.c @@ -157,9 +157,9 @@ API int yaca_sign_init(yaca_ctx_h *ctx, { case YACA_KEY_TYPE_SYMMETRIC: case YACA_KEY_TYPE_RSA_PRIV: + case YACA_KEY_TYPE_DSA_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; @@ -277,9 +277,9 @@ API int yaca_verify_init(yaca_ctx_h *ctx, nc->op_type = OP_VERIFY_SYMMETRIC; break; case YACA_KEY_TYPE_RSA_PUB: + case YACA_KEY_TYPE_DSA_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; -- 2.7.4