Browse Source

[tls] Use asynchronous certificate validator

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
f19565f58f
2 changed files with 120 additions and 48 deletions
  1. 7
    2
      src/include/ipxe/tls.h
  2. 113
    46
      src/net/tls.c

+ 7
- 2
src/include/ipxe/tls.h View File

237
 
237
 
238
 	/** Server certificate chain */
238
 	/** Server certificate chain */
239
 	struct x509_chain *chain;
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
 	/** TX sequence number */
248
 	/** TX sequence number */
242
 	uint64_t tx_seq;
249
 	uint64_t tx_seq;
244
 	unsigned int tx_pending;
251
 	unsigned int tx_pending;
245
 	/** TX process */
252
 	/** TX process */
246
 	struct process process;
253
 	struct process process;
247
-	/** TX ready for plaintext data */
248
-	int tx_ready;
249
 
254
 
250
 	/** RX sequence number */
255
 	/** RX sequence number */
251
 	uint64_t rx_seq;
256
 	uint64_t rx_seq;

+ 113
- 46
src/net/tls.c View File

43
 #include <ipxe/x509.h>
43
 #include <ipxe/x509.h>
44
 #include <ipxe/clientcert.h>
44
 #include <ipxe/clientcert.h>
45
 #include <ipxe/rbg.h>
45
 #include <ipxe/rbg.h>
46
+#include <ipxe/validator.h>
46
 #include <ipxe/tls.h>
47
 #include <ipxe/tls.h>
47
 
48
 
48
 /* Disambiguate the various error causes */
49
 /* Disambiguate the various error causes */
93
 	*field32 |= cpu_to_be32 ( value << 8 );
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
  * Hybrid MD5+SHA1 hash as used by TLSv1.1 and earlier
109
  * Hybrid MD5+SHA1 hash as used by TLSv1.1 and earlier
196
 
207
 
197
 	/* Remove process */
208
 	/* Remove process */
198
 	process_del ( &tls->process );
209
 	process_del ( &tls->process );
199
-	
200
-	/* Close ciphertext and plaintext streams */
210
+
211
+	/* Close all interfaces */
201
 	intf_shutdown ( &tls->cipherstream, rc );
212
 	intf_shutdown ( &tls->cipherstream, rc );
202
 	intf_shutdown ( &tls->plainstream, rc );
213
 	intf_shutdown ( &tls->plainstream, rc );
214
+	intf_shutdown ( &tls->validator, rc );
203
 }
215
 }
204
 
216
 
205
 /******************************************************************************
217
 /******************************************************************************
1111
 		uint8_t verify_data[12];
1123
 		uint8_t verify_data[12];
1112
 	} __attribute__ (( packed )) finished;
1124
 	} __attribute__ (( packed )) finished;
1113
 	uint8_t digest_out[ digest->digestsize ];
1125
 	uint8_t digest_out[ digest->digestsize ];
1126
+	int rc;
1114
 
1127
 
1128
+	/* Construct record */
1115
 	memset ( &finished, 0, sizeof ( finished ) );
1129
 	memset ( &finished, 0, sizeof ( finished ) );
1116
 	finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) |
1130
 	finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) |
1117
 				 htonl ( sizeof ( finished ) -
1131
 				 htonl ( sizeof ( finished ) -
1121
 			finished.verify_data, sizeof ( finished.verify_data ),
1135
 			finished.verify_data, sizeof ( finished.verify_data ),
1122
 			"client finished", digest_out, sizeof ( digest_out ) );
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
 	} __attribute__ (( packed )) *certificate = data;
1376
 	} __attribute__ (( packed )) *certificate = data;
1355
 	size_t certificates_len = tls_uint24 ( certificate->length );
1377
 	size_t certificates_len = tls_uint24 ( certificate->length );
1356
 	const void *end = ( certificate->certificates + certificates_len );
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
 	int rc;
1379
 	int rc;
1362
 
1380
 
1363
 	/* Sanity check */
1381
 	/* Sanity check */
1373
 				      certificates_len ) ) != 0 )
1391
 				      certificates_len ) ) != 0 )
1374
 		return rc;
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
 	return 0;
1394
 	return 0;
1406
 }
1395
 }
1407
 
1396
 
1442
 		char next[0];
1431
 		char next[0];
1443
 	} __attribute__ (( packed )) *hello_done = data;
1432
 	} __attribute__ (( packed )) *hello_done = data;
1444
 	const void *end = hello_done->next;
1433
 	const void *end = hello_done->next;
1434
+	int rc;
1445
 
1435
 
1446
 	/* Sanity check */
1436
 	/* Sanity check */
1447
 	if ( end != ( data + len ) ) {
1437
 	if ( end != ( data + len ) ) {
1451
 		return -EINVAL;
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
 	return 0;
1451
 	return 0;
1461
 }
1452
 }
1497
 		return -EPERM;
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
 	/* Send notification of a window change */
1494
 	/* Send notification of a window change */
1504
 	xfer_window_changed ( &tls->plainstream );
1495
 	xfer_window_changed ( &tls->plainstream );
1601
 	case TLS_TYPE_HANDSHAKE:
1592
 	case TLS_TYPE_HANDSHAKE:
1602
 		return tls_new_handshake ( tls, data, len );
1593
 		return tls_new_handshake ( tls, data, len );
1603
 	case TLS_TYPE_DATA:
1594
 	case TLS_TYPE_DATA:
1595
+		if ( ! tls_ready ( tls ) )
1596
+			return -ENOTCONN;
1604
 		return xfer_deliver_raw ( &tls->plainstream, data, len );
1597
 		return xfer_deliver_raw ( &tls->plainstream, data, len );
1605
 	default:
1598
 	default:
1606
 		/* RFC4346 says that we should just ignore unknown
1599
 		/* RFC4346 says that we should just ignore unknown
2015
 static size_t tls_plainstream_window ( struct tls_session *tls ) {
2008
 static size_t tls_plainstream_window ( struct tls_session *tls ) {
2016
 
2009
 
2017
 	/* Block window unless we are ready to accept data */
2010
 	/* Block window unless we are ready to accept data */
2018
-	if ( ! tls->tx_ready )
2011
+	if ( ! tls_ready ( tls ) )
2019
 		return 0;
2012
 		return 0;
2020
 
2013
 
2021
 	return xfer_window ( &tls->cipherstream );
2014
 	return xfer_window ( &tls->cipherstream );
2035
 	int rc;
2028
 	int rc;
2036
 	
2029
 	
2037
 	/* Refuse unless we are ready to accept data */
2030
 	/* Refuse unless we are ready to accept data */
2038
-	if ( ! tls->tx_ready ) {
2031
+	if ( ! tls_ready ( tls ) ) {
2039
 		rc = -ENOTCONN;
2032
 		rc = -ENOTCONN;
2040
 		goto done;
2033
 		goto done;
2041
 	}
2034
 	}
2192
 	INTF_DESC_PASSTHRU ( struct tls_session, cipherstream,
2185
 	INTF_DESC_PASSTHRU ( struct tls_session, cipherstream,
2193
 			     tls_cipherstream_ops, plainstream );
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
  * Controlling process
2263
  * Controlling process
2307
 	tls->name = name;
2373
 	tls->name = name;
2308
 	intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt );
2374
 	intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt );
2309
 	intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt );
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
 	tls->version = TLS_VERSION_TLS_1_2;
2378
 	tls->version = TLS_VERSION_TLS_1_2;
2311
 	tls_clear_cipher ( tls, &tls->tx_cipherspec );
2379
 	tls_clear_cipher ( tls, &tls->tx_cipherspec );
2312
 	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
2380
 	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
2327
 	tls->handshake_digest = &sha256_algorithm;
2395
 	tls->handshake_digest = &sha256_algorithm;
2328
 	tls->handshake_ctx = tls->handshake_sha256_ctx;
2396
 	tls->handshake_ctx = tls->handshake_sha256_ctx;
2329
 	tls->tx_pending = TLS_TX_CLIENT_HELLO;
2397
 	tls->tx_pending = TLS_TX_CLIENT_HELLO;
2330
-	process_init ( &tls->process, &tls_process_desc, &tls->refcnt );
2331
 
2398
 
2332
 	/* Attach to parent interface, mortalise self, and return */
2399
 	/* Attach to parent interface, mortalise self, and return */
2333
 	intf_plug_plug ( &tls->plainstream, xfer );
2400
 	intf_plug_plug ( &tls->plainstream, xfer );

Loading…
Cancel
Save