diff --git a/configure.ac b/configure.ac index d89a97a7..6cd2ae9a 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ AC_PROG_LIBTOOL # Checks for header files. # AC_HEADER_STDC -AC_CHECK_HEADERS([locale.h stdlib.h string.h sys/time.h unistd.h ctype.h]) +AC_CHECK_HEADERS([ctype.h netinet/in.h stdlib.h string.h strings.h sys/time.h termios.h unistd.h]) # Type checks. # @@ -52,7 +52,8 @@ AC_CHECK_SIZEOF(unsigned int) # AC_FUNC_MALLOC AC_FUNC_REALLOC -AC_CHECK_FUNCS([bzero gettimeofday memmove memset strchr strcspn strdup strndup strrchr strspn]) +AC_FUNC_STAT +AC_CHECK_FUNCS([bzero gettimeofday memmove memset socket strchr strcspn strdup strncasecmp strndup strrchr strspn]) # Check for gpgme #AM_PATH_GPGME diff --git a/fko/cipher_funcs.c b/fko/cipher_funcs.c index 77ccd6f9..e017c36e 100644 --- a/fko/cipher_funcs.c +++ b/fko/cipher_funcs.c @@ -72,7 +72,7 @@ get_random_data(unsigned char *data, size_t len) * the Perl Crypt::CBC module's use of Rijndael. */ void -rij_salt_and_iv(RIJNDAEL_context *ctx, const char *pass, unsigned char *data) +rij_salt_and_iv(RIJNDAEL_context *ctx, char *pass, unsigned char *data) { char pw_buf[16]; unsigned char tmp_buf[64]; /* How big does this need to be? */ @@ -138,7 +138,7 @@ rij_salt_and_iv(RIJNDAEL_context *ctx, const char *pass, unsigned char *data) /* Initialization entry point. */ void -rijndael_init(RIJNDAEL_context *ctx, const char *pass, unsigned char *data) +rijndael_init(RIJNDAEL_context *ctx, char *pass, unsigned char *data) { /* Use ECB mode to be compatible with the Crypt::CBC perl module. @@ -158,7 +158,7 @@ rijndael_init(RIJNDAEL_context *ctx, const char *pass, 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, char *pass, unsigned char *out) { RIJNDAEL_context ctx; unsigned char plaintext[16]; @@ -212,7 +212,7 @@ 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, char *pass, unsigned char *out) { RIJNDAEL_context ctx; unsigned char plaintext[16]; @@ -274,9 +274,4 @@ rij_decrypt(unsigned char *in, size_t in_len, const char *pass, unsigned char *o return(ondx - out); } -/*** These are GPG-specific functions ***/ - -//--DSS TODO: Finish me - - /***EOF***/ diff --git a/fko/cipher_funcs.h b/fko/cipher_funcs.h index 7470ea03..eb6aee6e 100644 --- a/fko/cipher_funcs.h +++ b/fko/cipher_funcs.h @@ -34,14 +34,12 @@ */ #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, char *key, unsigned char *out); +size_t rij_decrypt(unsigned char *in, size_t len, char *key, unsigned char *out); #if HAVE_LIBGPGME -int gpg_encrypt(fko_ctx_t ctx, const char *enc_key); -//int gpg_encrypt(unsigned char *in, size_t len, const char *signer, const char *recip, unsigned char **out, size_t *out_sz); -//int gpg_decrypt(unsigned char *in, size_t len, const char *key, unsigned char **out, size_t *out_sz); -int gpg_decrypt(fko_ctx_t ctx, const char *enc_key, size_t b64_len); +int gpg_encrypt(fko_ctx_t ctx, char *enc_key); +int gpg_decrypt(fko_ctx_t ctx, char *dec_key, size_t b64_len); #endif /* HAVE_LIBGPGME */ #endif /* CIPHER_FUNCS_H */ diff --git a/fko/fko.h b/fko/fko.h index 98f4d181..f2097807 100644 --- a/fko/fko.h +++ b/fko/fko.h @@ -46,7 +46,7 @@ typedef enum { /* Supported digest types... */ typedef enum { - FKO_DIGEST_MD5 = 0, + FKO_DIGEST_MD5 = 1, FKO_DIGEST_SHA1, FKO_DIGEST_SHA256, FKO_LAST_DIGEST_TYPE /* Always leave this as the last one */ @@ -55,7 +55,7 @@ typedef enum { /* Supported encryption types... */ typedef enum { - FKO_ENCRYPTION_RIJNDAEL = 0, + FKO_ENCRYPTION_RIJNDAEL = 1, FKO_ENCRYPTION_GPG, FKO_LAST_ENCRYPTION_TYPE /* Always leave this as the last one */ } fko_encryption_type_t; @@ -131,9 +131,9 @@ typedef struct fko_context *fko_ctx_t; /* General api calls */ int fko_new(fko_ctx_t *ctx); -int fko_new_with_data(fko_ctx_t *ctx, char *enc_msg, const char *dec_key); +int fko_new_with_data(fko_ctx_t *ctx, char *enc_msg, char *dec_key); void fko_destroy(fko_ctx_t ctx); -int fko_spa_data_final(fko_ctx_t ctx, const char *enc_key); +int fko_spa_data_final(fko_ctx_t ctx, char *enc_key); char* fko_get_spa_data(fko_ctx_t ctx); @@ -155,8 +155,8 @@ const char* fko_errstr(int err_code); int fko_encode_spa_data(fko_ctx_t ctx); int fko_decode_spa_data(fko_ctx_t ctx); -int fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key); -int fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key); +int fko_encrypt_spa_data(fko_ctx_t ctx, char *enc_key); +int fko_decrypt_spa_data(fko_ctx_t ctx, char *dec_key); char* fko_get_encoded_data(fko_ctx_t ctx); /* Get context data functions */ diff --git a/fko/fko_digest.c b/fko/fko_digest.c index 664bd5b3..6505b2b9 100644 --- a/fko/fko_digest.c +++ b/fko/fko_digest.c @@ -39,7 +39,7 @@ fko_set_spa_digest_type(fko_ctx_t ctx, short digest_type) if(!CTX_INITIALIZED(ctx)) return(FKO_ERROR_CTX_NOT_INITIALIZED); - if(digest_type < 0 || digest_type >= FKO_LAST_DIGEST_TYPE) + if(digest_type < 1 || digest_type >= FKO_LAST_DIGEST_TYPE) return(FKO_ERROR_INVALID_DATA); ctx->digest_type = digest_type; diff --git a/fko/fko_encryption.c b/fko/fko_encryption.c index d983a33e..a1a2073a 100644 --- a/fko/fko_encryption.c +++ b/fko/fko_encryption.c @@ -34,10 +34,19 @@ #define B64_RIJNDAEL_SALT "U2FsdGVkX1" +/* Wipe out the password buffer. +*/ +void +wipe_pw(char *pw) +{ + if(pw != NULL) + bzero(pw, strlen(pw)); +} + /* Prep and encrypt using Rijndael */ int -_rijndael_encrypt(fko_ctx_t ctx, const char *enc_key) +_rijndael_encrypt(fko_ctx_t ctx, char *enc_key) { char *plain; char *b64cipher; @@ -89,7 +98,7 @@ _rijndael_encrypt(fko_ctx_t ctx, const char *enc_key) /* Decode, decrypt, and parse SPA data into the context. */ int -_rijndael_decrypt(fko_ctx_t ctx, const char *dec_key, int b64_len) +_rijndael_decrypt(fko_ctx_t ctx, char *dec_key, int b64_len) { char *tbuf; unsigned char *cipher; @@ -156,7 +165,7 @@ _rijndael_decrypt(fko_ctx_t ctx, const char *dec_key, int b64_len) /* Prep and encrypt using gpgme */ int -gpg_encrypt(fko_ctx_t ctx, const char *enc_key) +gpg_encrypt(fko_ctx_t ctx, char *enc_key) { int res; char *plain; @@ -221,7 +230,7 @@ gpg_encrypt(fko_ctx_t ctx, const char *enc_key) /* Prep and encrypt using gpgme */ int -gpg_decrypt(fko_ctx_t ctx, const char *dec_key, size_t b64_len) +gpg_decrypt(fko_ctx_t ctx, char *dec_key, size_t b64_len) { unsigned char *cipher; size_t cipher_len; @@ -307,61 +316,68 @@ fko_get_spa_encryption_type(fko_ctx_t ctx) /* Encrypt the encoded SPA data. */ int -fko_encrypt_spa_data(fko_ctx_t ctx, const char *enc_key) +fko_encrypt_spa_data(fko_ctx_t ctx, char *enc_key) { int res; /* Must be initialized */ if(!CTX_INITIALIZED(ctx)) - return(FKO_ERROR_CTX_NOT_INITIALIZED); + { + res = FKO_ERROR_CTX_NOT_INITIALIZED; + goto EWIPEOUT; + } /* If there is no encoded data or the SPA data has been modified, * go ahead and re-encode here. */ if(ctx->encoded_msg == NULL || FKO_IS_SPA_DATA_MODIFIED(ctx)) - { res = fko_encode_spa_data(ctx); - if(res != FKO_SUCCESS) - return(res); - } - /* Croak on invalid encoded message as well. At present this is a * check for a somewhat arbitrary minimum length for the encoded * data. */ if(strlen(ctx->encoded_msg) < MIN_SPA_ENCODED_MSG_SIZE) - return(FKO_ERROR_MISSING_ENCODED_DATA); + { + res = FKO_ERROR_MISSING_ENCODED_DATA; + goto EWIPEOUT; + } /* Encrypt according to type and return... */ if(ctx->encryption_type == FKO_ENCRYPTION_RIJNDAEL) - return(_rijndael_encrypt(ctx, enc_key)); - + res = _rijndael_encrypt(ctx, enc_key); else if(ctx->encryption_type == FKO_ENCRYPTION_GPG) #if HAVE_LIBGPGME - return(gpg_encrypt(ctx, enc_key)); + res = gpg_encrypt(ctx, enc_key); #else - return(FKO_ERROR_UNSUPPORTED_FEATURE); + res = FKO_ERROR_UNSUPPORTED_FEATURE; #endif - else - return(FKO_ERROR_INVALID_ENCRYPTION_TYPE); + res = FKO_ERROR_INVALID_ENCRYPTION_TYPE; + +EWIPEOUT: + wipe_pw(enc_key); + + return(res); } /* Decode, decrypt, and parse SPA data into the context. */ int -fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key) +fko_decrypt_spa_data(fko_ctx_t ctx, char *dec_key) { - int b64_len; + int b64_len, res; /* First, make sure we have data to work with. */ if(ctx->encrypted_msg == NULL || strlen(ctx->encrypted_msg) < MIN_SPA_ENCODED_MSG_SIZE) - return(FKO_ERROR_INVALID_DATA); + { + res = FKO_ERROR_INVALID_DATA; + goto DWIPEOUT; + } /* Determine type of encryption used. For know, we are using the * size of the message. @@ -375,16 +391,21 @@ fko_decrypt_spa_data(fko_ctx_t ctx, const char *dec_key) { ctx->encryption_type = FKO_ENCRYPTION_GPG; #if HAVE_LIBGPGME - return(gpg_decrypt(ctx, dec_key, b64_len)); + res = gpg_decrypt(ctx, dec_key, b64_len); #else - return(FKO_ERROR_UNSUPPORTED_FEATURE); + res = FKO_ERROR_UNSUPPORTED_FEATURE; #endif } else /* We are assuming the default of Rijndael */ { ctx->encryption_type = FKO_ENCRYPTION_RIJNDAEL; - return(_rijndael_decrypt(ctx, dec_key, b64_len)); + res = _rijndael_decrypt(ctx, dec_key, b64_len); } + +DWIPEOUT: + wipe_pw(dec_key); + + return(res); } /* Set the GPG recipient key name. diff --git a/fko/fko_funcs.c b/fko/fko_funcs.c index 95d6205e..c1e44905 100644 --- a/fko/fko_funcs.c +++ b/fko/fko_funcs.c @@ -148,7 +148,7 @@ 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, char *enc_msg, const char *dec_key) +fko_new_with_data(fko_ctx_t *r_ctx, char *enc_msg, char *dec_key) { fko_ctx_t ctx; @@ -254,7 +254,7 @@ fko_version(fko_ctx_t ctx) * set. */ int -fko_spa_data_final(fko_ctx_t ctx, const char *enc_key) +fko_spa_data_final(fko_ctx_t ctx, char *enc_key) { /* Must be initialized */ diff --git a/src/Makefile.am b/src/Makefile.am index 5a7a1c70..54b8f0f0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,8 @@ bin_PROGRAMS = fwknop -fwknop_SOURCES = fwknop.c fwknop.h config_init.c config_init.h fwkop_common.h \ - spa_comm.c spa_comm.h utils.c utils.h +fwknop_SOURCES = fwknop.c fwknop.h config_init.c config_init.h \ + fwkop_common.h spa_comm.c spa_comm.h utils.c utils.h \ + getpasswd.c getpasswd.h fwknop_LDADD = $(top_builddir)/fko/libfko.la fwknop_CPPFLAGS = -I $(top_srcdir)/fko diff --git a/src/config_init.c b/src/config_init.c index c4524a13..969a202f 100644 --- a/src/config_init.c +++ b/src/config_init.c @@ -335,6 +335,7 @@ usage(void) " --gpg-encryption - Use GPG encyrption (default is Rijndael).\n" " --gpg-recipient-key - Specify the recipient GPG key name or ID.\n" " --gpg-signer-key - Specify the signer's GPG key name or ID.\n" + " --gpg-agent - Use GPG agent if available.\n" "\n" ); diff --git a/src/fwknop.c b/src/fwknop.c index 8c1cb6f4..19481426 100644 --- a/src/fwknop.c +++ b/src/fwknop.c @@ -27,12 +27,20 @@ #include "config_init.h" #include "spa_comm.h" #include "utils.h" +#include "getpasswd.h" + +/* Used be the getpw function below. +*/ +#define CRYPT_OP_ENCRYPT 1 +#define CRYPT_OP_DECRYPT 2 +char* getpw(fko_cli_options_t *options, int crypt_op); int main(int argc, char **argv) { fko_ctx_t ctx, ctx2; int res; + char *pw; fko_cli_options_t options; @@ -55,6 +63,12 @@ main(int argc, char **argv) */ if(options.use_gpg) { + /* If use-gpg-agent was not specified, then remove the GPG_AGENT_INFO + * ENV variable if it exists. + */ + if(!options.use_gpg_agent) + unsetenv("GPG_AGENT_INFO"); + res = fko_set_spa_encryption_type(ctx, FKO_ENCRYPTION_GPG); if(res != FKO_SUCCESS) { @@ -144,7 +158,7 @@ main(int argc, char **argv) /* Finalize the context data (encrypt and encode the SPA data) */ - res = fko_spa_data_final(ctx, FKO_PW); + res = fko_spa_data_final(ctx, getpw(&options, CRYPT_OP_ENCRYPT)); if(res != FKO_SUCCESS) { fprintf(stderr, @@ -178,7 +192,8 @@ main(int argc, char **argv) /* Now we create a new context based on data from the first one. */ - res = fko_new_with_data(&ctx2, fko_get_spa_data(ctx), FKO_PW); + res = fko_new_with_data(&ctx2, fko_get_spa_data(ctx), + getpw(&options, CRYPT_OP_DECRYPT)); if(res != FKO_SUCCESS) { fprintf(stderr, @@ -205,6 +220,25 @@ main(int argc, char **argv) return(0); } +char* +getpw(fko_cli_options_t *options, int crypt_op) +{ + if(options->use_gpg) + { + return(options->use_gpg_agent ? "" + : getpasswd("Enter passphrase for secret key: ")); + } + else + { + if(crypt_op == CRYPT_OP_ENCRYPT) + return(getpasswd("Enter encryption password: ")); + else if(crypt_op == CRYPT_OP_DECRYPT) + return(getpasswd("Enter decryption password: ")); + else + return(getpasswd("Enter password: ")); + } +} + static void display_ctx(fko_ctx_t ctx) { diff --git a/src/fwknop_common.h b/src/fwknop_common.h index dc6a7f4a..55a30bd6 100644 --- a/src/fwknop_common.h +++ b/src/fwknop_common.h @@ -28,14 +28,29 @@ /* Common includes for our other fwknop client source files. */ +#if HAVE_CONFIG_H + #include "config.h" +#endif + #include -#include -#include -#include -#include -#include #include -#include + +#if STDC_HEADERS + #include + #include +#elif HAVE_STRINGS_H + #include +#endif /* STDC_HEADERS*/ + +#if HAVE_UNISTD_H + #include +#endif + +#if HAVE_NETINET_IN_H + #include +#endif + +#include #include "fko.h" @@ -55,8 +70,6 @@ /* Other common defines */ -#define FKO_PW "BubbaWasHere" //--DSS Temp - #define FKO_DEFAULT_PROTO IPPROTO_UDP #define FKO_DEFAULT_PORT 62201 #define MAX_IP_STR_LEN 16 diff --git a/src/getpasswd.c b/src/getpasswd.c new file mode 100644 index 00000000..9937e8ff --- /dev/null +++ b/src/getpasswd.c @@ -0,0 +1,94 @@ +/* $Id$ + ***************************************************************************** + * + * File: getpasswd.c + * + * Author: Damien S. Stuart + * + * Purpose: Routines for obtaining a password from a user. + * + * Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org) + * + * License (GNU Public License): + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#include +#include +#include + +#include "getpasswd.h" + +#define MAX_PASS_LEN 128 + +/* Generic hex dump function. +*/ +char* +getpasswd(const char *prompt) +{ + static char pwbuf[MAX_PASS_LEN + 1] = {0}; + char *ptr; + sigset_t sig, old_sig; + struct termios ts, old_ts; + FILE *fp; + int c; + + if((fp = fopen(ctermid(NULL), "r+")) == NULL) + return(NULL); + + setbuf(fp, NULL); + + /* Setup blocks for SIGINT and SIGTSTP and save the original signal + * mask. + */ + sigemptyset(&sig); + sigaddset(&sig, SIGINT); + sigaddset(&sig, SIGTSTP); + sigprocmask(SIG_BLOCK, &sig, &old_sig); + + /* Save current tty state for later restoration after we disable echo + * of characters to the tty. + */ + tcgetattr(fileno(fp), &ts); + old_ts = ts; + ts.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); + tcsetattr(fileno(fp), TCSAFLUSH, &ts); + + fputs(prompt, fp); + + /* Read in the password. + */ + ptr = pwbuf; + while((c = getc(fp)) != EOF && c != '\n') + if(ptr < &pwbuf[MAX_PASS_LEN]) + *ptr++ = c; + + /* Null terminate the password. + */ + *ptr = 0; + + /* we can go ahead and echo out a newline. + */ + putc('\n', fp); + + /* Restore our tty state and signal handlers. + */ + tcsetattr(fileno(fp), TCSAFLUSH, &old_ts); + sigprocmask(SIG_BLOCK, &old_sig, NULL); + + fclose(fp); + + return(pwbuf); +} + +/***EOF***/ diff --git a/src/getpasswd.h b/src/getpasswd.h new file mode 100644 index 00000000..e5d21518 --- /dev/null +++ b/src/getpasswd.h @@ -0,0 +1,33 @@ +/* + ***************************************************************************** + * + * File: getpasswd.h + * + * Author: Damien Stuart (dstuart@dstuart.org) + * + * Purpose: Header file for getpasswd.c. + * + * Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org) + * + * License (GNU Public License): + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#ifndef GETPASSWD_H +#define GETPASSWD_H + +/* Prototypes +*/ +char* getpasswd(const char *prompt); + +#endif /* GETPASSWD_H */