Browse Source

[tls] Support RFC5746 secure renegotiation

Support renegotiation with servers supporting RFC5746.  This allows
for the use of per-directory client certificates.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
1e4a3f5bab
2 changed files with 203 additions and 19 deletions
  1. 15
    0
      src/include/ipxe/tls.h
  2. 188
    19
      src/net/tls.c

+ 15
- 0
src/include/ipxe/tls.h View File

@@ -108,6 +108,17 @@ struct tls_header {
108 108
 /* TLS signature algorithms extension */
109 109
 #define TLS_SIGNATURE_ALGORITHMS 13
110 110
 
111
+/* TLS renegotiation information extension */
112
+#define TLS_RENEGOTIATION_INFO 0xff01
113
+
114
+/** TLS verification data */
115
+struct tls_verify_data {
116
+	/** Client verification data */
117
+	uint8_t client[12];
118
+	/** Server verification data */
119
+	uint8_t server[12];
120
+} __attribute__ (( packed ));
121
+
111 122
 /** TLS RX state machine state */
112 123
 enum tls_rx_state {
113 124
 	TLS_RX_HEADER = 0,
@@ -271,6 +282,10 @@ struct tls_session {
271 282
 	uint8_t *handshake_ctx;
272 283
 	/** Client certificate (if used) */
273 284
 	struct x509_certificate *cert;
285
+	/** Secure renegotiation flag */
286
+	int secure_renegotiation;
287
+	/** Verification data */
288
+	struct tls_verify_data verify;
274 289
 
275 290
 	/** Server certificate chain */
276 291
 	struct x509_chain *chain;

+ 188
- 19
src/net/tls.c View File

@@ -162,6 +162,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
162 162
 #define EINFO_EPERM_CLIENT_CERT						\
163 163
 	__einfo_uniqify ( EINFO_EPERM, 0x03,				\
164 164
 			  "No suitable client certificate available" )
165
+#define EPERM_RENEG_INSECURE __einfo_error ( EINFO_EPERM_RENEG_INSECURE )
166
+#define EINFO_EPERM_RENEG_INSECURE					\
167
+	__einfo_uniqify ( EINFO_EPERM, 0x04,				\
168
+			  "Secure renegotiation not supported" )
169
+#define EPERM_RENEG_VERIFY __einfo_error ( EINFO_EPERM_RENEG_VERIFY )
170
+#define EINFO_EPERM_RENEG_VERIFY					\
171
+	__einfo_uniqify ( EINFO_EPERM, 0x05,				\
172
+			  "Secure renegotiation verification failed" )
165 173
 #define EPROTO_VERSION __einfo_error ( EINFO_EPROTO_VERSION )
166 174
 #define EINFO_EPROTO_VERSION						\
167 175
 	__einfo_uniqify ( EINFO_EPROTO, 0x01,				\
@@ -887,6 +895,30 @@ static void tls_verify_handshake ( struct tls_session *tls, void *out ) {
887 895
  ******************************************************************************
888 896
  */
889 897
 
898
+/**
899
+ * Restart negotiation
900
+ *
901
+ * @v tls		TLS session
902
+ */
903
+static void tls_restart ( struct tls_session *tls ) {
904
+
905
+	/* Sanity check */
906
+	assert ( ! tls->tx_pending );
907
+	assert ( ! is_pending ( &tls->client_negotiation ) );
908
+	assert ( ! is_pending ( &tls->server_negotiation ) );
909
+
910
+	/* (Re)initialise handshake context */
911
+	digest_init ( &md5_sha1_algorithm, tls->handshake_md5_sha1_ctx );
912
+	digest_init ( &sha256_algorithm, tls->handshake_sha256_ctx );
913
+	tls->handshake_digest = &sha256_algorithm;
914
+	tls->handshake_ctx = tls->handshake_sha256_ctx;
915
+
916
+	/* (Re)start negotiation */
917
+	tls->tx_pending = TLS_TX_CLIENT_HELLO;
918
+	pending_get ( &tls->client_negotiation );
919
+	pending_get ( &tls->server_negotiation );
920
+}
921
+
890 922
 /**
891 923
  * Resume TX state machine
892 924
  *
@@ -954,6 +986,13 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
954 986
 				struct tls_signature_hash_id
955 987
 					code[TLS_NUM_SIG_HASH_ALGORITHMS];
956 988
 			} __attribute__ (( packed )) signature_algorithms;
989
+			uint16_t renegotiation_info_type;
990
+			uint16_t renegotiation_info_len;
991
+			struct {
992
+				uint8_t len;
993
+				uint8_t data[ tls->secure_renegotiation ?
994
+					      sizeof ( tls->verify.client ) :0];
995
+			} __attribute__ (( packed )) renegotiation_info;
957 996
 		} __attribute__ (( packed )) extensions;
958 997
 	} __attribute__ (( packed )) hello;
959 998
 	struct tls_cipher_suite *suite;
@@ -995,6 +1034,14 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
995 1034
 		= htons ( sizeof ( hello.extensions.signature_algorithms.code));
996 1035
 	i = 0 ; for_each_table_entry ( sighash, TLS_SIG_HASH_ALGORITHMS )
997 1036
 		hello.extensions.signature_algorithms.code[i++] = sighash->code;
1037
+	hello.extensions.renegotiation_info_type
1038
+		= htons ( TLS_RENEGOTIATION_INFO );
1039
+	hello.extensions.renegotiation_info_len
1040
+		= htons ( sizeof ( hello.extensions.renegotiation_info ) );
1041
+	hello.extensions.renegotiation_info.len
1042
+		= sizeof ( hello.extensions.renegotiation_info.data );
1043
+	memcpy ( hello.extensions.renegotiation_info.data, tls->verify.client,
1044
+		 sizeof ( hello.extensions.renegotiation_info.data ) );
998 1045
 
999 1046
 	return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
1000 1047
 }
@@ -1201,20 +1248,24 @@ static int tls_send_finished ( struct tls_session *tls ) {
1201 1248
 	struct digest_algorithm *digest = tls->handshake_digest;
1202 1249
 	struct {
1203 1250
 		uint32_t type_length;
1204
-		uint8_t verify_data[12];
1251
+		uint8_t verify_data[ sizeof ( tls->verify.client ) ];
1205 1252
 	} __attribute__ (( packed )) finished;
1206 1253
 	uint8_t digest_out[ digest->digestsize ];
1207 1254
 	int rc;
1208 1255
 
1256
+	/* Construct client verification data */
1257
+	tls_verify_handshake ( tls, digest_out );
1258
+	tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
1259
+			tls->verify.client, sizeof ( tls->verify.client ),
1260
+			"client finished", digest_out, sizeof ( digest_out ) );
1261
+
1209 1262
 	/* Construct record */
1210 1263
 	memset ( &finished, 0, sizeof ( finished ) );
1211 1264
 	finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) |
1212 1265
 				 htonl ( sizeof ( finished ) -
1213 1266
 					 sizeof ( finished.type_length ) ) );
1214
-	tls_verify_handshake ( tls, digest_out );
1215
-	tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
1216
-			finished.verify_data, sizeof ( finished.verify_data ),
1217
-			"client finished", digest_out, sizeof ( digest_out ) );
1267
+	memcpy ( finished.verify_data, tls->verify.client,
1268
+		 sizeof ( finished.verify_data ) );
1218 1269
 
1219 1270
 	/* Transmit record */
1220 1271
 	if ( ( rc = tls_send_handshake ( tls, &finished,
@@ -1295,6 +1346,37 @@ static int tls_new_alert ( struct tls_session *tls, const void *data,
1295 1346
 	}
1296 1347
 }
1297 1348
 
1349
+/**
1350
+ * Receive new Hello Request handshake record
1351
+ *
1352
+ * @v tls		TLS session
1353
+ * @v data		Plaintext handshake record
1354
+ * @v len		Length of plaintext handshake record
1355
+ * @ret rc		Return status code
1356
+ */
1357
+static int tls_new_hello_request ( struct tls_session *tls,
1358
+				   const void *data __unused,
1359
+				   size_t len __unused ) {
1360
+
1361
+	/* Ignore if a handshake is in progress */
1362
+	if ( ! tls_ready ( tls ) ) {
1363
+		DBGC ( tls, "TLS %p ignoring Hello Request\n", tls );
1364
+		return 0;
1365
+	}
1366
+
1367
+	/* Fail unless server supports secure renegotiation */
1368
+	if ( ! tls->secure_renegotiation ) {
1369
+		DBGC ( tls, "TLS %p refusing to renegotiate insecurely\n",
1370
+		       tls );
1371
+		return -EPERM_RENEG_INSECURE;
1372
+	}
1373
+
1374
+	/* Restart negotiation */
1375
+	tls_restart ( tls );
1376
+
1377
+	return 0;
1378
+}
1379
+
1298 1380
 /**
1299 1381
  * Receive new Server Hello handshake record
1300 1382
  *
@@ -1317,7 +1399,23 @@ static int tls_new_server_hello ( struct tls_session *tls,
1317 1399
 		uint8_t compression_method;
1318 1400
 		char next[0];
1319 1401
 	} __attribute__ (( packed )) *hello_b;
1402
+	const struct {
1403
+		uint16_t len;
1404
+		uint8_t data[0];
1405
+	} __attribute__ (( packed )) *exts;
1406
+	const struct {
1407
+		uint16_t type;
1408
+		uint16_t len;
1409
+		uint8_t data[0];
1410
+	} __attribute__ (( packed )) *ext;
1411
+	const struct {
1412
+		uint8_t len;
1413
+		uint8_t data[0];
1414
+	} __attribute__ (( packed )) *reneg = NULL;
1320 1415
 	uint16_t version;
1416
+	size_t exts_len;
1417
+	size_t ext_len;
1418
+	size_t remaining;
1321 1419
 	int rc;
1322 1420
 
1323 1421
 	/* Parse header */
@@ -1332,6 +1430,56 @@ static int tls_new_server_hello ( struct tls_session *tls,
1332 1430
 	session_id = hello_a->session_id;
1333 1431
 	hello_b = ( ( void * ) ( session_id + hello_a->session_id_len ) );
1334 1432
 
1433
+	/* Parse extensions, if present */
1434
+	remaining = ( len - sizeof ( *hello_a ) - hello_a->session_id_len -
1435
+		      sizeof ( *hello_b ) );
1436
+	if ( remaining ) {
1437
+
1438
+		/* Parse extensions length */
1439
+		exts = ( ( void * ) hello_b->next );
1440
+		if ( ( sizeof ( *exts ) > remaining ) ||
1441
+		     ( ( exts_len = ntohs ( exts->len ) ) >
1442
+		       ( remaining - sizeof ( *exts ) ) ) ) {
1443
+			DBGC ( tls, "TLS %p received underlength extensions\n",
1444
+			       tls );
1445
+			DBGC_HD ( tls, data, len );
1446
+			return -EINVAL_HELLO;
1447
+		}
1448
+
1449
+		/* Parse extensions */
1450
+		for ( ext = ( ( void * ) exts->data ), remaining = exts_len ;
1451
+		      remaining ;
1452
+		      ext = ( ( ( void * ) ext ) + sizeof ( *ext ) + ext_len ),
1453
+			      remaining -= ( sizeof ( *ext ) + ext_len ) ) {
1454
+
1455
+			/* Parse extension length */
1456
+			if ( ( sizeof ( *ext ) > remaining ) ||
1457
+			     ( ( ext_len = ntohs ( ext->len ) ) >
1458
+			       ( remaining - sizeof ( *ext ) ) ) ) {
1459
+				DBGC ( tls, "TLS %p received underlength "
1460
+				       "extension\n", tls );
1461
+				DBGC_HD ( tls, data, len );
1462
+				return -EINVAL_HELLO;
1463
+			}
1464
+
1465
+			/* Record known extensions */
1466
+			switch ( ext->type ) {
1467
+			case htons ( TLS_RENEGOTIATION_INFO ) :
1468
+				reneg = ( ( void * ) ext->data );
1469
+				if ( ( sizeof ( *reneg ) > ext_len ) ||
1470
+				     ( reneg->len >
1471
+				       ( ext_len - sizeof ( *reneg ) ) ) ) {
1472
+					DBGC ( tls, "TLS %p received "
1473
+					       "underlength renegotiation "
1474
+					       "info\n", tls );
1475
+					DBGC_HD ( tls, data, len );
1476
+					return -EINVAL_HELLO;
1477
+				}
1478
+				break;
1479
+			}
1480
+		}
1481
+	}
1482
+
1335 1483
 	/* Check and store protocol version */
1336 1484
 	version = ntohs ( hello_a->version );
1337 1485
 	if ( version < TLS_VERSION_TLS_1_0 ) {
@@ -1370,6 +1518,30 @@ static int tls_new_server_hello ( struct tls_session *tls,
1370 1518
 	if ( ( rc = tls_generate_keys ( tls ) ) != 0 )
1371 1519
 		return rc;
1372 1520
 
1521
+	/* Handle secure renegotiation */
1522
+	if ( tls->secure_renegotiation ) {
1523
+
1524
+		/* Secure renegotiation is expected; verify data */
1525
+		if ( ( reneg == NULL ) ||
1526
+		     ( reneg->len != sizeof ( tls->verify ) ) ||
1527
+		     ( memcmp ( reneg->data, &tls->verify,
1528
+				sizeof ( tls->verify ) ) != 0 ) ) {
1529
+			DBGC ( tls, "TLS %p server failed secure "
1530
+			       "renegotiation\n", tls );
1531
+			return -EPERM_RENEG_VERIFY;
1532
+		}
1533
+
1534
+	} else if ( reneg != NULL ) {
1535
+
1536
+		/* Secure renegotiation is being enabled */
1537
+		if ( reneg->len != 0 ) {
1538
+			DBGC ( tls, "TLS %p server provided non-empty initial "
1539
+			       "renegotiation\n", tls );
1540
+			return -EPERM_RENEG_VERIFY;
1541
+		}
1542
+		tls->secure_renegotiation = 1;
1543
+	}
1544
+
1373 1545
 	return 0;
1374 1546
 }
1375 1547
 
@@ -1569,11 +1741,10 @@ static int tls_new_finished ( struct tls_session *tls,
1569 1741
 			      const void *data, size_t len ) {
1570 1742
 	struct digest_algorithm *digest = tls->handshake_digest;
1571 1743
 	const struct {
1572
-		uint8_t verify_data[12];
1744
+		uint8_t verify_data[ sizeof ( tls->verify.server ) ];
1573 1745
 		char next[0];
1574 1746
 	} __attribute__ (( packed )) *finished = data;
1575 1747
 	uint8_t digest_out[ digest->digestsize ];
1576
-	uint8_t verify_data[ sizeof ( finished->verify_data ) ];
1577 1748
 
1578 1749
 	/* Sanity check */
1579 1750
 	if ( sizeof ( *finished ) != len ) {
@@ -1585,10 +1756,10 @@ static int tls_new_finished ( struct tls_session *tls,
1585 1756
 	/* Verify data */
1586 1757
 	tls_verify_handshake ( tls, digest_out );
1587 1758
 	tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
1588
-			verify_data, sizeof ( verify_data ), "server finished",
1589
-			digest_out, sizeof ( digest_out ) );
1590
-	if ( memcmp ( verify_data, finished->verify_data,
1591
-		      sizeof ( verify_data ) ) != 0 ) {
1759
+			tls->verify.server, sizeof ( tls->verify.server ),
1760
+			"server finished", digest_out, sizeof ( digest_out ) );
1761
+	if ( memcmp ( tls->verify.server, finished->verify_data,
1762
+		      sizeof ( tls->verify.server ) ) != 0 ) {
1592 1763
 		DBGC ( tls, "TLS %p verification failed\n", tls );
1593 1764
 		return -EPERM_VERIFY;
1594 1765
 	}
@@ -1644,6 +1815,10 @@ static int tls_new_handshake ( struct tls_session *tls,
1644 1815
 
1645 1816
 		/* Handle payload */
1646 1817
 		switch ( handshake->type ) {
1818
+		case TLS_HELLO_REQUEST:
1819
+			rc = tls_new_hello_request ( tls, payload,
1820
+						     payload_len );
1821
+			break;
1647 1822
 		case TLS_SERVER_HELLO:
1648 1823
 			rc = tls_new_server_hello ( tls, payload, payload_len );
1649 1824
 			break;
@@ -2622,18 +2797,12 @@ int add_tls ( struct interface *xfer, const char *name,
2622 2797
 		      ( sizeof ( tls->pre_master_secret.random ) ) ) ) != 0 ) {
2623 2798
 		goto err_random;
2624 2799
 	}
2625
-	digest_init ( &md5_sha1_algorithm, tls->handshake_md5_sha1_ctx );
2626
-	digest_init ( &sha256_algorithm, tls->handshake_sha256_ctx );
2627
-	tls->handshake_digest = &sha256_algorithm;
2628
-	tls->handshake_ctx = tls->handshake_sha256_ctx;
2629
-	tls->tx_pending = TLS_TX_CLIENT_HELLO;
2630 2800
 	iob_populate ( &tls->rx_header_iobuf, &tls->rx_header, 0,
2631 2801
 		       sizeof ( tls->rx_header ) );
2632 2802
 	INIT_LIST_HEAD ( &tls->rx_data );
2633 2803
 
2634
-	/* Add pending operations for server and client Finished messages */
2635
-	pending_get ( &tls->client_negotiation );
2636
-	pending_get ( &tls->server_negotiation );
2804
+	/* Start negotiation */
2805
+	tls_restart ( tls );
2637 2806
 
2638 2807
 	/* Attach to parent interface, mortalise self, and return */
2639 2808
 	intf_plug_plug ( &tls->plainstream, xfer );

Loading…
Cancel
Save