diff --git a/jni/themis_message.c b/jni/themis_message.c index e9ed80a70..d3c0f4e8f 100644 --- a/jni/themis_message.c +++ b/jni/themis_message.c @@ -18,7 +18,12 @@ #include #include -JNIEXPORT jbyteArray JNICALL Java_com_cossacklabs_themis_SecureMessage_process(JNIEnv *env, jobject thiz, jbyteArray private, jbyteArray public, jbyteArray message, jboolean is_wrap) +#define SECURE_MESSAGE_ENCRYPT 1 +#define SECURE_MESSAGE_DECRYPT 2 +#define SECURE_MESSAGE_SIGN 3 +#define SECURE_MESSAGE_VERIFY 4 + +JNIEXPORT jbyteArray JNICALL Java_com_cossacklabs_themis_SecureMessage_process(JNIEnv *env, jobject thiz, jbyteArray private, jbyteArray public, jbyteArray message, jint action) { size_t private_length = 0; size_t public_length = 0; @@ -67,13 +72,23 @@ JNIEXPORT jbyteArray JNICALL Java_com_cossacklabs_themis_SecureMessage_process(J goto err; } - if (is_wrap) - { - res = themis_secure_message_wrap((uint8_t *)priv_buf, private_length, (uint8_t *)pub_buf, public_length, (uint8_t *)message_buf, message_length, NULL, &output_length); - } - else + switch (action) { - res = themis_secure_message_unwrap((uint8_t *)priv_buf, private_length, (uint8_t *)pub_buf, public_length, (uint8_t *)message_buf, message_length, NULL, &output_length); + case SECURE_MESSAGE_ENCRYPT: + res = themis_secure_message_encrypt((uint8_t *)priv_buf, private_length, (uint8_t *)pub_buf, public_length, (uint8_t *)message_buf, message_length, NULL, &output_length); + break; + case SECURE_MESSAGE_DECRYPT: + res = themis_secure_message_decrypt((uint8_t *)priv_buf, private_length, (uint8_t *)pub_buf, public_length, (uint8_t *)message_buf, message_length, NULL, &output_length); + break; + case SECURE_MESSAGE_SIGN: + res = themis_secure_message_sign((uint8_t *)priv_buf, private_length, (uint8_t *)message_buf, message_length, NULL, &output_length); + break; + case SECURE_MESSAGE_VERIFY: + res = themis_secure_message_verify((uint8_t *)pub_buf, public_length, (uint8_t *)message_buf, message_length, NULL, &output_length); + break; + default: + res = THEMIS_NOT_SUPPORTED; + break; } if (THEMIS_BUFFER_TOO_SMALL != res) @@ -93,13 +108,23 @@ JNIEXPORT jbyteArray JNICALL Java_com_cossacklabs_themis_SecureMessage_process(J goto err; } - if (is_wrap) - { - res = themis_secure_message_wrap((uint8_t *)priv_buf, private_length, (uint8_t *)pub_buf, public_length, (uint8_t *)message_buf, message_length, (uint8_t *)output_buf, &output_length); - } - else - { - res = themis_secure_message_unwrap((uint8_t *)priv_buf, private_length, (uint8_t *)pub_buf, public_length, (uint8_t *)message_buf, message_length, (uint8_t *)output_buf, &output_length); + switch (action) + { + case SECURE_MESSAGE_ENCRYPT: + res = themis_secure_message_encrypt((uint8_t *)priv_buf, private_length, (uint8_t *)pub_buf, public_length, (uint8_t *)message_buf, message_length, (uint8_t *)output_buf, &output_length); + break; + case SECURE_MESSAGE_DECRYPT: + res = themis_secure_message_decrypt((uint8_t *)priv_buf, private_length, (uint8_t *)pub_buf, public_length, (uint8_t *)message_buf, message_length, (uint8_t *)output_buf, &output_length); + break; + case SECURE_MESSAGE_SIGN: + res = themis_secure_message_sign((uint8_t *)priv_buf, private_length, (uint8_t *)message_buf, message_length, (uint8_t *)output_buf, &output_length); + break; + case SECURE_MESSAGE_VERIFY: + res = themis_secure_message_verify((uint8_t *)pub_buf, public_length, (uint8_t *)message_buf, message_length, (uint8_t *)output_buf, &output_length); + break; + default: + res = THEMIS_NOT_SUPPORTED; + break; } err: diff --git a/src/themis/secure_keygen.c b/src/themis/secure_keygen.c new file mode 100644 index 000000000..33be2ee06 --- /dev/null +++ b/src/themis/secure_keygen.c @@ -0,0 +1,126 @@ +/* +* Copyright (c) 2019 Cossack Labs Limited +* +* 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. +*/ + +#include "secure_keygen.h" + +#include +#include + +#include +#include +#include +#include +#include + +#ifndef THEMIS_RSA_KEY_LENGTH +#define THEMIS_RSA_KEY_LENGTH RSA_KEY_LENGTH_2048 +#endif +themis_status_t themis_gen_key_pair(soter_sign_alg_t alg, + uint8_t* private_key, + size_t* private_key_length, + uint8_t* public_key, + size_t* public_key_length) +{ + soter_sign_ctx_t* ctx=soter_sign_create(alg,NULL,0,NULL,0); + THEMIS_CHECK(ctx!=NULL); + soter_status_t res=soter_sign_export_key(ctx, private_key, private_key_length, true); + if(res!=THEMIS_SUCCESS && res!=THEMIS_BUFFER_TOO_SMALL){ + soter_sign_destroy(ctx); + return res; + } + soter_status_t res2=soter_sign_export_key(ctx, public_key, public_key_length, false); + if(res2!=THEMIS_SUCCESS && res2!=THEMIS_BUFFER_TOO_SMALL){ + soter_sign_destroy(ctx); + return res; + } + soter_sign_destroy(ctx); + if(res==THEMIS_BUFFER_TOO_SMALL || res2==THEMIS_BUFFER_TOO_SMALL){ + return THEMIS_BUFFER_TOO_SMALL; + } + return THEMIS_SUCCESS; +} + +themis_status_t themis_gen_rsa_key_pair(uint8_t* private_key, + size_t* private_key_length, + uint8_t* public_key, + size_t* public_key_length){ + soter_rsa_key_pair_gen_t* key_pair_ctx=soter_rsa_key_pair_gen_create(THEMIS_RSA_KEY_LENGTH); + THEMIS_CHECK(key_pair_ctx!=NULL); + soter_status_t res=soter_rsa_key_pair_gen_export_key(key_pair_ctx, private_key, private_key_length, true); + if(res!=THEMIS_SUCCESS && res != THEMIS_BUFFER_TOO_SMALL){ + soter_rsa_key_pair_gen_destroy(key_pair_ctx); + return res; + } + soter_status_t res2=soter_rsa_key_pair_gen_export_key(key_pair_ctx, public_key, public_key_length, false); + if(res2!=THEMIS_SUCCESS && res2!=THEMIS_BUFFER_TOO_SMALL){ + soter_rsa_key_pair_gen_destroy(key_pair_ctx); + return res2; + } + soter_rsa_key_pair_gen_destroy(key_pair_ctx); + if(res==THEMIS_BUFFER_TOO_SMALL || res2==THEMIS_BUFFER_TOO_SMALL){ + return THEMIS_BUFFER_TOO_SMALL; + } + return THEMIS_SUCCESS; +} + +themis_status_t themis_gen_ec_key_pair(uint8_t* private_key, + size_t* private_key_length, + uint8_t* public_key, + size_t* public_key_length){ + return themis_gen_key_pair(SOTER_SIGN_ecdsa_none_pkcs8, private_key, private_key_length, public_key, public_key_length); +} + +themis_key_kind_t themis_get_asym_key_kind(const uint8_t* key, size_t length){ + const soter_container_hdr_t* container=(const void*)key; + + if(!key || (lengthtag, RSA_PRIV_KEY_PREF, strlen(RSA_PRIV_KEY_PREF))){ + return THEMIS_KEY_RSA_PRIVATE; + } + if(!memcmp(container->tag, RSA_PUB_KEY_PREF, strlen(RSA_PUB_KEY_PREF))){ + return THEMIS_KEY_RSA_PUBLIC; + } + if(!memcmp(container->tag, EC_PRIV_KEY_PREF, strlen(EC_PRIV_KEY_PREF))){ + return THEMIS_KEY_EC_PRIVATE; + } + if(!memcmp(container->tag, EC_PUB_KEY_PREF, strlen(EC_PUB_KEY_PREF))){ + return THEMIS_KEY_EC_PUBLIC; + } + + return THEMIS_KEY_INVALID; +} + +themis_status_t themis_is_valid_asym_key(const uint8_t* key, size_t length){ + const soter_container_hdr_t* container=(const void*)key; + + if(!key || (lengthsize)){ + return THEMIS_INVALID_PARAMETER; + } + if(SOTER_SUCCESS!=soter_verify_container_checksum(container)){ + return THEMIS_DATA_CORRUPT; + } + + return THEMIS_SUCCESS; +} diff --git a/src/themis/secure_keygen.h b/src/themis/secure_keygen.h new file mode 100644 index 000000000..f09939781 --- /dev/null +++ b/src/themis/secure_keygen.h @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2019 Cossack Labs Limited +* +* 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 secure_keygen.h + * @brief secure key generation + */ + +#ifndef _THEMIS_SECURE_KEYGEN_H_ +#define _THEMIS_SECURE_KEYGEN_H_ + +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * @addtogroup THEMIS + * @{ + * @defgroup THEMIS_KEYS secure key generation + * @brief securely generating random key pairs + * @{ + */ + +/** + * @brief generate RSA key pair + * @param [out] private_key buffer for private key to store. May be set to NULL for private key length determination + * @param [in, out] private_key_length length of private_key + * @param [out] public_key buffer for public key to store. May be set to NULL for public key length determination + * @param [in, out] public_key_length length of public key + * @return THEMIS_SUCCESS on success or THEMIS_FAIL on failure + * @note If private_key==NULL or public_key==NULL or private_key_length is not enought for private key storage or public_key_length is not enought for public key storage then THEMIS_BUFFER_TOO_SMALL will return and private_key_length and public_key_length will store lengths of buffers needed for private key and public key store respectively + */ +themis_status_t themis_gen_rsa_key_pair(uint8_t* private_key, + size_t* private_key_length, + uint8_t* public_key, + size_t* public_key_length); + +/** + * @brief generate EC key pair + * @param [out] private_key buffer for private key to store. May be set to NULL for private key length determination + * @param [in, out] private_key_length length of private_key + * @param [out] public_key buffer for public key to store. May be set to NULL for public key length determination + * @param [in, out] public_key_length length of public key + * @return THEMIS_SUCCESS on success or THEMIS_FAIL on failure + * @note If private_key==NULL or public_key==NULL or private_key_length is not enought for private key storage or public_key_length is not enought for public key storage then THEMIS_BUFFER_TOO_SMALL will return and private_key_length and public_key_length will store lengths of buffers needed for private key and public key store respectively + */ +themis_status_t themis_gen_ec_key_pair(uint8_t* private_key, + size_t* private_key_length, + uint8_t* public_key, + size_t* public_key_length); + +enum themis_key_kind +{ + THEMIS_KEY_INVALID, + THEMIS_KEY_RSA_PRIVATE, + THEMIS_KEY_RSA_PUBLIC, + THEMIS_KEY_EC_PRIVATE, + THEMIS_KEY_EC_PUBLIC, +}; + +typedef enum themis_key_kind themis_key_kind_t; + +/** + * @brief get Themis key kind + * @param [in] key key buffer + * @param [in] length length of key + * @return corresponding key kind if the buffer contains a key, or THEMIS_KEY_INVALID otherwise + */ +themis_key_kind_t themis_get_asym_key_kind(const uint8_t* key, size_t length); + +/** + * @brief validate a Themis key + * @param [in] key key buffer to validate + * @param [in] length length of key + * @return THEMIS_SUCCESS if the buffer contains a valid Themis key, or an error code otherwise + */ +themis_status_t themis_is_valid_asym_key(const uint8_t* key, size_t length); + +/** @} */ +/** @} */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _THEMIS_SECURE_KEYGEN_H_ */ diff --git a/src/themis/secure_message.c b/src/themis/secure_message.c index d478e4cf2..31921aa2f 100644 --- a/src/themis/secure_message.c +++ b/src/themis/secure_message.c @@ -14,69 +14,169 @@ * limitations under the License. */ +#include "secure_message.h" + #include #include #include -#include - -#ifndef THEMIS_RSA_KEY_LENGTH -#define THEMIS_RSA_KEY_LENGTH RSA_KEY_LENGTH_2048 -#endif -themis_status_t themis_gen_key_pair(soter_sign_alg_t alg, - uint8_t* private_key, - size_t* private_key_length, - uint8_t* public_key, - size_t* public_key_length) -{ - soter_sign_ctx_t* ctx=soter_sign_create(alg,NULL,0,NULL,0); - THEMIS_CHECK(ctx!=NULL); - soter_status_t res=soter_sign_export_key(ctx, private_key, private_key_length, true); - if(res!=THEMIS_SUCCESS && res!=THEMIS_BUFFER_TOO_SMALL){ - soter_sign_destroy(ctx); - return res; - } - soter_status_t res2=soter_sign_export_key(ctx, public_key, public_key_length, false); - if(res2!=THEMIS_SUCCESS && res2!=THEMIS_BUFFER_TOO_SMALL){ - soter_sign_destroy(ctx); - return res; - } - soter_sign_destroy(ctx); - if(res==THEMIS_BUFFER_TOO_SMALL || res2==THEMIS_BUFFER_TOO_SMALL){ - return THEMIS_BUFFER_TOO_SMALL; + +static bool valid_private_key(const uint8_t* private_key, size_t private_key_length){ + if(themis_is_valid_asym_key(private_key, private_key_length)==THEMIS_SUCCESS){ + themis_key_kind_t private_key_kind=themis_get_asym_key_kind(private_key, private_key_length); + switch(private_key_kind){ + case THEMIS_KEY_EC_PRIVATE: + case THEMIS_KEY_RSA_PRIVATE: + return true; + default: + break; + } } - return THEMIS_SUCCESS; + return false; } -themis_status_t themis_gen_rsa_key_pair(uint8_t* private_key, - size_t* private_key_length, - uint8_t* public_key, - size_t* public_key_length){ - soter_rsa_key_pair_gen_t* key_pair_ctx=soter_rsa_key_pair_gen_create(THEMIS_RSA_KEY_LENGTH); - THEMIS_CHECK(key_pair_ctx!=NULL); - soter_status_t res=soter_rsa_key_pair_gen_export_key(key_pair_ctx, private_key, private_key_length, true); - if(res!=THEMIS_SUCCESS && res != THEMIS_BUFFER_TOO_SMALL){ - soter_rsa_key_pair_gen_destroy(key_pair_ctx); - return res; +static bool valid_public_key(const uint8_t* public_key, size_t public_key_length){ + if(themis_is_valid_asym_key(public_key, public_key_length)==THEMIS_SUCCESS){ + themis_key_kind_t public_key_kind=themis_get_asym_key_kind(public_key, public_key_length); + switch(public_key_kind){ + case THEMIS_KEY_EC_PUBLIC: + case THEMIS_KEY_RSA_PUBLIC: + return true; + default: + break; + } } - soter_status_t res2=soter_rsa_key_pair_gen_export_key(key_pair_ctx, public_key, public_key_length, false); - if(res2!=THEMIS_SUCCESS && res2!=THEMIS_BUFFER_TOO_SMALL){ - soter_rsa_key_pair_gen_destroy(key_pair_ctx); - return res2; + return false; +} + +static bool matching_key_kinds(const uint8_t* private_key, size_t private_key_length, + const uint8_t* public_key, size_t public_key_length) +{ + themis_key_kind_t private_key_kind=themis_get_asym_key_kind(private_key, private_key_length); + themis_key_kind_t public_key_kind=themis_get_asym_key_kind(public_key, public_key_length); + if(private_key_kind==THEMIS_KEY_EC_PRIVATE && public_key_kind==THEMIS_KEY_EC_PUBLIC){ + return true; } - soter_rsa_key_pair_gen_destroy(key_pair_ctx); - if(res==THEMIS_BUFFER_TOO_SMALL || res2==THEMIS_BUFFER_TOO_SMALL){ - return THEMIS_BUFFER_TOO_SMALL; + if(private_key_kind==THEMIS_KEY_RSA_PRIVATE && public_key_kind==THEMIS_KEY_RSA_PUBLIC){ + return true; } - return THEMIS_SUCCESS; + return false; } -themis_status_t themis_gen_ec_key_pair(uint8_t* private_key, - size_t* private_key_length, - uint8_t* public_key, - size_t* public_key_length){ - return themis_gen_key_pair(SOTER_SIGN_ecdsa_none_pkcs8, private_key, private_key_length, public_key, public_key_length); +themis_status_t themis_secure_message_encrypt(const uint8_t* private_key, + const size_t private_key_length, + const uint8_t* public_key, + const size_t public_key_length, + const uint8_t* message, + const size_t message_length, + uint8_t* encrypted_message, + size_t* encrypted_message_length) +{ + THEMIS_CHECK_PARAM(message!=NULL); + THEMIS_CHECK_PARAM(message_length!=0); + THEMIS_CHECK_PARAM(encrypted_message_length!=NULL); + THEMIS_CHECK_PARAM(valid_private_key(private_key, private_key_length)); + THEMIS_CHECK_PARAM(valid_public_key(public_key, public_key_length)); + THEMIS_CHECK_PARAM(matching_key_kinds(private_key, private_key_length, public_key, public_key_length)); + + themis_secure_message_encrypter_t* ctx=NULL; + ctx = themis_secure_message_encrypter_init(private_key, private_key_length, public_key, public_key_length); + THEMIS_CHECK_PARAM(ctx); + + themis_status_t status=themis_secure_message_encrypter_proceed(ctx, message, message_length, encrypted_message, encrypted_message_length); + themis_secure_message_encrypter_destroy(ctx); + return status; } +themis_status_t themis_secure_message_decrypt(const uint8_t* private_key, + const size_t private_key_length, + const uint8_t* public_key, + const size_t public_key_length, + const uint8_t* encrypted_message, + const size_t encrypted_message_length, + uint8_t* message, + size_t* message_length) +{ + THEMIS_CHECK_PARAM(encrypted_message!=NULL); + THEMIS_CHECK_PARAM(encrypted_message_length!=0); + THEMIS_CHECK_PARAM(message_length!=NULL); + THEMIS_CHECK_PARAM(valid_private_key(private_key, private_key_length)); + THEMIS_CHECK_PARAM(valid_public_key(public_key, public_key_length)); + THEMIS_CHECK_PARAM(matching_key_kinds(private_key, private_key_length, public_key, public_key_length)); + + themis_secure_message_hdr_t* message_hdr=(themis_secure_message_hdr_t*)encrypted_message; + THEMIS_CHECK_PARAM(IS_THEMIS_SECURE_MESSAGE_ENCRYPTED(message_hdr->message_type)); + THEMIS_CHECK_PARAM(encrypted_message_length>=THEMIS_SECURE_MESSAGE_LENGTH(message_hdr)); + + themis_secure_message_decrypter_t* ctx=NULL; + ctx = themis_secure_message_decrypter_init(private_key, private_key_length, public_key, public_key_length); + THEMIS_CHECK_PARAM(ctx); + + themis_status_t status=themis_secure_message_decrypter_proceed(ctx, encrypted_message, encrypted_message_length, message, message_length); + themis_secure_message_decrypter_destroy(ctx); + return status; +} + +themis_status_t themis_secure_message_sign(const uint8_t* private_key, + const size_t private_key_length, + const uint8_t* message, + const size_t message_length, + uint8_t* signed_message, + size_t* signed_message_length) +{ + THEMIS_CHECK_PARAM(message!=NULL); + THEMIS_CHECK_PARAM(message_length!=0); + THEMIS_CHECK_PARAM(signed_message_length!=NULL); + THEMIS_CHECK_PARAM(valid_private_key(private_key, private_key_length)); + + themis_secure_message_signer_t* ctx=NULL; + ctx = themis_secure_message_signer_init(private_key, private_key_length); + THEMIS_CHECK_PARAM(ctx); + + themis_status_t res=themis_secure_message_signer_proceed(ctx, message, message_length, signed_message, signed_message_length); + themis_secure_message_signer_destroy(ctx); + return res; +} + +themis_status_t themis_secure_message_verify(const uint8_t* public_key, + const size_t public_key_length, + const uint8_t* signed_message, + const size_t signed_message_length, + uint8_t* message, + size_t* message_length) +{ + THEMIS_CHECK_PARAM(signed_message!=NULL); + THEMIS_CHECK_PARAM(signed_message_length!=0); + THEMIS_CHECK_PARAM(message_length!=NULL); + THEMIS_CHECK_PARAM(valid_public_key(public_key, public_key_length)); + + themis_secure_message_hdr_t* message_hdr=(themis_secure_message_hdr_t*)signed_message; + THEMIS_CHECK_PARAM(IS_THEMIS_SECURE_MESSAGE_SIGNED(message_hdr->message_type)); + THEMIS_CHECK_PARAM(signed_message_length>=THEMIS_SECURE_MESSAGE_LENGTH(message_hdr)); + + themis_secure_message_verifier_t* ctx=NULL; + ctx = themis_secure_message_verifier_init(public_key, public_key_length); + THEMIS_CHECK_PARAM(ctx); + + themis_status_t status=themis_secure_message_verifier_proceed(ctx, signed_message, signed_message_length, message, message_length); + themis_secure_message_verifier_destroy(ctx); + return status; +} + +/* + * themis_secure_message_wrap() and themis_secure_message_unwrap() functions + * are deprecated in favor of more specific themis_secure_message_encrypt() + * themis_secure_message_decrypt(), themis_secure_message_sign(), + * themis_secure_message_verify(). + * + * The old functions combined the interface of the new ones (wrap = encrypt + * or sign, unwrap = decrypt or verify). The new functions provide a more + * cleanly separated interface for distinct concerns. + * + * Note that while their implementation looks similar, they are not quite + * the same and differ slightly in error handling. Don't try to reimplement + * them in terms of each other. We will remove wrap and unwrap eventually. + */ + themis_status_t themis_secure_message_wrap(const uint8_t* private_key, const size_t private_key_length, const uint8_t* public_key, diff --git a/src/themis/secure_message.h b/src/themis/secure_message.h index 4cb8328e1..b1d11c788 100644 --- a/src/themis/secure_message.h +++ b/src/themis/secure_message.h @@ -37,32 +37,96 @@ extern "C"{ */ /** - * @brief generate RSA key pair - * @param [out] private_key buffer for private key to store. May be set to NULL for private key length determination - * @param [in, out] private_key_length length of private_key - * @param [out] public_key buffer for public key to store. May be set to NULL for public key length determination - * @param [in, out] public_key_length length of public key - * @return THEMIS_SUCCESS on success or THEMIS_FAIL on failure - * @note If private_key==NULL or public_key==NULL or private_key_length is not enought for private key storage or public_key_length is not enought for public key storage then THEMIS_BUFFER_TOO_SMALL will return and private_key_length and public_key_length will store lengths of buffers needed for private key and public key store respectively - */ -themis_status_t themis_gen_rsa_key_pair(uint8_t* private_key, - size_t* private_key_length, - uint8_t* public_key, - size_t* public_key_length); + * @brief encrypt message to secure message + * @param [in] private_key private key + * @param [in] private_key_length length of private_key + * @param [in] public_key peer public key + * @param [in] public_key_length length of public_key + * @param [in] message message to encrypt + * @param [in] message_length length of message + * @param [out] encrypted_message buffer for encrypted message. + * May be set to NULL to determine expected length of encrypted message + * @param [in, out] encrypted_message_length length of encrypted_message + * @return THEMIS_SUCCESS on success or an error code on failure + * @note If encrypted_message is NULL or encrypted_message_length is not enough to store the encrypted message + * then THEMIS_BUFFER_TOO_SMALL will be returned and encrypted_message_length will contain + * the length of the buffer needed to store the encrypted message. + */ +themis_status_t themis_secure_message_encrypt(const uint8_t* private_key, + const size_t private_key_length, + const uint8_t* public_key, + const size_t public_key_length, + const uint8_t* message, + const size_t message_length, + uint8_t* encrypted_message, + size_t* encrypted_message_length); /** - * @brief generate EC key pair - * @param [out] private_key buffer for private key to store. May be set to NULL for private key length determination - * @param [in, out] private_key_length length of private_key - * @param [out] public_key buffer for public key to store. May be set to NULL for public key length determination - * @param [in, out] public_key_length length of public key - * @return THEMIS_SUCCESS on success or THEMIS_FAIL on failure - * @note If private_key==NULL or public_key==NULL or private_key_length is not enought for private key storage or public_key_length is not enought for public key storage then THEMIS_BUFFER_TOO_SMALL will return and private_key_length and public_key_length will store lengths of buffers needed for private key and public key store respectively - */ -themis_status_t themis_gen_ec_key_pair(uint8_t* private_key, - size_t* private_key_length, - uint8_t* public_key, - size_t* public_key_length); + * @brief decrypt secure message to plaintext message + * @param [in] private_key private key + * @param [in] private_key_length length of private_key + * @param [in] public_key peer public key + * @param [in] public_key_length length of public_key + * @param [in] encrypted_message encrypted message to decrypt + * @param [in] encrypted_message_length length of encrypted_message + * @param [out] message buffer for plaintext message. + * May be set to NULL to determine expected length of plaintext message + * @param [in, out] message_length length of message + * @return THEMIS_SUCCESS on success or an error code on failure + * @note If message is NULL or message_length is not enough to store the plaintext message + * then THEMIS_BUFFER_TOO_SMALL will be returned and message_length will contain + * the length of the buffer needed to store the encrypted message. + */ +themis_status_t themis_secure_message_decrypt(const uint8_t* private_key, + const size_t private_key_length, + const uint8_t* public_key, + const size_t public_key_length, + const uint8_t* encrypted_message, + const size_t encrypted_message_length, + uint8_t* message, + size_t* message_length); + +/** + * @brief securely sign a message + * @param [in] private_key private key + * @param [in] private_key_length length of private_key + * @param [in] message message to sign + * @param [in] message_length length of message + * @param [out] signed_message buffer for signed message. + * May be set to NULL to determine expected length of signed message + * @param [in, out] signed_message_length length of signed_message + * @return THEMIS_SUCCESS on success or an error code on failure + * @note If signed_message is NULL or signed_message_length is not enough to store the signed message + * then THEMIS_BUFFER_TOO_SMALL will be returned and signed_message_length will contain + * the length of the buffer needed to store the signed message. + */ +themis_status_t themis_secure_message_sign(const uint8_t* private_key, + const size_t private_key_length, + const uint8_t* message, + const size_t message_length, + uint8_t* signed_message, + size_t* signed_message_length); + +/** + * @brief verify signature on a signed message + * @param [in] public_key peer public key + * @param [in] public_key_length length of public_key + * @param [in] signed_message signed message to verify + * @param [in] signed_message_length length of signed_message + * @param [out] message buffer for original message (without signature). + * May be set to NULL to determine expected length of original message + * @param [in, out] message_length length of message + * @return THEMIS_SUCCESS on success or an error code on failure + * @note If message is NULL or message_length is not enough to store the original message + * then THEMIS_BUFFER_TOO_SMALL will be returned and message_length will contain + * the length of the buffer needed to store the original message. + */ +themis_status_t themis_secure_message_verify(const uint8_t* public_key, + const size_t public_key_length, + const uint8_t* signed_message, + const size_t signed_message_length, + uint8_t* message, + size_t* message_length); /** * @brief wrap message to secure message @@ -77,6 +141,7 @@ themis_status_t themis_gen_ec_key_pair(uint8_t* private_key, * @return THEMIS_SUCCESS on success or THEMIS_FAIL on failure * @note If wrapped_message==NULL or wrapped_message_length is not enought for wrapped message storage then THEMIS_BUFFER_TOO_SMALL will return and wrapped_message_length will store length of buffer needed for wrapped message store */ +DEPRECATED("use 'themis_secure_message_encrypt' with private and public keys to encrypt message, or 'themis_secure_message_sign' with private key to sign message") themis_status_t themis_secure_message_wrap(const uint8_t* private_key, const size_t private_key_length, const uint8_t* public_key, @@ -99,6 +164,7 @@ themis_status_t themis_secure_message_wrap(const uint8_t* private_key, * @return THEMIS_SUCCESS on success or THEMIS_FAIL on failure * @note If message==NULL or message_length is not enought for plain message storage then THEMIS_BUFFER_TOO_SMALL will return and message_length will store length of buffer needed for plain message store */ +DEPRECATED("use 'themis_secure_message_decrypt' with private and public key to decrypt message or 'themis_secure_message_verify' with public key to verify signed message") themis_status_t themis_secure_message_unwrap(const uint8_t* private_key, const size_t private_key_length, const uint8_t* public_key, diff --git a/src/themis/themis.h b/src/themis/themis.h index 149a6dcfe..0194120c2 100644 --- a/src/themis/themis.h +++ b/src/themis/themis.h @@ -31,6 +31,7 @@ */ #include +#include #include #include #include diff --git a/src/wrappers/themis/java/com/cossacklabs/themis/SecureMessage.java b/src/wrappers/themis/java/com/cossacklabs/themis/SecureMessage.java index 277cc987b..c5a81ae6d 100644 --- a/src/wrappers/themis/java/com/cossacklabs/themis/SecureMessage.java +++ b/src/wrappers/themis/java/com/cossacklabs/themis/SecureMessage.java @@ -75,9 +75,13 @@ public SecureMessage(PrivateKey privateKey, PublicKey peerPublicKey) throws Null this.privateKey = privateKey; this.peerPublicKey = peerPublicKey; } - - static native byte[] process(byte[] privateKey, byte[] publicKey, byte[] message, boolean isWrap); - + + static final int SECURE_MESSAGE_ENCRYPT = 1; + static final int SECURE_MESSAGE_DECRYPT = 2; + static final int SECURE_MESSAGE_SIGN = 3; + static final int SECURE_MESSAGE_VERIFY = 4; + static native byte[] process(byte[] privateKey, byte[] publicKey, byte[] message, int action); + /** * Wraps message for peer * @param message to wrap @@ -96,7 +100,7 @@ public byte[] wrap(byte[] message, PublicKey peerPublicKey) throws NullArgumentE throw new NullArgumentException("No message was provided"); } - byte[] wrappedMessage = process(this.privateKey.toByteArray(), peerPublicKey.toByteArray(), message, true); + byte[] wrappedMessage = process(this.privateKey.toByteArray(), peerPublicKey.toByteArray(), message, SECURE_MESSAGE_ENCRYPT); if (null == wrappedMessage) { throw new SecureMessageWrapException(); @@ -134,7 +138,7 @@ public byte[] unwrap(byte[] message, PublicKey peerPublicKey) throws NullArgumen throw new NullArgumentException("No message was provided"); } - byte[] unwrappedMessage = process(this.privateKey.toByteArray(), peerPublicKey.toByteArray(), message, false); + byte[] unwrappedMessage = process(this.privateKey.toByteArray(), peerPublicKey.toByteArray(), message, SECURE_MESSAGE_DECRYPT); if (null == unwrappedMessage) { throw new SecureMessageWrapException(); @@ -171,7 +175,7 @@ public byte[] sign(byte[] message) throws NullArgumentException, SecureMessageWr throw new NullArgumentException("No message was provided"); } - byte[] signedMessage = process(this.privateKey.toByteArray(), null, message, true); + byte[] signedMessage = process(this.privateKey.toByteArray(), null, message, SECURE_MESSAGE_SIGN); if (null == signedMessage) { throw new SecureMessageWrapException(); @@ -198,7 +202,7 @@ public byte[] verify(byte[] message, PublicKey peerPublicKey) throws NullArgumen throw new NullArgumentException("No message was provided"); } - byte[] verifiedMessage = process(null, peerPublicKey.toByteArray(), message, false); + byte[] verifiedMessage = process(null, peerPublicKey.toByteArray(), message, SECURE_MESSAGE_VERIFY); if (null == verifiedMessage) { throw new SecureMessageWrapException(); diff --git a/src/wrappers/themis/jsthemis/secure_keygen.cpp b/src/wrappers/themis/jsthemis/secure_keygen.cpp index 492a0537e..a71860471 100644 --- a/src/wrappers/themis/jsthemis/secure_keygen.cpp +++ b/src/wrappers/themis/jsthemis/secure_keygen.cpp @@ -105,5 +105,45 @@ namespace jsthemis { void KeyPair::public_key(const Nan::FunctionCallbackInfo& args){ KeyPair* obj = Nan::ObjectWrap::Unwrap(args.This()); args.GetReturnValue().Set(Nan::CopyBuffer((char*)(&(obj->public_key_)[0]), obj->public_key_.size()).ToLocalChecked()); - } + } + + themis_status_t ValidateKey(const std::vector& key){ + if(key.empty()){ + return false; + } + return themis_is_valid_asym_key(&key[0], key.size()); + } + + bool IsValidKey(const std::vector& key){ + return ValidateKey(key)==THEMIS_SUCCESS; + } + + bool IsPrivateKey(const std::vector& key){ + if(!key.empty()){ + themis_key_kind_t kind=themis_get_asym_key_kind(&key[0], key.size()); + switch(kind){ + case THEMIS_KEY_EC_PRIVATE: + case THEMIS_KEY_RSA_PRIVATE: + return true; + default: + break; + } + } + return false; + } + + bool IsPublicKey(const std::vector& key){ + if(!key.empty()){ + themis_key_kind_t kind=themis_get_asym_key_kind(&key[0], key.size()); + switch(kind){ + case THEMIS_KEY_EC_PUBLIC: + case THEMIS_KEY_RSA_PUBLIC: + return true; + default: + break; + } + } + return false; + } + } //end jsthemis diff --git a/src/wrappers/themis/jsthemis/secure_keygen.hpp b/src/wrappers/themis/jsthemis/secure_keygen.hpp index ece17a3b1..034383063 100644 --- a/src/wrappers/themis/jsthemis/secure_keygen.hpp +++ b/src/wrappers/themis/jsthemis/secure_keygen.hpp @@ -19,6 +19,7 @@ #include #include +#include namespace jsthemis{ @@ -41,5 +42,10 @@ namespace jsthemis{ std::vector public_key_; }; + themis_status_t ValidateKey(const std::vector& key); + bool IsValidKey(const std::vector& key); + bool IsPrivateKey(const std::vector& key); + bool IsPublicKey(const std::vector& key); + } #endif /* JSTHEMIS_KEY_PAIR_HPP_ */ diff --git a/src/wrappers/themis/jsthemis/secure_message.cpp b/src/wrappers/themis/jsthemis/secure_message.cpp index e080dd7a3..d81286453 100644 --- a/src/wrappers/themis/jsthemis/secure_message.cpp +++ b/src/wrappers/themis/jsthemis/secure_message.cpp @@ -18,6 +18,7 @@ #include #include #include "errors.hpp" +#include "secure_keygen.hpp" #include "secure_message.hpp" namespace jsthemis { @@ -63,6 +64,10 @@ namespace jsthemis { } std::vector private_key((uint8_t*)(node::Buffer::Data(args[0])), (uint8_t*)(node::Buffer::Data(args[0])+node::Buffer::Length(args[0]))); std::vector public_key((uint8_t*)(node::Buffer::Data(args[1])), (uint8_t*)(node::Buffer::Data(args[1])+node::Buffer::Length(args[1]))); + if(!ValidateKeys(private_key, public_key)){ + args.GetReturnValue().SetUndefined(); + return; + } SecureMessage* obj = new SecureMessage(private_key, public_key); obj->Wrap(args.This()); args.GetReturnValue().Set(args.This()); @@ -75,6 +80,30 @@ namespace jsthemis { } } + bool SecureMessage::ValidateKeys(const std::vector& private_key, const std::vector& public_key) { + if(!private_key.empty()){ + if(!IsValidKey(private_key)){ + ThrowParameterError("Secure Message constructor", "invalid private key"); + return false; + } + if(!IsPrivateKey(private_key)){ + ThrowParameterError("Secure Message constructor", "using public key instead of private key"); + return false; + } + } + if(!public_key.empty()){ + if(!IsValidKey(public_key)){ + ThrowParameterError("Secure Message constructor", "invalid public key"); + return false; + } + if(!IsPublicKey(public_key)){ + ThrowParameterError("Secure Message constructor", "using private key instead of public key"); + return false; + } + } + return true; + } + void SecureMessage::encrypt(const Nan::FunctionCallbackInfo& args) { themis_status_t status = THEMIS_FAIL; SecureMessage* obj = Nan::ObjectWrap::Unwrap(args.This()); @@ -104,14 +133,14 @@ namespace jsthemis { return; } size_t encrypted_length=0; - status=themis_secure_message_wrap(&(obj->private_key_)[0], obj->private_key_.size(), &(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), NULL, &encrypted_length); + status=themis_secure_message_encrypt(&(obj->private_key_)[0], obj->private_key_.size(), &(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), NULL, &encrypted_length); if(status!=THEMIS_BUFFER_TOO_SMALL){ ThrowError("Secure Message failed to encrypt message", status); args.GetReturnValue().SetUndefined(); return; } uint8_t* encrypted_data=(uint8_t*)(malloc(encrypted_length)); - status=themis_secure_message_wrap(&(obj->private_key_)[0], obj->private_key_.size(), &(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), encrypted_data, &encrypted_length); + status=themis_secure_message_encrypt(&(obj->private_key_)[0], obj->private_key_.size(), &(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), encrypted_data, &encrypted_length); if(status!=THEMIS_SUCCESS){ ThrowError("Secure Message failed to encrypt message", status); free(encrypted_data); @@ -150,14 +179,14 @@ namespace jsthemis { return; } size_t decrypted_length=0; - status=themis_secure_message_unwrap(&(obj->private_key_)[0], obj->private_key_.size(), &(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), NULL, &decrypted_length); + status=themis_secure_message_decrypt(&(obj->private_key_)[0], obj->private_key_.size(), &(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), NULL, &decrypted_length); if(status!=THEMIS_BUFFER_TOO_SMALL){ ThrowError("Secure Message failed to decrypt message", status); args.GetReturnValue().SetUndefined(); return; } uint8_t* decrypted_data=(uint8_t*)(malloc(decrypted_length)); - status=themis_secure_message_unwrap(&(obj->private_key_)[0], obj->private_key_.size(), &(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), decrypted_data, &decrypted_length); + status=themis_secure_message_decrypt(&(obj->private_key_)[0], obj->private_key_.size(), &(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), decrypted_data, &decrypted_length); if(status!=THEMIS_SUCCESS){ ThrowError("Secure Message failed to decrypt message", status); free(decrypted_data); @@ -191,14 +220,14 @@ namespace jsthemis { return; } size_t encrypted_length=0; - status=themis_secure_message_wrap(&(obj->private_key_)[0], obj->private_key_.size(), NULL, 0, (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), NULL, &encrypted_length); + status=themis_secure_message_sign(&(obj->private_key_)[0], obj->private_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), NULL, &encrypted_length); if(status!=THEMIS_BUFFER_TOO_SMALL){ ThrowError("Secure Message failed to sign message", status); args.GetReturnValue().SetUndefined(); return; } uint8_t* encrypted_data=(uint8_t*)(malloc(encrypted_length)); - status=themis_secure_message_wrap(&(obj->private_key_)[0], obj->private_key_.size(), NULL, 0, (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), encrypted_data, &encrypted_length); + status=themis_secure_message_sign(&(obj->private_key_)[0], obj->private_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), encrypted_data, &encrypted_length); if(status!=THEMIS_SUCCESS){ ThrowError("Secure Message failed to sign message", status); free(encrypted_data); @@ -232,14 +261,14 @@ namespace jsthemis { return; } size_t decrypted_length=0; - status=themis_secure_message_unwrap(NULL, 0, &(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), NULL, &decrypted_length); + status=themis_secure_message_verify(&(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), NULL, &decrypted_length); if(status!=THEMIS_BUFFER_TOO_SMALL){ ThrowError("Secure Message failed to verify signature", status); args.GetReturnValue().SetUndefined(); return; } uint8_t* decrypted_data=(uint8_t*)(malloc(decrypted_length)); - status=themis_secure_message_unwrap(NULL, 0, &(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), decrypted_data, &decrypted_length); + status=themis_secure_message_verify(&(obj->peer_public_key_)[0], obj->peer_public_key_.size(), (const uint8_t*)(node::Buffer::Data(args[0])), node::Buffer::Length(args[0]), decrypted_data, &decrypted_length); if(status!=THEMIS_SUCCESS){ ThrowError("Secure Message failed to verify signature", status); free(decrypted_data); diff --git a/src/wrappers/themis/jsthemis/secure_message.hpp b/src/wrappers/themis/jsthemis/secure_message.hpp index 12a23df02..36b5c3e49 100644 --- a/src/wrappers/themis/jsthemis/secure_message.hpp +++ b/src/wrappers/themis/jsthemis/secure_message.hpp @@ -38,6 +38,8 @@ namespace jsthemis{ static Nan::Persistent constructor; + static bool ValidateKeys(const std::vector& private_key, const std::vector& public_key); + std::vector private_key_; std::vector peer_public_key_; }; diff --git a/src/wrappers/themis/rust/libthemis-sys/build.rs b/src/wrappers/themis/rust/libthemis-sys/build.rs index dce06429e..27114cbad 100644 --- a/src/wrappers/themis/rust/libthemis-sys/build.rs +++ b/src/wrappers/themis/rust/libthemis-sys/build.rs @@ -36,12 +36,6 @@ fn main() { bindings .write_to_file(out_path.join("bindings.rs")) .expect("writing bindings!"); - - cc::Build::new() - .file("src/wrapper.c") - .include("src") - .includes(&themis.include_paths) - .compile("themis_shims"); } /// Embarks on an incredible adventure and returns with a suitable Themis (or dies trying). @@ -51,7 +45,6 @@ fn get_themis() -> Library { let mut pkg_config = pkg_config::Config::new(); pkg_config.env_metadata(true); - pkg_config.arg("libsoter"); // TODO: remove this together with themis_shims #[cfg(feature = "vendored")] pkg_config.statik(true); diff --git a/src/wrappers/themis/rust/libthemis-sys/src/wrapper.c b/src/wrappers/themis/rust/libthemis-sys/src/wrapper.c deleted file mode 100644 index 82e3bd45e..000000000 --- a/src/wrappers/themis/rust/libthemis-sys/src/wrapper.c +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2018 (c) rust-themis developers -// -// 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. - -#include "wrapper.h" - -#include - -#include - -#include -#include -#include - -themis_status_t themis_is_valid_key(const uint8_t *key, size_t length) -{ - // FIXME: do something about alignment mismatch in Themis code - // - // Strictly speaking, this cast is actually an undefined behavior because `key` is not - // guaranteed to be aligned for soter_container_hdr_t. The compiler actually produces - // a warning for the cast. We silence it by using void*, just like the rest of C code - // in Themis. - // - // The behavior is undefined because some architectures (most of the modern ones) allow - // unaligned memory accesses. Other CPUs may issue an exception, which may be handled - // by the OS, which may result in a SIGBUS being sent to the process, which usually - // kills it. Or you may silently read data from a wrong memory address and that's it. - // - // This kinda tends to work because modern hardware and software is forgiving. Themis - // is mostly used and tested on i386 and AMD64 which handle unaligned accesses just fine - // (albeit slower). The next most popular architecture -- ARM -- used to have strict - // alignment requirements, but they are significantly relaxed now on modern processors. - // Furthermore, you need to get lucky with actually using an improperly unaligned pointer. - // That's why you almost never observe any catastrophic results from such unsafe casts. - // - // In rust-themis we do our best to keep the pointers aligned. That's the reason for copying - // the byte slices into a fresh new KeyBytes before passing them to any C function. - // - // However, this is still undefined behavior. I have killed yet another internet kitten - // for the following line. I am sorry and ready to bear my sin. - const soter_container_hdr_t *container = (const void*) key; - - if (!key || (length < sizeof(soter_container_hdr_t))) - { - return THEMIS_INVALID_PARAMETER; - } - - if (length != ntohl(container->size)) - { - return THEMIS_INVALID_PARAMETER; - } - - if (SOTER_SUCCESS != soter_verify_container_checksum(container)) - { - return THEMIS_DATA_CORRUPT; - } - - return THEMIS_SUCCESS; -} - -enum themis_key_kind themis_get_key_kind(const uint8_t *key, size_t length) -{ - if (!key || (length < sizeof(soter_container_hdr_t))) - { - return THEMIS_KEY_INVALID; - } - - if (!memcmp(key, RSA_PRIV_KEY_PREF, strlen(RSA_PRIV_KEY_PREF))) - { - return THEMIS_KEY_RSA_PRIVATE; - } - if (!memcmp(key, RSA_PUB_KEY_PREF, strlen(RSA_PUB_KEY_PREF))) - { - return THEMIS_KEY_RSA_PUBLIC; - } - if (!memcmp(key, EC_PRIV_KEY_PREF, strlen(EC_PRIV_KEY_PREF))) - { - return THEMIS_KEY_EC_PRIVATE; - } - if (!memcmp(key, EC_PUB_KEY_PREF, strlen(EC_PUB_KEY_PREF))) - { - return THEMIS_KEY_EC_PUBLIC; - } - - return THEMIS_KEY_INVALID; -} diff --git a/src/wrappers/themis/rust/libthemis-sys/src/wrapper.h b/src/wrappers/themis/rust/libthemis-sys/src/wrapper.h index 94a7dca36..9a4da33c8 100644 --- a/src/wrappers/themis/rust/libthemis-sys/src/wrapper.h +++ b/src/wrappers/themis/rust/libthemis-sys/src/wrapper.h @@ -15,27 +15,3 @@ //! Wrapper header for bindgen containing all Themis API declarations. #include - -// TODO: move shims into Themis core -// -// These shims are here because they use C macros which are not exported by bindgen. -// Ideally, Themis should provide this functionality, but it's too unstable now -// for inclusion into the core library. - -#include -#include - -enum themis_key_kind -{ - THEMIS_KEY_INVALID, - THEMIS_KEY_RSA_PRIVATE, - THEMIS_KEY_RSA_PUBLIC, - THEMIS_KEY_EC_PRIVATE, - THEMIS_KEY_EC_PUBLIC, -}; - -/// Checks if the buffer contains a valid Themis key. -themis_status_t themis_is_valid_key(const uint8_t *key, size_t length); - -/// Extracts the presumed key kind from the buffer. -enum themis_key_kind themis_get_key_kind(const uint8_t *key, size_t length); diff --git a/src/wrappers/themis/rust/src/keys.rs b/src/wrappers/themis/rust/src/keys.rs index 0b72b9936..cc2b2dabb 100644 --- a/src/wrappers/themis/rust/src/keys.rs +++ b/src/wrappers/themis/rust/src/keys.rs @@ -130,7 +130,7 @@ use std::fmt; -use bindings::{themis_get_key_kind, themis_is_valid_key}; +use bindings::{themis_get_asym_key_kind, themis_is_valid_asym_key}; use zeroize::Zeroize; use crate::error::{Error, ErrorKind, Result}; @@ -503,7 +503,7 @@ impl PublicKey { // get_key_kind_trusted() again on the very same byte slice to get the result faster. // // There's also a reason why they receive &KeyBytes, not just &[u8]. This is to maintain correct -// pointer alignment. See "libthemis-sys/src/wrapper.c" for details. +// pointer alignment. fn get_key_kind(key: &KeyBytes) -> Result { is_valid_themis_key(key)?; @@ -517,7 +517,7 @@ fn get_key_kind_trusted(key: &KeyBytes) -> KeyKind { fn is_valid_themis_key(key: &KeyBytes) -> Result<()> { let (ptr, len) = into_raw_parts(key.as_bytes()); - let status = unsafe { themis_is_valid_key(ptr, len) }; + let status = unsafe { themis_is_valid_asym_key(ptr, len) }; let error = Error::from_themis_status(status); if error.kind() != ErrorKind::Success { return Err(error); @@ -528,7 +528,7 @@ fn is_valid_themis_key(key: &KeyBytes) -> Result<()> { fn try_get_key_kind(key: &KeyBytes) -> Result { use bindings::themis_key_kind::*; let (ptr, len) = into_raw_parts(key.as_bytes()); - let kind = unsafe { themis_get_key_kind(ptr, len) }; + let kind = unsafe { themis_get_asym_key_kind(ptr, len) }; match kind { THEMIS_KEY_RSA_PRIVATE => Ok(KeyKind::RsaPrivate), THEMIS_KEY_RSA_PUBLIC => Ok(KeyKind::RsaPublic), diff --git a/src/wrappers/themis/rust/src/secure_message.rs b/src/wrappers/themis/rust/src/secure_message.rs index 948a2f0fb..a108ebf05 100644 --- a/src/wrappers/themis/rust/src/secure_message.rs +++ b/src/wrappers/themis/rust/src/secure_message.rs @@ -64,7 +64,10 @@ use std::ptr; -use bindings::{themis_secure_message_unwrap, themis_secure_message_wrap}; +use bindings::{ + themis_secure_message_decrypt, themis_secure_message_encrypt, themis_secure_message_sign, + themis_secure_message_verify, +}; use crate::error::{Error, ErrorKind, Result}; use crate::keys::{KeyPair, PrivateKey, PublicKey}; @@ -138,20 +141,102 @@ impl SecureMessage { /// # } /// ``` pub fn encrypt(&self, message: impl AsRef<[u8]>) -> Result> { - wrap( - self.key_pair.private_key_bytes(), - self.key_pair.public_key_bytes(), - message.as_ref(), - ) + let (private_key_ptr, private_key_len) = into_raw_parts(self.key_pair.private_key_bytes()); + let (public_key_ptr, public_key_len) = into_raw_parts(self.key_pair.public_key_bytes()); + let (message_ptr, message_len) = into_raw_parts(message.as_ref()); + + let mut encrypted = Vec::new(); + let mut encrypted_len = 0; + + unsafe { + let status = themis_secure_message_encrypt( + private_key_ptr, + private_key_len, + public_key_ptr, + public_key_len, + message_ptr, + message_len, + ptr::null_mut(), + &mut encrypted_len, + ); + let error = Error::from_themis_status(status); + if error.kind() != ErrorKind::BufferTooSmall { + return Err(error); + } + } + + encrypted.reserve(encrypted_len); + + unsafe { + let status = themis_secure_message_encrypt( + private_key_ptr, + private_key_len, + public_key_ptr, + public_key_len, + message_ptr, + message_len, + encrypted.as_mut_ptr(), + &mut encrypted_len, + ); + let error = Error::from_themis_status(status); + if error.kind() != ErrorKind::Success { + return Err(error); + } + debug_assert!(encrypted_len <= encrypted.capacity()); + encrypted.set_len(encrypted_len as usize); + } + + Ok(encrypted) } /// Decrypts an encrypted message back into its original form. pub fn decrypt(&self, message: impl AsRef<[u8]>) -> Result> { - unwrap( - self.key_pair.private_key_bytes(), - self.key_pair.public_key_bytes(), - message.as_ref(), - ) + let (private_key_ptr, private_key_len) = into_raw_parts(self.key_pair.private_key_bytes()); + let (public_key_ptr, public_key_len) = into_raw_parts(self.key_pair.public_key_bytes()); + let (wrapped_ptr, wrapped_len) = into_raw_parts(message.as_ref()); + + let mut decrypted = Vec::new(); + let mut decrypted_len = 0; + + unsafe { + let status = themis_secure_message_decrypt( + private_key_ptr, + private_key_len, + public_key_ptr, + public_key_len, + wrapped_ptr, + wrapped_len, + ptr::null_mut(), + &mut decrypted_len, + ); + let error = Error::from_themis_status(status); + if error.kind() != ErrorKind::BufferTooSmall { + return Err(error); + } + } + + decrypted.reserve(decrypted_len); + + unsafe { + let status = themis_secure_message_decrypt( + private_key_ptr, + private_key_len, + public_key_ptr, + public_key_len, + wrapped_ptr, + wrapped_len, + decrypted.as_mut_ptr(), + &mut decrypted_len, + ); + let error = Error::from_themis_status(status); + if error.kind() != ErrorKind::Success { + return Err(error); + } + debug_assert!(decrypted_len <= decrypted.capacity()); + decrypted.set_len(decrypted_len as usize); + } + + Ok(decrypted) } } @@ -243,7 +328,47 @@ impl SecureSign { /// # } /// ``` pub fn sign(&self, message: impl AsRef<[u8]>) -> Result> { - wrap(self.private_key.as_ref(), &[], message.as_ref()) + let (private_key_ptr, private_key_len) = into_raw_parts(self.private_key.as_ref()); + let (message_ptr, message_len) = into_raw_parts(message.as_ref()); + + let mut signed = Vec::new(); + let mut signed_len = 0; + + unsafe { + let status = themis_secure_message_sign( + private_key_ptr, + private_key_len, + message_ptr, + message_len, + ptr::null_mut(), + &mut signed_len, + ); + let error = Error::from_themis_status(status); + if error.kind() != ErrorKind::BufferTooSmall { + return Err(error); + } + } + + signed.reserve(signed_len); + + unsafe { + let status = themis_secure_message_sign( + private_key_ptr, + private_key_len, + message_ptr, + message_len, + signed.as_mut_ptr(), + &mut signed_len, + ); + let error = Error::from_themis_status(status); + if error.kind() != ErrorKind::Success { + return Err(error); + } + debug_assert!(signed_len <= signed.capacity()); + signed.set_len(signed_len as usize); + } + + Ok(signed) } } @@ -331,106 +456,46 @@ impl SecureVerify { /// Verifies the signature and returns the original message. pub fn verify(&self, message: impl AsRef<[u8]>) -> Result> { - unwrap(&[], self.public_key.as_ref(), message.as_ref()) - } -} + let (public_key_ptr, public_key_len) = into_raw_parts(self.public_key.as_ref()); + let (signed_ptr, signed_len) = into_raw_parts(message.as_ref()); -/// Wrap a message into a secure message. -fn wrap(private_key: &[u8], public_key: &[u8], message: &[u8]) -> Result> { - let (private_key_ptr, private_key_len) = into_raw_parts(private_key); - let (public_key_ptr, public_key_len) = into_raw_parts(public_key); - let (message_ptr, message_len) = into_raw_parts(message); - - let mut wrapped = Vec::new(); - let mut wrapped_len = 0; - - unsafe { - let status = themis_secure_message_wrap( - private_key_ptr, - private_key_len, - public_key_ptr, - public_key_len, - message_ptr, - message_len, - ptr::null_mut(), - &mut wrapped_len, - ); - let error = Error::from_themis_status(status); - if error.kind() != ErrorKind::BufferTooSmall { - return Err(error); - } - } + let mut original = Vec::new(); + let mut original_len = 0; - wrapped.reserve(wrapped_len); - - unsafe { - let status = themis_secure_message_wrap( - private_key_ptr, - private_key_len, - public_key_ptr, - public_key_len, - message_ptr, - message_len, - wrapped.as_mut_ptr(), - &mut wrapped_len, - ); - let error = Error::from_themis_status(status); - if error.kind() != ErrorKind::Success { - return Err(error); + unsafe { + let status = themis_secure_message_verify( + public_key_ptr, + public_key_len, + signed_ptr, + signed_len, + ptr::null_mut(), + &mut original_len, + ); + let error = Error::from_themis_status(status); + if error.kind() != ErrorKind::BufferTooSmall { + return Err(error); + } } - debug_assert!(wrapped_len <= wrapped.capacity()); - wrapped.set_len(wrapped_len as usize); - } - Ok(wrapped) -} + original.reserve(original_len); -/// Unwrap a secure message into a message. -fn unwrap(private_key: &[u8], public_key: &[u8], wrapped: &[u8]) -> Result> { - let (private_key_ptr, private_key_len) = into_raw_parts(private_key); - let (public_key_ptr, public_key_len) = into_raw_parts(public_key); - let (wrapped_ptr, wrapped_len) = into_raw_parts(wrapped); - - let mut message = Vec::new(); - let mut message_len = 0; - - unsafe { - let status = themis_secure_message_unwrap( - private_key_ptr, - private_key_len, - public_key_ptr, - public_key_len, - wrapped_ptr, - wrapped_len, - ptr::null_mut(), - &mut message_len, - ); - let error = Error::from_themis_status(status); - if error.kind() != ErrorKind::BufferTooSmall { - return Err(error); + unsafe { + let status = themis_secure_message_verify( + public_key_ptr, + public_key_len, + signed_ptr, + signed_len, + original.as_mut_ptr(), + &mut original_len, + ); + let error = Error::from_themis_status(status); + if error.kind() != ErrorKind::Success { + return Err(error); + } + debug_assert!(original_len <= original.capacity()); + original.set_len(original_len as usize); } - } - message.reserve(message_len); - - unsafe { - let status = themis_secure_message_unwrap( - private_key_ptr, - private_key_len, - public_key_ptr, - public_key_len, - wrapped_ptr, - wrapped_len, - message.as_mut_ptr(), - &mut message_len, - ); - let error = Error::from_themis_status(status); - if error.kind() != ErrorKind::Success { - return Err(error); - } - debug_assert!(message_len <= message.capacity()); - message.set_len(message_len as usize); + Ok(original) } - - Ok(message) } diff --git a/src/wrappers/themis/themispp/secure_keygen.hpp b/src/wrappers/themis/themispp/secure_keygen.hpp index c93ea8580..aa850797d 100644 --- a/src/wrappers/themis/themispp/secure_keygen.hpp +++ b/src/wrappers/themis/themispp/secure_keygen.hpp @@ -70,6 +70,45 @@ namespace themispp{ std::vector public_key; }; + inline themis_status_t validate_key(const std::vector& key){ + if(key.empty()){ + return THEMIS_INVALID_PARAMETER; + } + return themis_is_valid_asym_key(&key[0], key.size()); + } + + inline bool is_valid_key(const std::vector& key){ + return validate_key(key)==THEMIS_SUCCESS; + } + + inline bool is_private_key(const std::vector& key){ + if(!key.empty()){ + themis_key_kind_t kind=themis_get_asym_key_kind(&key[0], key.size()); + switch(kind){ + case THEMIS_KEY_EC_PRIVATE: + case THEMIS_KEY_RSA_PRIVATE: + return true; + default: + break; + } + } + return false; + } + + inline bool is_public_key(const std::vector& key){ + if(!key.empty()){ + themis_key_kind_t kind=themis_get_asym_key_kind(&key[0], key.size()); + switch(kind){ + case THEMIS_KEY_EC_PUBLIC: + case THEMIS_KEY_RSA_PUBLIC: + return true; + default: + break; + } + } + return false; + } + }// ns themis #endif diff --git a/src/wrappers/themis/themispp/secure_message.hpp b/src/wrappers/themis/themispp/secure_message.hpp index 39b5aadbb..986fe90fc 100644 --- a/src/wrappers/themis/themispp/secure_message.hpp +++ b/src/wrappers/themis/themispp/secure_message.hpp @@ -18,6 +18,7 @@ #define THEMISPP_SECURE_MESSAGE_HPP_ #include "exception.hpp" +#include "secure_keygen.hpp" #include #include @@ -30,19 +31,31 @@ namespace themispp { secure_message_t(data_t::const_iterator private_key_begin, data_t::const_iterator private_key_end, data_t::const_iterator peer_public_key_begin, data_t::const_iterator peer_public_key_end): private_key_(private_key_begin, private_key_end), - peer_public_key_(peer_public_key_begin, peer_public_key_end){} + peer_public_key_(peer_public_key_begin, peer_public_key_end) + { + validate_keys(); + } secure_message_t(const data_t& private_key, data_t::const_iterator peer_public_key_begin, data_t::const_iterator peer_public_key_end): private_key_(private_key.begin(), private_key.end()), - peer_public_key_(peer_public_key_begin, peer_public_key_end){} + peer_public_key_(peer_public_key_begin, peer_public_key_end) + { + validate_keys(); + } secure_message_t(data_t::const_iterator private_key_begin, data_t::const_iterator private_key_end, const data_t& peer_public_key): private_key_(private_key_begin, private_key_end), - peer_public_key_(peer_public_key.begin(), peer_public_key.end()){} - + peer_public_key_(peer_public_key.begin(), peer_public_key.end()) + { + validate_keys(); + } + secure_message_t(const data_t& private_key, const data_t& peer_public_key): private_key_(private_key.begin(), private_key.end()), - peer_public_key_(peer_public_key.begin(), peer_public_key.end()){} + peer_public_key_(peer_public_key.begin(), peer_public_key.end()) + { + validate_keys(); + } virtual ~secure_message_t(){} @@ -58,12 +71,12 @@ namespace themispp { } themis_status_t status=THEMIS_FAIL; size_t encrypted_data_length=0; - status=themis_secure_message_wrap(&private_key_[0], private_key_.size(), &peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, NULL, &encrypted_data_length); + status=themis_secure_message_encrypt(&private_key_[0], private_key_.size(), &peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, NULL, &encrypted_data_length); if(status!=THEMIS_BUFFER_TOO_SMALL){ throw themispp::exception_t("Secure Message failed to encrypt message", status); } res_.resize(encrypted_data_length); - status=themis_secure_message_wrap(&private_key_[0], private_key_.size(), &peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, &res_[0], &encrypted_data_length); + status=themis_secure_message_encrypt(&private_key_[0], private_key_.size(), &peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, &res_[0], &encrypted_data_length); if(status!=THEMIS_SUCCESS){ throw themispp::exception_t("Secure Message failed to encrypt message", status); } @@ -86,12 +99,12 @@ namespace themispp { } themis_status_t status=THEMIS_FAIL; size_t decrypted_data_length=0; - status=themis_secure_message_unwrap(&private_key_[0], private_key_.size(), &peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, NULL, &decrypted_data_length); + status=themis_secure_message_decrypt(&private_key_[0], private_key_.size(), &peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, NULL, &decrypted_data_length); if(status!=THEMIS_BUFFER_TOO_SMALL){ throw themispp::exception_t("Secure Message failed to decrypt message", status); } res_.resize(decrypted_data_length); - status=themis_secure_message_unwrap(&private_key_[0], private_key_.size(), &peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, &res_[0], &decrypted_data_length); + status=themis_secure_message_decrypt(&private_key_[0], private_key_.size(), &peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, &res_[0], &decrypted_data_length); if(status!=THEMIS_SUCCESS){ throw themispp::exception_t("Secure Message failed to decrypt message", status); } @@ -111,12 +124,12 @@ namespace themispp { } themis_status_t status=THEMIS_FAIL; size_t encrypted_data_length=0; - status=themis_secure_message_wrap(&private_key_[0], private_key_.size(), NULL, 0, &(*data_begin), data_end-data_begin, NULL, &encrypted_data_length); + status=themis_secure_message_sign(&private_key_[0], private_key_.size(), &(*data_begin), data_end-data_begin, NULL, &encrypted_data_length); if(status!=THEMIS_BUFFER_TOO_SMALL){ throw themispp::exception_t("Secure Message failed to sign message", status); } res_.resize(encrypted_data_length); - status=themis_secure_message_wrap(&private_key_[0], private_key_.size(), NULL, 0, &(*data_begin), data_end-data_begin, &res_[0], &encrypted_data_length); + status=themis_secure_message_sign(&private_key_[0], private_key_.size(), &(*data_begin), data_end-data_begin, &res_[0], &encrypted_data_length); if(status!=THEMIS_SUCCESS){ throw themispp::exception_t("Secure Message failed to sign message", status); } @@ -136,12 +149,12 @@ namespace themispp { } themis_status_t status=THEMIS_FAIL; size_t decrypted_data_length=0; - status=themis_secure_message_unwrap(NULL, 0, &peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, NULL, &decrypted_data_length); + status=themis_secure_message_verify(&peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, NULL, &decrypted_data_length); if(status!=THEMIS_BUFFER_TOO_SMALL){ throw themispp::exception_t("Secure Message failed to verify signature", status); } res_.resize(decrypted_data_length); - status=themis_secure_message_unwrap(NULL, 0, &peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, &res_[0], &decrypted_data_length); + status=themis_secure_message_verify(&peer_public_key_[0], peer_public_key_.size(), &(*data_begin), data_end-data_begin, &res_[0], &decrypted_data_length); if(status!=THEMIS_SUCCESS){ throw themispp::exception_t("Secure Message failed to verify signature", status); } @@ -159,6 +172,25 @@ namespace themispp { private: secure_message_t(const secure_message_t&); secure_message_t& operator=(const secure_message_t&); + + void validate_keys(){ + if(!private_key_.empty()){ + if(!is_valid_key(private_key_)){ + throw themispp::exception_t("Secure Message: invalid private key"); + } + if(!is_private_key(private_key_)){ + throw themispp::exception_t("Secure Message: using public key instead of private key"); + } + } + if(!peer_public_key_.empty()){ + if(!is_valid_key(peer_public_key_)){ + throw themispp::exception_t("Secure Message: invalid public key"); + } + if(!is_public_key(peer_public_key_)){ + throw themispp::exception_t("Secure Message: using private key instead of public key"); + } + } + } }; } //end themispp diff --git a/tests/jsthemis/test.js b/tests/jsthemis/test.js index a45133a1c..19857c699 100644 --- a/tests/jsthemis/test.js +++ b/tests/jsthemis/test.js @@ -38,6 +38,9 @@ describe("jsthemis", function(){ assert.throws(function(){empty_secure_message.sign(message);}, expect_code(addon.INVALID_PARAMETER)); assert.throws(function(){empty_secure_message.verify(signed_message);}, expect_code(addon.INVALID_PARAMETER)); }) + it("mismatched keys", function(){ + assert.throws(function(){new addon.SecureMessage(keypair.public(), keypair.private())}, expect_code(addon.INVALID_PARAMETER)); + }) }) }) diff --git a/tests/soter/nist-sts/assess b/tests/soter/nist-sts/assess index 2d91db874..4e247dae0 100755 Binary files a/tests/soter/nist-sts/assess and b/tests/soter/nist-sts/assess differ diff --git a/tests/themis/themis_seccure_message.c b/tests/themis/themis_seccure_message.c index 5b70270d6..9ddc57a31 100644 --- a/tests/themis/themis_seccure_message.c +++ b/tests/themis/themis_seccure_message.c @@ -21,8 +21,10 @@ /* Fuzz parameters */ #define MAX_MESSAGE_SIZE 2048 +#define MAX_ENCRYPTED_MESSAGE_SIZE (MAX_MESSAGE_SIZE+1024) #define MESSAGES_TO_SEND 3 +#define MAX_KEY_SIZE 4096 #define RSA_ALG 1 #define EC_ALG 2 #define test_check(function_call, success_res, msg) { \ @@ -40,6 +42,14 @@ return -1; \ }} +/* + * Allow usage of deprecated Secure Message interface: + * - themis_secure_message_wrap() + * - themis_secure_message_unwrap() + */ +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif static themis_status_t themis_gen_key_pair(int alg, uint8_t* private_key, size_t* private_key_length, uint8_t* public_key, size_t* public_key_length){ themis_status_t res=THEMIS_FAIL; @@ -52,6 +62,154 @@ static themis_status_t themis_gen_key_pair(int alg, uint8_t* private_key, size_t return res; } +static int generic_themis_secure_message_encrypt_decrypt_test(int alg, const uint8_t* message, const size_t message_length){ + int res=-1; + themis_status_t status=THEMIS_FAIL; + + uint8_t private_key[MAX_KEY_SIZE]={0}; + uint8_t public_key[MAX_KEY_SIZE]={0}; + size_t private_key_length=sizeof(private_key); + size_t public_key_length=sizeof(public_key); + + uint8_t* encrypted_message=NULL; + uint8_t* decrypted_message=NULL; + size_t encrypted_message_length=0; + size_t decrypted_message_length=0; + + status=themis_gen_key_pair(alg, private_key, &private_key_length, public_key, &public_key_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_gen_key_pair failed"); + goto out; + } + + status=themis_secure_message_encrypt(private_key, private_key_length, public_key, public_key_length, message, message_length, NULL, &encrypted_message_length); + if(status!=THEMIS_BUFFER_TOO_SMALL){ + testsuite_fail_if(true, "themis_secure_message_encrypt failed to determine encrypted message length"); + goto out; + } + + encrypted_message=malloc(encrypted_message_length); + if(!encrypted_message){ + testsuite_fail_if(true, "failed to allocate memory for encrypted message"); + goto out; + } + + status=themis_secure_message_encrypt(private_key, private_key_length, public_key, public_key_length, message, message_length, encrypted_message, &encrypted_message_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_secure_message_encrypt failed to encrypt message"); + goto out; + } + + status=themis_secure_message_decrypt(private_key, private_key_length, public_key, public_key_length, encrypted_message, encrypted_message_length, NULL, &decrypted_message_length); + if(status!=THEMIS_BUFFER_TOO_SMALL){ + testsuite_fail_if(true, "themis_secure_message_decrypt failed to determine decrypted message length"); + goto out; + } + + decrypted_message=malloc(decrypted_message_length); + if(!decrypted_message){ + testsuite_fail_if(true, "failed to allocate memory for decrypted message"); + goto out; + } + + status=themis_secure_message_decrypt(private_key, private_key_length, public_key, public_key_length, encrypted_message, encrypted_message_length, decrypted_message, &decrypted_message_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_secure_message_decrypt failed to decrypt message"); + goto out; + } + + if(decrypted_message_length!=message_length){ + testsuite_fail_if(true, "themis_secure_message_encrypt/decrypt does not preserve message length"); + goto out; + } + + if(memcmp(decrypted_message, message, message_length)!=0){ + testsuite_fail_if(true, "themis_secure_message_encrypt/decrypt does not preserve message content"); + goto out; + } + + res=0; + +out: + free(decrypted_message); + free(encrypted_message); + return res; +} + +static int generic_themis_secure_message_sign_verify_test(int alg, const uint8_t* message, const size_t message_length){ + int res=-1; + themis_status_t status=THEMIS_FAIL; + + uint8_t private_key[MAX_KEY_SIZE]={0}; + uint8_t public_key[MAX_KEY_SIZE]={0}; + size_t private_key_length=sizeof(private_key); + size_t public_key_length=sizeof(public_key); + + uint8_t* signed_message=NULL; + uint8_t* verified_message=NULL; + size_t signed_message_length=0; + size_t verified_message_length=0; + + status=themis_gen_key_pair(alg, private_key, &private_key_length, public_key, &public_key_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_gen_key_pair failed"); + goto out; + } + + status=themis_secure_message_sign(private_key, private_key_length, message, message_length, NULL, &signed_message_length); + if(status!=THEMIS_BUFFER_TOO_SMALL){ + testsuite_fail_if(true, "themis_secure_message_sign failed to determine signed message length"); + goto out; + } + + signed_message=malloc(signed_message_length); + if(!signed_message){ + testsuite_fail_if(true, "failed to allocate memory for signed message"); + goto out; + } + + status=themis_secure_message_sign(private_key, private_key_length, message, message_length, signed_message, &signed_message_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_secure_message_sign failed to sign message"); + goto out; + } + + status=themis_secure_message_verify(public_key, public_key_length, signed_message, signed_message_length, NULL, &verified_message_length); + if(status!=THEMIS_BUFFER_TOO_SMALL){ + testsuite_fail_if(true, "themis_secure_message_verify failed to determine verified message length"); + goto out; + } + + verified_message=malloc(verified_message_length); + if(!verified_message){ + testsuite_fail_if(true, "failed to allocate memory for verified message"); + goto out; + } + + status=themis_secure_message_verify(public_key, public_key_length, signed_message, signed_message_length, verified_message, &verified_message_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_secure_message_verify failed to verify message"); + goto out; + } + + if(verified_message_length!=message_length){ + testsuite_fail_if(true, "themis_secure_message_sign/verify does not preserve message length"); + goto out; + } + + if(memcmp(verified_message, message, message_length)!=0){ + testsuite_fail_if(true, "themis_secure_message_sign/verify does not preserve message content"); + goto out; + } + + res=0; + + out: + free(verified_message); + free(signed_message); + return res; + } + static int themis_secure_signed_message_generic_test(int alg, const char* message, const size_t message_length){ uint8_t private_key[10240]; size_t private_key_length=10240; @@ -214,15 +372,211 @@ static void themis_secure_message_test(){ "Hit http://ftp.us.debian.org[10] wheezy/contrib i386 Packages" "Hit http://ftp.us.debian.org[11] wheezy/contrib Translation-en"; + const uint8_t* message_bytes=(const uint8_t*)message; size_t message_length=strlen(message); - - testsuite_fail_if(themis_secure_signed_message_generic_test(RSA_ALG, message, message_length), "themis secure signed message (RSA)"); - testsuite_fail_if(themis_secure_signed_message_generic_test(EC_ALG, message,message_length), "themis secure signed message (EC)"); - testsuite_fail_if(themis_secure_encrypted_message_generic_test(RSA_ALG, message, message_length), "themis secure encrypted message (RSA)"); - testsuite_fail_if(themis_secure_encrypted_message_generic_test(EC_ALG, message,message_length), "themis secure encrypted message (EC)"); + + testsuite_fail_if(generic_themis_secure_message_encrypt_decrypt_test(RSA_ALG, message_bytes, message_length), "themis secure encrypt/decrypt message (RSA)"); + testsuite_fail_if(generic_themis_secure_message_encrypt_decrypt_test(EC_ALG, message_bytes, message_length), "themis secure encrypt/decrypt message (EC)"); + testsuite_fail_if(generic_themis_secure_message_sign_verify_test(RSA_ALG, message_bytes, message_length), "themis secure sign/verify message (RSA)"); + testsuite_fail_if(generic_themis_secure_message_sign_verify_test(EC_ALG, message_bytes, message_length), "themis secure sign/verify message (EC)"); + + testsuite_fail_if(themis_secure_signed_message_generic_test(RSA_ALG, message, message_length), "(deprecated) themis secure signed message (RSA)"); + testsuite_fail_if(themis_secure_signed_message_generic_test(EC_ALG, message,message_length), "(deprecated) themis secure signed message (EC)"); + testsuite_fail_if(themis_secure_encrypted_message_generic_test(RSA_ALG, message, message_length), "(deprecated) themis secure encrypted message (RSA)"); + testsuite_fail_if(themis_secure_encrypted_message_generic_test(EC_ALG, message,message_length), "(deprecated) themis secure encrypted message (EC)"); +} + +static void themis_secure_message_encrypt_decrypt_api_test(void){ + themis_status_t status=THEMIS_FAIL; + + uint8_t private_key[MAX_KEY_SIZE]={0}; + uint8_t public_key[MAX_KEY_SIZE]={0}; + size_t private_key_length = sizeof(private_key); + size_t public_key_length = sizeof(public_key); + + uint8_t plaintext[MAX_MESSAGE_SIZE]={0}; + uint8_t encrypted[MAX_ENCRYPTED_MESSAGE_SIZE]={0}; + uint8_t decrypted[MAX_MESSAGE_SIZE]={0}; + size_t plaintext_length = sizeof(plaintext); + size_t encrypted_length = sizeof(encrypted); + size_t decrypted_length = sizeof(decrypted); + + status=themis_gen_ec_key_pair(private_key, &private_key_length, public_key, &public_key_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_gen_ec_key_pair failed"); + return; + } + + status=soter_rand(plaintext, plaintext_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "soter_rand failed"); + return; + } + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_encrypt(NULL, private_key_length, public_key, public_key_length, plaintext, plaintext_length, encrypted, &encrypted_length), + "themis_secure_message_encrypt: private key is NULL"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_encrypt(private_key, 0, public_key, public_key_length, plaintext, plaintext_length, encrypted, &encrypted_length), + "themis_secure_message_encrypt: private key is empty"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_encrypt(private_key, private_key_length-1, public_key, public_key_length, plaintext, plaintext_length, encrypted, &encrypted_length), + "themis_secure_message_encrypt: private key is invalid"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_encrypt(private_key, private_key_length, NULL, public_key_length, plaintext, plaintext_length, encrypted, &encrypted_length), + "themis_secure_message_encrypt: public key is NULL"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_encrypt(private_key, private_key_length, public_key, 0, plaintext, plaintext_length, encrypted, &encrypted_length), + "themis_secure_message_encrypt: public key is empty"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_encrypt(private_key, private_key_length, public_key, public_key_length-1, plaintext, plaintext_length, encrypted, &encrypted_length), + "themis_secure_message_encrypt: public key is invalid"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_encrypt(public_key, public_key_length, private_key, private_key_length, plaintext, plaintext_length, encrypted, &encrypted_length), + "themis_secure_message_encrypt: misplaced keys"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_encrypt(private_key, private_key_length, public_key, public_key_length, NULL, plaintext_length, encrypted, &encrypted_length), + "themis_secure_message_encrypt: plaintext is NULL"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_encrypt(private_key, private_key_length, public_key, public_key_length, plaintext, 0, encrypted, &encrypted_length), + "themis_secure_message_encrypt: plaintext is empty"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_encrypt(private_key, private_key_length, public_key, public_key_length, plaintext, plaintext_length, NULL, NULL), + "themis_secure_message_encrypt: encrypted_length is NULL"); + + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_secure_message_encrypt(private_key, private_key_length, public_key, public_key_length, plaintext, plaintext_length, NULL, &encrypted_length), + "themis_secure_message_encrypt: encrypted buffer length"); + encrypted_length -= 1; + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_secure_message_encrypt(private_key, private_key_length, public_key, public_key_length, plaintext, plaintext_length, encrypted, &encrypted_length), + "themis_secure_message_encrypt: encrypted buffer too small"); + + status=themis_secure_message_encrypt(private_key, private_key_length, public_key, public_key_length, plaintext, plaintext_length, encrypted, &encrypted_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_secure_message_encrypt failed to encrypt"); + return; + } + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_decrypt(NULL, private_key_length, public_key, public_key_length, encrypted, encrypted_length, decrypted, &decrypted_length), + "themis_secure_message_decrypt: private key is NULL"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_decrypt(private_key, 0, public_key, public_key_length, encrypted, encrypted_length, decrypted, &decrypted_length), + "themis_secure_message_decrypt: private key is empty"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_decrypt(private_key, private_key_length-1, public_key, public_key_length, encrypted, encrypted_length, decrypted, &decrypted_length), + "themis_secure_message_decrypt: private key is invalid"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_decrypt(private_key, private_key_length, NULL, public_key_length, encrypted, encrypted_length, decrypted, &decrypted_length), + "themis_secure_message_decrypt: public key is NULL"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_decrypt(private_key, private_key_length, public_key, 0, encrypted, encrypted_length, decrypted, &decrypted_length), + "themis_secure_message_decrypt: public key is empty"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_decrypt(private_key, private_key_length, public_key, public_key_length-1, encrypted, encrypted_length, decrypted, &decrypted_length), + "themis_secure_message_decrypt: public key is invalid"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_decrypt(public_key, public_key_length, private_key, private_key_length, encrypted, encrypted_length, decrypted, &decrypted_length), + "themis_secure_message_decrypt: misplaced keys"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_decrypt(private_key, private_key_length, public_key, public_key_length, NULL, encrypted_length, decrypted, &decrypted_length), + "themis_secure_message_decrypt: encrypted is NULL"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_decrypt(private_key, private_key_length, public_key, public_key_length, encrypted, 0, decrypted, &decrypted_length), + "themis_secure_message_decrypt: encrypted is empty"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_decrypt(private_key, private_key_length, public_key, public_key_length, encrypted, encrypted_length, NULL, NULL), + "themis_secure_message_decrypt: decrypted_length is NULL"); + + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_secure_message_decrypt(private_key, private_key_length, public_key, public_key_length, encrypted, encrypted_length, NULL, &decrypted_length), + "themis_secure_message_decrypt: decrypted buffer length"); + decrypted_length -= 1; + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_secure_message_decrypt(private_key, private_key_length, public_key, public_key_length, encrypted, encrypted_length, decrypted, &decrypted_length), + "themis_secure_message_decrypt: decrypted buffer too small"); + + status=themis_secure_message_decrypt(private_key, private_key_length, public_key, public_key_length, encrypted, encrypted_length, decrypted, &decrypted_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_secure_message_decrypt failed to decrypt"); + return; + } } -static void secure_message_api_test(void) +static void themis_secure_message_sign_verify_api_test(void){ + themis_status_t status=THEMIS_FAIL; + + uint8_t private_key[MAX_KEY_SIZE]={0}; + uint8_t public_key[MAX_KEY_SIZE]={0}; + size_t private_key_length = sizeof(private_key); + size_t public_key_length = sizeof(public_key); + + uint8_t plaintext[MAX_MESSAGE_SIZE]={0}; + uint8_t signed_msg[MAX_ENCRYPTED_MESSAGE_SIZE]={0}; + uint8_t verified[MAX_MESSAGE_SIZE]={0}; + size_t plaintext_length = sizeof(plaintext); + size_t signed_msg_length = sizeof(signed_msg); + size_t verified_length = sizeof(verified); + + status=themis_gen_ec_key_pair(private_key, &private_key_length, public_key, &public_key_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_gen_ec_key_pair failed"); + return; + } + + status=soter_rand(plaintext, plaintext_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "soter_rand failed"); + return; + } + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_sign(NULL, private_key_length, plaintext, plaintext_length, signed_msg, &signed_msg_length), + "themis_secure_message_sign: private key is NULL"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_sign(private_key, 0, plaintext, plaintext_length, signed_msg, &signed_msg_length), + "themis_secure_message_sign: private key is empty"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_sign(private_key, private_key_length-1, plaintext, plaintext_length, signed_msg, &signed_msg_length), + "themis_secure_message_sign: private key is invalid"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_sign(public_key, public_key_length, plaintext, plaintext_length, signed_msg, &signed_msg_length), + "themis_secure_message_sign: using public key"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_sign(private_key, private_key_length, NULL, plaintext_length, signed_msg, &signed_msg_length), + "themis_secure_message_sign: plaintext is NULL"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_sign(private_key, private_key_length, plaintext, 0, signed_msg, &signed_msg_length), + "themis_secure_message_sign: plaintext is empty"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_sign(private_key, private_key_length, plaintext, plaintext_length, NULL, NULL), + "themis_secure_message_sign: signed_msg_length is NULL"); + + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_secure_message_sign(private_key, private_key_length, plaintext, plaintext_length, NULL, &signed_msg_length), + "themis_secure_message_sign: signed buffer length"); + signed_msg_length -= 1; + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_secure_message_sign(private_key, private_key_length, plaintext, plaintext_length, signed_msg, &signed_msg_length), + "themis_secure_message_sign: signed buffer too small"); + + status=themis_secure_message_sign(private_key, private_key_length, plaintext, plaintext_length, signed_msg, &signed_msg_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_secure_message_sign failed to sign"); + return; + } + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_verify(NULL, public_key_length, signed_msg, signed_msg_length, verified, &verified_length), + "themis_secure_message_verify: public key is NULL"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_verify(public_key, 0, signed_msg, signed_msg_length, verified, &verified_length), + "themis_secure_message_verify: public key is empty"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_verify(public_key, public_key_length-1, signed_msg, signed_msg_length, verified, &verified_length), + "themis_secure_message_verify: public key is invalid"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_verify(private_key, private_key_length, signed_msg, signed_msg_length, verified, &verified_length), + "themis_secure_message_verify: using private key"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_verify(public_key, public_key_length, NULL, signed_msg_length, verified, &verified_length), + "themis_secure_message_verify: signed_msg is NULL"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_verify(public_key, public_key_length, signed_msg, 0, verified, &verified_length), + "themis_secure_message_verify: signed_msg is empty"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_secure_message_verify(public_key, public_key_length, signed_msg, signed_msg_length, NULL, NULL), + "themis_secure_message_verify: verified_length is NULL"); + + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_secure_message_verify(public_key, public_key_length, signed_msg, signed_msg_length, NULL, &verified_length), + "themis_secure_message_verify: verified buffer length"); + verified_length -= 1; + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_secure_message_verify(public_key, public_key_length, signed_msg, signed_msg_length, verified, &verified_length), + "themis_secure_message_verify: verified buffer too small"); + + status=themis_secure_message_verify(public_key, public_key_length, signed_msg, signed_msg_length, verified, &verified_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_secure_message_verify failed to verify"); + return; + } +} + +static void secure_message_old_api_test(void) { uint8_t plaintext[MAX_MESSAGE_SIZE]; size_t plaintext_length = 2048; //rand_int(MAX_MESSAGE_SIZE); @@ -314,23 +668,94 @@ static void secure_message_api_test(void) testsuite_fail_unless((!memcmp(plaintext, decryptext, plaintext_length)), "generic secure message: normal flow 2"); } +static void key_validation_test(void){ + themis_status_t status=THEMIS_FAIL; + + uint8_t ec_private_key[MAX_KEY_SIZE]={0}; + uint8_t ec_public_key[MAX_KEY_SIZE]={0}; + uint8_t rsa_private_key[MAX_KEY_SIZE]={0}; + uint8_t rsa_public_key[MAX_KEY_SIZE]={0}; + size_t ec_private_key_length = sizeof(ec_private_key); + size_t ec_public_key_length = sizeof(ec_public_key); + size_t rsa_private_key_length = sizeof(rsa_private_key); + size_t rsa_public_key_length = sizeof(rsa_public_key); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_gen_ec_key_pair(NULL, NULL, NULL, NULL), + "themis_gen_ec_key_pair: null pointers"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_gen_rsa_key_pair(NULL, NULL, NULL, NULL), + "themis_gen_rsa_key_pair: null pointers"); + + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_gen_ec_key_pair(NULL, &ec_private_key_length, NULL, &ec_public_key_length), + "themis_gen_ec_key_pair: check length"); + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_gen_rsa_key_pair(NULL, &rsa_private_key_length, NULL, &rsa_public_key_length), + " themis_gen_rsa_key_pair: check length"); + + ec_private_key_length -= 1; + ec_public_key_length -= 1; + rsa_private_key_length -= 1; + rsa_public_key_length -= 1; + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_gen_ec_key_pair(ec_private_key, &ec_private_key_length, ec_public_key, &ec_public_key_length), + "themis_gen_ec_key_pair: small buffer"); + testsuite_fail_unless(THEMIS_BUFFER_TOO_SMALL == themis_gen_rsa_key_pair(rsa_private_key, &rsa_private_key_length, rsa_public_key, &rsa_public_key_length), + "themis_gen_rsa_key_pair: small buffer"); + + status=themis_gen_ec_key_pair(ec_private_key, &ec_private_key_length, ec_public_key, &ec_public_key_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_gen_ec_key_pair failed"); + return; + } + + status=themis_gen_rsa_key_pair(rsa_private_key, &rsa_private_key_length, rsa_public_key, &rsa_public_key_length); + if(status!=THEMIS_SUCCESS){ + testsuite_fail_if(true, "themis_gen_rsa_key_pair failed"); + return; + } + + testsuite_fail_unless(THEMIS_KEY_EC_PRIVATE == themis_get_asym_key_kind(ec_private_key, ec_private_key_length), + "themis_get_asym_key_kind: EC private"); + testsuite_fail_unless(THEMIS_KEY_EC_PUBLIC == themis_get_asym_key_kind(ec_public_key, ec_public_key_length), + "themis_get_asym_key_kind: EC public"); + + testsuite_fail_unless(THEMIS_KEY_RSA_PRIVATE == themis_get_asym_key_kind(rsa_private_key, rsa_private_key_length), + "themis_get_asym_key_kind: RSA private"); + testsuite_fail_unless(THEMIS_KEY_RSA_PUBLIC == themis_get_asym_key_kind(rsa_public_key, rsa_public_key_length), + "themis_get_asym_key_kind: RSA public"); + + testsuite_fail_unless(THEMIS_SUCCESS == themis_is_valid_asym_key(ec_private_key, ec_private_key_length), + "themis_is_valid_asym_key: EC private"); + testsuite_fail_unless(THEMIS_SUCCESS == themis_is_valid_asym_key(ec_public_key, ec_public_key_length), + "themis_is_valid_asym_key: EC public"); + testsuite_fail_unless(THEMIS_SUCCESS == themis_is_valid_asym_key(rsa_private_key, rsa_private_key_length), + "themis_is_valid_asym_key: RSA private"); + testsuite_fail_unless(THEMIS_SUCCESS == themis_is_valid_asym_key(rsa_public_key, rsa_public_key_length), + "themis_is_valid_asym_key: RSA public"); + + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_is_valid_asym_key(NULL, 0), + "themis_is_valid_asym_key: invalid arguments"); + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_is_valid_asym_key(ec_private_key, ec_private_key_length-1), + "themis_is_valid_asym_key: truncated buffer"); + + testsuite_fail_unless(THEMIS_KEY_INVALID == themis_get_asym_key_kind(NULL, 0), + "themis_get_asym_key_kind: invalid arguments"); + testsuite_fail_unless(THEMIS_KEY_INVALID == themis_get_asym_key_kind(ec_private_key, 2), + "themis_get_asym_key_kind: truncated buffer"); + + const char* input = "definitely not a valid key"; + testsuite_fail_unless(THEMIS_INVALID_PARAMETER == themis_is_valid_asym_key((const uint8_t*)input, strlen(input)), + "themis_is_valid_asym_key: garbage input"); + testsuite_fail_unless(THEMIS_KEY_INVALID == themis_get_asym_key_kind((const uint8_t*)input, strlen(input)), + "themis_get_asym_key_kind: garbage input"); +} + void run_secure_message_test(){ testsuite_enter_suite("generic secure message"); testsuite_run_test(themis_secure_message_test); testsuite_enter_suite("generic secure message: api test"); - testsuite_run_test(secure_message_api_test); -} - - - - - - - - - - - - + testsuite_run_test(themis_secure_message_encrypt_decrypt_api_test); + testsuite_run_test(themis_secure_message_sign_verify_api_test); + testsuite_run_test(secure_message_old_api_test); + testsuite_enter_suite("key generation and validation"); + testsuite_run_test(key_validation_test); +} diff --git a/tests/themispp/secure_message_test.hpp b/tests/themispp/secure_message_test.hpp index f53981391..fd9b67760 100644 --- a/tests/themispp/secure_message_test.hpp +++ b/tests/themispp/secure_message_test.hpp @@ -113,12 +113,27 @@ namespace themispp { return secure_message_sign_verify_test(); } + int secure_message_test_key_mismatch(){ + themispp::secure_key_pair_generator_t gen_ec; + std::vector private_key(gen_ec.get_priv()); + std::vector public_key(gen_ec.get_pub()); + try{ + themispp::secure_message_t a(public_key, private_key); + sput_fail_unless(false, "mismatched keys (no failure)", __LINE__); + } + catch(const themispp::exception_t& e){ + sput_fail_unless(e.status()==THEMIS_INVALID_PARAMETER, "mismatched keys", __LINE__); + } + return 0; + } + void run_secure_message_test() { sput_enter_suite("ThemisPP secure message test"); sput_run_test(secure_message_test_rsa, "secure_message_test_rsa", __FILE__); sput_run_test(secure_message_test_ec, "secure_message_test_ec", __FILE__); sput_run_test(secure_message_sign_verify_test_rsa, "secure_message_sign_verify_test_rsa", __FILE__); sput_run_test(secure_message_sign_verify_test_ec, "secure_message_sign_verify_test_ec", __FILE__); + sput_run_test(secure_message_test_key_mismatch, "secure_message_test_key_mismatch", __FILE__); } } }