diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2026-02-15 00:13:51 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2026-02-15 15:16:26 +0100 |
| commit | 7773faa8781d91bb328d38fcef1c5fd393e03230 (patch) | |
| tree | 2832c942e888139334c11cd69964b0388b0bc9c8 | |
| parent | 2ab2c258479ef140ea59481fb493b113219201b9 (diff) | |
| download | busybox-w32-7773faa8781d91bb328d38fcef1c5fd393e03230.tar.gz busybox-w32-7773faa8781d91bb328d38fcef1c5fd393e03230.tar.bz2 busybox-w32-7773faa8781d91bb328d38fcef1c5fd393e03230.zip | |
tls: make ECDHE_RSA work against our client (openssl s_client not yet)
function old new delta
tls_handshake_as_server 1601 2033 +432
sp_ecc_make_key_256 - 103 +103
curve_P256_compute_premaster - 65 +65
.rodata 108023 108079 +56
curve_x25519_generate_keypair - 44 +44
tls_get_zeroed_outbuf - 28 +28
curve_P256_generate_keypair - 27 +27
sp_256_from_bin_8 - 26 +26
curve_x25519_compute_premaster - 15 +15
tls_xread_record 708 704 -4
tls_handshake 1530 1519 -11
get_outbuf_fill_handshake_record 51 37 -14
sp_256_point_from_bin2x32 70 43 -27
curve_x25519_compute_pubkey_and_premaster 71 39 -32
curve_P256_compute_pubkey_and_premaster 167 65 -102
------------------------------------------------------------------------------
(add/remove: 7/0 grow/shrink: 2/6 up/down: 796/-190) Total: 606 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | networking/tls.c | 278 | ||||
| -rw-r--r-- | networking/tls.h | 16 | ||||
| -rw-r--r-- | networking/tls_fe.c | 47 | ||||
| -rw-r--r-- | networking/tls_sp_c32.c | 46 |
4 files changed, 320 insertions, 67 deletions
diff --git a/networking/tls.c b/networking/tls.c index 2f0afe00a..cde92ad1e 100644 --- a/networking/tls.c +++ b/networking/tls.c | |||
| @@ -312,7 +312,9 @@ enum { | |||
| 312 | GOT_CERT_RSA_KEY_ALG = 1 << 1, | 312 | GOT_CERT_RSA_KEY_ALG = 1 << 1, |
| 313 | GOT_CERT_ECDSA_KEY_ALG = 1 << 2, // so far unused | 313 | GOT_CERT_ECDSA_KEY_ALG = 1 << 2, // so far unused |
| 314 | GOT_EC_KEY = 1 << 3, | 314 | GOT_EC_KEY = 1 << 3, |
| 315 | GOT_EC_CURVE_X25519 = 1 << 4, // else P256 | 315 | /* Client: server sent x25519 key in SERVER_KEY_EXCHANGE (else P256) |
| 316 | * Server: we chose x25519 based on client's supported_groups (else P256) */ | ||
| 317 | USE_EC_CURVE_X25519 = 1 << 4, | ||
| 316 | ENCRYPTION_AESGCM = 1 << 5, // else AES-SHA (or NULL-SHA if ALLOW_RSA_NULL_SHA256=1) | 318 | ENCRYPTION_AESGCM = 1 << 5, // else AES-SHA (or NULL-SHA if ALLOW_RSA_NULL_SHA256=1) |
| 317 | }; | 319 | }; |
| 318 | 320 | ||
| @@ -412,8 +414,8 @@ struct tls_handshake_data { | |||
| 412 | int key_type_chosen; | 414 | int key_type_chosen; |
| 413 | psRsaKey_t rsa_priv_key; | 415 | psRsaKey_t rsa_priv_key; |
| 414 | 416 | ||
| 415 | ///* For ECDHE: server's ephemeral EC private key */ | 417 | /* For ECDHE: server's ephemeral EC private key */ |
| 416 | //uint8_t ecc_priv_key32[32]; | 418 | uint8_t ecc_priv_key32[32]; |
| 417 | #endif | 419 | #endif |
| 418 | }; | 420 | }; |
| 419 | enum { | 421 | enum { |
| @@ -430,7 +432,6 @@ static int is_minor_version_valid(tls_state_t *tls, uint8_t minor_ver) | |||
| 430 | { | 432 | { |
| 431 | #if ENABLE_SSL_SERVER // || ENABLE_FEATURE_HTTPD_SSL | 433 | #if ENABLE_SSL_SERVER // || ENABLE_FEATURE_HTTPD_SSL |
| 432 | if (tls->expecting_first_packet == 1) { | 434 | if (tls->expecting_first_packet == 1) { |
| 433 | tls->expecting_first_packet = 0; | ||
| 434 | /* First packet: accept TLS 1.0 (3.1) through TLS 1.3 (3.4) | 435 | /* First packet: accept TLS 1.0 (3.1) through TLS 1.3 (3.4) |
| 435 | * for compatibility with clients using other record versions */ | 436 | * for compatibility with clients using other record versions */ |
| 436 | return (minor_ver > 0 && minor_ver <= 4); | 437 | return (minor_ver > 0 && minor_ver <= 4); |
| @@ -1836,7 +1837,7 @@ static void process_server_key(tls_state_t *tls, int len) | |||
| 1836 | switch (t32) { | 1837 | switch (t32) { |
| 1837 | case _0x03001d20: //curve_x25519 | 1838 | case _0x03001d20: //curve_x25519 |
| 1838 | dbg("got x25519 eccPubKey"); | 1839 | dbg("got x25519 eccPubKey"); |
| 1839 | tls->flags |= GOT_EC_CURVE_X25519; | 1840 | tls->flags |= USE_EC_CURVE_X25519; |
| 1840 | memcpy(tls->hsd->ecc_pub_key32, keybuf, 32); | 1841 | memcpy(tls->hsd->ecc_pub_key32, keybuf, 32); |
| 1841 | break; | 1842 | break; |
| 1842 | case _0x03001741: //curve_secp256r1 (aka P256) | 1843 | case _0x03001741: //curve_secp256r1 (aka P256) |
| @@ -2001,7 +2002,7 @@ static void send_client_key_exchange(tls_state_t *tls) | |||
| 2001 | if (!(tls->flags & GOT_EC_KEY)) | 2002 | if (!(tls->flags & GOT_EC_KEY)) |
| 2002 | bb_simple_error_msg_and_die("server did not provide EC key"); | 2003 | bb_simple_error_msg_and_die("server did not provide EC key"); |
| 2003 | 2004 | ||
| 2004 | if (tls->flags & GOT_EC_CURVE_X25519) { | 2005 | if (tls->flags & USE_EC_CURVE_X25519) { |
| 2005 | /* ECDHE, curve x25519 */ | 2006 | /* ECDHE, curve x25519 */ |
| 2006 | dbg("computing x25519_premaster"); | 2007 | dbg("computing x25519_premaster"); |
| 2007 | curve_x25519_compute_pubkey_and_premaster( | 2008 | curve_x25519_compute_pubkey_and_premaster( |
| @@ -2431,7 +2432,8 @@ static void get_client_hello(tls_state_t *tls) | |||
| 2431 | unsigned i, j; | 2432 | unsigned i, j; |
| 2432 | struct client_hello *hp; | 2433 | struct client_hello *hp; |
| 2433 | uint8_t *p; | 2434 | uint8_t *p; |
| 2434 | unsigned cipher_list_len; | 2435 | int cipher_list_len; |
| 2436 | int extensions_len; | ||
| 2435 | int len; | 2437 | int len; |
| 2436 | 2438 | ||
| 2437 | len = tls_xread_handshake_block(tls, sizeof(*hp)); | 2439 | len = tls_xread_handshake_block(tls, sizeof(*hp)); |
| @@ -2439,9 +2441,9 @@ static void get_client_hello(tls_state_t *tls) | |||
| 2439 | hp = (void*)(tls->inbuf + RECHDR_LEN); | 2441 | hp = (void*)(tls->inbuf + RECHDR_LEN); |
| 2440 | if (hp->type != HANDSHAKE_CLIENT_HELLO | 2442 | if (hp->type != HANDSHAKE_CLIENT_HELLO |
| 2441 | || hp->len24_hi != 0 | 2443 | || hp->len24_hi != 0 |
| 2442 | /* hp->len24_mid,lo checked later */ | 2444 | || len != ((hp->len24_mid << 8) | hp->len24_lo) + 4 |
| 2443 | || hp->proto_maj != TLS_MAJ | 2445 | || hp->proto_maj != TLS_MAJ |
| 2444 | ///? || hp->proto_min != TLS_MIN | 2446 | || !is_minor_version_valid(tls, hp->proto_min) |
| 2445 | ) { | 2447 | ) { |
| 2446 | bad_record_die(tls, "'client hello'", len); | 2448 | bad_record_die(tls, "'client hello'", len); |
| 2447 | } | 2449 | } |
| @@ -2453,13 +2455,13 @@ static void get_client_hello(tls_state_t *tls) | |||
| 2453 | /* Parse cipher suites to select one we support */ | 2455 | /* Parse cipher suites to select one we support */ |
| 2454 | p = (uint8_t*)(hp + 1); | 2456 | p = (uint8_t*)(hp + 1); |
| 2455 | 2457 | ||
| 2456 | /* Skip session ID */ | 2458 | /* Skip session ID and handshake header */ |
| 2457 | len -= RECHDR_LEN + sizeof(*hp); | 2459 | len -= sizeof(*hp); |
| 2458 | if (len < hp->session_id_len) { | ||
| 2459 | bb_simple_error_msg_and_die("malformed ClientHello"); | ||
| 2460 | } | ||
| 2461 | p += hp->session_id_len; | 2460 | p += hp->session_id_len; |
| 2462 | len -= hp->session_id_len; | 2461 | len -= hp->session_id_len; |
| 2462 | if (len < 0) { | ||
| 2463 | bb_simple_error_msg_and_die("malformed ClientHello"); | ||
| 2464 | } | ||
| 2463 | 2465 | ||
| 2464 | /* Parse cipher suite list */ | 2466 | /* Parse cipher suite list */ |
| 2465 | if (len < 2) { | 2467 | if (len < 2) { |
| @@ -2478,16 +2480,6 @@ static void get_client_hello(tls_state_t *tls) | |||
| 2478 | const uint8_t *our_cipher = &supported_ciphers[i]; | 2480 | const uint8_t *our_cipher = &supported_ciphers[i]; |
| 2479 | int key_type; | 2481 | int key_type; |
| 2480 | 2482 | ||
| 2481 | /* Skip all ECDHE ciphers (0xC0xx) - we don't support server-side ephemeral | ||
| 2482 | * EC key generation yet. ECDHE_RSA uses RSA certificates (which we have) | ||
| 2483 | * but still requires generating ephemeral EC keys for the key exchange. | ||
| 2484 | * We only support plain RSA key exchange (0x00xx) on the server side. | ||
| 2485 | */ | ||
| 2486 | if (our_cipher[0] == 0xC0) { | ||
| 2487 | //TODO: implement server-side ECDHE | ||
| 2488 | continue; | ||
| 2489 | } | ||
| 2490 | |||
| 2491 | /* Determine required key type for this cipher */ | 2483 | /* Determine required key type for this cipher */ |
| 2492 | key_type = is_cipher_ECDSA(our_cipher); | 2484 | key_type = is_cipher_ECDSA(our_cipher); |
| 2493 | if (key_type == KEY_ECDSA) { | 2485 | if (key_type == KEY_ECDSA) { |
| @@ -2510,12 +2502,78 @@ static void get_client_hello(tls_state_t *tls) | |||
| 2510 | set_cipher_parameters(tls, our_cipher); | 2502 | set_cipher_parameters(tls, our_cipher); |
| 2511 | dbg("Selected cipher: %04x", tls->cipher_id); | 2503 | dbg("Selected cipher: %04x", tls->cipher_id); |
| 2512 | tls->hsd->key_type_chosen = key_type; | 2504 | tls->hsd->key_type_chosen = key_type; |
| 2513 | return; | 2505 | goto cipher_selected; |
| 2514 | } | 2506 | } |
| 2515 | } | 2507 | } |
| 2516 | /* try our next cipherid */ | 2508 | /* try our next cipherid */ |
| 2517 | } | 2509 | } |
| 2518 | bb_simple_error_msg_and_die("no common cipher suites"); | 2510 | bb_simple_error_msg_and_die("no common cipher suites"); |
| 2511 | |||
| 2512 | cipher_selected: | ||
| 2513 | /* Skip past cipher list */ | ||
| 2514 | p += cipher_list_len; | ||
| 2515 | len -= cipher_list_len; | ||
| 2516 | |||
| 2517 | /* Skip compression methods */ | ||
| 2518 | len -= 1 + p[0]; | ||
| 2519 | p += 1 + p[0]; | ||
| 2520 | |||
| 2521 | /* Parse extensions if present */ | ||
| 2522 | if (len < 2) { | ||
| 2523 | dbg("No extensions"); | ||
| 2524 | return; /* no extensions */ | ||
| 2525 | } | ||
| 2526 | extensions_len = (p[0] << 8) | p[1]; | ||
| 2527 | p += 2; | ||
| 2528 | len -= 2; | ||
| 2529 | dbg("Extensions total length: %u, remaining len: %d", extensions_len, len); | ||
| 2530 | |||
| 2531 | if (len < extensions_len) { | ||
| 2532 | dbg("Malformed extensions length (len %d < extensions_len %u)", len, extensions_len); | ||
| 2533 | return; /* malformed extensions, ignore */ | ||
| 2534 | } | ||
| 2535 | |||
| 2536 | /* Look for supported_groups extension (type 0x000a) */ | ||
| 2537 | while (extensions_len >= 4) { | ||
| 2538 | unsigned ext_type = (p[0] << 8) | p[1]; | ||
| 2539 | int ext_len = (p[2] << 8) | p[3]; | ||
| 2540 | dbg("Extension type: 0x%04x, len: %u", ext_type, ext_len); | ||
| 2541 | p += 4; | ||
| 2542 | extensions_len -= 4; | ||
| 2543 | |||
| 2544 | if (extensions_len < ext_len) { | ||
| 2545 | dbg("Extension length overflow"); | ||
| 2546 | return; /* malformed */ | ||
| 2547 | } | ||
| 2548 | |||
| 2549 | if (ext_type == 0x000a) { /* supported_groups */ | ||
| 2550 | /* Parse named curve list */ | ||
| 2551 | int curve_list_len = (p[0] << 8) | p[1]; | ||
| 2552 | dbg("Found supported_groups extension"); | ||
| 2553 | p += 2; | ||
| 2554 | ext_len -= 2; | ||
| 2555 | if (ext_len != curve_list_len) | ||
| 2556 | return; /* malformed */ | ||
| 2557 | while (1) { | ||
| 2558 | unsigned curve; | ||
| 2559 | ext_len -= 2; /* skip (presumably existing) curve id */ | ||
| 2560 | if (ext_len < 0) | ||
| 2561 | break; /* oops, it didn't */ | ||
| 2562 | curve = (p[0] << 8) | p[1]; | ||
| 2563 | if (curve == 0x001d) /* x25519 */ | ||
| 2564 | tls->flags |= USE_EC_CURVE_X25519; | ||
| 2565 | // if (curve == 0x0017) /* secp256r1 (P256) */ | ||
| 2566 | // /* We'll try P256 as fallback without checking client support */ | ||
| 2567 | p += 2; | ||
| 2568 | } | ||
| 2569 | dbg("Client supports:%s", | ||
| 2570 | (tls->flags & USE_EC_CURVE_X25519) ? " x25519" : " P256(assumed)"); | ||
| 2571 | return; /* found what we need */ | ||
| 2572 | } | ||
| 2573 | |||
| 2574 | p += ext_len; | ||
| 2575 | extensions_len -= ext_len; | ||
| 2576 | } | ||
| 2519 | } | 2577 | } |
| 2520 | 2578 | ||
| 2521 | static void send_server_hello(tls_state_t *tls) | 2579 | static void send_server_hello(tls_state_t *tls) |
| @@ -2580,6 +2638,67 @@ static void send_server_certificate(tls_state_t *tls) | |||
| 2580 | xwrite_and_update_handshake_hash(tls, sz); | 2638 | xwrite_and_update_handshake_hash(tls, sz); |
| 2581 | } | 2639 | } |
| 2582 | 2640 | ||
| 2641 | static void send_server_key_exchange(tls_state_t *tls) | ||
| 2642 | { | ||
| 2643 | struct server_key_exchange { | ||
| 2644 | uint8_t type; | ||
| 2645 | uint8_t len24_hi, len24_mid, len24_lo; | ||
| 2646 | uint8_t curve_type; /* 3 = named curve */ | ||
| 2647 | uint8_t curve_id_hi, curve_id_lo; | ||
| 2648 | uint8_t pubkey_len; | ||
| 2649 | uint8_t pubkey[1 + 2 * 32]; /* for P256: 04 + x(32) + y(32) */ | ||
| 2650 | }; | ||
| 2651 | struct server_key_exchange *record; | ||
| 2652 | int pubkey_len; | ||
| 2653 | int total_len; | ||
| 2654 | |||
| 2655 | record = tls_get_zeroed_outbuf(tls, sizeof(*record)); | ||
| 2656 | |||
| 2657 | record->type = HANDSHAKE_SERVER_KEY_EXCHANGE; | ||
| 2658 | record->curve_type = 3; /* named curve */ | ||
| 2659 | |||
| 2660 | /* Determine which curve to use based on client's supported_groups extension. | ||
| 2661 | * Prefer x25519 (faster) if client supports it, otherwise use P256. | ||
| 2662 | * If client didn't send supported_groups, default to P256 (most widely supported). | ||
| 2663 | */ | ||
| 2664 | if (tls->flags & USE_EC_CURVE_X25519) { /* Use x25519 */ | ||
| 2665 | //record->curve_id_hi = 0x00; /* already zero from tls_get_zeroed_outbuf() */ | ||
| 2666 | record->curve_id_lo = 0x1d; /* x25519 */ | ||
| 2667 | |||
| 2668 | /* Generate ephemeral keypair directly into output buffer */ | ||
| 2669 | curve_x25519_generate_keypair(tls->hsd->ecc_priv_key32, record->pubkey); | ||
| 2670 | |||
| 2671 | pubkey_len = 32; | ||
| 2672 | dbg("Using x25519 for ECDHE"); | ||
| 2673 | } else { /* Use P256 (default or if client advertised it) */ | ||
| 2674 | //record->curve_id_hi = 0x00; /* already zero from tls_get_zeroed_outbuf() */ | ||
| 2675 | record->curve_id_lo = 0x17; /* secp256r1 (P256) */ | ||
| 2676 | |||
| 2677 | /* Generate ephemeral keypair directly into output buffer */ | ||
| 2678 | record->pubkey[0] = 0x04; /* uncompressed point */ | ||
| 2679 | curve_P256_generate_keypair(tls->hsd->ecc_priv_key32, record->pubkey + 1); | ||
| 2680 | |||
| 2681 | pubkey_len = 1 + 2 * 32; | ||
| 2682 | /* P256 is the default, no need to set USE_EC_CURVE_X25519 flag */ | ||
| 2683 | dbg("Using P256 for ECDHE"); | ||
| 2684 | } | ||
| 2685 | |||
| 2686 | record->pubkey_len = pubkey_len; | ||
| 2687 | |||
| 2688 | /* Calculate total length: curve_type(1) + curve_id(2) + pubkey_len(1) + pubkey */ | ||
| 2689 | total_len = 4 + pubkey_len; | ||
| 2690 | |||
| 2691 | //record->len24_hi = 0; /* already zero from tls_get_zeroed_outbuf() */ | ||
| 2692 | record->len24_mid = total_len >> 8; | ||
| 2693 | record->len24_lo = total_len & 0xff; | ||
| 2694 | |||
| 2695 | /* Total message length */ | ||
| 2696 | total_len += 4; /* type + len24 */ | ||
| 2697 | |||
| 2698 | dbg(">> SERVER_KEY_EXCHANGE"); | ||
| 2699 | xwrite_and_update_handshake_hash(tls, total_len); | ||
| 2700 | } | ||
| 2701 | |||
| 2583 | static void send_server_hello_done(tls_state_t *tls) | 2702 | static void send_server_hello_done(tls_state_t *tls) |
| 2584 | { | 2703 | { |
| 2585 | struct server_hello_done { | 2704 | struct server_hello_done { |
| @@ -2600,15 +2719,14 @@ static void get_client_key_exchange(tls_state_t *tls) | |||
| 2600 | struct client_key_exchange { | 2719 | struct client_key_exchange { |
| 2601 | uint8_t type; | 2720 | uint8_t type; |
| 2602 | uint8_t len24_hi, len24_mid, len24_lo; | 2721 | uint8_t len24_hi, len24_mid, len24_lo; |
| 2603 | uint8_t enckey_len_hi, enckey_len_lo; /* RSA encrypted premaster length */ | 2722 | uint8_t key[1]; /* Variable length: encrypted premaster (RSA) or EC point (ECDHE) */ |
| 2604 | /* followed by RSA encrypted premaster secret */ | ||
| 2605 | }; | 2723 | }; |
| 2606 | struct client_key_exchange *record; | 2724 | struct client_key_exchange *record; |
| 2607 | uint8_t premaster[RSA_PREMASTER_SIZE]; | 2725 | uint8_t premaster[RSA_PREMASTER_SIZE > EC_CURVE_KEYSIZE ? RSA_PREMASTER_SIZE : EC_CURVE_KEYSIZE]; |
| 2608 | int len, enckey_len; | 2726 | int len, premaster_size; |
| 2609 | uint8_t *encrypted_premaster; | 2727 | uint8_t *key_data; |
| 2610 | 2728 | ||
| 2611 | len = tls_xread_handshake_block(tls, 64); | 2729 | len = tls_xread_handshake_block(tls, sizeof(*record)); |
| 2612 | record = (void*)(tls->inbuf + RECHDR_LEN); | 2730 | record = (void*)(tls->inbuf + RECHDR_LEN); |
| 2613 | 2731 | ||
| 2614 | if (record->type != HANDSHAKE_CLIENT_KEY_EXCHANGE) { | 2732 | if (record->type != HANDSHAKE_CLIENT_KEY_EXCHANGE) { |
| @@ -2616,40 +2734,85 @@ static void get_client_key_exchange(tls_state_t *tls) | |||
| 2616 | } | 2734 | } |
| 2617 | dbg("<< CLIENT_KEY_EXCHANGE"); | 2735 | dbg("<< CLIENT_KEY_EXCHANGE"); |
| 2618 | 2736 | ||
| 2619 | /* Get the length of the encrypted premaster secret */ | 2737 | key_data = record->key; |
| 2620 | enckey_len = (record->enckey_len_hi << 8) | record->enckey_len_lo; | ||
| 2621 | dbg("enckey_len:%d len:%d", enckey_len, len); | ||
| 2622 | 2738 | ||
| 2623 | if (enckey_len < 128 || enckey_len > 512) { | 2739 | if (!(tls->flags & NEED_EC_KEY)) { |
| 2624 | bb_simple_error_msg_and_die("bad encrypted premaster length"); | 2740 | /* RSA key exchange */ |
| 2625 | } | 2741 | int enckey_len; |
| 2626 | 2742 | ||
| 2627 | encrypted_premaster = (uint8_t*)(record + 1); | 2743 | /* Get the length of the encrypted premaster secret */ |
| 2744 | enckey_len = (key_data[0] << 8) | key_data[1]; | ||
| 2745 | key_data += 2; | ||
| 2746 | dbg("enckey_len:%d len:%d", enckey_len, len); | ||
| 2628 | 2747 | ||
| 2629 | /* Decrypt the premaster secret using server's private RSA key */ | 2748 | if (enckey_len < 128 || enckey_len > 512) { |
| 2630 | { | 2749 | bb_simple_error_msg_and_die("bad encrypted premaster length"); |
| 2631 | int32 ret; | 2750 | } |
| 2632 | uint32 premaster_len; | 2751 | |
| 2633 | psRsaKey_t *key = &tls->hsd->rsa_priv_key; | 2752 | /* Decrypt the premaster secret using server's private RSA key */ |
| 2753 | { | ||
| 2754 | int32 ret; | ||
| 2755 | uint32 plen; | ||
| 2756 | psRsaKey_t *key = &tls->hsd->rsa_priv_key; | ||
| 2757 | |||
| 2758 | plen = RSA_PREMASTER_SIZE; | ||
| 2759 | ret = psRsaDecryptPriv(NULL, key, | ||
| 2760 | key_data, enckey_len, | ||
| 2761 | premaster, plen, NULL); | ||
| 2634 | 2762 | ||
| 2635 | premaster_len = RSA_PREMASTER_SIZE; | 2763 | if (ret != RSA_PREMASTER_SIZE) { |
| 2636 | ret = psRsaDecryptPriv(NULL, key, | 2764 | bb_error_msg_and_die("RSA decrypt failed or wrong premaster size: %d", ret); |
| 2637 | encrypted_premaster, enckey_len, | 2765 | } |
| 2638 | premaster, premaster_len, NULL); | 2766 | |
| 2767 | dbg("Decrypted premaster secret (%d bytes)", ret); | ||
| 2639 | 2768 | ||
| 2640 | if (ret != RSA_PREMASTER_SIZE) { | 2769 | /* Verify premaster format: should start with version 0x03 0x03 (TLS 1.2) */ |
| 2641 | bb_error_msg_and_die("RSA decrypt failed or wrong premaster size: %d", ret); | 2770 | if (premaster[0] != 0x03 || premaster[1] != 0x03) { |
| 2771 | bb_simple_error_msg_and_die("bad premaster secret version"); | ||
| 2772 | } | ||
| 2642 | } | 2773 | } |
| 2774 | premaster_size = RSA_PREMASTER_SIZE; | ||
| 2775 | } else { | ||
| 2776 | /* ECDHE key exchange */ | ||
| 2777 | int pubkey_len; | ||
| 2778 | uint8_t *client_pubkey; | ||
| 2779 | |||
| 2780 | /* Get client's ephemeral public key length */ | ||
| 2781 | pubkey_len = *key_data++; | ||
| 2782 | client_pubkey = key_data; | ||
| 2643 | 2783 | ||
| 2644 | dbg("Decrypted premaster secret (%d bytes)", ret); | 2784 | dbg("ECDHE: client pubkey_len:%d", pubkey_len); |
| 2645 | 2785 | ||
| 2646 | /* Verify premaster format: should start with version 0x03 0x03 (TLS 1.2) */ | 2786 | /* Compute shared secret using client's public key and our private key */ |
| 2647 | if (premaster[0] != 0x03 || premaster[1] != 0x03) { | 2787 | if (tls->flags & USE_EC_CURVE_X25519) { |
| 2648 | bb_simple_error_msg_and_die("bad premaster secret version"); | 2788 | /* x25519 */ |
| 2789 | if (pubkey_len != CURVE25519_KEYSIZE) { | ||
| 2790 | bb_simple_error_msg_and_die("bad x25519 public key length"); | ||
| 2791 | } | ||
| 2792 | curve_x25519_compute_premaster( | ||
| 2793 | tls->hsd->ecc_priv_key32, client_pubkey, | ||
| 2794 | premaster | ||
| 2795 | ); | ||
| 2796 | premaster_size = CURVE25519_KEYSIZE; | ||
| 2797 | } else { | ||
| 2798 | /* P256 */ | ||
| 2799 | if (pubkey_len != 1 + 2 * P256_KEYSIZE) { | ||
| 2800 | bb_simple_error_msg_and_die("bad P256 public key length"); | ||
| 2801 | } | ||
| 2802 | if (*client_pubkey++ != 0x04) { | ||
| 2803 | bb_simple_error_msg_and_die("compressed EC points not supported"); | ||
| 2804 | } | ||
| 2805 | curve_P256_compute_premaster( | ||
| 2806 | tls->hsd->ecc_priv_key32, client_pubkey, | ||
| 2807 | premaster | ||
| 2808 | ); | ||
| 2809 | premaster_size = P256_KEYSIZE; | ||
| 2649 | } | 2810 | } |
| 2811 | |||
| 2812 | dbg("Computed ECDHE premaster secret (%d bytes)", premaster_size); | ||
| 2650 | } | 2813 | } |
| 2651 | 2814 | ||
| 2652 | derive_master_secret_and_keys(tls, premaster, RSA_PREMASTER_SIZE); | 2815 | derive_master_secret_and_keys(tls, premaster, premaster_size); |
| 2653 | 2816 | ||
| 2654 | /* Server decrypts with client_write_key, encrypts with server_write_key */ | 2817 | /* Server decrypts with client_write_key, encrypts with server_write_key */ |
| 2655 | aes_setkey(&tls->aes_decrypt, tls->client_write_key, tls->key_size); | 2818 | aes_setkey(&tls->aes_decrypt, tls->client_write_key, tls->key_size); |
| @@ -2932,9 +3095,8 @@ void FAST_FUNC tls_handshake_as_server(tls_state_t *tls, | |||
| 2932 | load_pem_key_cert_pairs(tls, pem_filename); | 3095 | load_pem_key_cert_pairs(tls, pem_filename); |
| 2933 | 3096 | ||
| 2934 | sha256_begin(&tls->hsd->handshake_hash_ctx); | 3097 | sha256_begin(&tls->hsd->handshake_hash_ctx); |
| 2935 | tls->expecting_first_packet = 1; | ||
| 2936 | 3098 | ||
| 2937 | /* Server handshake sequence (RSA mode): | 3099 | /* Server handshake sequence: |
| 2938 | * 1. Receive ClientHello | 3100 | * 1. Receive ClientHello |
| 2939 | * 2. Send ServerHello | 3101 | * 2. Send ServerHello |
| 2940 | * 3. Send Certificate | 3102 | * 3. Send Certificate |
| @@ -2947,9 +3109,13 @@ void FAST_FUNC tls_handshake_as_server(tls_state_t *tls, | |||
| 2947 | * 10. Send ChangeCipherSpec | 3109 | * 10. Send ChangeCipherSpec |
| 2948 | * 11. Send Finished (encrypted) | 3110 | * 11. Send Finished (encrypted) |
| 2949 | */ | 3111 | */ |
| 3112 | tls->expecting_first_packet = 1; | ||
| 2950 | get_client_hello(tls); | 3113 | get_client_hello(tls); |
| 3114 | tls->expecting_first_packet = 0; | ||
| 2951 | send_server_hello(tls); | 3115 | send_server_hello(tls); |
| 2952 | send_server_certificate(tls); | 3116 | send_server_certificate(tls); |
| 3117 | if (tls->flags & NEED_EC_KEY) | ||
| 3118 | send_server_key_exchange(tls); | ||
| 2953 | send_server_hello_done(tls); | 3119 | send_server_hello_done(tls); |
| 2954 | 3120 | ||
| 2955 | get_client_key_exchange(tls); | 3121 | get_client_key_exchange(tls); |
diff --git a/networking/tls.h b/networking/tls.h index 167f8baf1..e59a77824 100644 --- a/networking/tls.h +++ b/networking/tls.h | |||
| @@ -108,6 +108,22 @@ void tls_get_random(void *buf, unsigned len) FAST_FUNC; | |||
| 108 | #define P256_KEYSIZE 32 | 108 | #define P256_KEYSIZE 32 |
| 109 | #define CURVE25519_KEYSIZE 32 | 109 | #define CURVE25519_KEYSIZE 32 |
| 110 | 110 | ||
| 111 | /* Separate keypair generation and premaster computation functions */ | ||
| 112 | void curve_x25519_generate_keypair( | ||
| 113 | uint8_t *privkey32, uint8_t *pubkey32) FAST_FUNC; | ||
| 114 | void curve_x25519_compute_premaster( | ||
| 115 | const uint8_t *privkey32, const uint8_t *peerkey32, | ||
| 116 | uint8_t *premaster32) FAST_FUNC; | ||
| 117 | |||
| 118 | #if ENABLE_SSL_SERVER | ||
| 119 | void curve_P256_generate_keypair( | ||
| 120 | uint8_t *privkey32, uint8_t *pubkey2x32) FAST_FUNC; | ||
| 121 | void curve_P256_compute_premaster( | ||
| 122 | const uint8_t *privkey32, const uint8_t *peerkey2x32, | ||
| 123 | uint8_t *premaster32) FAST_FUNC; | ||
| 124 | #endif | ||
| 125 | |||
| 126 | /* Combined operations (for client-side use) */ | ||
| 111 | void curve_x25519_compute_pubkey_and_premaster( | 127 | void curve_x25519_compute_pubkey_and_premaster( |
| 112 | uint8_t *pubkey32, uint8_t *premaster32, | 128 | uint8_t *pubkey32, uint8_t *premaster32, |
| 113 | const uint8_t *peerkey32) FAST_FUNC; | 129 | const uint8_t *peerkey32) FAST_FUNC; |
diff --git a/networking/tls_fe.c b/networking/tls_fe.c index e5580fbcf..479d0aaee 100644 --- a/networking/tls_fe.c +++ b/networking/tls_fe.c | |||
| @@ -607,22 +607,47 @@ static void curve25519(byte *result, const byte *e, const byte *q) | |||
| 607 | fe_normalize(result); | 607 | fe_normalize(result); |
| 608 | } | 608 | } |
| 609 | 609 | ||
| 610 | /* interface to bbox's TLS code: */ | 610 | /* interface to bbox's TLS code: |
| 611 | * | ||
| 612 | * Wire format for elliptic curve points differs between curves: | ||
| 613 | * - P256: point is (x,y) where each coordinate is a 256-bit (32-byte) big-endian integer. | ||
| 614 | * Wire format: 64 bytes total (plus 0x04 prefix byte for "uncompressed point"). | ||
| 615 | * - x25519: point is a single 256-bit (32-byte) little-endian integer. | ||
| 616 | * Wire format: 32 bytes. | ||
| 617 | * | ||
| 618 | * The interface functions below accept and generate EC points in their respective | ||
| 619 | * wire formats. Internal calculations may use different representations, but all | ||
| 620 | * conversions are handled internally within these functions. | ||
| 621 | * (Note: x25519 implementation in this file uses wire format internally as well) | ||
| 622 | */ | ||
| 623 | |||
| 624 | /* Generate x25519 keypair: random private key + corresponding public key */ | ||
| 625 | void FAST_FUNC curve_x25519_generate_keypair(uint8_t *privkey32, uint8_t *pubkey32) | ||
| 626 | { | ||
| 627 | /* Generate random private key, see RFC 7748 */ | ||
| 628 | tls_get_random(privkey32, CURVE25519_KEYSIZE); | ||
| 629 | privkey32[0] &= 0xf8; | ||
| 630 | privkey32[CURVE25519_KEYSIZE-1] = ((privkey32[CURVE25519_KEYSIZE-1] & 0x7f) | 0x40); | ||
| 631 | |||
| 632 | /* Compute public key from private key */ | ||
| 633 | curve25519(pubkey32, privkey32, NULL /* "use base point of x25519" */); | ||
| 634 | } | ||
| 635 | |||
| 636 | /* Compute shared secret (premaster) from our private key and peer's public key */ | ||
| 637 | void FAST_FUNC curve_x25519_compute_premaster( | ||
| 638 | const uint8_t *privkey32, const uint8_t *peerkey32, | ||
| 639 | uint8_t *premaster32) | ||
| 640 | { | ||
| 641 | curve25519(premaster32, privkey32, peerkey32); | ||
| 642 | } | ||
| 611 | 643 | ||
| 644 | /* Combined operation: generate keypair and compute premaster in one call */ | ||
| 612 | void FAST_FUNC curve_x25519_compute_pubkey_and_premaster( | 645 | void FAST_FUNC curve_x25519_compute_pubkey_and_premaster( |
| 613 | uint8_t *pubkey, uint8_t *premaster, | 646 | uint8_t *pubkey, uint8_t *premaster, |
| 614 | const uint8_t *peerkey32) | 647 | const uint8_t *peerkey32) |
| 615 | { | 648 | { |
| 616 | uint8_t privkey[CURVE25519_KEYSIZE]; //[32] | 649 | uint8_t privkey[CURVE25519_KEYSIZE]; //[32] |
| 617 | 650 | ||
| 618 | /* Generate random private key, see RFC 7748 */ | 651 | curve_x25519_generate_keypair(privkey, pubkey); |
| 619 | tls_get_random(privkey, sizeof(privkey)); | 652 | curve_x25519_compute_premaster(privkey, peerkey32, premaster); |
| 620 | privkey[0] &= 0xf8; | ||
| 621 | privkey[CURVE25519_KEYSIZE-1] = ((privkey[CURVE25519_KEYSIZE-1] & 0x7f) | 0x40); | ||
| 622 | |||
| 623 | /* Compute public key */ | ||
| 624 | curve25519(pubkey, privkey, NULL /* "use base point of x25519" */); | ||
| 625 | |||
| 626 | /* Compute premaster using peer's public key */ | ||
| 627 | curve25519(premaster, privkey, peerkey32); | ||
| 628 | } | 653 | } |
diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c index e493c436a..90ab61a56 100644 --- a/networking/tls_sp_c32.c +++ b/networking/tls_sp_c32.c | |||
| @@ -1514,6 +1514,52 @@ static void sp_ecc_make_key_256(sp_digit privkey[8], uint8_t *pubkey) | |||
| 1514 | memset(point, 0, sizeof(point)); //paranoia | 1514 | memset(point, 0, sizeof(point)); //paranoia |
| 1515 | } | 1515 | } |
| 1516 | 1516 | ||
| 1517 | /* interface to bbox's TLS code: | ||
| 1518 | * | ||
| 1519 | * Wire format for elliptic curve points differs between curves: | ||
| 1520 | * - P256: point is (x,y) where each coordinate is a 256-bit (32-byte) big-endian integer. | ||
| 1521 | * Wire format: 64 bytes total (plus 0x04 prefix byte for "uncompressed point"). | ||
| 1522 | * - x25519: point is a single 256-bit (32-byte) little-endian integer. | ||
| 1523 | * Wire format: 32 bytes. | ||
| 1524 | * | ||
| 1525 | * The interface functions below accept and generate EC points in their respective | ||
| 1526 | * wire formats. Internal calculations may use different representations, but all | ||
| 1527 | * conversions are handled internally within these functions. | ||
| 1528 | */ | ||
| 1529 | |||
| 1530 | #if ENABLE_SSL_SERVER | ||
| 1531 | /* Generate P256 keypair: random private key + corresponding public key */ | ||
| 1532 | void FAST_FUNC curve_P256_generate_keypair(uint8_t *privkey32, uint8_t *pubkey2x32) | ||
| 1533 | { | ||
| 1534 | sp_digit privkey_sp[8]; | ||
| 1535 | |||
| 1536 | /* Generate keypair using internal representation */ | ||
| 1537 | sp_ecc_make_key_256(privkey_sp, pubkey2x32); | ||
| 1538 | |||
| 1539 | /* Convert private key to binary format for storage */ | ||
| 1540 | sp_256_to_bin_8(privkey_sp, privkey32); | ||
| 1541 | |||
| 1542 | memset(privkey_sp, 0, sizeof(privkey_sp)); //paranoia | ||
| 1543 | } | ||
| 1544 | |||
| 1545 | /* Compute shared secret (premaster) from our private key and peer's public key */ | ||
| 1546 | void FAST_FUNC curve_P256_compute_premaster( | ||
| 1547 | const uint8_t *privkey32, const uint8_t *peerkey2x32, | ||
| 1548 | uint8_t *premaster32) | ||
| 1549 | { | ||
| 1550 | sp_digit privkey_sp[8]; | ||
| 1551 | |||
| 1552 | /* Convert binary private key to internal representation */ | ||
| 1553 | sp_256_from_bin_8(privkey_sp, privkey32); | ||
| 1554 | |||
| 1555 | /* Compute shared secret */ | ||
| 1556 | sp_ecc_secret_gen_256(privkey_sp, peerkey2x32, premaster32); | ||
| 1557 | |||
| 1558 | memset(privkey_sp, 0, sizeof(privkey_sp)); //paranoia | ||
| 1559 | } | ||
| 1560 | #endif | ||
| 1561 | |||
| 1562 | /* Combined operation: generate keypair and compute premaster in one call */ | ||
| 1517 | void FAST_FUNC curve_P256_compute_pubkey_and_premaster( | 1563 | void FAST_FUNC curve_P256_compute_pubkey_and_premaster( |
| 1518 | uint8_t *pubkey2x32, uint8_t *premaster32, | 1564 | uint8_t *pubkey2x32, uint8_t *premaster32, |
| 1519 | const uint8_t *peerkey2x32) | 1565 | const uint8_t *peerkey2x32) |
