]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added new "extra-certs" and "verify-hash" options (see man page for
authorJames Yonan <james@openvpn.net>
Mon, 25 Apr 2011 04:58:34 +0000 (04:58 +0000)
committerDavid Sommerseth <dazo@users.sourceforge.net>
Tue, 26 Apr 2011 20:29:12 +0000 (22:29 +0200)
details).

Increase the timeout after SIGUSR1 restart when restart is not
due to server_poll_timeout.

Version 2.1.3v

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7215 e7ae566f-a301-0410-adde-c780ea21d3b5

init.c
openvpn.8
options.c
options.h
ssl.c
ssl.h
version.m4

diff --git a/init.c b/init.c
index ef09e8e66b242b2653853cb30785410af419e112..b1f65a9774db55486c1dca41aeb5d972c378e7a9 100644 (file)
--- a/init.c
+++ b/init.c
@@ -1706,8 +1706,10 @@ socket_restart_pause (struct context *c)
   if (auth_retry_get () == AR_NOINTERACT)
     sec = 10;
 
+#if 0 /* not really needed because of c->persist.restart_sleep_seconds */
   if (c->options.server_poll_timeout && sec > 1)
     sec = 1;
+#endif
 #endif
 
   if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec)
@@ -2057,6 +2059,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
   to.ns_cert_type = options->ns_cert_type;
   memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku));
   to.remote_cert_eku = options->remote_cert_eku;
+  to.verify_hash = options->verify_hash;
   to.es = c->c2.es;
 
 #ifdef ENABLE_DEBUG
index 1953b161bda87e28762b8bedab0234f87e5ad71c..85889de6a430980c60b371d77aba3c1378a7015f 100644 (file)
--- a/openvpn.8
+++ b/openvpn.8
@@ -3887,6 +3887,22 @@ that for certificate authority functions, you must set up the files
 ).
 .\"*********************************************************
 .TP
+.B --extra-certs file
+Specify a
+.B file
+containing one or more PEM certs (concatenated together)
+that complete the
+local certificate chain.
+
+This option is useful for "split" CAs, where the CA for server
+certs is different than the CA for client certs.  Putting certs
+in this file allows them to be used to complete the local
+certificate chain without trusting them to verify the peer-submitted
+certificate, as would be the case if the certs were placed in the
+.B ca
+file.
+.\"*********************************************************
+.TP
 .B --key file
 Local peer's private key in .pem format.  Use the private key which was generated
 when you built your peer's certificate (see
@@ -3903,6 +3919,17 @@ and
 .B --key.
 .\"*********************************************************
 .TP
+.B --verify-hash hash
+Specify SHA1 fingerprint for level-1 cert.  The level-1 cert is the
+CA (or intermediate cert) that signs the leaf certificate, and is
+one removed from the leaf certificate in the direction of the root.
+When accepting a connection from a peer, the level-1 cert
+fingerprint must match
+.B hash
+or certificate verification will fail.  Hash is specified
+as XX:XX:...  For example: AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16
+.\"*********************************************************
+.TP
 .B --pkcs11-cert-private [0|1]...
 Set if access to certificate object should be performed after login.
 Every provider has its own setting.
index fd3fec609a6e98ab3ee38e37bae264d267cedd61..1cfccd3fea3635174759398e651151798ab13c69 100644 (file)
--- a/options.c
+++ b/options.c
@@ -507,9 +507,11 @@ static const char usage_message[] =
   "                  Use \"openssl dhparam -out dh1024.pem 1024\" to generate.\n"
   "--cert file     : Local certificate in .pem format -- must be signed\n"
   "                  by a Certificate Authority in --ca file.\n"
+  "--extra-certs file : one or more PEM certs that complete the cert chain.\n"
   "--key file      : Local private key in .pem format.\n"
   "--pkcs12 file   : PKCS#12 file containing local private key, local certificate\n"
   "                  and optionally the root CA certificate.\n"
+  "--verify-hash   : Specify SHA1 fingerprint for level-1 cert.\n"
 #ifdef WIN32
   "--cryptoapicert select-string : Load the certificate and private key from the\n"
   "                  Windows Certificate System Store.\n"
@@ -894,6 +896,40 @@ is_stateful_restart (const struct options *o)
   return is_persist_option (o) || connection_list_defined (o);
 }
 
+#ifdef USE_SSL
+static uint8_t *
+parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_arena *gc)
+{
+  int i;
+  const char *cp = str;
+  uint8_t *ret = (uint8_t *) gc_malloc (nbytes, true, gc);
+  char term = 1;
+  int byte;
+  char bs[3];
+
+  for (i = 0; i < nbytes; ++i)
+    {
+      if (strlen(cp) < 2)
+       msg (msglevel, "format error in hash fingerprint: %s", str);
+      bs[0] = *cp++;
+      bs[1] = *cp++;
+      bs[2] = 0;
+      byte = 0;
+      if (sscanf(bs, "%x", &byte) != 1)
+       msg (msglevel, "format error in hash fingerprint hex byte: %s", str);
+      ret[i] = (uint8_t)byte;
+      term = *cp++;
+      if (term != ':' && term != 0)
+       msg (msglevel, "format error in hash fingerprint delimiter: %s", str);
+      if (term == 0)
+       break;
+    }
+  if (term != 0 || i != nbytes-1)
+    msg (msglevel, "hash fingerprint is different length than expected (%d bytes): %s", nbytes, str);
+  return ret;
+}
+#endif
+
 #ifdef WIN32
 
 #ifdef ENABLE_DEBUG
@@ -5758,6 +5794,22 @@ add_option (struct options *options,
        }
 #endif
     }
+  else if (streq (p[0], "extra-certs") && p[1])
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->extra_certs_file = p[1];
+#if ENABLE_INLINE_FILES
+      if (streq (p[1], INLINE_FILE_TAG) && p[2])
+       {
+         options->extra_certs_file_inline = p[2];
+       }
+#endif
+    }
+  else if (streq (p[0], "verify-hash") && p[1])
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc);
+    }
 #ifdef WIN32
   else if (streq (p[0], "cryptoapicert") && p[1])
     {
index 74ba9d42c2be7210cadc1082321ffb0ee3961625..f0baabe0896dc72b7a78cf96814a2eca4c5b12bb 100644 (file)
--- a/options.h
+++ b/options.h
@@ -477,6 +477,7 @@ struct options
   const char *ca_path;
   const char *dh_file;
   const char *cert_file;
+  const char *extra_certs_file;
   const char *priv_key_file;
   const char *pkcs12_file;
   const char *cipher_list;
@@ -487,6 +488,7 @@ struct options
 #if ENABLE_INLINE_FILES
   const char *ca_file_inline;
   const char *cert_file_inline;
+  const char *extra_certs_file_inline;
   char *priv_key_file_inline;
   const char *dh_file_inline;
   const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */
@@ -495,6 +497,7 @@ struct options
   int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */
   unsigned remote_cert_ku[MAX_PARMS];
   const char *remote_cert_eku;
+  uint8_t *verify_hash;
 
 #ifdef ENABLE_PKCS11
   const char *pkcs11_providers[MAX_PARMS];
diff --git a/ssl.c b/ssl.c
index 095b6a62daaadb7c4583e08bc00202a413a78b3e..df237ccf697bb1172428500b2fffcfba671e81e0 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -910,6 +910,16 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
       goto err;                        /* Reject connection */
     }
 
+  /* verify level 1 cert, i.e. the CA that signed our leaf cert */
+  if (ctx->error_depth == 1 && opt->verify_hash)
+    {
+      if (memcmp (ctx->current_cert->sha1_hash, opt->verify_hash, SHA_DIGEST_LENGTH))
+       {
+         msg (D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed");
+         goto err;
+       }
+    }
+
   /* save common name in session object */
   if (ctx->error_depth == 0)
     set_common_name (session, common_name);
@@ -2140,6 +2150,37 @@ init_ssl (const struct options *options)
        msg (M_SSLERR, "Cannot load certificate chain file %s (SSL_use_certificate_chain_file)", options->cert_file);
     }
 
+  /* Load extra certificates that are part of our own certificate
+     chain but shouldn't be included in the verify chain */
+  if (options->extra_certs_file || options->extra_certs_file_inline)
+    {
+      BIO *bio;
+      X509 *cert;
+#if ENABLE_INLINE_FILES
+      if (!strcmp (options->extra_certs_file, INLINE_FILE_TAG) && options->extra_certs_file_inline)
+       {
+         bio = BIO_new_mem_buf ((char *)options->extra_certs_file_inline, -1);
+       }
+      else
+#endif
+       {
+         bio = BIO_new(BIO_s_file());
+         if (BIO_read_filename(bio, options->extra_certs_file) <= 0)
+           msg (M_SSLERR, "Cannot load extra-certs file: %s", options->extra_certs_file);
+       }
+      for (;;)
+       {
+         cert = NULL;
+         if (!PEM_read_bio_X509 (bio, &cert, 0, NULL)) /* takes ownership of cert */
+           break;
+         if (!cert)
+           msg (M_SSLERR, "Error reading extra-certs certificate");
+         if (SSL_CTX_add_extra_chain_cert(ctx, cert) != 1)
+           msg (M_SSLERR, "Error adding extra-certs certificate");
+       }
+      BIO_free (bio);
+    }
+
   /* Require peer certificate verification */
 #if P2MP_SERVER
   if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
diff --git a/ssl.h b/ssl.h
index fe494b1037a90064903e3ef9e53a318ebd027da1..1b23d7d37171748e8cc59d24dd88bba53585e3d4 100644 (file)
--- a/ssl.h
+++ b/ssl.h
@@ -466,6 +466,7 @@ struct tls_options
   int ns_cert_type;
   unsigned remote_cert_ku[MAX_PARMS];
   const char *remote_cert_eku;
+  uint8_t *verify_hash;
 
   /* allow openvpn config info to be
      passed over control channel */
index 85cd0434290edfe8393537fe272808ce238e8718..3642b719601987b5467817e963dc7276bb30ebd6 100644 (file)
@@ -1,5 +1,5 @@
 dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1.3u])
+define(PRODUCT_VERSION,[2.1.3v])
 dnl define the TAP version
 define(PRODUCT_TAP_ID,[tap0901])
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])