|
@@ -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 );
|