Browse code

On server, lock client-provided certs against mid-session TLS renegotiations -- this is similer to how the common name is also locked.

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

james authored on 2009/10/26 00:51:04
Showing 3 changed files
... ...
@@ -1458,8 +1458,9 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
1458 1458
 
1459 1459
       ASSERT (mi->context.c1.tuntap);
1460 1460
 
1461
-      /* lock down the common name so it can't change during future TLS renegotiations */
1461
+      /* lock down the common name and cert hashes so they can't change during future TLS renegotiations */
1462 1462
       tls_lock_common_name (mi->context.c2.tls_multi);
1463
+      tls_lock_cert_hash_set (mi->context.c2.tls_multi);
1463 1464
 
1464 1465
       /* generate a msg() prefix for this client instance */
1465 1466
       generate_prefix (mi);
... ...
@@ -340,6 +340,104 @@ tmp_rsa_cb (SSL * s, int is_export, int keylength)
340 340
 }
341 341
 
342 342
 /*
343
+ * Cert hash functions
344
+ */
345
+static void
346
+cert_hash_remember (struct tls_session *session, const int error_depth, const unsigned char *sha1_hash)
347
+{
348
+  if (error_depth >= 0 && error_depth < MAX_CERT_DEPTH)
349
+    {
350
+      if (!session->cert_hash_set)
351
+	ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set);
352
+      if (!session->cert_hash_set->ch[error_depth])
353
+	ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash);
354
+      {
355
+	struct cert_hash *ch = session->cert_hash_set->ch[error_depth];
356
+	memcpy (ch->sha1_hash, sha1_hash, SHA_DIGEST_LENGTH);
357
+      }
358
+    }
359
+}
360
+
361
+#if 0
362
+static void
363
+cert_hash_print (const struct cert_hash_set *chs, int msglevel)
364
+{
365
+  struct gc_arena gc = gc_new ();
366
+  msg (msglevel, "CERT_HASH");
367
+  if (chs)
368
+    {
369
+      int i;
370
+      for (i = 0; i < MAX_CERT_DEPTH; ++i)
371
+	{
372
+	  const struct cert_hash *ch = chs->ch[i];
373
+	  if (ch)
374
+	    msg (msglevel, "%d:%s", i, format_hex(ch->sha1_hash, SHA_DIGEST_LENGTH, 0, &gc));
375
+	}
376
+    }
377
+  gc_free (&gc);
378
+}
379
+#endif
380
+
381
+static void
382
+cert_hash_free (struct cert_hash_set *chs)
383
+{
384
+  if (chs)
385
+    {
386
+      int i;
387
+      for (i = 0; i < MAX_CERT_DEPTH; ++i)
388
+	free (chs->ch[i]);
389
+      free (chs);
390
+    }
391
+}
392
+
393
+static bool
394
+cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set *chs2)
395
+{
396
+  if (chs1 && chs2)
397
+    {
398
+      int i;
399
+      for (i = 0; i < MAX_CERT_DEPTH; ++i)
400
+	{
401
+	  const struct cert_hash *ch1 = chs1->ch[i];
402
+	  const struct cert_hash *ch2 = chs2->ch[i];
403
+
404
+	  if (!ch1 && !ch2)
405
+	    continue;
406
+	  else if (ch1 && ch2 && !memcmp (ch1->sha1_hash, ch2->sha1_hash, SHA_DIGEST_LENGTH))
407
+	    continue;
408
+	  else
409
+	    return false;
410
+	}
411
+      return true;
412
+    }
413
+  else if (!chs1 && !chs2)
414
+    return true;
415
+  else
416
+    return false;
417
+}
418
+
419
+static struct cert_hash_set *
420
+cert_hash_copy (const struct cert_hash_set *chs)
421
+{
422
+  struct cert_hash_set *dest = NULL;
423
+  if (chs)
424
+    {
425
+      int i;
426
+      ALLOC_OBJ_CLEAR (dest, struct cert_hash_set);
427
+      for (i = 0; i < MAX_CERT_DEPTH; ++i)
428
+	{
429
+	  const struct cert_hash *ch = chs->ch[i];
430
+	  if (ch)
431
+	    {
432
+	      ALLOC_OBJ (dest->ch[i], struct cert_hash);
433
+	      memcpy (dest->ch[i]->sha1_hash, ch->sha1_hash, SHA_DIGEST_LENGTH);
434
+	    }
435
+	}
436
+    }
437
+  return dest;
438
+}
439
+
440
+/*
343 441
  * Extract a field from an X509 subject name.
344 442
  *
345 443
  * Example:
... ...
@@ -603,7 +701,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
603 603
   SSL *ssl;
604 604
   struct tls_session *session;
605 605
   const struct tls_options *opt;
606
-  const int max_depth = 8;
606
+  const int max_depth = MAX_CERT_DEPTH;
607 607
   struct argv argv = argv_new ();
608 608
 
609 609
   /* get the tls_session pointer */
... ...
@@ -645,9 +743,16 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
645 645
 
646 646
   string_mod_sslname (common_name, COMMON_NAME_CHAR_CLASS, opt->ssl_flags);
647 647
 
648
+  cert_hash_remember (session, ctx->error_depth, ctx->current_cert->sha1_hash);
649
+
648 650
 #if 0 /* print some debugging info */
649
-  msg (D_LOW, "LOCAL OPT: %s", opt->local_options);
650
-  msg (D_LOW, "X509: %s", subject);
651
+  {
652
+    struct gc_arena gc = gc_new ();
653
+    msg (M_INFO, "LOCAL OPT[%d]: %s", ctx->error_depth, opt->local_options);
654
+    msg (M_INFO, "X509[%d]: %s", ctx->error_depth, subject);
655
+    msg (M_INFO, "SHA1[%d]: %s", ctx->error_depth, format_hex(ctx->current_cert->sha1_hash, SHA_DIGEST_LENGTH, 0, &gc));
656
+    gc_free (&gc);
657
+  }
651 658
 #endif
652 659
 
653 660
   /* did peer present cert which was signed our root cert? */
... ...
@@ -898,6 +1003,14 @@ tls_lock_common_name (struct tls_multi *multi)
898 898
     multi->locked_cn = string_alloc (cn, NULL);
899 899
 }
900 900
 
901
+void
902
+tls_lock_cert_hash_set (struct tls_multi *multi)
903
+{
904
+  const struct cert_hash_set *chs = multi->session[TM_ACTIVE].cert_hash_set;
905
+  if (chs && !multi->locked_cert_hash_set)
906
+    multi->locked_cert_hash_set = cert_hash_copy (chs);
907
+}
908
+
901 909
 static bool
902 910
 tls_lock_username (struct tls_multi *multi, const char *username)
903 911
 {
... ...
@@ -2251,6 +2364,8 @@ tls_session_free (struct tls_session *session, bool clear)
2251 2251
   if (session->common_name)
2252 2252
     free (session->common_name);
2253 2253
 
2254
+  cert_hash_free (session->cert_hash_set);
2255
+
2254 2256
   if (clear)
2255 2257
     CLEAR (*session);
2256 2258
 }
... ...
@@ -2444,6 +2559,8 @@ tls_multi_free (struct tls_multi *multi, bool clear)
2444 2444
   if (multi->locked_username)
2445 2445
     free (multi->locked_username);
2446 2446
 
2447
+  cert_hash_free (multi->locked_cert_hash_set);
2448
+
2447 2449
   for (i = 0; i < TM_SIZE; ++i)
2448 2450
     tls_session_free (&multi->session[i], false);
2449 2451
 
... ...
@@ -3492,6 +3609,20 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
3492 3492
 	}
3493 3493
     }
3494 3494
 
3495
+  /* Don't allow the cert hashes to change once they have been locked */
3496
+  if (ks->authenticated && multi->locked_cert_hash_set)
3497
+    {
3498
+      const struct cert_hash_set *chs = session->cert_hash_set;
3499
+      if (chs && !cert_hash_compare (chs, multi->locked_cert_hash_set))
3500
+	{
3501
+	  msg (D_TLS_ERRORS, "TLS Auth Error: TLS object CN=%s client-provided SSL certs unexpectedly changed during mid-session reauth",
3502
+	       session->common_name);
3503
+
3504
+	  /* disable the tunnel */
3505
+	  tls_deauthenticate (multi);
3506
+	}
3507
+    }
3508
+
3495 3509
   /* verify --client-config-dir based authentication */
3496 3510
   if (ks->authenticated && session->opt->client_config_dir_exclusive)
3497 3511
     {
... ...
@@ -303,6 +303,21 @@
303 303
 /* #define MEASURE_TLS_HANDSHAKE_STATS */
304 304
 
305 305
 /*
306
+ * Keep track of certificate hashes at various depths
307
+ */
308
+
309
+/* Maximum certificate depth we will allow */
310
+#define MAX_CERT_DEPTH 8
311
+
312
+struct cert_hash {
313
+  unsigned char sha1_hash[SHA_DIGEST_LENGTH];
314
+};
315
+
316
+struct cert_hash_set {
317
+  struct cert_hash *ch[MAX_CERT_DEPTH];
318
+};
319
+
320
+/*
306 321
  * Key material, used as source for PRF-based
307 322
  * key expansion.
308 323
  */
... ...
@@ -518,6 +533,8 @@ struct tls_session
518 518
 
519 519
   char *common_name;
520 520
 
521
+  struct cert_hash_set *cert_hash_set;
522
+
521 523
 #ifdef ENABLE_PF
522 524
   uint32_t common_name_hashval;
523 525
 #endif
... ...
@@ -589,10 +606,11 @@ struct tls_multi
589 589
   int n_soft_errors;   /* errors due to unrecognized or failed-to-authenticate incoming packets */
590 590
 
591 591
   /*
592
-   * Our locked common name and username (cannot change during the life of this tls_multi object)
592
+   * Our locked common name, username, and cert hashes (cannot change during the life of this tls_multi object)
593 593
    */
594 594
   char *locked_cn;
595 595
   char *locked_username;
596
+  struct cert_hash_set *locked_cert_hash_set;
596 597
 
597 598
 #ifdef ENABLE_DEF_AUTH
598 599
   /*
... ...
@@ -692,6 +710,7 @@ bool tls_rec_payload (struct tls_multi *multi,
692 692
 const char *tls_common_name (const struct tls_multi* multi, const bool null);
693 693
 void tls_set_common_name (struct tls_multi *multi, const char *common_name);
694 694
 void tls_lock_common_name (struct tls_multi *multi);
695
+void tls_lock_cert_hash_set (struct tls_multi *multi);
695 696
 
696 697
 #define TLS_AUTHENTICATION_SUCCEEDED  0
697 698
 #define TLS_AUTHENTICATION_FAILED     1