diff options
author | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2005-11-08 12:50:11 +0000 |
---|---|---|
committer | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2005-11-08 12:50:11 +0000 |
commit | d40f2b204b78ace5c2c9c3007887571ca5a2ec11 (patch) | |
tree | 979cef9340fd0ae688e6a11d01a61bdc856bedaf | |
parent | Merged /contrib/alon/BETA21@778 (diff) | |
download | openvpn-d40f2b204b78ace5c2c9c3007887571ca5a2ec11.tar.xz |
Added ENABLE_INLINE_FILES feature.
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@784 e7ae566f-a301-0410-adde-c780ea21d3b5
-rw-r--r-- | buffer.c | 14 | ||||
-rw-r--r-- | buffer.h | 2 | ||||
-rw-r--r-- | init.c | 8 | ||||
-rw-r--r-- | options.c | 134 | ||||
-rw-r--r-- | options.h | 12 | ||||
-rw-r--r-- | plugin.c | 1 | ||||
-rw-r--r-- | ssl.c | 264 | ||||
-rw-r--r-- | syshead.h | 6 |
8 files changed, 418 insertions, 23 deletions
@@ -461,6 +461,20 @@ string_alloc (const char *str, struct gc_arena *gc) } /* + * Erase all characters in a string + */ +void +string_clear (char *str) +{ + if (str) + { + const int len = strlen (str); + if (len > 0) + memset (str, 0, len); + } +} + +/* * Allocate a string inside a buffer */ struct buffer @@ -83,7 +83,7 @@ void free_buf (struct buffer *buf); bool buf_assign (struct buffer *dest, const struct buffer *src); - +void string_clear (char *str); /* for dmalloc debugging */ @@ -1365,6 +1365,14 @@ do_init_crypto_tls_c1 (struct context *c) &c->c1.ks.tls_auth_key, options->tls_auth_file, options->key_direction); + +#if ENABLE_INLINE_FILES + if (options->priv_key_file_inline) + { + string_clear (c->options.priv_key_file_inline); + c->options.priv_key_file_inline = NULL; + } +#endif } else { @@ -2622,6 +2622,102 @@ bypass_doubledash (char **p) *p += 2; } +#if ENABLE_INLINE_FILES + +struct in_src { +# define IS_TYPE_FP 1 +# define IS_TYPE_BUF 2 + int type; + union { + FILE *fp; + struct buffer *multiline; + } u; +}; + +static bool +in_src_get (const struct in_src *is, char *line, const int size) +{ + if (is->type == IS_TYPE_FP) + { + return BOOL_CAST (fgets (line, size, is->u.fp)); + } + else if (is->type == IS_TYPE_BUF) + { + bool status = buf_parse (is->u.multiline, '\n', line, size); + if ((int) strlen (line) + 1 < size) + strcat (line, "\n"); + return status; + } + else + { + ASSERT (0); + return false; + } +} + +static char * +read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc) +{ + char line[OPTION_LINE_SIZE]; + struct buffer buf = alloc_buf (10000); + char *ret; + while (in_src_get (is, line, sizeof (line))) + { + if (!strncmp (line, close_tag, strlen (close_tag))) + break; + buf_printf (&buf, line); + } + ret = string_alloc (BSTR (&buf), gc); + buf_clear (&buf); + free_buf (&buf); + CLEAR (line); + return ret; +} + +static bool +check_inline_file (struct in_src *is, char *p[], struct gc_arena *gc) +{ + bool ret = false; + if (p[0] && !p[1]) + { + char *arg = p[0]; + if (arg[0] == '<' && arg[strlen(arg)-1] == '>') + { + struct buffer close_tag; + arg[strlen(arg)-1] = '\0'; + p[0] = string_alloc (arg+1, gc); + p[1] = string_alloc (INLINE_FILE_TAG, gc); + close_tag = alloc_buf (strlen(p[0]) + 4); + buf_printf (&close_tag, "</%s>", p[0]); + p[2] = read_inline_file (is, BSTR (&close_tag), gc); + p[3] = NULL; + free_buf (&close_tag); + ret = true; + } + } + return ret; +} + +static bool +check_inline_file_via_fp (FILE *fp, char *p[], struct gc_arena *gc) +{ + struct in_src is; + is.type = IS_TYPE_FP; + is.u.fp = fp; + return check_inline_file (&is, p, gc); +} + +static bool +check_inline_file_via_buf (struct buffer *multiline, char *p[], struct gc_arena *gc) +{ + struct in_src is; + is.type = IS_TYPE_BUF; + is.u.multiline = multiline; + return check_inline_file (&is, p, gc); +} + +#endif + static int add_option (struct options *options, int i, @@ -2665,6 +2761,9 @@ read_config_file (struct options *options, if (parse_line (line, p, SIZE (p), file, line_num, msglevel, &options->gc)) { bypass_doubledash (&p[0]); +#if ENABLE_INLINE_FILES + check_inline_file_via_fp (fp, p, &options->gc); +#endif add_option (options, 0, p, file, line_num, level, msglevel, permission_mask, option_types_found, es); } } @@ -2679,6 +2778,8 @@ read_config_file (struct options *options, { msg (msglevel, "In %s:%d: Maximum recursive include levels exceeded in include attempt of file %s -- probably you have a configuration file that tries to include itself.", top_file, top_line, file); } + CLEAR (line); + CLEAR (p); } static void @@ -2704,9 +2805,14 @@ read_config_string (struct options *options, if (parse_line (line, p, SIZE (p), file, line_num, msglevel, &options->gc)) { bypass_doubledash (&p[0]); +#if ENABLE_INLINE_FILES + check_inline_file_via_buf (&multiline, p, &options->gc); +#endif add_option (options, 0, p, NULL, line_num, 0, msglevel, permission_mask, option_types_found, es); } + CLEAR (p); } + CLEAR (line); } void @@ -4724,6 +4830,13 @@ add_option (struct options *options, ++i; VERIFY_PERMISSION (OPT_P_GENERAL); options->ca_file = p[1]; +#if ENABLE_INLINE_FILES + if (streq (p[1], INLINE_FILE_TAG) && p[2]) + { + ++i; + options->ca_file_inline = p[2]; + } +#endif } else if (streq (p[0], "capath") && p[1]) { @@ -4736,12 +4849,26 @@ add_option (struct options *options, ++i; VERIFY_PERMISSION (OPT_P_GENERAL); options->dh_file = p[1]; +#if ENABLE_INLINE_FILES + if (streq (p[1], INLINE_FILE_TAG) && p[2]) + { + ++i; + options->dh_file_inline = p[2]; + } +#endif } else if (streq (p[0], "cert") && p[1]) { ++i; VERIFY_PERMISSION (OPT_P_GENERAL); options->cert_file = p[1]; +#if ENABLE_INLINE_FILES + if (streq (p[1], INLINE_FILE_TAG) && p[2]) + { + ++i; + options->cert_file_inline = p[2]; + } +#endif } #ifdef WIN32 else if (streq (p[0], "cryptoapicert") && p[1]) @@ -4756,6 +4883,13 @@ add_option (struct options *options, ++i; VERIFY_PERMISSION (OPT_P_GENERAL); options->priv_key_file = p[1]; +#if ENABLE_INLINE_FILES + if (streq (p[1], INLINE_FILE_TAG) && p[2]) + { + ++i; + options->priv_key_file_inline = p[2]; + } +#endif } else if (streq (p[0], "pkcs12") && p[1]) { @@ -82,6 +82,10 @@ struct options_pre_pull #endif +#if ENABLE_INLINE_FILES +#define INLINE_FILE_TAG "[[INLINE]]" +#endif + /* Command line options */ struct options { @@ -378,6 +382,14 @@ struct options const char *tls_verify; const char *tls_remote; const char *crl_file; + +#if ENABLE_INLINE_FILES + const char *ca_file_inline; + const char *cert_file_inline; + char *priv_key_file_inline; + const char *dh_file_inline; +#endif + int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */ const char *pkcs11_providers[MAX_PARMS]; const char *pkcs11_sign_mode[MAX_PARMS]; @@ -622,6 +622,7 @@ openvpn_plugin_string_list_item_free (struct openvpn_plugin_string_list *l) if (l) { free (l->name); + string_clear (l->value); free (l->value); free (l); } @@ -734,6 +734,170 @@ info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret) } } +#if ENABLE_INLINE_FILES + +static int +use_inline_load_verify_locations (SSL_CTX *ctx, const char *ca_string) +{ + X509_STORE *store = NULL; + X509* cert = NULL; + BIO *in = NULL; + int ret = 0; + + in = BIO_new_mem_buf ((char *)ca_string, -1); + if (!in) + goto err; + + for (;;) + { + if (!PEM_read_bio_X509 (in, &cert, 0, NULL)) + { + ret = 1; + break; + } + if (!cert) + break; + + store = SSL_CTX_get_cert_store (ctx); + if (!store) + break; + + if (!X509_STORE_add_cert (store, cert)) + break; + + if (cert) + { + X509_free (cert); + cert = NULL; + } + } + + err: + if (cert) + X509_free (cert); + if (in) + BIO_free (in); + return ret; +} + +static int +xname_cmp(const X509_NAME * const *a, const X509_NAME * const *b) +{ + return(X509_NAME_cmp(*a,*b)); +} + +static STACK_OF(X509_NAME) * +use_inline_load_client_CA_file (SSL_CTX *ctx, const char *ca_string) +{ + BIO *in = NULL; + X509 *x = NULL; + X509_NAME *xn = NULL; + STACK_OF(X509_NAME) *ret = NULL, *sk; + + sk=sk_X509_NAME_new(xname_cmp); + + in = BIO_new_mem_buf ((char *)ca_string, -1); + if (!in) + goto err; + + if ((sk == NULL) || (in == NULL)) + goto err; + + for (;;) + { + if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL) + break; + if (ret == NULL) + { + ret = sk_X509_NAME_new_null(); + if (ret == NULL) + goto err; + } + if ((xn=X509_get_subject_name(x)) == NULL) goto err; + /* check for duplicates */ + xn=X509_NAME_dup(xn); + if (xn == NULL) goto err; + if (sk_X509_NAME_find(sk,xn) >= 0) + X509_NAME_free(xn); + else + { + sk_X509_NAME_push(sk,xn); + sk_X509_NAME_push(ret,xn); + } + } + + if (0) + { + err: + if (ret != NULL) sk_X509_NAME_pop_free(ret,X509_NAME_free); + ret=NULL; + } + if (sk != NULL) sk_X509_NAME_free(sk); + if (in != NULL) BIO_free(in); + if (x != NULL) X509_free(x); + if (ret != NULL) + ERR_clear_error(); + return(ret); +} + +static int +use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string) +{ + BIO *in = NULL; + X509 *x = NULL; + int ret = 0; + + in = BIO_new_mem_buf ((char *)cert_string, -1); + if (!in) + goto end; + + x = PEM_read_bio_X509 (in, + NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + if (!x) + goto end; + + ret = SSL_CTX_use_certificate(ctx, x); + + end: + if (x) + X509_free (x); + if (in) + BIO_free (in); + return ret; +} + +static int +use_inline_PrivateKey_file (SSL_CTX *ctx, const char *key_string) +{ + BIO *in = NULL; + EVP_PKEY *pkey = NULL; + int ret = 0; + + in = BIO_new_mem_buf ((char *)key_string, -1); + if (!in) + goto end; + + pkey = PEM_read_bio_PrivateKey (in, + NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + if (!pkey) + goto end; + + ret = SSL_CTX_use_PrivateKey (ctx, pkey); + + end: + if (pkey) + EVP_PKEY_free (pkey); + if (in) + BIO_free (in); + return ret; +} + +#endif + /* * Initialize SSL context. * All files are in PEM format. @@ -756,9 +920,20 @@ init_ssl (const struct options *options) SSL_CTX_set_tmp_rsa_callback (ctx, tmp_rsa_cb); - /* Get Diffie Hellman Parameters */ - if (!(bio = BIO_new_file (options->dh_file, "r"))) - msg (M_SSLERR, "Cannot open %s for DH parameters", options->dh_file); +#if ENABLE_INLINE_FILES + if (!strcmp (options->dh_file, INLINE_FILE_TAG) && options->dh_file_inline) + { + if (!(bio = BIO_new_mem_buf ((char *)options->dh_file_inline, -1))) + msg (M_SSLERR, "Cannot open memory BIO for inline DH parameters"); + } + else +#endif + { + /* Get Diffie Hellman Parameters */ + if (!(bio = BIO_new_file (options->dh_file, "r"))) + msg (M_SSLERR, "Cannot open %s for DH parameters", options->dh_file); + } + dh = PEM_read_bio_DHparams (bio, NULL, NULL, NULL); BIO_free (bio); if (!dh) @@ -874,15 +1049,37 @@ init_ssl (const struct options *options) /* Load Certificate */ if (options->cert_file) { - using_cert_file = true; - if (!SSL_CTX_use_certificate_file (ctx, options->cert_file, SSL_FILETYPE_PEM)) - msg (M_SSLERR, "Cannot load certificate file %s", options->cert_file); +#if ENABLE_INLINE_FILES + if (!strcmp (options->cert_file, INLINE_FILE_TAG) && options->cert_file_inline) + { + if (!use_inline_certificate_file (ctx, options->cert_file_inline)) + msg (M_SSLERR, "Cannot load inline certificate file"); + } + else +#endif + { + if (!SSL_CTX_use_certificate_file (ctx, options->cert_file, SSL_FILETYPE_PEM)) + msg (M_SSLERR, "Cannot load certificate file %s", options->cert_file); + using_cert_file = true; + } } /* Load Private Key */ if (options->priv_key_file) { - if (!SSL_CTX_use_PrivateKey_file (ctx, options->priv_key_file, SSL_FILETYPE_PEM)) + int status; + +#if ENABLE_INLINE_FILES + if (!strcmp (options->priv_key_file, INLINE_FILE_TAG) && options->priv_key_file_inline) + { + status = use_inline_PrivateKey_file (ctx, options->priv_key_file_inline); + } + else +#endif + { + status = SSL_CTX_use_PrivateKey_file (ctx, options->priv_key_file, SSL_FILETYPE_PEM); + } + if (!status) { #ifdef ENABLE_MANAGEMENT if (management && (ERR_GET_REASON (ERR_peek_error()) == EVP_R_BAD_DECRYPT)) @@ -902,34 +1099,57 @@ init_ssl (const struct options *options) if (options->ca_file || options->ca_path) { - /* Load CA file for verifying peer supplied certificate */ - ASSERT (options->ca_file || options->ca_path); - if (!SSL_CTX_load_verify_locations (ctx, options->ca_file, options->ca_path)) - msg (M_SSLERR, "Cannot load CA certificate file %s path %s (SSL_CTX_load_verify_locations)", options->ca_file, options->ca_path); + int status; + +#if ENABLE_INLINE_FILES + if (!strcmp (options->ca_file, INLINE_FILE_TAG) && options->ca_file_inline) + { + status = use_inline_load_verify_locations (ctx, options->ca_file_inline); + } + else +#endif + { + /* Load CA file for verifying peer supplied certificate */ + status = SSL_CTX_load_verify_locations (ctx, options->ca_file, options->ca_path); + } + + if (!status) + msg (M_SSLERR, "Cannot load CA certificate file %s path %s (SSL_CTX_load_verify_locations)", options->ca_file, options->ca_path); /* Set a store for certs (CA & CRL) with a lookup on the "capath" hash directory */ if (options->ca_path) { X509_STORE *store = SSL_CTX_get_cert_store(ctx); - if (store) { - X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); - if (!X509_LOOKUP_add_dir(lookup, options->ca_path, X509_FILETYPE_PEM)) - X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); - else - msg(M_WARN, "WARNING: experimental option --capath %s", options->ca_path); + if (store) + { + X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); + if (!X509_LOOKUP_add_dir(lookup, options->ca_path, X509_FILETYPE_PEM)) + X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); + else + msg(M_WARN, "WARNING: experimental option --capath %s", options->ca_path); #if OPENSSL_VERSION_NUMBER >= 0x00907000L - X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); #else - msg(M_WARN, "WARNING: this version of OpenSSL cannot handle CRL files in capath"); + msg(M_WARN, "WARNING: this version of OpenSSL cannot handle CRL files in capath"); #endif - } else + } + else msg(M_SSLERR, "Cannot get certificate store (SSL_CTX_get_cert_store)"); } /* Load names of CAs from file and use it as a client CA list */ if (options->ca_file) { - STACK_OF(X509_NAME) *cert_names; - cert_names = SSL_load_client_CA_file (options->ca_file); + STACK_OF(X509_NAME) *cert_names = NULL; +#if ENABLE_INLINE_FILES + if (!strcmp (options->ca_file, INLINE_FILE_TAG) && options->ca_file_inline) + { + cert_names = use_inline_load_client_CA_file (ctx, options->ca_file_inline); + } + else +#endif + { + cert_names = SSL_load_client_CA_file (options->ca_file); + } if (!cert_names) msg (M_SSLERR, "Cannot load CA certificate file %s (SSL_load_client_CA_file)", options->ca_file); SSL_CTX_set_client_CA_list (ctx, cert_names); @@ -466,4 +466,10 @@ socket_defined (const socket_descriptor_t sd) #define EPOLL 0 #endif +/* + * Should we allow ca/cert/key files to be + * included inline, in the configuration file? + */ +#define ENABLE_INLINE_FILES 1 + #endif |