Hi,

Matthias Andree wrote:
NAK on the patch:

1. unsafe use of strncpy (remember that strncpy does not NUL terminate if
there's no room!), and

You are right, I just noticed the existence of strcpynt for this purpose.

2. without reading ASN1_STRING_to_UTF8() docs, I do not believe that the ASN
extraction is safe in itself.  There is no check for embedded NULs, and this
needs to be checked whenever you convert between NUL-terminated C-strings and
pointer/length strings and vice versa.  There have been prior vulnerabilities,
such as CVE-2009-2666.

You are right - same problem holds true for extract_x509_field_ssl, setenv_x509?
http://openvpn.git.sourceforge.net/git/gitweb.cgi?p=openvpn/openvpn-testing.git;a=blob;f=ssl.c;h=a1268ac2a9291dc1512fa28e3ab4efc65085c952;hb=HEAD#l453

Make sure that the extraction reports failure (aka "return false;") and the
caller deals with that in case there are embedded NULs, IOW strlen() != 
ia5.size.

Given the fetchmail ref, seems like the value returned by
X509_get_ext_d2i needs to be freed with sk_GENERAL_NAME_free afterwards
anyway.

Attached is an updated version of the patch using remotes/origin/feat_misc as base.

Thanks for reviewing.

Markus
>From c750625294b4680ac8a8f2c7216f3796631bbbcb Mon Sep 17 00:00:00 2001
From: Markus Koetter <koet...@rrzn-hiwi.uni-hannover.de>
List-Post: openvpn-devel@lists.sourceforge.net
Date: Wed, 1 Dec 2010 22:03:27 +0100
Subject: [PATCH] x509-username-field - add extv3 support
   - this allows using altSubjectName of the certificate
     to be used for authentication. To use, set
     x509-username-field ext:altSubjectName

Signed-off-by: Markus Koetter <koet...@rrzn-hiwi.uni-hannover.de>
---
 options.c |    3 +-
 ssl.c     |   74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+), 1 deletions(-)

diff --git a/options.c b/options.c
index d0cec7d..1e3fc6e 100644
--- a/options.c
+++ b/options.c
@@ -5647,7 +5647,8 @@ add_option (struct options *options,
     {
       char *s = p[1];
       VERIFY_PERMISSION (OPT_P_GENERAL);
-      while ((*s = toupper(*s)) != '\0') s++; /* Uppercase if necessary */
+      if( strncmp ("ext:",s,4) != 0 )
+        while ((*s = toupper(*s)) != '\0') s++; /* Uppercase if necessary */
       options->x509_username_field = p[1];
     }
 #endif /* USE_SSL */
diff --git a/ssl.c b/ssl.c
index 8644ae4..a69195e 100644
--- a/ssl.c
+++ b/ssl.c
@@ -489,6 +489,65 @@ extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, int
   }
 }

+static 
+bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size)
+{
+  X509_EXTENSION *pExt;
+  char *buf = 0;
+  int length = 0;
+  GENERAL_NAMES *extensions;
+  int nid = OBJ_txt2nid(fieldname);
+
+  extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL);
+  if ( extensions )
+    {
+      int numalts;
+      int i;
+      /* get amount of alternatives, 
+       * RFC2459 claims there MUST be at least 
+       * one, but we don't depend on it... 
+       */
+
+      numalts = sk_GENERAL_NAME_num(extensions);
+
+      /* loop through all alternatives */
+      for (i=0; i<numalts; i++)
+        {
+          /* get a handle to alternative name number i */
+          const GENERAL_NAME *name = sk_GENERAL_NAME_value (extensions, i );
+
+          switch (name->type)
+            {
+              case GEN_EMAIL:
+                ASN1_STRING_to_UTF8((unsigned char**)&buf, name->d.ia5);
+                if ( strlen (buf) != name->d.ia5->length )
+                  {
+                    msg (D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero");
+                    sk_GENERAL_NAME_free (extensions);
+                    OPENSSL_free (buf);
+                    return false;
+                  }
+                strncpynt(out, buf, size);
+                OPENSSL_free(buf);
+                break;
+              case GEN_OTHERNAME:
+              case GEN_DNS:
+              case GEN_X400:
+              case GEN_DIRNAME:
+              case GEN_EDIPARTY:
+              case GEN_URI:
+              case GEN_IPADD:
+              case GEN_RID:
+                return false;
+                break;
+            }
+          }
+        sk_GENERAL_NAME_free (extensions);
+    } else
+      return false;
+  return true;
+}
+
 /*
  * Save X509 fields to environment, using the naming convention:
  *
@@ -774,6 +833,21 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
   string_replace_leading (subject, '-', '_');

   /* extract the username (default is CN) */
+  if (strncmp("ext:",x509_username_field,4) == 0)
+    {
+      if (!extract_x509_extension (ctx->current_cert, x509_username_field+4, common_name, sizeof(common_name)))
+        {
+          if (!ctx->error_depth)
+            {
+              msg (D_TLS_ERRORS, "VERIFY ERROR: could not extract %s extension from X509 subject string ('%s') "
+                                 "-- note that the username length is limited to %d characters",
+                                 x509_username_field+4,
+                                 subject,
+                                 TLS_USERNAME_LEN);
+              goto err;
+            }
+        }
+    } else
   if (!extract_x509_field_ssl (X509_get_subject_name (ctx->current_cert), x509_username_field, common_name, sizeof(common_name)))
     {
       if (!ctx->error_depth)
-- 
1.6.3.3

Reply via email to