Browse code

Refactor CRL handling

This patch refactors the CRL handling to rely more on the implementation
of the crypto library. It will insert the CRL at the correct time to keep
it up to date, but all additional verification logic is removed from
ssl_verify_<backend>.c. "Less code of our own, less bugs of our own."

In practice, this means extra checks will be performed on the CRL, such as
checking it validBefore and validAfter fields.

This patch was originally written by Ivo Manca, and then molded by Steffan
before sending to the list. All bugs are Steffan's fault.

Thanks also go to Antonio Quartulli for useful feedback. He'll send
follow-up patches to improve CRL handling performance.

Signed-off-by: Ivo Manca <ivo.manca@fox-it.com>
Signed-off-by: Steffan Karger <steffan.karger@fox-it.com>
Acked-by: David Sommerseth <davids@openvpn.net>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <1477670087-30063-1-git-send-email-steffan.karger@fox-it.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12809.html
Signed-off-by: David Sommerseth <davids@openvpn.net>

Steffan Karger authored on 2016/10/29 00:54:47
Showing 10 changed files
... ...
@@ -120,6 +120,12 @@ Deprecated features
120 120
   will then use ``--key-method 2`` by default.  Note that this requires changing
121 121
   the option in both the client and server side configs.
122 122
 
123
+- CRLs are now handled by the crypto library (OpenSSL or mbed TLS), instead of
124
+  inside OpenVPN itself.  The crypto library implementations are more strict
125
+  than the OpenVPN implementation was.  This might reject peer certificates
126
+  that would previously be accepted.  If this occurs, OpenVPN will log the
127
+  crypto library's error description.
128
+
123 129
 
124 130
 User-visible Changes
125 131
 --------------------
... ...
@@ -608,6 +608,12 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
608 608
   /* Check certificate notBefore and notAfter */
609 609
   tls_ctx_check_cert_time(new_ctx);
610 610
 
611
+  /* Read CRL */
612
+  if (options->crl_file && !(options->ssl_flags & SSLF_CRL_VERIFY_DIR))
613
+    {
614
+      tls_ctx_reload_crl(new_ctx, options->crl_file, options->crl_file_inline);
615
+    }
616
+
611 617
   /* Once keys and cert are loaded, load ECDH parameters */
612 618
   if (options->tls_server)
613 619
     tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve);
... ...
@@ -2502,6 +2508,15 @@ tls_process (struct tls_multi *multi,
2502 2502
 	{
2503 2503
 	  ks->state = S_START;
2504 2504
 	  state_change = true;
2505
+
2506
+	  /* Reload the CRL before TLS negotiation */
2507
+	  if (session->opt->crl_file &&
2508
+	      !(session->opt->ssl_flags & SSLF_CRL_VERIFY_DIR))
2509
+	    {
2510
+	      tls_ctx_reload_crl(&session->opt->ssl_ctx,
2511
+		  session->opt->crl_file, session->opt->crl_file_inline);
2512
+	    }
2513
+
2505 2514
 	  dmsg (D_TLS_DEBUG_MED, "STATE S_START");
2506 2515
 	}
2507 2516
 
... ...
@@ -346,6 +346,17 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
346 346
 void key_state_ssl_free(struct key_state_ssl *ks_ssl);
347 347
 
348 348
 /**
349
+ * Reload the Certificate Revocation List for the SSL channel
350
+ *
351
+ * @param ssl_ctx       The TLS context to use when reloading the CRL
352
+ * @param crl_file      The file name to load the CRL from, or
353
+ *                      "[[INLINE]]" in the case of inline files.
354
+ * @param crl_inline    A string containing the CRL
355
+ */
356
+void tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx,
357
+    const char *crl_file, const char *crl_inline);
358
+
359
+/**
349 360
  * Keying Material Exporters [RFC 5705] allows additional keying material to be
350 361
  * derived from existing TLS channel. This exported keying material can then be
351 362
  * used for a variety of purposes.
... ...
@@ -120,6 +120,12 @@ tls_ctx_free(struct tls_root_ctx *ctx)
120 120
       if (ctx->dhm_ctx)
121 121
 	free(ctx->dhm_ctx);
122 122
 
123
+      mbedtls_x509_crl_free(ctx->crl);
124
+      if (ctx->crl)
125
+	{
126
+	  free(ctx->crl);
127
+	}
128
+
123 129
 #if defined(ENABLE_PKCS11)
124 130
       if (ctx->priv_key_pkcs11 != NULL) {
125 131
 	  mbedtls_pkcs11_priv_key_free(ctx->priv_key_pkcs11);
... ...
@@ -764,6 +770,41 @@ static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) {
764 764
   }
765 765
 }
766 766
 
767
+void
768
+tls_ctx_reload_crl(struct tls_root_ctx *ctx, const char *crl_file,
769
+    const char *crl_inline)
770
+{
771
+  ASSERT (crl_file);
772
+
773
+  if (ctx->crl == NULL)
774
+    {
775
+      ALLOC_OBJ_CLEAR(ctx->crl, mbedtls_x509_crl);
776
+    }
777
+  mbedtls_x509_crl_free(ctx->crl);
778
+
779
+  if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline)
780
+    {
781
+      if (!mbed_ok(mbedtls_x509_crl_parse(ctx->crl,
782
+	(const unsigned char *)crl_inline, strlen(crl_inline)+1)))
783
+	{
784
+	  msg (M_WARN, "CRL: cannot parse inline CRL");
785
+	  goto err;
786
+	}
787
+    }
788
+  else
789
+    {
790
+      if (!mbed_ok(mbedtls_x509_crl_parse_file(ctx->crl, crl_file)))
791
+	{
792
+	  msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file);
793
+	  goto err;
794
+	}
795
+    }
796
+  return;
797
+
798
+err:
799
+  mbedtls_x509_crl_free(ctx->crl);
800
+}
801
+
767 802
 void key_state_ssl_init(struct key_state_ssl *ks_ssl,
768 803
     const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session)
769 804
 {
... ...
@@ -816,7 +857,7 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
816 816
   mbedtls_ssl_conf_verify (&ks_ssl->ssl_config, verify_callback, session);
817 817
 
818 818
   /* TODO: mbed TLS does not currently support sending the CA chain to the client */
819
-  mbedtls_ssl_conf_ca_chain (&ks_ssl->ssl_config, ssl_ctx->ca_chain, NULL );
819
+  mbedtls_ssl_conf_ca_chain (&ks_ssl->ssl_config, ssl_ctx->ca_chain, ssl_ctx->crl);
820 820
 
821 821
   /* Initialize minimum TLS version */
822 822
   {
... ...
@@ -73,6 +73,7 @@ struct tls_root_ctx {
73 73
     mbedtls_x509_crt *crt_chain;	/**< Local Certificate chain */
74 74
     mbedtls_x509_crt *ca_chain;		/**< CA chain for remote verification */
75 75
     mbedtls_pk_context *priv_key;	/**< Local private key */
76
+    mbedtls_x509_crl *crl;              /**< Certificate Revocation List */
76 77
 #if defined(ENABLE_PKCS11)
77 78
     mbedtls_pkcs11_context *priv_key_pkcs11;	/**< PKCS11 private key */
78 79
 #endif
... ...
@@ -771,6 +771,64 @@ end:
771 771
   return ret;
772 772
 }
773 773
 
774
+void
775
+tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
776
+        const char *crl_inline)
777
+{
778
+  X509_CRL *crl = NULL;
779
+  BIO *in = NULL;
780
+
781
+  X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
782
+  if (!store)
783
+    crypto_msg (M_FATAL, "Cannot get certificate store");
784
+
785
+  /* Always start with a cleared CRL list, for that we
786
+   * we need to manually find the CRL object from the stack
787
+   * and remove it */
788
+  for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++)
789
+    {
790
+      X509_OBJECT* obj = sk_X509_OBJECT_value(store->objs, i);
791
+      ASSERT(obj);
792
+      if (obj->type == X509_LU_CRL)
793
+	{
794
+	  sk_X509_OBJECT_delete(store->objs, i);
795
+	  X509_OBJECT_free_contents(obj);
796
+	  OPENSSL_free(obj);
797
+	}
798
+    }
799
+
800
+  X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
801
+
802
+  if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline)
803
+    in = BIO_new_mem_buf ((char *)crl_inline, -1);
804
+  else
805
+    in = BIO_new_file (crl_file, "r");
806
+
807
+  if (in == NULL)
808
+    {
809
+      msg (M_WARN, "CRL: cannot read: %s", crl_file);
810
+      goto end;
811
+    }
812
+
813
+  crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
814
+  if (crl == NULL)
815
+    {
816
+      msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file);
817
+      goto end;
818
+    }
819
+
820
+  if (!X509_STORE_add_crl(store, crl))
821
+    {
822
+      msg (M_WARN, "CRL: cannot add %s to store", crl_file);
823
+      goto end;
824
+    }
825
+
826
+end:
827
+  X509_CRL_free(crl);
828
+  BIO_free(in);
829
+}
830
+
831
+
774 832
 #ifdef MANAGMENT_EXTERNAL_KEY
775 833
 
776 834
 /* encrypt */
... ...
@@ -672,15 +672,18 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep
672 672
   if (opt->crl_file)
673 673
     {
674 674
       if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR)
675
-      {
676
-	if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert))
677
-	  goto cleanup;
678
-      }
675
+	{
676
+	  if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert))
677
+	    goto cleanup;
678
+	}
679 679
       else
680
-      {
681
-	if (SUCCESS != x509_verify_crl(opt->crl_file, opt->crl_file_inline, cert, subject))
682
-	  goto cleanup;
683
-      }
680
+	{
681
+	  if (tls_verify_crl_missing (opt))
682
+	    {
683
+	      msg (D_TLS_ERRORS, "VERIFY ERROR: CRL not loaded");
684
+	      goto cleanup;
685
+	    }
686
+	}
684 687
     }
685 688
 
686 689
   msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", cert_depth, subject);
... ...
@@ -252,19 +252,12 @@ result_t x509_verify_cert_eku (openvpn_x509_cert_t *x509, const char * const exp
252 252
  */
253 253
 result_t x509_write_pem(FILE *peercert_file, openvpn_x509_cert_t *peercert);
254 254
 
255
-/*
256
- * Check the certificate against a CRL file.
257
- *
258
- * @param crl_file	File name of the CRL file
259
- * @param cert		Certificate to verify
260
- * @param crl_inline	Contents of the crl file if it is inlined
261
- * @param subject	Subject of the given certificate
262
- *
263
- * @return 		\c SUCCESS if the CRL was not signed by the issuer of the
264
- * 			certificate or does not contain an entry for it.
265
- * 			\c FAILURE otherwise.
255
+/**
256
+ * Return true iff a CRL is configured, but is not loaded.  This can be caused
257
+ * by e.g. a CRL parsing error, a missing CRL file or CRL file permission
258
+ * errors.  (These conditions are checked upon startup, but the CRL might be
259
+ * updated and reloaded during runtime.)
266 260
  */
267
-result_t x509_verify_crl(const char *crl_file, const char *crl_inline,
268
-                         openvpn_x509_cert_t *cert, const char *subject);
261
+bool tls_verify_crl_missing(const struct tls_options *opt);
269 262
 
270 263
 #endif /* SSL_VERIFY_BACKEND_H_ */
... ...
@@ -497,59 +497,15 @@ x509_write_pem(FILE *peercert_file, mbedtls_x509_crt *peercert)
497 497
     return FAILURE;
498 498
 }
499 499
 
500
-/*
501
- * check peer cert against CRL
502
- */
503
-result_t
504
-x509_verify_crl(const char *crl_file, const char *crl_inline,
505
-                mbedtls_x509_crt *cert, const char *subject)
500
+bool
501
+tls_verify_crl_missing(const struct tls_options *opt)
506 502
 {
507
-  result_t retval = FAILURE;
508
-  mbedtls_x509_crl crl = {0};
509
-  struct gc_arena gc = gc_new();
510
-  char *serial;
511
-
512
-  if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline)
513
-    {
514
-      if (!mbed_ok(mbedtls_x509_crl_parse(&crl,
515
-	  (const unsigned char *)crl_inline, strlen(crl_inline)+1)))
516
-        {
517
-           msg (M_WARN, "CRL: cannot parse inline CRL");
518
-           goto end;
519
-        }
520
-    }
521
-  else
522
-    {
523
-      if (!mbed_ok(mbedtls_x509_crl_parse_file(&crl, crl_file)))
524
-      {
525
-          msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file);
526
-          goto end;
527
-      }
528
-  }
529
-
530
-  if(cert->issuer_raw.len != crl.issuer_raw.len ||
531
-      memcmp(crl.issuer_raw.p, cert->issuer_raw.p, crl.issuer_raw.len) != 0)
532
-    {
533
-      msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of "
534
-	  "certificate %s", crl_file, subject);
535
-      retval = SUCCESS;
536
-      goto end;
537
-    }
538
-
539
-  if (!mbed_ok(mbedtls_x509_crt_is_revoked(cert, &crl)))
503
+  if (opt->crl_file && !(opt->ssl_flags & SSLF_CRL_VERIFY_DIR)
504
+      && (opt->ssl_ctx.crl == NULL || opt->ssl_ctx.crl->version == 0))
540 505
     {
541
-      serial = backend_x509_get_serial_hex(cert, &gc);
542
-      msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE"));
543
-      goto end;
506
+      return true;
544 507
     }
545
-
546
-  retval = SUCCESS;
547
-  msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
548
-
549
-end:
550
-  gc_free(&gc);
551
-  mbedtls_x509_crl_free(&crl);
552
-  return retval;
508
+  return false;
553 509
 }
554 510
 
555 511
 #endif /* #if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */
... ...
@@ -70,15 +70,28 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
70 70
       /* get the X509 name */
71 71
       char *subject = x509_get_subject(ctx->current_cert, &gc);
72 72
 
73
-      if (subject)
73
+      if (!subject)
74 74
 	{
75
-	  /* Remote site specified a certificate, but it's not correct */
76
-	  msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s",
77
-	      ctx->error_depth,
78
-	      X509_verify_cert_error_string (ctx->error),
79
-	      subject);
75
+	  subject = "(Failed to retrieve certificate subject)";
80 76
 	}
81 77
 
78
+      /* Log and ignore missing CRL errors */
79
+      if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL)
80
+	{
81
+	  msg (D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s",
82
+	       ctx->error_depth,
83
+	       X509_verify_cert_error_string (ctx->error),
84
+	       subject);
85
+	  ret = 1;
86
+	  goto cleanup;
87
+	}
88
+
89
+      /* Remote site specified a certificate, but it's not correct */
90
+      msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s",
91
+	   ctx->error_depth,
92
+	   X509_verify_cert_error_string (ctx->error),
93
+	   subject);
94
+
82 95
       ERR_clear_error();
83 96
 
84 97
       session->verified = false;
... ...
@@ -625,63 +638,28 @@ x509_write_pem(FILE *peercert_file, X509 *peercert)
625 625
   return SUCCESS;
626 626
 }
627 627
 
628
-/*
629
- * check peer cert against CRL
630
- */
631
-result_t
632
-x509_verify_crl(const char *crl_file, const char* crl_inline,
633
-                X509 *peer_cert, const char *subject)
628
+bool
629
+tls_verify_crl_missing(const struct tls_options *opt)
634 630
 {
635
-  X509_CRL *crl=NULL;
636
-  X509_REVOKED *revoked;
637
-  BIO *in=NULL;
638
-  int n,i;
639
-  result_t retval = FAILURE;
640
-  struct gc_arena gc = gc_new();
641
-  char *serial;
642
-
643
-  if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline)
644
-    in = BIO_new_mem_buf ((char *)crl_inline, -1);
645
-  else
646
-    in = BIO_new_file (crl_file, "r");
647
-
648
-  if (in == NULL) {
649
-    msg (M_WARN, "CRL: cannot read: %s", crl_file);
650
-    goto end;
651
-  }
652
-  crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
653
-  if (crl == NULL) {
654
-    msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file);
655
-    goto end;
656
-  }
657
-
658
-  if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(peer_cert)) != 0) {
659
-    msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of "
660
-	"certificate %s", crl_file, subject);
661
-    retval = SUCCESS;
662
-    goto end;
663
-  }
664
-
665
-  n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
666
-  for (i = 0; i < n; i++) {
667
-    revoked = (X509_REVOKED *)sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
668
-    if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(peer_cert)) == 0) {
669
-      serial = backend_x509_get_serial_hex(peer_cert, &gc);
670
-      msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE"));
671
-      goto end;
631
+  if (!opt->crl_file || (opt->ssl_flags & SSLF_CRL_VERIFY_DIR))
632
+    {
633
+      return false;
672 634
     }
673
-  }
674
-
675
-  retval = SUCCESS;
676
-  msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
677 635
 
678
-end:
679
-  gc_free(&gc);
680
-  BIO_free(in);
681
-  if (crl)
682
-    X509_CRL_free (crl);
636
+  X509_STORE *store = SSL_CTX_get_cert_store(opt->ssl_ctx.ctx);
637
+  if (!store)
638
+    crypto_msg (M_FATAL, "Cannot get certificate store");
683 639
 
684
-  return retval;
640
+  for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++)
641
+    {
642
+      X509_OBJECT* obj = sk_X509_OBJECT_value(store->objs, i);
643
+      ASSERT(obj);
644
+      if (obj->type == X509_LU_CRL)
645
+	{
646
+	  return false;
647
+	}
648
+    }
649
+  return true;
685 650
 }
686 651
 
687 652
 #endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) */