]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added 'dir' flag to "crl-verify" (see man page for info).
authorJames Yonan <james@openvpn.net>
Sun, 24 Apr 2011 00:59:28 +0000 (00:59 +0000)
committerDavid Sommerseth <dazo@users.sourceforge.net>
Tue, 26 Apr 2011 20:29:12 +0000 (22:29 +0200)
Don't call SSL_CTX_set_client_CA_list or SSL_CTX_set_client_CA_list
if not running in server mode (these functions are only useful for
TLS/SSL servers).

Modified openvpn_snprintf to return false on overflow, and true
otherwise.

When AUTH_FAILED,... is received, log the full string.

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

buffer.c
buffer.h
openvpn.8
options.c
push.c
ssl.c
ssl.h

index 29527677633137d582d9f79e3e39d6b093586860..5499d99f2b49b2f3342978d5ba4e0eb56e7ed0e7 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -218,20 +218,21 @@ buf_printf (struct buffer *buf, const char *format, ...)
 /*
  * This is necessary due to certain buggy implementations of snprintf,
  * that don't guarantee null termination for size > 0.
+ * Return false on overflow.
  */
 
-int openvpn_snprintf(char *str, size_t size, const char *format, ...)
+bool openvpn_snprintf(char *str, size_t size, const char *format, ...)
 {
   va_list arglist;
-  int ret = 0;
+  int len = -1;
   if (size > 0)
     {
       va_start (arglist, format);
-      ret = vsnprintf (str, size, format, arglist);
+      len = vsnprintf (str, size, format, arglist);
       va_end (arglist);
       str[size - 1] = 0;
     }
-  return ret;
+  return (len >= 0 && len < size);
 }
 
 /*
index 0f22cda4070a6f8a8cae047df7dfd5aba8908667..58273e291d255bdb0689e033a5a90f502d53e529 100644 (file)
--- a/buffer.h
+++ b/buffer.h
@@ -280,7 +280,7 @@ bool buf_printf (struct buffer *buf, const char *format, ...)
 /*
  * Like snprintf but guarantees null termination for size > 0
  */
-int openvpn_snprintf(char *str, size_t size, const char *format, ...)
+bool openvpn_snprintf(char *str, size_t size, const char *format, ...)
 #ifdef __GNUC__
     __attribute__ ((format (printf, 3, 4)))
 #endif
index 037ba7e1d43d4fe0db4b0fc3d331a02df88b90cc..1953b161bda87e28762b8bedab0234f87e5ad71c 100644 (file)
--- a/openvpn.8
+++ b/openvpn.8
@@ -4457,7 +4457,7 @@ or
 .B --tls-verify.
 .\"*********************************************************
 .TP
-.B --crl-verify crl
+.B --crl-verify crl ['dir']
 Check peer certificate against the file
 .B crl
 in PEM format.
@@ -4473,6 +4473,16 @@ overall integrity of the PKI.
 
 The only time when it would be necessary to rebuild the entire PKI from scratch would be
 if the root certificate key itself was compromised.
+
+If the optional
+.B dir
+flag is specified, enable a different mode where
+.B crl
+is a directory containing files named as revoked serial numbers
+(the files may be empty, the contents are never read).  If a client
+requests a connection, where the client certificate serial number
+(decimal string) is the name of a file present in the directory,
+it will be rejected.
 .\"*********************************************************
 .SS SSL Library information:
 .\"*********************************************************
index 32ea07f18c7b2079f54b950a670e5d494bc23d16..fd3fec609a6e98ab3ee38e37bae264d267cedd61 100644 (file)
--- a/options.c
+++ b/options.c
@@ -534,7 +534,7 @@ static const char usage_message[] =
   "                  see --secret option for more info.\n"
   "--askpass [file]: Get PEM password from controlling tty before we daemonize.\n"
   "--auth-nocache  : Don't cache --askpass or --auth-user-pass passwords.\n"
-  "--crl-verify crl: Check peer certificate against a CRL.\n"
+  "--crl-verify crl ['dir']: Check peer certificate against a CRL.\n"
   "--tls-verify cmd: Execute shell command cmd to verify the X509 name of a\n"
   "                  pending TLS connection that has otherwise passed all other\n"
   "                  tests of certification.  cmd should return 0 to allow\n"
@@ -5836,6 +5836,8 @@ add_option (struct options *options,
   else if (streq (p[0], "crl-verify") && p[1])
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
+      if (p[2] && streq(p[2], "dir"))
+       options->ssl_flags |= SSLF_CRL_VERIFY_DIR;
       options->crl_file = p[1];
     }
   else if (streq (p[0], "tls-verify") && p[1])
diff --git a/push.c b/push.c
index 339478ad95c4116755eb7cdbdfcaf05147a58380..5b870ce7ce3055584a0ff38c2b507f4f34e81c4a 100644 (file)
--- a/push.c
+++ b/push.c
@@ -42,7 +42,7 @@
 void
 receive_auth_failed (struct context *c, const struct buffer *buffer)
 {
-  msg (M_VERB0, "AUTH: Received AUTH_FAILED control message");
+  msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer));
   connection_list_set_no_advance(&c->options);
   if (c->options.pull)
     {
diff --git a/ssl.c b/ssl.c
index 572d8e25ff3a23a26e21aa45956ba9ae1c5b6867..095b6a62daaadb7c4583e08bc00202a413a78b3e 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -836,6 +836,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
   const struct tls_options *opt;
   const int max_depth = MAX_CERT_DEPTH;
   struct argv argv = argv_new ();
+  char *serial = NULL;
 
   /* get the tls_session pointer */
   ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
@@ -929,14 +930,12 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
   {
     ASN1_INTEGER *asn1_i;
     BIGNUM *bignum;
-    char *dec;
     asn1_i = X509_get_serialNumber(ctx->current_cert);
     bignum = ASN1_INTEGER_to_BN(asn1_i, NULL);
-    dec = BN_bn2dec(bignum);
+    serial = BN_bn2dec(bignum);
     openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", ctx->error_depth);
-    setenv_str (opt->es, envname, dec);
+    setenv_str (opt->es, envname, serial);
     BN_free(bignum);
-    OPENSSL_free(dec);
   }
 
   /* export current untrusted IP */
@@ -1060,67 +1059,89 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
   /* check peer cert against CRL */
   if (opt->crl_file)
     {
-      X509_CRL *crl=NULL;
-      X509_REVOKED *revoked;
-      BIO *in=NULL;
-      int n,i,retval = 0;
+      if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR)
+       {
+         char fn[256];
+         int fd;
+         if (!openvpn_snprintf(fn, sizeof(fn), "%s%c%s", opt->crl_file, OS_SPECIFIC_DIRSEP, serial))
+           {
+             msg (D_HANDSHAKE, "VERIFY CRL: filename overflow");
+             goto err;
+           }
+         fd = open (fn, O_RDONLY);
+         if (fd >= 0)
+           {
+             msg (D_HANDSHAKE, "VERIFY CRL: certificate serial number %s is revoked", serial);
+             close(fd);
+             goto err;
+           }
+       }
+      else
+       {
+         X509_CRL *crl=NULL;
+         X509_REVOKED *revoked;
+         BIO *in=NULL;
+         int n,i,retval = 0;
 
-      in=BIO_new(BIO_s_file());
+         in=BIO_new(BIO_s_file());
 
-      if (in == NULL) {
-       msg (M_ERR, "CRL: BIO err");
-       goto end;
-      }
-      if (BIO_read_filename(in, opt->crl_file) <= 0) {
-       msg (M_ERR, "CRL: cannot read: %s", opt->crl_file);
-       goto end;
-      }
-      crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
-      if (crl == NULL) {
-       msg (M_ERR, "CRL: cannot read CRL from file %s", opt->crl_file);
-       goto end;
-      }
+         if (in == NULL) {
+           msg (M_ERR, "CRL: BIO err");
+           goto end;
+         }
+         if (BIO_read_filename(in, opt->crl_file) <= 0) {
+           msg (M_ERR, "CRL: cannot read: %s", opt->crl_file);
+           goto end;
+         }
+         crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
+         if (crl == NULL) {
+           msg (M_ERR, "CRL: cannot read CRL from file %s", opt->crl_file);
+           goto end;
+         }
 
-      if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(ctx->current_cert)) != 0) {
-       msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of certificate %s", opt->crl_file, subject);
-       retval = 1;
-       goto end;
-      }
+         if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(ctx->current_cert)) != 0) {
+           msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of certificate %s", opt->crl_file, subject);
+           retval = 1;
+           goto end;
+         }
 
-      n = sk_num(X509_CRL_get_REVOKED(crl));
+         n = sk_num(X509_CRL_get_REVOKED(crl));
 
-      for (i = 0; i < n; i++) {
-       revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i);
-       if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) {
-         msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject);
-         goto end;
-       }
-      }
+         for (i = 0; i < n; i++) {
+           revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i);
+           if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) {
+             msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject);
+             goto end;
+           }
+         }
 
-      retval = 1;
-      msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
+         retval = 1;
+         msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
 
-    end:
+       end:
 
-      BIO_free(in);
-      if (crl)
-       X509_CRL_free (crl);
-      if (!retval)
-       goto err;
+         BIO_free(in);
+         if (crl)
+           X509_CRL_free (crl);
+         if (!retval)
+           goto err;
+       }
     }
 
   msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", ctx->error_depth, subject);
-
   session->verified = true;
+
+ done:
   OPENSSL_free (subject);
+  if (serial)
+    OPENSSL_free(serial);
   argv_reset (&argv);
-  return 1;                    /* Accept connection */
+  return (session->verified == true) ? 1 : 0;
 
  err:
   ERR_clear_error ();
-  OPENSSL_free (subject);
-  argv_reset (&argv);
-  return 0;                     /* Reject connection */
+  session->verified = false;
+  goto done;
 }
 
 void
@@ -1954,7 +1975,7 @@ init_ssl (const struct options *options)
                 {
                  if (!X509_STORE_add_cert(ctx->cert_store,sk_X509_value(ca, i)))
                     msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)");
-                  if (!SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i)))
+                  if (options->tls_server && !SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i)))
                     msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)");
                 }
             }
@@ -2066,11 +2087,11 @@ init_ssl (const struct options *options)
 #endif
        {
          /* Load CA file for verifying peer supplied certificate */
-         status = SSL_CTX_load_verify_locations (ctx, options->ca_file, options->ca_path);
+         status = SSL_CTX_load_verify_locations (ctx, options->ca_file, NULL);
        }
       
       if (!status)
-       msg (M_SSLERR, "Cannot load CA certificate file %s path %s (SSL_CTX_load_verify_locations)", options->ca_file, options->ca_path);
+       msg (M_SSLERR, "Cannot load CA certificate file %s path %s (SSL_CTX_load_verify_locations)", np(options->ca_file), np(options->ca_path));
 
       /* Set a store for certs (CA & CRL) with a lookup on the "capath" hash directory */
       if (options->ca_path) {
@@ -2094,7 +2115,7 @@ init_ssl (const struct options *options)
       }
 
       /* Load names of CAs from file and use it as a client CA list */
-      if (options->ca_file) {
+      if (options->ca_file && options->tls_server) {
         STACK_OF(X509_NAME) *cert_names = NULL;
 #if ENABLE_INLINE_FILES
        if (!strcmp (options->ca_file, INLINE_FILE_TAG) && options->ca_file_inline)
@@ -2108,7 +2129,7 @@ init_ssl (const struct options *options)
          }
         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);
+       SSL_CTX_set_client_CA_list (ctx, cert_names);
       }
     }
 
diff --git a/ssl.h b/ssl.h
index eca3922f7628e48ba67ab45a6aa16293e99fd795..fe494b1037a90064903e3ef9e53a318ebd027da1 100644 (file)
--- a/ssl.h
+++ b/ssl.h
@@ -504,6 +504,7 @@ struct tls_options
 # define SSLF_AUTH_USER_PASS_OPTIONAL  (1<<2)
 # define SSLF_NO_NAME_REMAPPING        (1<<3)
 # define SSLF_OPT_VERIFY               (1<<4)
+# define SSLF_CRL_VERIFY_DIR           (1<<5)
   unsigned int ssl_flags;
 
 #ifdef MANAGEMENT_DEF_AUTH