Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce new Secure Message API #389

Merged
merged 22 commits into from Feb 25, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ef65c98
Introduce new Secure Message API
ilammy Feb 20, 2019
54aefce
Cast test message as uint8_t
ilammy Feb 20, 2019
aaaccdb
Implement new Secure Message API using primitives
ilammy Feb 20, 2019
609a6bf
Mark old Secure Message API as deprecated
ilammy Feb 20, 2019
02b38ea
Merge branch 'master' into new-smessage-api
ilammy Feb 20, 2019
acb767b
Use new Secure Message API: ThemisPP
ilammy Feb 20, 2019
9ff2cf0
Use new Secure Message API: rust-themis
ilammy Feb 20, 2019
c21a87f
Use new Secure Message API: Java/Android Themis
ilammy Feb 20, 2019
ac107b4
Use new Secure Message API: JsThemis
ilammy Feb 20, 2019
8306f70
Avoid magic constants in tests
ilammy Feb 20, 2019
7f4f939
Improve wording in comments and deprecations
vixentael Feb 21, 2019
35e3cde
Move key kind validation to Themis Core
ilammy Feb 21, 2019
c341511
Key kind checks in Secure Message
ilammy Feb 21, 2019
0d3edf5
Key kind checks in Secure Message: ThemisPP
ilammy Feb 21, 2019
7075209
Key kind checks in Secure Message: JsThemis
ilammy Feb 21, 2019
3549f9d
Move keygen and validation into a new file
ilammy Feb 21, 2019
fdc4bc6
Move key checking utilities to secure_keygen.hpp (ThemisPP)
ilammy Feb 21, 2019
7e75bb7
Move key checking utilities to secure_keygen.hpp (JsThemis)
ilammy Feb 21, 2019
dfbd1b3
Remove redundant checks for null and empty keys
ilammy Feb 21, 2019
ec67c84
Provide more detailed key validation
ilammy Feb 21, 2019
27970d3
Improve key validation accuracy
ilammy Feb 22, 2019
2f02158
Rename key validation functions
ilammy Feb 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
121 changes: 121 additions & 0 deletions src/themis/secure_keygen.c
@@ -0,0 +1,121 @@
/*
* 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 <string.h>
#include <arpa/inet.h>

#include <themis/themis_error.h>
#include <soter/soter_t.h>
#include <soter/soter_container.h>
#include <soter/soter_ec_key.h>
#include <soter/soter_rsa_key.h>

#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_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;
}

themis_status_t themis_is_valid_key(const uint8_t* key, size_t length){
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;
}
102 changes: 102 additions & 0 deletions 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 <themis/themis.h>

#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_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_key(const uint8_t* key, size_t length);

/** @} */
/** @} */

#ifdef __cplusplus
}
#endif


#endif /* _THEMIS_SECURE_KEYGEN_H_ */
114 changes: 1 addition & 113 deletions src/themis/secure_message.c
Expand Up @@ -14,111 +14,11 @@
* limitations under the License.
*/

#include <string.h>
#include <arpa/inet.h>
#include "secure_message.h"

#include <themis/themis_error.h>
#include <themis/secure_message.h>
#include <themis/secure_message_wrapper.h>
#include <soter/soter_t.h>
#include <soter/soter_container.h>
#include <soter/soter_ec_key.h>
#include <soter/soter_rsa_key.h>

#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_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;
}

themis_status_t themis_is_valid_key(const uint8_t* key, size_t length){
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;
}

static bool valid_private_key(const uint8_t* private_key, size_t private_key_length){
if(themis_is_valid_key(private_key, private_key_length)==THEMIS_SUCCESS){
Expand Down Expand Up @@ -171,10 +71,6 @@ themis_status_t themis_secure_message_encrypt(const uint8_t* private_key,
uint8_t* encrypted_message,
size_t* encrypted_message_length)
{
THEMIS_CHECK_PARAM(private_key!=NULL);
THEMIS_CHECK_PARAM(private_key_length!=0);
THEMIS_CHECK_PARAM(public_key!=NULL);
THEMIS_CHECK_PARAM(public_key_length!=0);
THEMIS_CHECK_PARAM(message!=NULL);
THEMIS_CHECK_PARAM(message_length!=0);
THEMIS_CHECK_PARAM(encrypted_message_length!=NULL);
Expand All @@ -200,10 +96,6 @@ themis_status_t themis_secure_message_decrypt(const uint8_t* private_key,
uint8_t* message,
size_t* message_length)
{
THEMIS_CHECK_PARAM(private_key!=NULL);
THEMIS_CHECK_PARAM(private_key_length!=0);
THEMIS_CHECK_PARAM(public_key!=NULL);
THEMIS_CHECK_PARAM(public_key_length!=0);
THEMIS_CHECK_PARAM(encrypted_message!=NULL);
THEMIS_CHECK_PARAM(encrypted_message_length!=0);
THEMIS_CHECK_PARAM(message_length!=NULL);
Expand Down Expand Up @@ -231,8 +123,6 @@ themis_status_t themis_secure_message_sign(const uint8_t* private_key,
uint8_t* signed_message,
size_t* signed_message_length)
{
THEMIS_CHECK_PARAM(private_key!=NULL);
THEMIS_CHECK_PARAM(private_key_length!=0);
THEMIS_CHECK_PARAM(message!=NULL);
THEMIS_CHECK_PARAM(message_length!=0);
THEMIS_CHECK_PARAM(signed_message_length!=NULL);
Expand All @@ -254,8 +144,6 @@ themis_status_t themis_secure_message_verify(const uint8_t* public_key,
uint8_t* message,
size_t* message_length)
{
THEMIS_CHECK_PARAM(public_key!=NULL);
THEMIS_CHECK_PARAM(public_key_length!=0);
THEMIS_CHECK_PARAM(signed_message!=NULL);
THEMIS_CHECK_PARAM(signed_message_length!=0);
THEMIS_CHECK_PARAM(message_length!=NULL);
Expand Down