Browse code

Modified extract_x509_field_ssl to return a status value indicating success/error, and any truncation of output due to an insufficiently large output buffer will be cause for error.

In verify_callback, read X509 Subject Name without truncation.

In verify_callback, rather than silently truncating Common Name at
64 bytes, throw an error if Common Name is larger than 64 bytes.


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

james authored on 2008/07/19 12:33:27
Showing 1 changed files
... ...
@@ -347,8 +347,11 @@ tmp_rsa_cb (SSL * s, int is_export, int keylength)
347 347
  * /C=US/ST=CO/L=Denver/O=ORG/CN=First-CN/CN=Test-CA/Email=jim@yonan.net
348 348
  *
349 349
  * The common name is 'Test-CA'
350
+ *
351
+ * Return true on success, false on error (insufficient buffer size in 'out'
352
+ * to contain result is grounds for error).
350 353
  */
351
-static void
354
+static bool
352 355
 extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, int size)
353 356
 {
354 357
   int lastpos = -1;
... ...
@@ -367,21 +370,26 @@ extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, int
367 367
 
368 368
   /* Nothing found */
369 369
   if (lastpos == -1)
370
-    return;
370
+    return false;
371 371
 
372 372
   x509ne = X509_NAME_get_entry(x509, lastpos);
373 373
   if (!x509ne)
374
-    return;
374
+    return false;
375 375
 
376 376
   asn1 = X509_NAME_ENTRY_get_data(x509ne);
377 377
   if (!asn1)
378
-    return;
378
+    return false;
379 379
   tmp = ASN1_STRING_to_UTF8(&buf, asn1);
380 380
   if (tmp <= 0)
381
-    return;
381
+    return false;
382 382
 
383 383
   strncpynt(out, (char *)buf, size);
384
-  OPENSSL_free(buf);
384
+
385
+  {
386
+    const bool ret = (strlen ((char *)buf) < size);
387
+    OPENSSL_free (buf);
388
+    return ret;
389
+  }
385 390
 }
386 391
 
387 392
 static void
... ...
@@ -529,7 +537,7 @@ print_nsCertType (int type)
529 529
 static int
530 530
 verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
531 531
 {
532
-  char subject[256];
532
+  char *subject = NULL;
533 533
   char envname[64];
534 534
   char common_name[TLS_CN_LEN];
535 535
   SSL *ssl;
... ...
@@ -548,22 +556,28 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
548 548
   session->verified = false;
549 549
 
550 550
   /* get the X509 name */
551
-  X509_NAME_oneline (X509_get_subject_name (ctx->current_cert), subject,
552
-		     sizeof (subject));
553
-  subject[sizeof (subject) - 1] = '\0';
551
+  subject = X509_NAME_oneline (X509_get_subject_name (ctx->current_cert), NULL, 0);
552
+  if (!subject)
553
+    {
554
+      msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, could not extract X509 subject string from certificate", ctx->error_depth);
555
+      goto err;
556
+    }
554 557
 
555 558
   /* enforce character class restrictions in X509 name */
556 559
   string_mod (subject, X509_NAME_CHAR_CLASS, 0, '_');
557 560
   string_replace_leading (subject, '-', '_');
558 561
 
559
-  msg (M_INFO, "X509: '%s'", subject); // JYFIXME
560
-
561 562
   /* extract the common name */
562
-#ifdef USE_OLD_EXTRACT_X509_FIELD
563
-  extract_x509_field (subject, "CN", common_name, TLS_CN_LEN);
564
-#else
565
-  extract_x509_field_ssl (X509_get_subject_name (ctx->current_cert), "CN", common_name, TLS_CN_LEN);
566
-#endif
563
+  if (!extract_x509_field_ssl (X509_get_subject_name (ctx->current_cert), "CN", common_name, TLS_CN_LEN))
564
+    {
565
+      if (!ctx->error_depth)
566
+	{
567
+	  msg (D_TLS_ERRORS, "VERIFY ERROR: could not extract Common Name from X509 subject string ('%s') -- note that the Common Name length is limited to %d characters",
568
+	       subject,
569
+	       TLS_CN_LEN);
570
+	  goto err;
571
+	}
572
+    }
567 573
 
568 574
   string_mod (common_name, COMMON_NAME_CHAR_CLASS, 0, '_');
569 575
 
... ...
@@ -786,10 +800,12 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
786 786
   msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", ctx->error_depth, subject);
787 787
 
788 788
   session->verified = true;
789
+  free (subject);
789 790
   return 1;			/* Accept connection */
790 791
 
791 792
  err:
792 793
   ERR_clear_error ();
794
+  free (subject);
793 795
   return 0;                     /* Reject connection */
794 796
 }
795 797
 
... ...
@@ -3291,7 +3307,14 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
3291 3291
 	s1 = verify_user_pass_plugin (session, up, raw_username);
3292 3292
       if (session->opt->auth_user_pass_verify_script)
3293 3293
 	s2 = verify_user_pass_script (session, up);
3294
-      
3294
+
3295
+      /* check sizing of username if it will become our common name */
3296
+      if (session->opt->username_as_common_name && strlen (up->username) >= TLS_CN_LEN)
3297
+	{
3298
+	  msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_CN_LEN);
3299
+	  s1 = OPENVPN_PLUGIN_FUNC_ERROR;
3300
+	}
3301
+
3295 3302
       /* auth succeeded? */
3296 3303
       if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS
3297 3304
 #ifdef PLUGIN_DEF_AUTH
... ...
@@ -4783,25 +4806,6 @@ done:
4783 4783
   return BSTR (&out);
4784 4784
 }
4785 4785
 
4786
-#ifdef EXTRACT_X509_FIELD_TEST
4787
-
4788
-void
4789
-extract_x509_field_test (void)
4790
-{
4791
-  char line[8];
4792
-  char field[4];
4793
-  static const char field_name[] = "CN";
4794
-
4795
-  while (fgets (line, sizeof (line), stdin))
4796
-    {
4797
-      chomp (line);
4798
-      extract_x509_field (line, field_name, field, sizeof (field));
4799
-      printf ("CN: '%s'\n", field);
4800
-    }
4801
-}
4802
-
4803
-#endif
4804
-
4805 4786
 #else
4806 4787
 static void dummy(void) {}
4807 4788
 #endif /* USE_CRYPTO && USE_SSL*/