Update to make AES encryption modes selectable
authorMichael Rash <mbr@cipherdyne.org>
Wed, 25 Jan 2012 01:26:21 +0000 (20:26 -0500)
committerMichael Rash <mbr@cipherdyne.org>
Wed, 25 Jan 2012 01:26:21 +0000 (20:26 -0500)
This is a significant update to allow AES encryption modes to be selected on a
per-key basis.  For now, only ECB and CBC (recommended) modes are supported.
The default is ECB modes in order to maintain backwards compatibility with the
older perl version of fwknop and the Crypt::CBC CPAN module.  This will likely
be changed to use CBC mode by default because of its better security
properties.

In the access.conf file on the server side, there is a new configuration
variable "ENCRYPTION_MODE" that controls the mode for the corresponding AES
key.  On the client side, a new command line argument "--encryption-mode"
controls how the client encrypts SPA packets.

16 files changed:
client/cmd_opts.h
client/config_init.c
client/fwknop.c
client/fwknop_common.h
doc/fwknop.man.asciidoc
doc/fwknopd.man.asciidoc
lib/cipher_funcs.c
lib/cipher_funcs.h
lib/fko.h
lib/fko_context.h
lib/fko_encryption.c
lib/fko_funcs.c
lib/fko_state.h
server/access.c
server/fwknopd_common.h
server/incoming_spa.c

index cd042c1..ab2f8f4 100644 (file)
@@ -35,6 +35,7 @@
 */
 enum {
     FKO_DIGEST_NAME     = 0x100,
+    ENCRYPTION_MODE,
     NAT_LOCAL,
     NAT_PORT,
     NAT_RAND_PORT,
@@ -55,7 +56,7 @@ enum {
 
 /* Our getopt_long options string.
 */
-#define GETOPTS_OPTION_STRING "a:A:bB:C:D:f:gG:hH:lm:n:N:p:P:Q:rRsS:Tu:U:vV"
+#define GETOPTS_OPTION_STRING "a:A:bB:C:D:f:gG:hH:lm:M:n:N:p:P:Q:rRsS:Tu:U:vV"
 
 /* Our program command-line options...
 */
@@ -69,6 +70,7 @@ static struct option cmd_opts[] =
     {"server-cmd",          1, NULL, 'C'},
     {"digest-type",         1, NULL, FKO_DIGEST_NAME},
     {"destination",         1, NULL, 'D'},
+    {"encryption-mode",     1, NULL, ENCRYPTION_MODE},
     {"fw-timeout",          1, NULL, 'f'},
     {"gpg-encryption",      0, NULL, 'g'},
     {"gpg-recipient-key",   1, NULL, GPG_RECIP_KEY },
index f0cd41b..e97ea0e 100644 (file)
@@ -33,9 +33,9 @@
 #include "cmd_opts.h"
 #include "utils.h"
 
-/* Convert a digest_type string to its intger value.
+/* Convert a digest_type string to its integer value.
 */
-static int
+static short
 digest_strtoint(const char *dt_str)
 {
     if(strcasecmp(dt_str, "md5") == 0)
@@ -52,7 +52,28 @@ digest_strtoint(const char *dt_str)
         return(-1);
 }
 
-/* Convert a protocol string to its intger value.
+/* Convert an encryption_mode string to its integer value.
+*/
+static int
+enc_mode_strtoint(const char *enc_mode_str)
+{
+    if(strcasecmp(enc_mode_str, "cbc") == 0)
+        return(FKO_ENC_MODE_CBC);
+    else if(strcasecmp(enc_mode_str, "ecb") == 0)
+        return(FKO_ENC_MODE_ECB);
+    else if(strcasecmp(enc_mode_str, "cfb") == 0)
+        return(FKO_ENC_MODE_CFB);
+    else if(strcasecmp(enc_mode_str, "pcbc") == 0)
+        return(FKO_ENC_MODE_PCBC);
+    else if(strcasecmp(enc_mode_str, "ofb") == 0)
+        return(FKO_ENC_MODE_OFB);
+    else if(strcasecmp(enc_mode_str, "ctr") == 0)
+        return(FKO_ENC_MODE_CTR);
+    else
+        return(-1);
+}
+
+/* Convert a protocol string to its integer value.
 */
 static int
 proto_strtoint(const char *pr_str)
@@ -290,6 +311,15 @@ parse_rc_param(fko_cli_options_t *options, const char *var, char * val)
         else
             options->time_offset_plus = parse_time_offset(val);
     }
+    /* symmetric encryption mode */
+    else if(CONF_VAR_IS(var, "ENCRYPTION_MODE"))
+    {
+        tmpint = enc_mode_strtoint(val);
+        if(tmpint < 0)
+            return(-1);
+        else
+            options->encryption_mode = tmpint;
+    }
     /* Use GPG ? */
     else if(CONF_VAR_IS(var, "USE_GPG"))
     {
@@ -724,7 +754,19 @@ config_init(fko_cli_options_t *options, int argc, char **argv)
             case FKO_DIGEST_NAME:
                 if((options->digest_type = digest_strtoint(optarg)) < 0)
                 {
-                    fprintf(stderr, "* Invalid digest type: %s\n", optarg);
+                    fprintf(stderr,
+                        "* Invalid digest type: %s, use {md5,sha1,sha256,sha384,sha512}\n",
+                    optarg);
+                    exit(EXIT_FAILURE);
+                }
+                break;
+            case 'M':
+            case ENCRYPTION_MODE:
+                if((options->encryption_mode = enc_mode_strtoint(optarg)) < 0)
+                {
+                    fprintf(stderr,
+                        "* Invalid encryption mode: %s, use {cbc,ecb}\n",
+                    optarg);
                     exit(EXIT_FAILURE);
                 }
                 break;
index 687f5a0..1e545f7 100644 (file)
@@ -252,6 +252,23 @@ main(int argc, char **argv)
                 return(EXIT_FAILURE);
             }
         }
+
+        res = fko_set_spa_encryption_mode(ctx, FKO_ENC_MODE_ASYMMETRIC);
+        if(res != FKO_SUCCESS)
+        {
+            errmsg("fko_set_spa_encryption_mode", res);
+            return(EXIT_FAILURE);
+        }
+    }
+
+    if(options.encryption_mode && !options.use_gpg)
+    {
+        res = fko_set_spa_encryption_mode(ctx, options.encryption_mode);
+        if(res != FKO_SUCCESS)
+        {
+            errmsg("fko_set_spa_encryption_mode", res);
+            return(EXIT_FAILURE);
+        }
     }
 
     /* Set Digest type.
@@ -328,13 +345,20 @@ main(int argc, char **argv)
          * an empty context, populate it with the encrypted data, set our
          * options, then decode it.
         */
-        res = fko_new_with_data(&ctx2, spa_data, NULL);
+        res = fko_new_with_data(&ctx2, spa_data, NULL, ctx->encryption_mode);
         if(res != FKO_SUCCESS)
         {
             errmsg("fko_new_with_data", res);
             return(EXIT_FAILURE);
         }
 
+        res = fko_set_spa_encryption_mode(ctx2, ctx->encryption_mode);
+        if(res != FKO_SUCCESS)
+        {
+            errmsg("fko_set_spa_encryption_mode", res);
+            return(EXIT_FAILURE);
+        }
+
         /* See if we are using gpg and if we need to set the GPG home dir.
         */
         if(options.use_gpg)
@@ -770,6 +794,7 @@ display_ctx(fko_ctx_t ctx)
     time_t      timestamp       = 0;
     short       msg_type        = -1;
     short       digest_type     = -1;
+    int         encryption_mode = -1;
     int         client_timeout  = -1;
 
     /* Should be checking return values, but this is temp code. --DSS
@@ -784,6 +809,7 @@ display_ctx(fko_ctx_t ctx)
     fko_get_spa_server_auth(ctx, &server_auth);
     fko_get_spa_client_timeout(ctx, &client_timeout);
     fko_get_spa_digest_type(ctx, &digest_type);
+    fko_get_spa_encryption_mode(ctx, &encryption_mode);
     fko_get_encoded_data(ctx, &enc_data);
     fko_get_spa_digest(ctx, &spa_digest);
     fko_get_spa_data(ctx, &spa_data);
@@ -798,7 +824,8 @@ display_ctx(fko_ctx_t ctx)
     printf("     Nat Access: %s\n", nat_access == NULL ? "<NULL>" : nat_access);
     printf("    Server Auth: %s\n", server_auth == NULL ? "<NULL>" : server_auth);
     printf(" Client Timeout: %u\n", client_timeout);
-    printf("    Digest Type: %u\n", digest_type);
+    printf("    Digest Type: %d\n", digest_type);
+    printf("Encryption Mode: %d\n", encryption_mode);
     printf("\n   Encoded Data: %s\n", enc_data == NULL ? "<NULL>" : enc_data);
     printf("\nSPA Data Digest: %s\n", spa_digest == NULL ? "<NULL>" : spa_digest);
     printf("\nFinal Packed/Encrypted/Encoded Data:\n\n%s\n\n", spa_data);
index 5d7e8ef..4e494aa 100644 (file)
@@ -116,7 +116,8 @@ typedef struct fko_cli_options
     unsigned int spa_dst_port;
     unsigned int spa_src_port; /* only used with --source-port */
 
-    unsigned int digest_type;
+    short digest_type;
+    int encryption_mode;
 
     /* Various command-line flags */
     unsigned char   verbose; /* --verbose mode */
index f110d20..ade2674 100644 (file)
@@ -1,5 +1,5 @@
 :man source: Fwknop Client
-:man manual: Fwknop Client 
+:man manual: Fwknop Client
 
 FWKNOP(8)
 =========
@@ -38,7 +38,7 @@ sequence on the server to break port knocking authentication.
 SPA packets can easily be spoofed as well (this is a good thing in this
 context), and this makes it possible to make it appear as though, say,
 www.yahoo.com is trying to authenticate to a target system but in reality
-the actual connection will come from a seemingly unrelated IP.  
+the actual connection will come from a seemingly unrelated IP.
 
 Authorization packets are either encrypted with the 'Rijndael' block cipher
 or via 'GnuPG' and associated asymmetric ciphers.  If the symmetric encryption
@@ -161,10 +161,10 @@ SPA OPTIONS
 *-a, --allow-ip*='<IP-address>'::
     Specify IP address that should be permitted through the destination
     *fwknopd* server firewall (this IP is encrypted within the SPA packet
-    itself).  This is useful to prevent a MTIM attack where a SPA packet
+    itself).  This is useful to prevent a MITM attack where a SPA packet
     can be intercepted en-route and sent from a different IP than the
     original.  Hence, if the *fwknopd* server trusts the source address
-    on the  SPA  packet IP header then the attacker gains access. 
+    on the  SPA  packet IP header then the attacker gains access.
     The *-a* option puts the source address within the encrypted SPA
     packet, and so thwarts this attack.  The *-a* option is also
     useful to specify the IP that will be granted access when the
@@ -197,6 +197,15 @@ SPA OPTIONS
     Specify the message digest algorithm to use in the SPA data.  Choices
     are: *MD5*, *SHA1*, *SHA256* (the default), *SHA384*, and *SHA512*.
 
+*-M, --encryption-mode*='<mode>'::
+    Specify the encryption mode when AES is used.  The default (for now) is
+    ECB mode in order to remain backwards compatible with pre-2.0 versions of
+    fwknop which relied on the Crypt::CBC perl module.  This will be changed
+    in an upcoming version of fwknop to use the more secure CBC mode.  In the
+    meantime, it is recommend to use this option to specify CBC mode (use the
+    string "CBC" as the argument), and then also use the ENCRYPTION_MODE
+    variable in the 'access.conf' file on the server.
+
 *-N, --nat-access*='<internalIP:forwardPort>'::
     The *fwknopd* server offers the ability to provide SPA access through
     an iptables firewall to an internal service by interfacing with the
@@ -205,7 +214,7 @@ SPA OPTIONS
     client can request that the server port forward an external port to an
     internal IP, i.e. ``+--NAT-access 192.168.10.2,55000+''.  In this case,
     access will be granted to 192.168.10.2 via port 55000 to whatever
-    service is requested via the *--access* argument (usually tcp/22). 
+    service is requested via the *--access* argument (usually tcp/22).
     Hence, after sending such an SPA packet, one would then do
     ``ssh -p 55000 user@host'' and the connection would be forwarded on
     through to the internal 192.168.10.2 system automatically.  Note that
@@ -404,6 +413,10 @@ description and its matching command-line option(s):
     Set a value to apply to the timestamp in the SPA packet.  This can
     be either a positive or negative value ('--time-offset-plus/minus').
 
+*ENCRYPTION_MODE*::
+    Specify the encryption mode when AES is used.  This variable is a synonym
+    for the '--encryption-mode' command line argument.
+
 *USE_GPG*::
     Set to 'Y' to specify the use of GPG for encryption ('--gpg-encryption').
 
@@ -552,7 +565,7 @@ More information on Single Packet Authorization can be found in the paper
 
 AUTHORS
 -------
-Damien Stuart <dstuart@dstuart.org>, 
+Damien Stuart <dstuart@dstuart.org>,
 Michael Rash <mbr@cipherdyne.org>
 
 CONTRIBUTORS
index a4b8666..36cb3e3 100644 (file)
@@ -344,6 +344,15 @@ directive starts a new stanza.
     ``FW_ACCESS_TIMEOUT'' is not set then the default timeout of 30 seconds
     will automatically be set.
 
+*ENCRYPTION_MODE*: '<mode>'::
+    Specify the encryption mode when AES is used.  The default (for now) is
+    ECB mode in order to remain backwards compatible with pre-2.0 versions of
+    fwknop which relied on the Crypt::CBC perl module.  This will be changed
+    in an upcoming version of fwknop to use the more secure CBC mode.  In the
+    meantime, it is recommend to use this option to specify CBC mode (use the
+    string "CBC" as the argument), and then also use '--encryption-mode'
+    command line argument on the *fwknop* client.
+
 *ENABLE_CMD_EXEC*: '<Y/N>'::
     This instructs *fwknopd* to accept complete commands that are contained
     within an authorization packet.  Any such command will be executed on
index 8fee690..872ab81 100644 (file)
@@ -181,12 +181,13 @@ rij_salt_and_iv(RIJNDAEL_context *ctx, const char *pass, const unsigned char *da
 /* Initialization entry point.
 */
 static void
-rijndael_init(RIJNDAEL_context *ctx, const char *pass, const unsigned char *data)
+rijndael_init(RIJNDAEL_context *ctx, const char *pass,
+    const unsigned char *data, int encryption_mode)
 {
 
     /* Use ECB mode to be compatible with the Crypt::CBC perl module.
     */
-    ctx->mode = MODE_ECB;
+    ctx->mode = encryption_mode;
 
     /* Generate the salt and initialization vector.
     */
@@ -201,7 +202,8 @@ rijndael_init(RIJNDAEL_context *ctx, const char *pass, const unsigned char *data
  * module would.
 */
 size_t
-rij_encrypt(unsigned char *in, size_t in_len, const char *pass, unsigned char *out)
+rij_encrypt(unsigned char *in, size_t in_len,
+    const char *pass, unsigned char *out, int encryption_mode)
 {
     RIJNDAEL_context    ctx;
     unsigned char       plaintext[RIJNDAEL_BLOCKSIZE];
@@ -211,7 +213,7 @@ rij_encrypt(unsigned char *in, size_t in_len, const char *pass, unsigned char *o
 
     unsigned char      *ondx = out;
 
-    rijndael_init(&ctx, pass, NULL);
+    rijndael_init(&ctx, pass, NULL, encryption_mode);
 
     /* Prepend the salt...
     */
@@ -255,7 +257,8 @@ rij_encrypt(unsigned char *in, size_t in_len, const char *pass, unsigned char *o
 /* Decrypt the given data.
 */
 size_t
-rij_decrypt(unsigned char *in, size_t in_len, const char *pass, unsigned char *out)
+rij_decrypt(unsigned char *in, size_t in_len,
+    const char *pass, unsigned char *out, int encryption_mode)
 {
     RIJNDAEL_context    ctx;
     unsigned char       plaintext[RIJNDAEL_BLOCKSIZE];
@@ -265,7 +268,7 @@ rij_decrypt(unsigned char *in, size_t in_len, const char *pass, unsigned char *o
     unsigned char      *pad_s;
     unsigned char      *ondx = out;
 
-    rijndael_init(&ctx, pass, in);
+    rijndael_init(&ctx, pass, in, encryption_mode);
 
     /* Remove the salt from the input.
     */
index 07edace..a311d10 100644 (file)
 */
 #define PREDICT_ENCSIZE(x) (1+(x>>4)+(x&0xf?1:0))<<4
 
-size_t rij_encrypt(unsigned char *in, size_t len, const char *key, unsigned char *out);
-size_t rij_decrypt(unsigned char *in, size_t len, const char *key, unsigned char *out);
+size_t rij_encrypt(unsigned char *in, size_t len,
+    const char *key, unsigned char *out, int encryption_mode);
+size_t rij_decrypt(unsigned char *in, size_t len,
+    const char *key, unsigned char *out, int encryption_mode);
 
 #endif /* CIPHER_FUNCS_H */
 
index 9dadcc3..d6bdbfd 100644 (file)
--- a/lib/fko.h
+++ b/lib/fko.h
@@ -33,6 +33,8 @@
 
 #include <time.h>
 
+#include "rijndael.h"   /* For encryption modes */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -91,6 +93,20 @@ typedef enum {
     FKO_LAST_ENCRYPTION_TYPE /* Always leave this as the last one */
 } fko_encryption_type_t;
 
+/* Symmetric encryption modes derived from rijndael.h
+*/
+typedef enum {
+    FKO_ENC_MODE_UNKNOWN = 0,
+    FKO_ENC_MODE_ECB  = MODE_ECB,
+    FKO_ENC_MODE_CBC  = MODE_CBC,
+    FKO_ENC_MODE_CFB  = MODE_CFB,
+    FKO_ENC_MODE_PCBC = MODE_PCBC,
+    FKO_ENC_MODE_OFB  = MODE_OFB,
+    FKO_ENC_MODE_CTR  = MODE_CTR,
+    FKO_ENC_MODE_ASYMMETRIC,  /* placeholder when GPG is used */
+    FKO_LAST_ENC_MODE /* Always leave this as the last one */
+} fko_encryption_mode_t;
+
 /* FKO ERROR_CODES
  *
  * Note: If you change this list in any way, please be sure to make the
@@ -160,6 +176,7 @@ typedef enum {
 #define FKO_DEFAULT_MSG_TYPE    FKO_ACCESS_MSG
 #define FKO_DEFAULT_DIGEST      FKO_DIGEST_SHA256
 #define FKO_DEFAULT_ENCRYPTION  FKO_ENCRYPTION_RIJNDAEL
+#define FKO_DEFAULT_ENC_MODE    MODE_ECB
 
 /* The context holds the global state and config options, as
  * well as some intermediate results during processing. This
@@ -189,7 +206,8 @@ enum {
 /* General api calls
 */
 DLL_API int fko_new(fko_ctx_t *ctx);
-DLL_API int fko_new_with_data(fko_ctx_t *ctx, const char *enc_msg, const char *dec_key);
+DLL_API int fko_new_with_data(fko_ctx_t *ctx, const char *enc_msg, const char *dec_key,
+    int encryption_mode);
 DLL_API void fko_destroy(fko_ctx_t ctx);
 DLL_API int fko_spa_data_final(fko_ctx_t ctx, const char *enc_key);
 
@@ -207,6 +225,7 @@ DLL_API int fko_set_spa_client_timeout(fko_ctx_t ctx, const int timeout);
 DLL_API int fko_set_spa_digest_type(fko_ctx_t ctx, const short digest_type);
 DLL_API int fko_set_spa_digest(fko_ctx_t ctx);
 DLL_API int fko_set_spa_encryption_type(fko_ctx_t ctx, const short encrypt_type);
+DLL_API int fko_set_spa_encryption_mode(fko_ctx_t ctx, const int encrypt_mode);
 DLL_API int fko_set_spa_data(fko_ctx_t ctx, const char *enc_msg);
 
 /* Data processing and misc utility functions
@@ -235,6 +254,7 @@ DLL_API int fko_get_spa_client_timeout(fko_ctx_t ctx, int *client_timeout);
 DLL_API int fko_get_spa_digest_type(fko_ctx_t ctx, short *spa_digest_type);
 DLL_API int fko_get_spa_digest(fko_ctx_t ctx, char **spa_digest);
 DLL_API int fko_get_spa_encryption_type(fko_ctx_t ctx, short *spa_enc_type);
+DLL_API int fko_get_spa_encryption_mode(fko_ctx_t ctx, int *spa_enc_mode);
 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);
index 8a98b55..18d5a8a 100644 (file)
@@ -63,6 +63,7 @@ struct fko_context {
     /* FKO SPA user-settable message encoding types */
     short  digest_type;
     short  encryption_type;
+    int    encryption_mode;
 
     /* Computed or predefined data */
     char           *version;
index 4b81a41..6eca929 100644 (file)
@@ -66,7 +66,8 @@ _rijndael_encrypt(fko_ctx_t ctx, const char *enc_key)
         return(FKO_ERROR_MEMORY_ALLOCATION);
 
     cipher_len = rij_encrypt(
-        (unsigned char*)plain, strlen(plain), (char*)enc_key, cipher
+        (unsigned char*)plain, strlen(plain), (char*)enc_key, cipher,
+        ctx->encryption_mode
     );
 
     /* Now make a bucket for the base64-encoded version and populate it.
@@ -95,7 +96,7 @@ _rijndael_encrypt(fko_ctx_t ctx, const char *enc_key)
 /* Decode, decrypt, and parse SPA data into the context.
 */
 static int
-_rijndael_decrypt(fko_ctx_t ctx, const char *dec_key)
+_rijndael_decrypt(fko_ctx_t ctx, const char *dec_key, int encryption_mode)
 {
     char           *tbuf;
     unsigned char  *ndx;
@@ -143,7 +144,8 @@ _rijndael_decrypt(fko_ctx_t ctx, const char *dec_key)
     if(ctx->encoded_msg == NULL)
         return(FKO_ERROR_MEMORY_ALLOCATION);
 
-    pt_len = rij_decrypt(cipher, cipher_len, dec_key, (unsigned char*)ctx->encoded_msg);
+    pt_len = rij_decrypt(cipher, cipher_len, dec_key,
+                (unsigned char*)ctx->encoded_msg, encryption_mode);
 
     /* Done with cipher...
     */
@@ -351,6 +353,41 @@ fko_get_spa_encryption_type(fko_ctx_t ctx, short *enc_type)
     return(FKO_SUCCESS);
 }
 
+/* Set the SPA encryption mode.
+*/
+int
+fko_set_spa_encryption_mode(fko_ctx_t ctx, const int encrypt_mode)
+{
+    /* Must be initialized
+    */
+    if(!CTX_INITIALIZED(ctx))
+        return(FKO_ERROR_CTX_NOT_INITIALIZED);
+
+    if(encrypt_mode < 0 || encrypt_mode >= FKO_LAST_ENC_MODE)
+        return(FKO_ERROR_INVALID_DATA);
+
+    ctx->encryption_mode = encrypt_mode;
+
+    ctx->state |= FKO_ENCRYPT_MODE_MODIFIED;
+
+    return(FKO_SUCCESS);
+}
+
+/* Return the SPA encryption mode.
+*/
+int
+fko_get_spa_encryption_mode(fko_ctx_t ctx, int *enc_mode)
+{
+    /* Must be initialized
+    */
+    if(!CTX_INITIALIZED(ctx))
+        return(FKO_ERROR_CTX_NOT_INITIALIZED);
+
+    *enc_mode = ctx->encryption_mode;
+
+    return(FKO_SUCCESS);
+}
+
 /* Encrypt the encoded SPA data.
 */
 int
@@ -425,7 +462,7 @@ fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key)
     else if(enc_type == FKO_ENCRYPTION_RIJNDAEL)
     {
         ctx->encryption_type = FKO_ENCRYPTION_RIJNDAEL;
-        res = _rijndael_decrypt(ctx, dec_key);
+        res = _rijndael_decrypt(ctx, dec_key, ctx->encryption_mode);
     }
     else
         return(FKO_ERROR_INVALID_DATA);
index 4a74438..e6fe8a8 100644 (file)
@@ -133,6 +133,18 @@ fko_new(fko_ctx_t *r_ctx)
         return res;
     }
 
+    /* Default Encryption Mode (Rijndael in EBC mode for backwards
+     * compatibility - it recommended to change this to CBC mode)
+    */
+    ctx->initval = FKO_CTX_INITIALIZED;
+    res = fko_set_spa_encryption_mode(ctx, FKO_DEFAULT_ENC_MODE);
+    ctx->initval = 0;
+    if(res != FKO_SUCCESS)
+    {
+        fko_destroy(ctx);
+        return res;
+    }
+
 #if HAVE_LIBGPGME
     /* Set gpg signature verify on.
     */
@@ -156,7 +168,8 @@ fko_new(fko_ctx_t *r_ctx)
  * and parsing the provided data into the context data.
 */
 int
-fko_new_with_data(fko_ctx_t *r_ctx, const char *enc_msg, const char *dec_key)
+fko_new_with_data(fko_ctx_t *r_ctx, const char *enc_msg,
+    const char *dec_key, int encryption_mode)
 {
     fko_ctx_t   ctx;
     int         res = FKO_SUCCESS; /* Are we optimistic or what? */
@@ -174,13 +187,23 @@ fko_new_with_data(fko_ctx_t *r_ctx, const char *enc_msg, const char *dec_key)
         return(FKO_ERROR_MEMORY_ALLOCATION);
     }
 
+    /* Default Encryption Mode (Rijndael in CBC mode)
+    */
+    ctx->initval = FKO_CTX_INITIALIZED;
+    res = fko_set_spa_encryption_mode(ctx, encryption_mode);
+    ctx->initval = 0;
+    if(res != FKO_SUCCESS)
+    {
+        fko_destroy(ctx);
+        return res;
+    }
+
     /* Consider it initialized here.
     */
     ctx->initval = FKO_CTX_INITIALIZED;
     FKO_SET_CTX_INITIALIZED(ctx);
 
-    /* If a decryption password is provided, go ahead and decrypt and
-     * decode.
+    /* If a decryption key is provided, go ahead and decrypt and decode.
     */
     if(dec_key != NULL)
     {
index 8c37f0a..8349e5f 100644 (file)
@@ -49,7 +49,8 @@ typedef enum {
     FKO_DIGEST_TYPE_MODIFIED    = 1 << 12,
     FKO_ENCRYPT_TYPE_MODIFIED   = 1 << 13,
     STATE_RESERVED_14           = 1 << 14,
-    FKO_BACKWARD_COMPATIBLE     = 1 << 15
+    FKO_BACKWARD_COMPATIBLE     = 1 << 15,
+    FKO_ENCRYPT_MODE_MODIFIED   = 1 << 16,
 } fko_state_flags_t;
 
 /* This is used in conjunction with the ctx->initial value as a means to
index 889d2f7..15a6088 100644 (file)
@@ -132,6 +132,27 @@ add_acc_expire_time_epoch(fko_srv_options_t *opts, time_t *access_expire_time, c
     return;
 }
 
+/* Convert an encryption_mode string to its integer value.
+*/
+static int
+enc_mode_strtoint(const char *enc_mode_str)
+{
+    if(strcasecmp(enc_mode_str, "cbc") == 0)
+        return(FKO_ENC_MODE_CBC);
+    else if(strcasecmp(enc_mode_str, "ecb") == 0)
+        return(FKO_ENC_MODE_ECB);
+    else if(strcasecmp(enc_mode_str, "cfb") == 0)
+        return(FKO_ENC_MODE_CFB);
+    else if(strcasecmp(enc_mode_str, "pcbc") == 0)
+        return(FKO_ENC_MODE_PCBC);
+    else if(strcasecmp(enc_mode_str, "ofb") == 0)
+        return(FKO_ENC_MODE_OFB);
+    else if(strcasecmp(enc_mode_str, "ctr") == 0)
+        return(FKO_ENC_MODE_CTR);
+    else
+        return(-1);
+}
+
 #if FIREWALL_IPTABLES
 static void
 add_acc_force_nat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, const char *val)
@@ -708,8 +729,15 @@ set_acc_defaults(fko_srv_options_t *opts)
 
         /* set default gpg keyring path if necessary
         */
-        if(acc->gpg_decrypt_pw != NULL && acc->gpg_home_dir == NULL)
-            add_acc_string(&(acc->gpg_home_dir), opts->config[CONF_GPG_HOME_DIR]);
+        if(acc->gpg_decrypt_pw != NULL)
+        {
+            acc->encryption_mode = FKO_ENC_MODE_ASYMMETRIC;
+            if(acc->gpg_home_dir == NULL)
+                add_acc_string(&(acc->gpg_home_dir), opts->config[CONF_GPG_HOME_DIR]);
+        }
+
+        if (acc->encryption_mode == FKO_ENC_MODE_UNKNOWN)
+            acc->encryption_mode = FKO_DEFAULT_ENC_MODE;
 
         acc = acc->next;
     }
@@ -869,6 +897,16 @@ parse_access_file(fko_srv_options_t *opts)
         {
             add_acc_int(&(curr_acc->fw_access_timeout), val);
         }
+        else if(CONF_VAR_IS(var, "ENCRYPTION_MODE"))
+        {
+            if((curr_acc->encryption_mode = enc_mode_strtoint(val)) < 0)
+            {
+                fprintf(stderr,
+                    "[*] Unrecognized ENCRYPTION_MODE '%s', use {cbc,ecb}\n",
+                    val);
+                clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
+            }
+        }
         else if(CONF_VAR_IS(var, "ENABLE_CMD_EXEC"))
         {
             add_acc_bool(&(curr_acc->enable_cmd_exec), val);
@@ -1005,7 +1043,6 @@ parse_access_file(fko_srv_options_t *opts)
     expand_acc_ent_lists(opts);
 
     /* Make sure default values are set where needed.
-     * a default value.
     */
     set_acc_defaults(opts);
 
index 4fe7ec4..3661227 100644 (file)
@@ -282,6 +282,7 @@ typedef struct acc_stanza
     acc_string_list_t   *gpg_remote_id_list;
     time_t              access_expire_time;
     int                 expired;
+    int                 encryption_mode;
     unsigned char       force_nat;
     char                *force_nat_ip;
     char                *force_nat_proto;
index 27e17f0..922b120 100644 (file)
@@ -242,7 +242,8 @@ incoming_spa(fko_srv_options_t *opts)
         if(enc_type == FKO_ENCRYPTION_RIJNDAEL)
         {
             if(acc->key != NULL)
-                res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data, acc->key);
+                res = fko_new_with_data(&ctx,
+                    (char *)spa_pkt->packet_data, acc->key, acc->encryption_mode);
             else
             {
                 log_msg(LOG_ERR,
@@ -260,7 +261,8 @@ incoming_spa(fko_srv_options_t *opts)
             */
             if(acc->gpg_decrypt_pw != NULL)
             {
-                res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data, NULL);
+                res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data, NULL,
+                        acc->encryption_mode);
                 if(res != FKO_SUCCESS)
                 {
                     log_msg(LOG_WARNING,