Преглед на файлове

[tls] Use asynchronous certificate validator

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown преди 12 години
родител
ревизия
f19565f58f
променени са 2 файла, в които са добавени 120 реда и са изтрити 48 реда
  1. 7
    2
      src/include/ipxe/tls.h
  2. 113
    46
      src/net/tls.c

+ 7
- 2
src/include/ipxe/tls.h Целия файл

@@ -237,6 +237,13 @@ struct tls_session {
237 237
 
238 238
 	/** Server certificate chain */
239 239
 	struct x509_chain *chain;
240
+	/** Certificate validator */
241
+	struct interface validator;
242
+
243
+	/** Client has finished security negotiation */
244
+	unsigned int client_finished;
245
+	/** Server has finished security negotiation */
246
+	unsigned int server_finished;
240 247
 
241 248
 	/** TX sequence number */
242 249
 	uint64_t tx_seq;
@@ -244,8 +251,6 @@ struct tls_session {
244 251
 	unsigned int tx_pending;
245 252
 	/** TX process */
246 253
 	struct process process;
247
-	/** TX ready for plaintext data */
248
-	int tx_ready;
249 254
 
250 255
 	/** RX sequence number */
251 256
 	uint64_t rx_seq;

+ 113
- 46
src/net/tls.c Целия файл

@@ -43,6 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
43 43
 #include <ipxe/x509.h>
44 44
 #include <ipxe/clientcert.h>
45 45
 #include <ipxe/rbg.h>
46
+#include <ipxe/validator.h>
46 47
 #include <ipxe/tls.h>
47 48
 
48 49
 /* Disambiguate the various error causes */
@@ -93,6 +94,16 @@ static void tls_set_uint24 ( uint8_t field24[3], unsigned long value ) {
93 94
 	*field32 |= cpu_to_be32 ( value << 8 );
94 95
 }
95 96
 
97
+/**
98
+ * Determine if TLS session is ready for application data
99
+ *
100
+ * @v tls		TLS session
101
+ * @ret is_ready	TLS session is ready
102
+ */
103
+static int tls_ready ( struct tls_session *tls ) {
104
+	return ( tls->client_finished && tls->server_finished );
105
+}
106
+
96 107
 /******************************************************************************
97 108
  *
98 109
  * Hybrid MD5+SHA1 hash as used by TLSv1.1 and earlier
@@ -196,10 +207,11 @@ static void tls_close ( struct tls_session *tls, int rc ) {
196 207
 
197 208
 	/* Remove process */
198 209
 	process_del ( &tls->process );
199
-	
200
-	/* Close ciphertext and plaintext streams */
210
+
211
+	/* Close all interfaces */
201 212
 	intf_shutdown ( &tls->cipherstream, rc );
202 213
 	intf_shutdown ( &tls->plainstream, rc );
214
+	intf_shutdown ( &tls->validator, rc );
203 215
 }
204 216
 
205 217
 /******************************************************************************
@@ -1111,7 +1123,9 @@ static int tls_send_finished ( struct tls_session *tls ) {
1111 1123
 		uint8_t verify_data[12];
1112 1124
 	} __attribute__ (( packed )) finished;
1113 1125
 	uint8_t digest_out[ digest->digestsize ];
1126
+	int rc;
1114 1127
 
1128
+	/* Construct record */
1115 1129
 	memset ( &finished, 0, sizeof ( finished ) );
1116 1130
 	finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) |
1117 1131
 				 htonl ( sizeof ( finished ) -
@@ -1121,7 +1135,15 @@ static int tls_send_finished ( struct tls_session *tls ) {
1121 1135
 			finished.verify_data, sizeof ( finished.verify_data ),
1122 1136
 			"client finished", digest_out, sizeof ( digest_out ) );
1123 1137
 
1124
-	return tls_send_handshake ( tls, &finished, sizeof ( finished ) );
1138
+	/* Transmit record */
1139
+	if ( ( rc = tls_send_handshake ( tls, &finished,
1140
+					 sizeof ( finished ) ) ) != 0 )
1141
+		return rc;
1142
+
1143
+	/* Mark client as finished */
1144
+	tls->client_finished = 1;
1145
+
1146
+	return 0;
1125 1147
 }
1126 1148
 
1127 1149
 /**
@@ -1354,10 +1376,6 @@ static int tls_new_certificate ( struct tls_session *tls,
1354 1376
 	} __attribute__ (( packed )) *certificate = data;
1355 1377
 	size_t certificates_len = tls_uint24 ( certificate->length );
1356 1378
 	const void *end = ( certificate->certificates + certificates_len );
1357
-	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
1358
-	struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
1359
-	struct x509_certificate *cert;
1360
-	time_t now;
1361 1379
 	int rc;
1362 1380
 
1363 1381
 	/* Sanity check */
@@ -1373,35 +1391,6 @@ static int tls_new_certificate ( struct tls_session *tls,
1373 1391
 				      certificates_len ) ) != 0 )
1374 1392
 		return rc;
1375 1393
 
1376
-	/* Validate certificate chain */
1377
-	now = time ( NULL );
1378
-	if ( ( rc = x509_validate_chain ( tls->chain, now, NULL ) ) != 0 ) {
1379
-		DBGC ( tls, "TLS %p could not validate certificate chain: %s\n",
1380
-		       tls, strerror ( rc ) );
1381
-		return rc;
1382
-	}
1383
-
1384
-	/* Extract first certificate */
1385
-	cert = x509_first ( tls->chain );
1386
-	assert ( cert != NULL );
1387
-
1388
-	/* Verify server name */
1389
-	if ( ( cert->subject.name == NULL ) ||
1390
-	     ( strcmp ( cert->subject.name, tls->name ) != 0 ) ) {
1391
-		DBGC ( tls, "TLS %p server name incorrect (expected %s, got "
1392
-		       "%s)\n", tls, tls->name, cert->subject.name );
1393
-		return -EACCES_WRONG_NAME;
1394
-	}
1395
-
1396
-	/* Initialise public key algorithm */
1397
-	if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
1398
-				  cert->subject.public_key.raw.data,
1399
-				  cert->subject.public_key.raw.len ) ) != 0 ) {
1400
-		DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
1401
-		       tls, strerror ( rc ) );
1402
-		return rc;
1403
-	}
1404
-
1405 1394
 	return 0;
1406 1395
 }
1407 1396
 
@@ -1442,6 +1431,7 @@ static int tls_new_server_hello_done ( struct tls_session *tls,
1442 1431
 		char next[0];
1443 1432
 	} __attribute__ (( packed )) *hello_done = data;
1444 1433
 	const void *end = hello_done->next;
1434
+	int rc;
1445 1435
 
1446 1436
 	/* Sanity check */
1447 1437
 	if ( end != ( data + len ) ) {
@@ -1451,11 +1441,12 @@ static int tls_new_server_hello_done ( struct tls_session *tls,
1451 1441
 		return -EINVAL;
1452 1442
 	}
1453 1443
 
1454
-	/* Schedule Client Key Exchange, Change Cipher, and Finished */
1455
-	tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
1456
-			     TLS_TX_CHANGE_CIPHER |
1457
-			     TLS_TX_FINISHED );
1458
-	tls_tx_resume ( tls );
1444
+	/* Begin certificate validation */
1445
+	if ( ( rc = create_validator ( &tls->validator, tls->chain ) ) != 0 ) {
1446
+		DBGC ( tls, "TLS %p could not start certificate validation: "
1447
+		       "%s\n", tls, strerror ( rc ) );
1448
+		return rc;
1449
+	}
1459 1450
 
1460 1451
 	return 0;
1461 1452
 }
@@ -1497,8 +1488,8 @@ static int tls_new_finished ( struct tls_session *tls,
1497 1488
 		return -EPERM;
1498 1489
 	}
1499 1490
 
1500
-	/* Mark session as ready to transmit plaintext data */
1501
-	tls->tx_ready = 1;
1491
+	/* Mark server as finished */
1492
+	tls->server_finished = 1;
1502 1493
 
1503 1494
 	/* Send notification of a window change */
1504 1495
 	xfer_window_changed ( &tls->plainstream );
@@ -1601,6 +1592,8 @@ static int tls_new_record ( struct tls_session *tls, unsigned int type,
1601 1592
 	case TLS_TYPE_HANDSHAKE:
1602 1593
 		return tls_new_handshake ( tls, data, len );
1603 1594
 	case TLS_TYPE_DATA:
1595
+		if ( ! tls_ready ( tls ) )
1596
+			return -ENOTCONN;
1604 1597
 		return xfer_deliver_raw ( &tls->plainstream, data, len );
1605 1598
 	default:
1606 1599
 		/* RFC4346 says that we should just ignore unknown
@@ -2015,7 +2008,7 @@ static int tls_new_ciphertext ( struct tls_session *tls,
2015 2008
 static size_t tls_plainstream_window ( struct tls_session *tls ) {
2016 2009
 
2017 2010
 	/* Block window unless we are ready to accept data */
2018
-	if ( ! tls->tx_ready )
2011
+	if ( ! tls_ready ( tls ) )
2019 2012
 		return 0;
2020 2013
 
2021 2014
 	return xfer_window ( &tls->cipherstream );
@@ -2035,7 +2028,7 @@ static int tls_plainstream_deliver ( struct tls_session *tls,
2035 2028
 	int rc;
2036 2029
 	
2037 2030
 	/* Refuse unless we are ready to accept data */
2038
-	if ( ! tls->tx_ready ) {
2031
+	if ( ! tls_ready ( tls ) ) {
2039 2032
 		rc = -ENOTCONN;
2040 2033
 		goto done;
2041 2034
 	}
@@ -2192,6 +2185,79 @@ static struct interface_descriptor tls_cipherstream_desc =
2192 2185
 	INTF_DESC_PASSTHRU ( struct tls_session, cipherstream,
2193 2186
 			     tls_cipherstream_ops, plainstream );
2194 2187
 
2188
+/******************************************************************************
2189
+ *
2190
+ * Certificate validator
2191
+ *
2192
+ ******************************************************************************
2193
+ */
2194
+
2195
+/**
2196
+ * Handle certificate validation completion
2197
+ *
2198
+ * @v tls		TLS session
2199
+ * @v rc		Reason for completion
2200
+ */
2201
+static void tls_validator_done ( struct tls_session *tls, int rc ) {
2202
+	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
2203
+	struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
2204
+	struct x509_certificate *cert;
2205
+
2206
+	/* Close validator interface */
2207
+	intf_restart ( &tls->validator, rc );
2208
+
2209
+	/* Check for validation failure */
2210
+	if ( rc != 0 ) {
2211
+		DBGC ( tls, "TLS %p certificate validation failed: %s\n",
2212
+		       tls, strerror ( rc ) );
2213
+		goto err;
2214
+	}
2215
+	DBGC ( tls, "TLS %p certificate validation succeeded\n", tls );
2216
+
2217
+	/* Extract first certificate */
2218
+	cert = x509_first ( tls->chain );
2219
+	assert ( cert != NULL );
2220
+
2221
+	/* Verify server name */
2222
+	if ( ( cert->subject.name == NULL ) ||
2223
+	     ( strcmp ( cert->subject.name, tls->name ) != 0 ) ) {
2224
+		DBGC ( tls, "TLS %p server name incorrect (expected %s, got "
2225
+		       "%s)\n", tls, tls->name, cert->subject.name );
2226
+		rc = -EACCES_WRONG_NAME;
2227
+		goto err;
2228
+	}
2229
+
2230
+	/* Initialise public key algorithm */
2231
+	if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
2232
+				  cert->subject.public_key.raw.data,
2233
+				  cert->subject.public_key.raw.len ) ) != 0 ) {
2234
+		DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
2235
+		       tls, strerror ( rc ) );
2236
+		goto err;
2237
+	}
2238
+
2239
+	/* Schedule Client Key Exchange, Change Cipher, and Finished */
2240
+	tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
2241
+			     TLS_TX_CHANGE_CIPHER |
2242
+			     TLS_TX_FINISHED );
2243
+	tls_tx_resume ( tls );
2244
+
2245
+	return;
2246
+
2247
+ err:
2248
+	tls_close ( tls, rc );
2249
+	return;
2250
+}
2251
+
2252
+/** TLS certificate validator interface operations */
2253
+static struct interface_operation tls_validator_ops[] = {
2254
+	INTF_OP ( intf_close, struct tls_session *, tls_validator_done ),
2255
+};
2256
+
2257
+/** TLS certificate validator interface descriptor */
2258
+static struct interface_descriptor tls_validator_desc =
2259
+	INTF_DESC ( struct tls_session, validator, tls_validator_ops );
2260
+
2195 2261
 /******************************************************************************
2196 2262
  *
2197 2263
  * Controlling process
@@ -2307,6 +2373,8 @@ int add_tls ( struct interface *xfer, const char *name,
2307 2373
 	tls->name = name;
2308 2374
 	intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt );
2309 2375
 	intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt );
2376
+	intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt );
2377
+	process_init ( &tls->process, &tls_process_desc, &tls->refcnt );
2310 2378
 	tls->version = TLS_VERSION_TLS_1_2;
2311 2379
 	tls_clear_cipher ( tls, &tls->tx_cipherspec );
2312 2380
 	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
@@ -2327,7 +2395,6 @@ int add_tls ( struct interface *xfer, const char *name,
2327 2395
 	tls->handshake_digest = &sha256_algorithm;
2328 2396
 	tls->handshake_ctx = tls->handshake_sha256_ctx;
2329 2397
 	tls->tx_pending = TLS_TX_CLIENT_HELLO;
2330
-	process_init ( &tls->process, &tls_process_desc, &tls->refcnt );
2331 2398
 
2332 2399
 	/* Attach to parent interface, mortalise self, and return */
2333 2400
 	intf_plug_plug ( &tls->plainstream, xfer );

Loading…
Отказ
Запис