]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added ENABLE_INLINE_FILES feature.
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Tue, 8 Nov 2005 12:50:11 +0000 (12:50 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Tue, 8 Nov 2005 12:50:11 +0000 (12:50 +0000)
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@784 e7ae566f-a301-0410-adde-c780ea21d3b5

buffer.c
buffer.h
init.c
options.c
options.h
plugin.c
ssl.c
syshead.h

index cfff06ed21e6773d8488180bad30e842847db294..3b856bc77098c369d24343e7b30ce5eb84004ed6 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -460,6 +460,20 @@ string_alloc (const char *str, struct gc_arena *gc)
     return NULL;
 }
 
+/*
+ * 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
  */
index 1e5266bd6089fe3f968ca05bea4b3240a7108a7d..17bc37e12db2e2681f1a7ee82f5484691a1cebb6 100644 (file)
--- a/buffer.h
+++ b/buffer.h
@@ -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 */
 
diff --git a/init.c b/init.c
index ac40dc55ec6f18b81f8b75dfd820376b642a2a4c..4e3b6e72b532b641ff5b263285545c2c1fe735e5 100644 (file)
--- a/init.c
+++ b/init.c
@@ -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
     {
index 4b66a451cfe1399500afe1a2d41befd22ca3b210..2df07f4d59b1891c13ab6cfc257216cf955f865d 100644 (file)
--- a/options.c
+++ b/options.c
@@ -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])
     {
index 85f989d2ebe749b83a09e288a3486dc4c8738c1e..aa2b1c12e3b4667120b9b2a699d77c0c2ac7c5a0 100644 (file)
--- a/options.h
+++ b/options.h
@@ -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];
index 044929372cf145d089b2aacdcc2499ef796abaa0..26d1d1bbffa2703d0e2c0cc107932428535c140e 100644 (file)
--- a/plugin.c
+++ b/plugin.c
@@ -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);
     }
diff --git a/ssl.c b/ssl.c
index 945edd0c390238815782434b5793c25364979601..2b78bd033d1f83d1675c420538dd479d4616194a 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -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);
index c5ef47b41e86201b191ee9ae39a874a9b5807984..4c79286614bbdff3608dfd918569e2cc4e8cb5e0 100644 (file)
--- a/syshead.h
+++ b/syshead.h
@@ -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