[libfko] reject negative length values
authorMichael Rash <mbr@cipherdyne.org>
Mon, 30 Dec 2013 02:05:04 +0000 (21:05 -0500)
committerMichael Rash <mbr@cipherdyne.org>
Mon, 30 Dec 2013 02:05:04 +0000 (21:05 -0500)
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.

lib/base64.c
lib/cipher_funcs.c
lib/fko.h
lib/fko_encryption.c
lib/fko_funcs.c
lib/fko_hmac.c
lib/fko_util.c
lib/gpgme_funcs.c
test/fko-wrapper/fko_wrapper.c

index 5a5569f..35498b6 100644 (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--;
index 93b118c..e4da6eb 100644 (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).
index a21df0a..5d5cb03 100644 (file)
--- a/lib/fko.h
+++ b/lib/fko.h
@@ -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);
 
index bdecb32..69b353f 100644 (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.
     */
index b8efb7d..afb9ff8 100644 (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)
index 88ba553..b674c01 100644 (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)
index 83997df..f885b59 100644 (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);
 
index af92dec..889b190 100644 (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;
index 644bed3..eac69be 100644 (file)
 #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;
 }