From c959fc742eb10c516261765718a761536b0b8f4a Mon Sep 17 00:00:00 2001 From: james Date: Thu, 8 Dec 2005 18:29:38 +0000 Subject: Inline file capability now works for --secret and --tls-auth. For example: [ascii key data] git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@844 e7ae566f-a301-0410-adde-c780ea21d3b5 --- common.h | 8 +++ crypto.c | 225 +++++++++++++++++++++++++++++++++++--------------------------- crypto.h | 8 ++- init.c | 34 ++++++++-- misc.c | 21 +++--- options.c | 24 +++++++ options.h | 10 +-- 7 files changed, 215 insertions(+), 115 deletions(-) diff --git a/common.h b/common.h index ffaa165..e7320f3 100644 --- a/common.h +++ b/common.h @@ -64,4 +64,12 @@ typedef unsigned long ptr_type; */ #define TLS_CHANNEL_BUF_SIZE 1024 +/* + * A sort of pseudo-filename for data provided inline within + * the configuration file. + */ +#if ENABLE_INLINE_FILES +#define INLINE_FILE_TAG "[[INLINE]]" +#endif + #endif diff --git a/crypto.c b/crypto.c index 4f07651..5ddc269 100644 --- a/crypto.c +++ b/crypto.c @@ -905,11 +905,12 @@ test_crypto (const struct crypto_options *co, struct frame* frame) } #ifdef USE_SSL + void get_tls_handshake_key (const struct key_type *key_type, struct key_ctx_bi *ctx, const char *passphrase_file, - bool key_direction) + const unsigned int flags) { if (passphrase_file && key_type->hmac_length) { @@ -921,40 +922,55 @@ get_tls_handshake_key (const struct key_type *key_type, kt.cipher_length = 0; kt.cipher = NULL; - /* first try to parse as an OpenVPN static key file */ - read_key_file (&key2, passphrase_file, false); - - /* succeeded? */ - if (key2.n == 2) +#if ENABLE_INLINE_FILES + if (flags & GHK_INLINE) { - msg (M_INFO, - "Control Channel Authentication: using '%s' as a " PACKAGE_NAME " static key file", - passphrase_file); + /* key was specified inline, key text is in passphrase_file */ + read_key_file (&key2, passphrase_file, RKF_INLINE|RKF_MUST_SUCCEED); + + /* succeeded? */ + if (key2.n == 2) + msg (M_INFO, "Control Channel Authentication: tls-auth using INLINE static key file"); + else + msg (M_FATAL, "INLINE tls-auth file lacks the requisite 2 keys"); } else - { - int hash_size; +#endif + { + /* first try to parse as an OpenVPN static key file */ + read_key_file (&key2, passphrase_file, 0); - CLEAR (key2); + /* succeeded? */ + if (key2.n == 2) + { + msg (M_INFO, + "Control Channel Authentication: using '%s' as a " PACKAGE_NAME " static key file", + passphrase_file); + } + else + { + int hash_size; - /* failed, now try to get hash from a freeform file */ - hash_size = read_passphrase_hash (passphrase_file, - kt.digest, - key2.keys[0].hmac, - MAX_HMAC_KEY_LENGTH); - ASSERT (hash_size == kt.hmac_length); + CLEAR (key2); - /* suceeded */ - key2.n = 1; + /* failed, now try to get hash from a freeform file */ + hash_size = read_passphrase_hash (passphrase_file, + kt.digest, + key2.keys[0].hmac, + MAX_HMAC_KEY_LENGTH); + ASSERT (hash_size == kt.hmac_length); - msg (M_INFO, - "Control Channel Authentication: using '%s' as a free-form passphrase file", - passphrase_file); - } + /* suceeded */ + key2.n = 1; + msg (M_INFO, + "Control Channel Authentication: using '%s' as a free-form passphrase file", + passphrase_file); + } + } /* handle key direction */ - key_direction_state_init (&kds, key_direction); + key_direction_state_init (&kds, BOOL_CAST (flags & GHK_KEY_DIR)); must_have_n_keys (passphrase_file, "tls-auth", &key2, kds.need_keys); /* initialize hmac key in both directions */ @@ -984,13 +1000,15 @@ static const char unprintable_char_fmt[] = "Non-Hex, unprintable character (0x%02x) found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)"; /* read key from file */ + void -read_key_file (struct key2 *key2, const char *filename, bool must_succeed) +read_key_file (struct key2 *key2, const char *file, const unsigned int flags) { struct gc_arena gc = gc_new (); - struct buffer in = alloc_buf_gc (64, &gc); + struct buffer in; int fd, size; uint8_t hex_byte[3] = {0, 0, 0}; + const char *error_filename = file; /* parse info */ int hb_index = 0; @@ -1019,96 +1037,111 @@ read_key_file (struct key2 *key2, const char *filename, bool must_succeed) CLEAR (*key2); - fd = open (filename, O_RDONLY); - if (fd == -1) - msg (M_ERR, "Cannot open file key file '%s'", filename); + /* + * Key can be provided as a filename in 'file' or if RKF_INLINE + * is set, the actual key data itself in ascii form. + */ +#if ENABLE_INLINE_FILES + if (flags & RKF_INLINE) /* 'file' is a string containing ascii representation of key */ + { + size = strlen (file) + 1; + buf_set_read (&in, (const uint8_t *)file, size); + error_filename = INLINE_FILE_TAG; + } + else /* 'file' is a filename which refers to a file containing the ascii key */ +#endif + { + in = alloc_buf_gc (2048, &gc); + fd = open (file, O_RDONLY); + if (fd == -1) + msg (M_ERR, "Cannot open file key file '%s'", file); + size = read (fd, in.data, in.capacity); + if (size == in.capacity) + msg (M_FATAL, "Key file ('%s') can be a maximum of %d bytes", file, (int)in.capacity); + close (fd); + } - while ((size = read (fd, in.data, in.capacity))) + const char *cp = (char *)in.data; + while (size) { - const char *cp = (char *)in.data; - while (size) - { - const char c = *cp; + const char c = *cp; #if 0 - msg (M_INFO, "char='%c' s=%d ln=%d li=%d m=%d c=%d", - c, state, line_num, line_index, match, count); + msg (M_INFO, "char='%c' s=%d ln=%d li=%d m=%d c=%d", + c, state, line_num, line_index, match, count); #endif - if (c == '\n') + if (c == '\n') + { + line_index = match = 0; + ++line_num; + } + else + { + /* first char of new line */ + if (!line_index) { - line_index = match = 0; - ++line_num; + /* first char of line after header line? */ + if (state == PARSE_HEAD) + state = PARSE_DATA; + + /* first char of footer */ + if ((state == PARSE_DATA || state == PARSE_DATA_COMPLETE) && c == '-') + state = PARSE_FOOT; } - else + + /* compare read chars with header line */ + if (state == PARSE_INITIAL) { - /* first char of new line */ - if (!line_index) + if (line_index < hlen && c == static_key_head[line_index]) { - /* first char of line after header line? */ - if (state == PARSE_HEAD) - state = PARSE_DATA; - - /* first char of footer */ - if ((state == PARSE_DATA || state == PARSE_DATA_COMPLETE) && c == '-') - state = PARSE_FOOT; + if (++match == hlen) + state = PARSE_HEAD; } + } - /* compare read chars with header line */ - if (state == PARSE_INITIAL) + /* compare read chars with footer line */ + if (state == PARSE_FOOT) + { + if (line_index < flen && c == static_key_foot[line_index]) { - if (line_index < hlen && c == static_key_head[line_index]) - { - if (++match == hlen) - state = PARSE_HEAD; - } + if (++match == flen) + state = PARSE_FINISHED; } + } - /* compare read chars with footer line */ - if (state == PARSE_FOOT) + /* reading key */ + if (state == PARSE_DATA) + { + if (isxdigit(c)) { - if (line_index < flen && c == static_key_foot[line_index]) + ASSERT (hb_index >= 0 && hb_index < 2); + hex_byte[hb_index++] = c; + if (hb_index == 2) { - if (++match == flen) - state = PARSE_FINISHED; + unsigned int u; + ASSERT(sscanf((const char *)hex_byte, "%x", &u) == 1); + *out++ = u; + hb_index = 0; + if (++count == keylen) + state = PARSE_DATA_COMPLETE; } } - - /* reading key */ - if (state == PARSE_DATA) + else if (isspace(c)) + ; + else { - if (isxdigit(c)) - { - ASSERT (hb_index >= 0 && hb_index < 2); - hex_byte[hb_index++] = c; - if (hb_index == 2) - { - unsigned int u; - ASSERT(sscanf((const char *)hex_byte, "%x", &u) == 1); - *out++ = u; - hb_index = 0; - if (++count == keylen) - state = PARSE_DATA_COMPLETE; - } - } - else if (isspace(c)) - ; - else - { - msg (M_FATAL, - (isprint (c) ? printable_char_fmt : unprintable_char_fmt), - c, line_num, filename, count, onekeylen, keylen); - } + msg (M_FATAL, + (isprint (c) ? printable_char_fmt : unprintable_char_fmt), + c, line_num, error_filename, count, onekeylen, keylen); } - ++line_index; } - ++cp; - --size; + ++line_index; } + ++cp; + --size; } - close (fd); - /* * Normally we will read either 1 or 2 keys from file. */ @@ -1116,22 +1149,22 @@ read_key_file (struct key2 *key2, const char *filename, bool must_succeed) ASSERT (key2->n >= 0 && key2->n <= (int) SIZE (key2->keys)); - if (must_succeed) + if (flags & RKF_MUST_SUCCEED) { if (!key2->n) msg (M_FATAL, "Insufficient key material or header text not found found in file '%s' (%d/%d/%d bytes found/min/max)", - filename, count, onekeylen, keylen); + error_filename, count, onekeylen, keylen); if (state != PARSE_FINISHED) msg (M_FATAL, "Footer text not found in file '%s' (%d/%d/%d bytes found/min/max)", - filename, count, onekeylen, keylen); + error_filename, count, onekeylen, keylen); } /* zero file read buffer */ buf_clear (&in); if (key2->n) - warn_if_group_others_accessible (filename); + warn_if_group_others_accessible (error_filename); #if 0 /* DEBUGGING */ diff --git a/crypto.h b/crypto.h index bf81595..e658e73 100644 --- a/crypto.h +++ b/crypto.h @@ -270,7 +270,9 @@ void init_key_type (struct key_type *kt, const char *ciphername, bool authname_defined, int keysize, bool cfb_ofb_allowed, bool warn); -void read_key_file (struct key2 *key2, const char *filename, bool must_succeed); +#define RKF_MUST_SUCCEED (1<<0) +#define RKF_INLINE (1<<1) +void read_key_file (struct key2 *key2, const char *file, const unsigned int flags); int write_key_file (const int nkeys, const char *filename); @@ -367,10 +369,12 @@ void openssl_dmalloc_init (void); #ifdef USE_SSL +#define GHK_KEY_DIR (1<<0) +#define GHK_INLINE (1<<1) void get_tls_handshake_key (const struct key_type *key_type, struct key_ctx_bi *ctx, const char *passphrase_file, - bool key_direction); + const unsigned int flags); #else diff --git a/init.c b/init.c index b4ff6cd..ea1acc3 100644 --- a/init.c +++ b/init.c @@ -1276,7 +1276,19 @@ do_init_crypto_static (struct context *c, const unsigned int flags) options->test_crypto, true); /* Read cipher and hmac keys from shared secret file */ - read_key_file (&key2, options->shared_secret_file, true); + { + unsigned int rkf_flags = RKF_MUST_SUCCEED; + const char *rkf_file = options->shared_secret_file; + +#if ENABLE_INLINE_FILES + if (options->shared_secret_file_inline) + { + rkf_file = options->shared_secret_file_inline; + rkf_flags |= RKF_INLINE; + } +#endif + read_key_file (&key2, rkf_file, rkf_flags); + } /* Check for and fix highly unlikely key problems */ verify_fix_key2 (&key2, &c->c1.ks.key_type, @@ -1361,10 +1373,22 @@ do_init_crypto_tls_c1 (struct context *c) /* TLS handshake authentication (--tls-auth) */ if (options->tls_auth_file) - get_tls_handshake_key (&c->c1.ks.key_type, - &c->c1.ks.tls_auth_key, - options->tls_auth_file, - options->key_direction); + { + unsigned int flags = options->key_direction ? GHK_KEY_DIR : 0; + const char *file = options->tls_auth_file; + +#if ENABLE_INLINE_FILES + if (options->tls_auth_file_inline) + { + flags |= GHK_INLINE; + file = options->tls_auth_file_inline; + } +#endif + get_tls_handshake_key (&c->c1.ks.key_type, + &c->c1.ks.tls_auth_key, + file, + flags); + } #if ENABLE_INLINE_FILES if (options->priv_key_file_inline) diff --git a/misc.c b/misc.c index 349a608..6184208 100644 --- a/misc.c +++ b/misc.c @@ -433,15 +433,20 @@ void warn_if_group_others_accessible (const char* filename) { #ifdef HAVE_STAT - struct stat st; - if (stat (filename, &st)) - { - msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", filename); - } - else +#if ENABLE_INLINE_FILES + if (strcmp (filename, INLINE_FILE_TAG)) +#endif { - if (st.st_mode & (S_IRWXG|S_IRWXO)) - msg (M_WARN, "WARNING: file '%s' is group or others accessible", filename); + struct stat st; + if (stat (filename, &st)) + { + msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", filename); + } + else + { + if (st.st_mode & (S_IRWXG|S_IRWXO)) + msg (M_WARN, "WARNING: file '%s' is group or others accessible", filename); + } } #endif } diff --git a/options.c b/options.c index 72e2f4f..9e38da6 100644 --- a/options.c +++ b/options.c @@ -4538,9 +4538,26 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->show_engines = true; } + else if (streq (p[0], "key-direction") && p[1]) + { + int key_direction; + + key_direction = ascii2keydirection (msglevel, p[1]); + if (key_direction >= 0) + options->key_direction = key_direction; + else + goto err; + } else if (streq (p[0], "secret") && p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); +#if ENABLE_INLINE_FILES + if (streq (p[1], INLINE_FILE_TAG) && p[2]) + { + options->shared_secret_file_inline = p[2]; + } + else +#endif if (p[2]) { int key_direction; @@ -4889,6 +4906,13 @@ add_option (struct options *options, else if (streq (p[0], "tls-auth") && p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); +#if ENABLE_INLINE_FILES + if (streq (p[1], INLINE_FILE_TAG) && p[2]) + { + options->tls_auth_file_inline = p[2]; + } + else +#endif if (p[2]) { int key_direction; diff --git a/options.h b/options.h index 3c3c202..21484b7 100644 --- a/options.h +++ b/options.h @@ -82,10 +82,6 @@ struct options_pre_pull #endif -#if ENABLE_INLINE_FILES -#define INLINE_FILE_TAG "[[INLINE]]" -#endif - /* Command line options */ struct options { @@ -356,6 +352,9 @@ struct options #ifdef USE_CRYPTO /* Cipher parms */ const char *shared_secret_file; +#if ENABLE_INLINE_FILES + const char *shared_secret_file_inline; +#endif int key_direction; bool ciphername_defined; const char *ciphername; @@ -433,6 +432,9 @@ struct options /* Special authentication MAC for TLS control channel */ const char *tls_auth_file; /* shared secret */ +#if ENABLE_INLINE_FILES + const char *tls_auth_file_inline; +#endif /* Allow only one session */ bool single_session; -- cgit v1.2.3