[libfko] reject negative length values

Integer lengths that are negative are never valid.  This commit also
extends the fuzzing capabilities of the test/fko-wrapper code to
validate libfko calls with negative length arguments, and one crash
scenario with a negative length for the encryption key was found (and
fixed) this way.
This commit is contained in:
Michael Rash 2013-12-29 21:05:04 -05:00
parent d09e278646
commit 0c6911941b
9 changed files with 154 additions and 39 deletions

View File

@ -88,7 +88,7 @@ b64_encode(unsigned char *in, char *out, int in_len)
char *dst = out;
if (in_len) { /* Special edge case, what should we really do here? */
if (in_len > 0) { /* Special edge case, what should we really do here? */
while (bytes_remaining) {
i_bits = (i_bits << 8) + *in++;
bytes_remaining--;

View File

@ -74,6 +74,9 @@ get_random_data(unsigned char *data, const size_t len)
int do_time = 0;
size_t amt_read;
if(len < 0)
return;
/* Attempt to read seed data from /dev/urandom. If that does not
* work, then fall back to a time-based method (less secure, but
* probably more portable).

View File

@ -337,7 +337,6 @@ DLL_API int fko_destroy(fko_ctx_t ctx);
DLL_API int fko_spa_data_final(fko_ctx_t ctx, const char * const enc_key,
const int enc_key_len, const char * const hmac_key, const int hmac_key_len);
/* Set context data functions
*/
DLL_API int fko_set_rand_value(fko_ctx_t ctx, const char * const val);
@ -381,7 +380,6 @@ DLL_API int fko_get_spa_hmac(fko_ctx_t ctx, char **enc_data);
DLL_API int fko_get_encoded_data(fko_ctx_t ctx, char **enc_data);
/* Get context data functions
*/
DLL_API int fko_get_rand_value(fko_ctx_t ctx, char **rand_val);
@ -403,7 +401,8 @@ DLL_API int fko_get_spa_data(fko_ctx_t ctx, char **spa_data);
DLL_API int fko_get_version(fko_ctx_t ctx, char **version);
/* GPG-related functions */
/* GPG-related functions
*/
DLL_API int fko_set_gpg_exe(fko_ctx_t ctx, const char * const gpg_exe);
DLL_API int fko_get_gpg_exe(fko_ctx_t ctx, char **gpg_exe);

View File

@ -53,7 +53,7 @@ _rijndael_encrypt(fko_ctx_t ctx, const char *enc_key, const int enc_key_len)
int pt_len;
int zero_free_rv = FKO_SUCCESS;
if(enc_key_len > RIJNDAEL_MAX_KEYSIZE)
if(enc_key_len < 0 || enc_key_len > RIJNDAEL_MAX_KEYSIZE)
return(FKO_ERROR_INVALID_KEY_LEN);
if (! is_valid_encoded_msg_len(ctx->encoded_msg_len))
@ -166,7 +166,7 @@ _rijndael_decrypt(fko_ctx_t ctx,
int cipher_len, pt_len, i, err = 0, res = FKO_SUCCESS;
int zero_free_rv = FKO_SUCCESS;
if(key_len > RIJNDAEL_MAX_KEYSIZE)
if(key_len < 0 || key_len > RIJNDAEL_MAX_KEYSIZE)
return(FKO_ERROR_INVALID_KEY_LEN);
/* Now see if we need to add the "Salted__" string to the front of the
@ -558,6 +558,9 @@ fko_encrypt_spa_data(fko_ctx_t ctx, const char * const enc_key,
if(!CTX_INITIALIZED(ctx))
return(FKO_ERROR_CTX_NOT_INITIALIZED);
if(enc_key_len < 0)
return(FKO_ERROR_INVALID_KEY_LEN);
/* If there is no encoded data or the SPA data has been modified,
* go ahead and re-encode here.
*/
@ -600,6 +603,9 @@ fko_decrypt_spa_data(fko_ctx_t ctx, const char * const dec_key, const int key_le
if(!CTX_INITIALIZED(ctx))
return(FKO_ERROR_CTX_NOT_INITIALIZED);
if(key_len < 0)
return(FKO_ERROR_INVALID_KEY_LEN);
/* Get the (assumed) type of encryption used. This will also provide
* some data validation.
*/

View File

@ -476,6 +476,9 @@ fko_spa_data_final(fko_ctx_t ctx,
if(!CTX_INITIALIZED(ctx))
return(FKO_ERROR_CTX_NOT_INITIALIZED);
if(enc_key_len < 0)
return(FKO_ERROR_INVALID_KEY_LEN);
res = fko_encrypt_spa_data(ctx, enc_key, enc_key_len);
/* Now calculate hmac if so configured
@ -483,6 +486,9 @@ fko_spa_data_final(fko_ctx_t ctx,
if (res == FKO_SUCCESS &&
ctx->hmac_type != FKO_HMAC_UNKNOWN && hmac_key != NULL)
{
if(hmac_key_len < 0)
return(FKO_ERROR_INVALID_KEY_LEN);
res = fko_set_spa_hmac(ctx, hmac_key, hmac_key_len);
if (res == FKO_SUCCESS)

View File

@ -51,7 +51,7 @@ fko_verify_hmac(fko_ctx_t ctx,
if (! is_valid_encoded_msg_len(ctx->encrypted_msg_len))
return(FKO_ERROR_INVALID_DATA_HMAC_MSGLEN_VALIDFAIL);
if(hmac_key_len > MAX_DIGEST_BLOCK_LEN)
if(hmac_key_len < 0 || hmac_key_len > MAX_DIGEST_BLOCK_LEN)
return(FKO_ERROR_INVALID_HMAC_KEY_LEN);
if(ctx->hmac_type == FKO_HMAC_MD5)
@ -224,7 +224,7 @@ int fko_set_spa_hmac(fko_ctx_t ctx,
if(!CTX_INITIALIZED(ctx))
return(FKO_ERROR_CTX_NOT_INITIALIZED);
if(hmac_key_len > MAX_DIGEST_BLOCK_LEN)
if(hmac_key_len < 0 || hmac_key_len > MAX_DIGEST_BLOCK_LEN)
return(FKO_ERROR_INVALID_HMAC_KEY_LEN);
if(ctx->hmac_type == FKO_HMAC_MD5)

View File

@ -200,6 +200,9 @@ digest_inttostr(int digest, char* digest_str, size_t digest_size)
{
short digest_not_valid = 0;
if(digest_size < 0)
return -1;
memset(digest_str, 0, digest_size);
switch (digest)
@ -300,6 +303,9 @@ hmac_digest_inttostr(int digest, char* digest_str, size_t digest_size)
{
short digest_not_valid = 0;
if(digest_size < 0)
return -1;
memset(digest_str, 0, digest_size);
switch (digest)
@ -390,6 +396,9 @@ enc_mode_inttostr(int enc_mode, char* enc_mode_str, size_t enc_mode_size)
unsigned char ndx_enc_mode;
fko_enc_mode_str_t *enc_mode_str_pt;
if(enc_mode_size < 0)
return enc_mode_error;
/* Initialize the protocol string */
memset(enc_mode_str, 0, enc_mode_size);
@ -641,6 +650,9 @@ dump_ctx_to_buffer(fko_ctx_t ctx, char *dump_buf, size_t dump_buf_len)
int encryption_mode = -1;
int client_timeout = -1;
if(dump_buf_len < 0)
return err;
/* Zero-ed the buffer */
memset(dump_buf, 0, dump_buf_len);

View File

@ -270,7 +270,8 @@ get_gpg_key(fko_ctx_t fko_ctx, gpgme_key_t *mykey, const int signer)
/* The main GPG encryption routine for libfko.
*/
int
gpgme_encrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const char *pw, unsigned char **out, size_t *out_len)
gpgme_encrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len,
const char *pw, unsigned char **out, size_t *out_len)
{
char *tmp_buf;
int res;
@ -413,7 +414,8 @@ gpgme_encrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const cha
/* The main GPG decryption routine for libfko.
*/
int
gpgme_decrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const char *pw, unsigned char **out, size_t *out_len)
gpgme_decrypt(fko_ctx_t fko_ctx, unsigned char *indata,
size_t in_len, const char *pw, unsigned char **out, size_t *out_len)
{
char *tmp_buf;
int res;

View File

@ -16,10 +16,16 @@
#define NO_CTX_DESTROY 1
#define NEW_CTX 0
#define NO_NEW_CTX 1
#define DO_PRINT 1
#define NO_PRINT 2
#define ENC_KEY "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* 32 bytes */
#define HMAC_KEY "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* 32 bytes */
static void display_ctx(fko_ctx_t ctx);
static void test_loop(int new_ctx_flag, int destroy_ctx_flag);
static void ctx_update(fko_ctx_t *ctx, int new_ctx_flag, int destroy_ctx_flag);
static void ctx_update(fko_ctx_t *ctx, int new_ctx_flag,
int destroy_ctx_flag, int print_flag);
static void spa_default_ctx(fko_ctx_t *ctx);
static void spa_func_int(fko_ctx_t *ctx, char *name,
int (*spa_func)(fko_ctx_t ctx, const int modifier), int min, int max,
@ -58,7 +64,7 @@ static void
test_loop(int new_ctx_flag, int destroy_ctx_flag)
{
fko_ctx_t ctx = NULL, decrypt_ctx = NULL;
int i;
int i, j;
char *spa_data = NULL;
printf("fko_new(): %s\n", fko_errstr(fko_new(&ctx)));
@ -84,19 +90,19 @@ test_loop(int new_ctx_flag, int destroy_ctx_flag)
for (i=0; i<FCN_CALLS; i++) {
printf("fko_set_spa_message(1.1.1.1,tcp/22): %s\n",
fko_errstr(fko_set_spa_message(ctx, "1.1.1.1,tcp/22")));
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
for (i=0; i<FCN_CALLS; i++) {
printf("fko_set_spa_nat_access(1.2.3.4,1234): %s\n",
fko_errstr(fko_set_spa_nat_access(ctx, "1.2.3.4,1234")));
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
for (i=0; i<FCN_CALLS; i++) {
printf("fko_set_username(someuser): %s\n",
fko_errstr(fko_set_username(ctx, "someuser")));
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
spa_func_getset_short(&ctx, "fko_set_spa_encryption_type",
@ -115,19 +121,19 @@ test_loop(int new_ctx_flag, int destroy_ctx_flag)
for (i=0; i<FCN_CALLS; i++) {
printf("fko_set_spa_encryption_type(FKO_ENCRYPTION_GPG): %s\n",
fko_errstr(fko_set_spa_encryption_type(ctx, FKO_ENCRYPTION_GPG)));
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
for (i=0; i<FCN_CALLS; i++) {
printf("fko_set_gpg_home_dir(/home/mbr/.gnupg): %s\n",
fko_errstr(fko_set_gpg_home_dir(ctx, "/home/mbr/.gnupg")));
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
for (i=0; i<FCN_CALLS; i++) {
printf("fko_set_gpg_recipient(1234asdf): %s\n",
fko_errstr(fko_set_gpg_recipient(ctx, "1234asdf")));
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
}
@ -137,23 +143,37 @@ test_loop(int new_ctx_flag, int destroy_ctx_flag)
FKO_LAST_DIGEST_TYPE+F_INT, FKO_DEFAULT_DIGEST,
new_ctx_flag, destroy_ctx_flag);
spa_func_getset_short(&ctx, "fko_set_raw_spa_digest_type",
&fko_set_spa_digest_type, "fko_get_raw_spa_digest_type",
&fko_get_spa_digest_type, FKO_DIGEST_INVALID_DATA-F_INT,
FKO_LAST_DIGEST_TYPE+F_INT, FKO_DEFAULT_DIGEST,
new_ctx_flag, destroy_ctx_flag);
spa_func_getset_short(&ctx, "fko_set_spa_hmac_type",
&fko_set_spa_hmac_type, "fko_get_spa_hmac_type",
&fko_get_spa_hmac_type, FKO_HMAC_INVALID_DATA-F_INT,
FKO_LAST_HMAC_MODE+F_INT, FKO_HMAC_SHA256,
new_ctx_flag, destroy_ctx_flag);
printf("Trying encrypt / authenticate step with bogus key lengths...\n");
for (i=-100; i < 200; i += 10) {
for (j=-100; j < 200; j += 10) {
fko_spa_data_final(ctx, ENC_KEY, i, HMAC_KEY, j);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, NO_PRINT);
}
}
for (i=0; i<FCN_CALLS; i++) {
printf("fko_spa_data_final(testtest, 8, hmactest, 8): %s\n",
fko_errstr(fko_spa_data_final(ctx, "testtest", 8, "hmactest", 8)));
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
printf("fko_spa_data_final(ENC_KEY, 8, HMAC_KEY, 8): %s\n",
fko_errstr(fko_spa_data_final(ctx, ENC_KEY, 16, HMAC_KEY, 16)));
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
for (i=0; i<FCN_CALLS; i++) {
printf("fko_get_spa_data(): %s\n",
fko_errstr(fko_get_spa_data(ctx, &spa_data)));
printf(" %s\n", spa_data == NULL ? "<NULL>" : spa_data);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
printf(" SPA DATA: %s\n", spa_data == NULL ? "<NULL>" : spa_data);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
printf("fko_new_with_data(): %s\n",
@ -170,26 +190,26 @@ test_loop(int new_ctx_flag, int destroy_ctx_flag)
display_ctx(decrypt_ctx);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
/* now, separately verify hmac, decrypt, and display ctx */
for (i=0; i<FCN_CALLS; i++) {
printf("fko_verify_hmac(): %s\n",
fko_errstr(fko_verify_hmac(decrypt_ctx, "hmactest", 8)));
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
/* now decrypt */
for (i=0; i<FCN_CALLS; i++) {
printf("fko_decrypt_spa_data(): %s\n",
fko_errstr(fko_decrypt_spa_data(decrypt_ctx, "testtest", 8)));
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
for (i=0; i<FCN_CALLS; i++) {
display_ctx(decrypt_ctx);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(&ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
}
for (i=0; i<FCN_CALLS; i++) {
@ -205,29 +225,67 @@ test_loop(int new_ctx_flag, int destroy_ctx_flag)
return;
}
static void ctx_update(fko_ctx_t *ctx, int new_ctx_flag, int destroy_ctx_flag)
static void ctx_update(fko_ctx_t *ctx, int new_ctx_flag,
int destroy_ctx_flag, int print_flag)
{
if (destroy_ctx_flag == CTX_DESTROY) {
printf("fko_destroy(): %s\n", fko_errstr(fko_destroy(*ctx)));
if (print_flag == DO_PRINT)
printf("fko_destroy(): %s\n", fko_errstr(fko_destroy(*ctx)));
else
fko_destroy(*ctx);
*ctx = NULL;
}
if (new_ctx_flag == NEW_CTX) {
/* always destroy before re-creating */
printf("fko_destroy(): %s\n", fko_errstr(fko_destroy(*ctx)));
if (print_flag == DO_PRINT)
printf("fko_destroy(): %s\n", fko_errstr(fko_destroy(*ctx)));
else
fko_destroy(*ctx);
*ctx = NULL;
printf("fko_new(): %s\n", fko_errstr(fko_new(ctx)));
if (print_flag == DO_PRINT)
printf("fko_new(): %s\n", fko_errstr(fko_new(ctx)));
else
fko_new(ctx);
}
return;
}
static void spa_default_ctx(fko_ctx_t *ctx)
{
fko_new(ctx);
fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16);
fko_set_spa_message(*ctx, "123.123.123.123,tcp/22");
fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16);
fko_set_spa_message_type(*ctx, FKO_ACCESS_MSG);
fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16);
fko_set_username(*ctx, "someuser");
fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16);
fko_set_spa_encryption_type(*ctx, FKO_ENCRYPTION_RIJNDAEL);
fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16);
fko_set_spa_encryption_mode(*ctx, FKO_ENC_MODE_CBC);
fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16);
fko_set_spa_digest_type(*ctx, FKO_DEFAULT_DIGEST);
fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16);
fko_set_spa_hmac_type(*ctx, FKO_HMAC_SHA256);
fko_spa_data_final(*ctx, ENC_KEY, 16, HMAC_KEY, 16);
// display_ctx(*ctx);
spa_calls += 16;
return;
}
static void spa_func_getset_int(fko_ctx_t *ctx, char *set_name,
int (*spa_set)(fko_ctx_t ctx, const int modifier),
char *get_name, int (*spa_get)(fko_ctx_t ctx, int *val),
int min, int max, int final_val, int new_ctx_flag, int destroy_ctx_flag)
{
fko_ctx_t default_ctx = NULL;
int get_val;
int i, res;
spa_default_ctx(&default_ctx);
printf("[+] calling libfko get/set: %s/%s\n", get_name, set_name);
for (i=min; i <= max; i++) {
get_val = 1234; /* meaningless default */
@ -236,33 +294,51 @@ static void spa_func_getset_int(fko_ctx_t *ctx, char *set_name,
res = (spa_get)(*ctx, &get_val);
printf("%s(%d): %s\n", get_name, get_val, fko_errstr(res));
ctx_update(ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
spa_calls += 3;
/* also set on a fully populated context */
(spa_set)(default_ctx, i);
}
printf("%s(%d): %s (FINAL)\n", set_name, final_val,
fko_errstr((spa_set)(*ctx, final_val)));
display_ctx(*ctx);
fko_spa_data_final(default_ctx, ENC_KEY, 16, HMAC_KEY, 16);
fko_destroy(default_ctx);
default_ctx = NULL;
return;
}
static void spa_func_int(fko_ctx_t *ctx, char *name,
int (*spa_func)(fko_ctx_t ctx, const int modifier), int min, int max,
int (*spa_set)(fko_ctx_t ctx, const int modifier), int min, int max,
int final_val, int new_ctx_flag, int destroy_ctx_flag)
{
fko_ctx_t default_ctx = NULL;
int i;
spa_default_ctx(&default_ctx);
printf("[+] calling libfko function: %s\n", name);
for (i=min; i <= max; i++) {
printf("%s(%d): %s\n", name, i, fko_errstr((spa_func)(*ctx, i)));
printf("%s(%d): %s (DUPE)\n", name, i, fko_errstr((spa_func)(*ctx, i)));
printf("%s(%d): %s\n", name, i, fko_errstr((spa_set)(*ctx, i)));
printf("%s(%d): %s (DUPE)\n", name, i, fko_errstr((spa_set)(*ctx, i)));
ctx_update(ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
spa_calls += 2;
/* also set on a fully populated context */
(spa_set)(default_ctx, i);
}
printf("%s(%d): %s (FINAL)\n", name, final_val,
fko_errstr((spa_func)(*ctx, final_val)));
fko_errstr((spa_set)(*ctx, final_val)));
display_ctx(*ctx);
fko_spa_data_final(default_ctx, ENC_KEY, 16, HMAC_KEY, 16);
fko_destroy(default_ctx);
default_ctx = NULL;
return;
}
@ -271,9 +347,12 @@ static void spa_func_getset_short(fko_ctx_t *ctx, char *set_name,
char *get_name, int (*spa_get)(fko_ctx_t ctx, short *val),
int min, int max, int final_val, int new_ctx_flag, int destroy_ctx_flag)
{
fko_ctx_t default_ctx = NULL;
short get_val;
int i, res;
spa_default_ctx(&default_ctx);
printf("[+] calling libfko get/set: %s/%s\n", get_name, set_name);
for (i=min; i <= max; i++) {
get_val = 1234; /* meaningless default */
@ -282,13 +361,21 @@ static void spa_func_getset_short(fko_ctx_t *ctx, char *set_name,
res = (spa_get)(*ctx, &get_val);
printf("%s(%d): %s\n", get_name, get_val, fko_errstr(res));
ctx_update(ctx, new_ctx_flag, destroy_ctx_flag);
ctx_update(ctx, new_ctx_flag, destroy_ctx_flag, DO_PRINT);
spa_calls += 3;
/* also set on a fully populated context */
(spa_set)(default_ctx, i);
}
printf("%s(%d): %s (FINAL)\n", set_name, final_val,
fko_errstr((spa_set)(*ctx, final_val)));
display_ctx(*ctx);
fko_spa_data_final(default_ctx, ENC_KEY, 16, HMAC_KEY, 16);
fko_destroy(default_ctx);
default_ctx = NULL;
return;
}