Inline file capability now works for

--secret and --tls-auth.  For example:

<secret>
[ascii key data]
</secret>


git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@844 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
james 2005-12-08 18:29:38 +00:00
parent e1447acc97
commit c959fc742e
7 changed files with 235 additions and 135 deletions

View File

@ -64,4 +64,12 @@ typedef unsigned long ptr_type;
*/ */
#define TLS_CHANNEL_BUF_SIZE 1024 #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 #endif

265
crypto.c
View File

@ -905,11 +905,12 @@ test_crypto (const struct crypto_options *co, struct frame* frame)
} }
#ifdef USE_SSL #ifdef USE_SSL
void void
get_tls_handshake_key (const struct key_type *key_type, get_tls_handshake_key (const struct key_type *key_type,
struct key_ctx_bi *ctx, struct key_ctx_bi *ctx,
const char *passphrase_file, const char *passphrase_file,
bool key_direction) const unsigned int flags)
{ {
if (passphrase_file && key_type->hmac_length) 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_length = 0;
kt.cipher = NULL; kt.cipher = NULL;
/* first try to parse as an OpenVPN static key file */ #if ENABLE_INLINE_FILES
read_key_file (&key2, passphrase_file, false); if (flags & GHK_INLINE)
/* succeeded? */
if (key2.n == 2)
{ {
msg (M_INFO, /* key was specified inline, key text is in passphrase_file */
"Control Channel Authentication: using '%s' as a " PACKAGE_NAME " static key file", read_key_file (&key2, passphrase_file, RKF_INLINE|RKF_MUST_SUCCEED);
passphrase_file);
/* 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 else
{ #endif
int hash_size; {
/* 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 */ CLEAR (key2);
hash_size = read_passphrase_hash (passphrase_file,
kt.digest,
key2.keys[0].hmac,
MAX_HMAC_KEY_LENGTH);
ASSERT (hash_size == kt.hmac_length);
/* suceeded */ /* failed, now try to get hash from a freeform file */
key2.n = 1; 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, /* suceeded */
"Control Channel Authentication: using '%s' as a free-form passphrase file", key2.n = 1;
passphrase_file);
}
msg (M_INFO,
"Control Channel Authentication: using '%s' as a free-form passphrase file",
passphrase_file);
}
}
/* handle key direction */ /* 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); must_have_n_keys (passphrase_file, "tls-auth", &key2, kds.need_keys);
/* initialize hmac key in both directions */ /* 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)"; "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 */ /* read key from file */
void 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 gc_arena gc = gc_new ();
struct buffer in = alloc_buf_gc (64, &gc); struct buffer in;
int fd, size; int fd, size;
uint8_t hex_byte[3] = {0, 0, 0}; uint8_t hex_byte[3] = {0, 0, 0};
const char *error_filename = file;
/* parse info */ /* parse info */
int hb_index = 0; int hb_index = 0;
@ -1019,95 +1037,110 @@ read_key_file (struct key2 *key2, const char *filename, bool must_succeed)
CLEAR (*key2); CLEAR (*key2);
fd = open (filename, O_RDONLY); /*
if (fd == -1) * Key can be provided as a filename in 'file' or if RKF_INLINE
msg (M_ERR, "Cannot open file key file '%s'", filename); * is set, the actual key data itself in ascii form.
*/
while ((size = read (fd, in.data, in.capacity))) #if ENABLE_INLINE_FILES
if (flags & RKF_INLINE) /* 'file' is a string containing ascii representation of key */
{ {
const char *cp = (char *)in.data; size = strlen (file) + 1;
while (size) buf_set_read (&in, (const uint8_t *)file, size);
{ error_filename = INLINE_FILE_TAG;
const char c = *cp; }
else /* 'file' is a filename which refers to a file containing the ascii key */
#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);
#endif #endif
{
if (c == '\n') in = alloc_buf_gc (2048, &gc);
{ fd = open (file, O_RDONLY);
line_index = match = 0; if (fd == -1)
++line_num; msg (M_ERR, "Cannot open file key file '%s'", file);
} size = read (fd, in.data, in.capacity);
else if (size == in.capacity)
{ msg (M_FATAL, "Key file ('%s') can be a maximum of %d bytes", file, (int)in.capacity);
/* first char of new line */ close (fd);
if (!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;
}
/* compare read chars with header line */
if (state == PARSE_INITIAL)
{
if (line_index < hlen && c == static_key_head[line_index])
{
if (++match == hlen)
state = PARSE_HEAD;
}
}
/* compare read chars with footer line */
if (state == PARSE_FOOT)
{
if (line_index < flen && c == static_key_foot[line_index])
{
if (++match == flen)
state = PARSE_FINISHED;
}
}
/* reading key */
if (state == PARSE_DATA)
{
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);
}
}
++line_index;
}
++cp;
--size;
}
} }
close (fd); const char *cp = (char *)in.data;
while (size)
{
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);
#endif
if (c == '\n')
{
line_index = match = 0;
++line_num;
}
else
{
/* first char of new line */
if (!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;
}
/* compare read chars with header line */
if (state == PARSE_INITIAL)
{
if (line_index < hlen && c == static_key_head[line_index])
{
if (++match == hlen)
state = PARSE_HEAD;
}
}
/* compare read chars with footer line */
if (state == PARSE_FOOT)
{
if (line_index < flen && c == static_key_foot[line_index])
{
if (++match == flen)
state = PARSE_FINISHED;
}
}
/* reading key */
if (state == PARSE_DATA)
{
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, error_filename, count, onekeylen, keylen);
}
}
++line_index;
}
++cp;
--size;
}
/* /*
* Normally we will read either 1 or 2 keys from file. * 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)); ASSERT (key2->n >= 0 && key2->n <= (int) SIZE (key2->keys));
if (must_succeed) if (flags & RKF_MUST_SUCCEED)
{ {
if (!key2->n) 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)", 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) if (state != PARSE_FINISHED)
msg (M_FATAL, "Footer text not found in file '%s' (%d/%d/%d bytes found/min/max)", 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 */ /* zero file read buffer */
buf_clear (&in); buf_clear (&in);
if (key2->n) if (key2->n)
warn_if_group_others_accessible (filename); warn_if_group_others_accessible (error_filename);
#if 0 #if 0
/* DEBUGGING */ /* DEBUGGING */

View File

@ -270,7 +270,9 @@ void init_key_type (struct key_type *kt, const char *ciphername,
bool authname_defined, int keysize, bool authname_defined, int keysize,
bool cfb_ofb_allowed, bool warn); 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); int write_key_file (const int nkeys, const char *filename);
@ -367,10 +369,12 @@ void openssl_dmalloc_init (void);
#ifdef USE_SSL #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, void get_tls_handshake_key (const struct key_type *key_type,
struct key_ctx_bi *ctx, struct key_ctx_bi *ctx,
const char *passphrase_file, const char *passphrase_file,
bool key_direction); const unsigned int flags);
#else #else

34
init.c
View File

@ -1276,7 +1276,19 @@ do_init_crypto_static (struct context *c, const unsigned int flags)
options->test_crypto, true); options->test_crypto, true);
/* Read cipher and hmac keys from shared secret file */ /* 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 */ /* Check for and fix highly unlikely key problems */
verify_fix_key2 (&key2, &c->c1.ks.key_type, 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) */ /* TLS handshake authentication (--tls-auth) */
if (options->tls_auth_file) if (options->tls_auth_file)
get_tls_handshake_key (&c->c1.ks.key_type, {
&c->c1.ks.tls_auth_key, unsigned int flags = options->key_direction ? GHK_KEY_DIR : 0;
options->tls_auth_file, const char *file = options->tls_auth_file;
options->key_direction);
#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 ENABLE_INLINE_FILES
if (options->priv_key_file_inline) if (options->priv_key_file_inline)

21
misc.c
View File

@ -433,15 +433,20 @@ void
warn_if_group_others_accessible (const char* filename) warn_if_group_others_accessible (const char* filename)
{ {
#ifdef HAVE_STAT #ifdef HAVE_STAT
struct stat st; #if ENABLE_INLINE_FILES
if (stat (filename, &st)) if (strcmp (filename, INLINE_FILE_TAG))
#endif
{ {
msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", filename); struct stat st;
} if (stat (filename, &st))
else {
{ msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", filename);
if (st.st_mode & (S_IRWXG|S_IRWXO)) }
msg (M_WARN, "WARNING: file '%s' is group or others accessible", filename); else
{
if (st.st_mode & (S_IRWXG|S_IRWXO))
msg (M_WARN, "WARNING: file '%s' is group or others accessible", filename);
}
} }
#endif #endif
} }

View File

@ -4538,9 +4538,26 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL); VERIFY_PERMISSION (OPT_P_GENERAL);
options->show_engines = true; 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]) else if (streq (p[0], "secret") && p[1])
{ {
VERIFY_PERMISSION (OPT_P_GENERAL); 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]) if (p[2])
{ {
int key_direction; int key_direction;
@ -4889,6 +4906,13 @@ add_option (struct options *options,
else if (streq (p[0], "tls-auth") && p[1]) else if (streq (p[0], "tls-auth") && p[1])
{ {
VERIFY_PERMISSION (OPT_P_GENERAL); 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]) if (p[2])
{ {
int key_direction; int key_direction;

View File

@ -82,10 +82,6 @@ struct options_pre_pull
#endif #endif
#if ENABLE_INLINE_FILES
#define INLINE_FILE_TAG "[[INLINE]]"
#endif
/* Command line options */ /* Command line options */
struct options struct options
{ {
@ -356,6 +352,9 @@ struct options
#ifdef USE_CRYPTO #ifdef USE_CRYPTO
/* Cipher parms */ /* Cipher parms */
const char *shared_secret_file; const char *shared_secret_file;
#if ENABLE_INLINE_FILES
const char *shared_secret_file_inline;
#endif
int key_direction; int key_direction;
bool ciphername_defined; bool ciphername_defined;
const char *ciphername; const char *ciphername;
@ -433,6 +432,9 @@ struct options
/* Special authentication MAC for TLS control channel */ /* Special authentication MAC for TLS control channel */
const char *tls_auth_file; /* shared secret */ const char *tls_auth_file; /* shared secret */
#if ENABLE_INLINE_FILES
const char *tls_auth_file_inline;
#endif
/* Allow only one session */ /* Allow only one session */
bool single_session; bool single_session;