Browse code

Add SHA256 fingerprint support

Add SHA256 fingerprint support for both the normal exported fingerprints
(tls_digest_n -> tls_digest_sha256_n), as well as for --x509-track.

Also switch to using the SHA256 fingerprint instead of the SHA1 fingerprint
internally, in cert_hash_remember() / cert_hash_compare(). And instead of
updating an #if 0'd code block that has been disabled since 2009, just
remove that.

This should take care of trac #675.

v2: update openvpn.8 accordingly

[ DS: This commit squashes in the clean-up cert_hash_remember scoping patch,
as it is highly related and tied to this primary patch ]

Signed-off-by: Steffan Karger <steffan@karger.me>
Acked-by: David Sommerseth <davids@openvpn.net>
Message-Id: 1462479247-21854-1-git-send-email-steffan@karger.me
Message-Id: 1474055635-7427-1-git-send-email-steffan@karger.me
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg11859.html
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12464.html
Signed-off-by: David Sommerseth <davids@openvpn.net>

Steffan Karger authored on 2016/05/06 05:14:07
Showing 6 changed files
... ...
@@ -6443,9 +6443,8 @@ Set prior to execution of the
6443 6443
 script.
6444 6444
 .\"*********************************************************
6445 6445
 .TP
6446
-.B tls_digest_{n}
6447
-Contains the certificate SHA1 fingerprint/digest hash value,
6448
-where
6446
+.B tls_digest_{n} / tls_digest_sha256_{n}
6447
+Contains the certificate SHA1 / SHA256 fingerprint, where
6449 6448
 .B n
6450 6449
 is the verification level.  Only set for TLS connections.  Set prior
6451 6450
 to execution of
... ...
@@ -191,40 +191,25 @@ tls_username (const struct tls_multi *multi, const bool null)
191 191
 }
192 192
 
193 193
 void
194
-cert_hash_remember (struct tls_session *session, const int error_depth, const unsigned char *sha1_hash)
194
+cert_hash_remember (struct tls_session *session, const int error_depth,
195
+    const struct buffer *cert_hash)
195 196
 {
196 197
   if (error_depth >= 0 && error_depth < MAX_CERT_DEPTH)
197 198
     {
198 199
       if (!session->cert_hash_set)
199
-	ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set);
200
+	{
201
+	  ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set);
202
+	}
200 203
       if (!session->cert_hash_set->ch[error_depth])
201
-	ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash);
202
-      {
203
-	struct cert_hash *ch = session->cert_hash_set->ch[error_depth];
204
-	memcpy (ch->sha1_hash, sha1_hash, SHA_DIGEST_LENGTH);
205
-      }
206
-    }
207
-}
208
-
209
-#if 0
210
-static void
211
-cert_hash_print (const struct cert_hash_set *chs, int msglevel)
212
-{
213
-  struct gc_arena gc = gc_new ();
214
-  msg (msglevel, "CERT_HASH");
215
-  if (chs)
216
-    {
217
-      int i;
218
-      for (i = 0; i < MAX_CERT_DEPTH; ++i)
219 204
 	{
220
-	  const struct cert_hash *ch = chs->ch[i];
221
-	  if (ch)
222
-	    msg (msglevel, "%d:%s", i, format_hex(ch->sha1_hash, SHA_DIGEST_LENGTH, 0, &gc));
205
+	  ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash);
223 206
 	}
207
+
208
+      struct cert_hash *ch = session->cert_hash_set->ch[error_depth];
209
+      ASSERT (sizeof (ch->sha256_hash) == BLEN (cert_hash));
210
+      memcpy (ch->sha256_hash, BPTR (cert_hash), sizeof (ch->sha256_hash));
224 211
     }
225
-  gc_free (&gc);
226 212
 }
227
-#endif
228 213
 
229 214
 void
230 215
 cert_hash_free (struct cert_hash_set *chs)
... ...
@@ -251,7 +236,8 @@ cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set
251 251
 
252 252
 	  if (!ch1 && !ch2)
253 253
 	    continue;
254
-	  else if (ch1 && ch2 && !memcmp (ch1->sha1_hash, ch2->sha1_hash, SHA_DIGEST_LENGTH))
254
+	  else if (ch1 && ch2 && !memcmp (ch1->sha256_hash, ch2->sha256_hash,
255
+	      sizeof(ch1->sha256_hash)))
255 256
 	    continue;
256 257
 	  else
257 258
 	    return false;
... ...
@@ -278,7 +264,8 @@ cert_hash_copy (const struct cert_hash_set *chs)
278 278
 	  if (ch)
279 279
 	    {
280 280
 	      ALLOC_OBJ (dest->ch[i], struct cert_hash);
281
-	      memcpy (dest->ch[i]->sha1_hash, ch->sha1_hash, SHA_DIGEST_LENGTH);
281
+	      memcpy (dest->ch[i]->sha256_hash, ch->sha256_hash,
282
+		  sizeof(dest->ch[i]->sha256_hash));
282 283
 	    }
283 284
 	}
284 285
     }
... ...
@@ -416,13 +403,19 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert
416 416
   setenv_str (es, envname, common_name);
417 417
 #endif
418 418
 
419
-  /* export X509 cert SHA1 fingerprint */
419
+  /* export X509 cert fingerprints */
420 420
   {
421
-    unsigned char *sha1_hash = x509_get_sha1_hash(peer_cert, &gc);
421
+    struct buffer sha1 = x509_get_sha1_fingerprint(peer_cert, &gc);
422
+    struct buffer sha256 = x509_get_sha256_fingerprint(peer_cert, &gc);
422 423
 
423 424
     openvpn_snprintf (envname, sizeof(envname), "tls_digest_%d", cert_depth);
424
-    setenv_str (es, envname, format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1,
425
-					  ":", &gc));
425
+    setenv_str (es, envname,
426
+	format_hex_ex(BPTR(&sha1), BLEN(&sha1), 0, 1, ":", &gc));
427
+
428
+    openvpn_snprintf (envname, sizeof(envname), "tls_digest_sha256_%d",
429
+	cert_depth);
430
+    setenv_str (es, envname,
431
+	format_hex_ex(BPTR(&sha256), BLEN(&sha256), 0, 1, ":", &gc));
426 432
   }
427 433
 
428 434
   /* export serial number as environmental variable */
... ...
@@ -638,8 +631,8 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep
638 638
   /* verify level 1 cert, i.e. the CA that signed our leaf cert */
639 639
   if (cert_depth == 1 && opt->verify_hash)
640 640
     {
641
-      unsigned char *sha1_hash = x509_get_sha1_hash(cert, &gc);
642
-      if (memcmp (sha1_hash, opt->verify_hash, SHA_DIGEST_LENGTH))
641
+      struct buffer sha1_hash = x509_get_sha1_fingerprint(cert, &gc);
642
+      if (memcmp (BPTR (&sha1_hash), opt->verify_hash, BLEN(&sha1_hash)))
643 643
       {
644 644
 	msg (D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed");
645 645
 	goto cleanup;
... ...
@@ -55,7 +55,7 @@
55 55
 
56 56
 /** Structure containing the hash for a single certificate */
57 57
 struct cert_hash {
58
-  unsigned char sha1_hash[SHA_DIGEST_LENGTH]; /**< The SHA1 hash for a certificate */
58
+  unsigned char sha256_hash[256/8];
59 59
 };
60 60
 
61 61
 /** Structure containing the hashes for a full certificate chain */
... ...
@@ -66,10 +66,10 @@ result_t verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int
66 66
  *
67 67
  * @param session	TLS Session associated with this tunnel
68 68
  * @param cert_depth	Depth of the current certificate
69
- * @param sha1_hash	Hash of the current certificate
69
+ * @param cert_hash	Hash of the current certificate
70 70
  */
71 71
 void cert_hash_remember (struct tls_session *session, const int cert_depth,
72
-    const unsigned char *sha1_hash);
72
+    const struct buffer *cert_hash);
73 73
 
74 74
 /*
75 75
  * Library-specific functions.
... ...
@@ -87,14 +87,27 @@ void cert_hash_remember (struct tls_session *session, const int cert_depth,
87 87
  */
88 88
 char *x509_get_subject (openvpn_x509_cert_t *cert, struct gc_arena *gc);
89 89
 
90
-/* Retrieve the certificate's SHA1 hash.
90
+/**
91
+ * Retrieve the certificate's SHA1 fingerprint.
91 92
  *
92
- * @param cert		Certificate to retrieve the hash from.
93
+ * @param cert		Certificate to retrieve the fingerprint from.
93 94
  * @param gc		Garbage collection arena to use when allocating string.
94 95
  *
95
- * @return 		a string containing the SHA1 hash of the certificate
96
+ * @return 		a string containing the certificate fingerprint
96 97
  */
97
-unsigned char *x509_get_sha1_hash (openvpn_x509_cert_t *cert, struct gc_arena *gc);
98
+struct buffer x509_get_sha1_fingerprint (openvpn_x509_cert_t *cert,
99
+    struct gc_arena *gc);
100
+
101
+/**
102
+ * Retrieve the certificate's SHA256 fingerprint.
103
+ *
104
+ * @param cert		Certificate to retrieve the fingerprint from.
105
+ * @param gc		Garbage collection arena to use when allocating string.
106
+ *
107
+ * @return 		a string containing the certificate fingerprint
108
+ */
109
+struct buffer x509_get_sha256_fingerprint (openvpn_x509_cert_t *cert,
110
+    struct gc_arena *gc);
98 111
 
99 112
 /*
100 113
  * Retrieve the certificate's username from the specified field.
... ...
@@ -60,7 +60,8 @@ verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth,
60 60
   session->verified = false;
61 61
 
62 62
   /* Remember certificate hash */
63
-  cert_hash_remember (session, cert_depth, x509_get_sha1_hash(cert, &gc));
63
+  struct buffer cert_fingerprint = x509_get_sha256_fingerprint (cert, &gc);
64
+  cert_hash_remember (session, cert_depth, &cert_fingerprint);
64 65
 
65 66
   /* did peer present cert which was signed by our root cert? */
66 67
   if (*flags != 0)
... ...
@@ -196,12 +197,29 @@ backend_x509_get_serial_hex (mbedtls_x509_crt *cert, struct gc_arena *gc)
196 196
   return buf;
197 197
 }
198 198
 
199
-unsigned char *
200
-x509_get_sha1_hash (mbedtls_x509_crt *cert, struct gc_arena *gc)
199
+static struct buffer
200
+x509_get_fingerprint (const mbedtls_md_info_t *md_info, mbedtls_x509_crt *cert,
201
+    struct gc_arena *gc)
201 202
 {
202
-  unsigned char *sha1_hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc);
203
-  mbedtls_sha1(cert->raw.p, cert->tbs.len, sha1_hash);
204
-  return sha1_hash;
203
+  const size_t md_size = mbedtls_md_get_size (md_info);
204
+  struct buffer fingerprint = alloc_buf_gc (md_size, gc);
205
+  mbedtls_md(md_info, cert->raw.p, cert->tbs.len, BPTR (&fingerprint));
206
+  ASSERT (buf_inc_len(&fingerprint, md_size));
207
+  return fingerprint;
208
+}
209
+
210
+struct buffer
211
+x509_get_sha1_fingerprint (mbedtls_x509_crt *cert, struct gc_arena *gc)
212
+{
213
+  return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1),
214
+      cert, gc);
215
+}
216
+
217
+struct buffer
218
+x509_get_sha256_fingerprint (mbedtls_x509_crt *cert, struct gc_arena *gc)
219
+{
220
+  return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
221
+      cert, gc);
205 222
 }
206 223
 
207 224
 char *
... ...
@@ -294,12 +312,20 @@ x509_setenv_track (const struct x509_track *xt, struct env_set *es,
294 294
     {
295 295
       if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
296 296
 	{
297
-	  if (0 == strcmp(xt->name, "SHA1"))
297
+	  if (0 == strcmp(xt->name, "SHA1") || 0 == strcmp(xt->name, "SHA256"))
298 298
 	    {
299
-	      /* SHA1 fingerprint is not part of X509 structure */
300
-	      unsigned char *sha1_hash = x509_get_sha1_hash(cert, &gc);
301
-	      char *sha1_fingerprint = format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1 | FHE_CAPS, ":", &gc);
302
-	      do_setenv_x509(es, xt->name, sha1_fingerprint, depth);
299
+	      /* Fingerprint is not part of X509 structure */
300
+	      struct buffer cert_hash;
301
+	      char *fingerprint;
302
+
303
+	      if (0 == strcmp(xt->name, "SHA1"))
304
+		cert_hash = x509_get_sha1_fingerprint(cert, &gc);
305
+	      else
306
+		cert_hash = x509_get_sha256_fingerprint(cert, &gc);
307
+
308
+	      fingerprint = format_hex_ex(BPTR(&cert_hash),
309
+		  BLEN(&cert_hash), 0, 1 | FHE_CAPS, ":", &gc);
310
+	      do_setenv_x509(es, xt->name, fingerprint, depth);
303 311
 	    }
304 312
 	  else
305 313
 	    {
... ...
@@ -61,8 +61,8 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
61 61
   session = (struct tls_session *) SSL_get_ex_data (ssl, mydata_index);
62 62
   ASSERT (session);
63 63
 
64
-  cert_hash_remember (session, ctx->error_depth,
65
-      x509_get_sha1_hash(ctx->current_cert, &gc));
64
+  struct buffer cert_hash = x509_get_sha256_fingerprint(ctx->current_cert, &gc);
65
+  cert_hash_remember (session, ctx->error_depth, &cert_hash);
66 66
 
67 67
   /* did peer present cert which was signed by our root cert? */
68 68
   if (!preverify_ok)
... ...
@@ -248,11 +248,21 @@ backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc)
248 248
   return format_hex_ex(asn1_i->data, asn1_i->length, 0, 1, ":", gc);
249 249
 }
250 250
 
251
-unsigned char *
252
-x509_get_sha1_hash (X509 *cert, struct gc_arena *gc)
251
+struct buffer
252
+x509_get_sha1_fingerprint (X509 *cert, struct gc_arena *gc)
253 253
 {
254
-  unsigned char *hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc);
255
-  memcpy(hash, cert->sha1_hash, SHA_DIGEST_LENGTH);
254
+  struct buffer hash = alloc_buf_gc(sizeof(cert->sha1_hash), gc);
255
+  memcpy(BPTR(&hash), cert->sha1_hash, sizeof(cert->sha1_hash));
256
+  ASSERT (buf_inc_len(&hash, sizeof (cert->sha1_hash)));
257
+  return hash;
258
+}
259
+
260
+struct buffer
261
+x509_get_sha256_fingerprint (X509 *cert, struct gc_arena *gc)
262
+{
263
+  struct buffer hash = alloc_buf_gc((EVP_sha256())->md_size, gc);
264
+  X509_digest(cert, EVP_sha256(), BPTR(&hash), NULL);
265
+  ASSERT (buf_inc_len(&hash, (EVP_sha256())->md_size));
256 266
   return hash;
257 267
 }
258 268
 
... ...
@@ -376,10 +386,19 @@ x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int de
376 376
 	  switch (xt->nid)
377 377
 	    {
378 378
 	    case NID_sha1:
379
+	    case NID_sha256:
379 380
 	      {
380
-		char *sha1_fingerprint = format_hex_ex(x509->sha1_hash,
381
-                                 SHA_DIGEST_LENGTH, 0, 1 | FHE_CAPS, ":", &gc);
382
-		do_setenv_x509(es, xt->name, sha1_fingerprint, depth);
381
+		struct buffer fp_buf;
382
+		char *fp_str = NULL;
383
+
384
+		if (xt->nid == NID_sha1)
385
+		  fp_buf = x509_get_sha1_fingerprint(x509, &gc);
386
+		else
387
+		  fp_buf = x509_get_sha256_fingerprint(x509, &gc);
388
+
389
+		fp_str = format_hex_ex(BPTR(&fp_buf), BLEN(&fp_buf), 0,
390
+		    1 | FHE_CAPS, ":", &gc);
391
+		do_setenv_x509(es, xt->name, fp_str, depth);
383 392
 	      }
384 393
 	      break;
385 394
 	    default: