[git commit] tls: implement server code
Denys Vlasenko
vda.linux at googlemail.com
Sun Feb 15 14:16:26 UTC 2026
commit: https://git.busybox.net/busybox/commit/?id=657fbcd62c6cb1e15692ad471bc94cfe6efd8a5f
branch: https://git.busybox.net/busybox/log/?h=master
function old new delta
tls_handshake_as_server 7 852 +845
.rodata 107103 107764 +661
psRsaCrypt - 577 +577
load_rsa_priv_key - 329 +329
psRsaDecryptPriv - 200 +200
derive_master_secret_and_keys - 154 +154
send_finished - 95 +95
get_change_cipher_spec - 88 +88
der_binary_to_pstm - 50 +50
get_finished - 42 +42
tls_xread_record 681 708 +27
ssl_server_main 285 288 +3
psRsaEncryptPub 395 199 -196
tls_handshake 2069 1690 -379
------------------------------------------------------------------------------
(add/remove: 8/0 grow/shrink: 4/2 up/down: 3071/-575) Total: 2496 bytes
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
include/libbb.h | 9 +-
networking/ssl_server.c | 5 +-
networking/tls.c | 668 +++++++++++++++++++++++++++++++++++++++---------
networking/tls_rsa.c | 101 ++++++++
networking/tls_rsa.h | 6 +
5 files changed, 660 insertions(+), 129 deletions(-)
diff --git a/include/libbb.h b/include/libbb.h
index ecdbd9234..434a660bd 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -870,8 +870,11 @@ typedef struct tls_state {
int ofd;
int ifd;
- unsigned min_encrypted_len_on_read;
+#if ENABLE_SSL_SERVER // || ENABLE_FEATURE_HTTPD_SSL
+ smallint expecting_first_packet;
+#endif
uint16_t cipher_id;
+ unsigned min_encrypted_len_on_read;
unsigned MAC_size;
unsigned key_size;
unsigned IV_size;
@@ -913,8 +916,8 @@ typedef struct tls_state {
uint8_t H[16]; //used by AES_GCM
#if ENABLE_SSL_SERVER // || ENABLE_FEATURE_HTTPD_SSL
- const char *privkey_in_der_format;
- const char *cert_in_der_format;
+ /* For ECDHE: server's ephemeral EC private key */
+ //uint8_t ecc_priv_key32[32];
#endif
} tls_state_t;
diff --git a/networking/ssl_server.c b/networking/ssl_server.c
index a8d6ba1c2..665009aea 100644
--- a/networking/ssl_server.c
+++ b/networking/ssl_server.c
@@ -90,8 +90,7 @@ int ssl_server_main(int argc UNUSED_PARAM, char **argv)
/* tls_run_copy_loop() needs non-TLS fds on STDIN and STDOUT */
xmove_fd(from_prog.rd, STDIN_FILENO);
xmove_fd(to_prog.wr, STDOUT_FILENO);
- tls_run_copy_loop(tls, /*flags*/ 0
-//flags????
-);
+ tls_run_copy_loop(tls, /*flags*/ TLSLOOP_EXIT_ON_LOCAL_EOF);
+
return EXIT_SUCCESS;
}
diff --git a/networking/tls.c b/networking/tls.c
index 852fd8002..307b0d301 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -56,7 +56,7 @@
#endif
#if TLS_DEBUG
-# define dbg(...) fprintf(stderr, __VA_ARGS__)
+# define dbg(...) bb_error_msg(__VA_ARGS__)
#else
# define dbg(...) ((void)0)
#endif
@@ -270,14 +270,36 @@ struct tls_handshake_data {
/* HANDSHAKE HASH: */
//unsigned saved_client_hello_size;
//uint8_t saved_client_hello[1];
-};
+#if ENABLE_SSL_SERVER // || ENABLE_FEATURE_HTTPD_SSL
+ psRsaKey_t server_rsa_priv_key;
+ uint8_t *server_cert_der;
+ size_t server_cert_der_len;
+
+ ///* For ECDHE: server's ephemeral EC private key */
+ //uint8_t ecc_priv_key32[32];
+#endif
+};
static unsigned get24be(const uint8_t *p)
{
return 0x100*(0x100*p[0] + p[1]) + p[2];
}
+static int is_minor_version_valid(tls_state_t *tls, uint8_t minor_ver)
+{
+#if ENABLE_SSL_SERVER // || ENABLE_FEATURE_HTTPD_SSL
+ if (tls->expecting_first_packet == 1) {
+ tls->expecting_first_packet = 0;
+ /* First packet: accept TLS 1.0 (3.1) through TLS 1.3 (3.4)
+ * for compatibility with clients using other record versions */
+ return (minor_ver > 0 && minor_ver <= 4);
+ }
+ /* Subsequent packets: must match negotiated version exactly */
+#endif
+ return minor_ver == TLS_MIN;
+}
+
#if TLS_DEBUG
/* Nondestructively see the current hash value */
# if TLS_DEBUG_HASH
@@ -294,7 +316,7 @@ static void dump_hex(const char *fmt, const void *vp, int len)
const uint8_t *p = vp;
bin2hex(hexbuf, (void*)p, len)[0] = '\0';
- dbg(fmt, hexbuf);
+ bb_error_msg(fmt, hexbuf);
}
static void dump_tls_record(const void *vp, int len)
@@ -796,6 +818,7 @@ static void xwrite_handshake_record(tls_state_t *tls, unsigned size)
static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size)
{
if (!(tls->flags & ENCRYPT_ON_WRITE)) {
+//always true!
uint8_t *buf;
xwrite_handshake_record(tls, size);
@@ -940,7 +963,7 @@ static int tls_xread_record(tls_state_t *tls, const char *expected)
if (target > MAX_INBUF /* malformed input (too long) */
|| xhdr->proto_maj != TLS_MAJ
- || xhdr->proto_min != TLS_MIN
+ || !is_minor_version_valid(tls, xhdr->proto_min)
) {
sz = total < target ? total : target;
bad_record_die(tls, expected, sz);
@@ -1849,6 +1872,92 @@ static void send_empty_client_cert(tls_state_t *tls)
xwrite_and_update_handshake_hash(tls, sizeof(*record));
}
+static void derive_master_secret_and_keys(tls_state_t *tls, uint8_t *premaster, int premaster_size)
+{
+ uint8_t tmp64[64];
+ // RFC 5246
+ // For all key exchange methods, the same algorithm is used to convert
+ // the pre_master_secret into the master_secret. The pre_master_secret
+ // should be deleted from memory once the master_secret has been
+ // computed.
+ // master_secret = PRF(pre_master_secret, "master secret",
+ // ClientHello.random + ServerHello.random)
+ // [0..47];
+ // The master secret is always exactly 48 bytes in length. The length
+ // of the premaster secret will vary depending on key exchange method.
+ prf_hmac_sha256(/*tls,*/
+ tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
+ premaster, premaster_size,
+ "master secret",
+ tls->hsd->client_and_server_rand32, sizeof(tls->hsd->client_and_server_rand32)
+ );
+ dump_hex("master secret:%s\n", tls->hsd->master_secret, sizeof(tls->hsd->master_secret));
+
+ // RFC 5246
+ // 6.3. Key Calculation
+ //
+ // The Record Protocol requires an algorithm to generate keys required
+ // by the current connection state (see Appendix A.6) from the security
+ // parameters provided by the handshake protocol.
+ //
+ // The master secret is expanded into a sequence of secure bytes, which
+ // is then split to a client write MAC key, a server write MAC key, a
+ // client write encryption key, and a server write encryption key. Each
+ // of these is generated from the byte sequence in that order. Unused
+ // values are empty. Some AEAD ciphers may additionally require a
+ // client write IV and a server write IV (see Section 6.2.3.3).
+ //
+ // When keys and MAC keys are generated, the master secret is used as an
+ // entropy source.
+ //
+ // To generate the key material, compute
+ //
+ // key_block = PRF(SecurityParameters.master_secret,
+ // "key expansion",
+ // SecurityParameters.server_random +
+ // SecurityParameters.client_random);
+ //
+ // until enough output has been generated. Then, the key_block is
+ // partitioned as follows:
+ //
+ // client_write_MAC_key[SecurityParameters.mac_key_length]
+ // server_write_MAC_key[SecurityParameters.mac_key_length]
+ // client_write_key[SecurityParameters.enc_key_length]
+ // server_write_key[SecurityParameters.enc_key_length]
+ // client_write_IV[SecurityParameters.fixed_iv_length]
+ // server_write_IV[SecurityParameters.fixed_iv_length]
+
+ /* make "server_rand32 + client_rand32" */
+ memcpy(&tmp64[0] , &tls->hsd->client_and_server_rand32[32], 32);
+ memcpy(&tmp64[32], &tls->hsd->client_and_server_rand32[0] , 32);
+
+ prf_hmac_sha256(/*tls,*/
+ tls->client_write_MAC_key, 2 * (tls->MAC_size + tls->key_size + tls->IV_size),
+ // also fills:
+ // server_write_MAC_key[]
+ // client_write_key[]
+ // server_write_key[]
+ // client_write_IV[]
+ // server_write_IV[]
+ tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
+ "key expansion",
+ tmp64, 64
+ );
+ tls->client_write_key = tls->client_write_MAC_key + (2 * tls->MAC_size);
+ tls->server_write_key = tls->client_write_key + tls->key_size;
+ tls->client_write_IV = tls->server_write_key + tls->key_size;
+ tls->server_write_IV = tls->client_write_IV + tls->IV_size;
+ dump_hex("client_write_MAC_key:%s\n",
+ tls->client_write_MAC_key, tls->MAC_size
+ );
+ dump_hex("client_write_key:%s\n",
+ tls->client_write_key, tls->key_size
+ );
+ dump_hex("client_write_IV:%s\n",
+ tls->client_write_IV, tls->IV_size
+ );
+}
+
static void send_client_key_exchange(tls_state_t *tls)
{
struct client_key_exchange {
@@ -1928,97 +2037,14 @@ static void send_client_key_exchange(tls_state_t *tls)
dbg(">> CLIENT_KEY_EXCHANGE\n");
xwrite_and_update_handshake_hash(tls, len);
- // RFC 5246
- // For all key exchange methods, the same algorithm is used to convert
- // the pre_master_secret into the master_secret. The pre_master_secret
- // should be deleted from memory once the master_secret has been
- // computed.
- // master_secret = PRF(pre_master_secret, "master secret",
- // ClientHello.random + ServerHello.random)
- // [0..47];
- // The master secret is always exactly 48 bytes in length. The length
- // of the premaster secret will vary depending on key exchange method.
- prf_hmac_sha256(/*tls,*/
- tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
- premaster, premaster_size,
- "master secret",
- tls->hsd->client_and_server_rand32, sizeof(tls->hsd->client_and_server_rand32)
- );
- dump_hex("master secret:%s\n", tls->hsd->master_secret, sizeof(tls->hsd->master_secret));
+ derive_master_secret_and_keys(tls, premaster, premaster_size);
- // RFC 5246
- // 6.3. Key Calculation
- //
- // The Record Protocol requires an algorithm to generate keys required
- // by the current connection state (see Appendix A.6) from the security
- // parameters provided by the handshake protocol.
- //
- // The master secret is expanded into a sequence of secure bytes, which
- // is then split to a client write MAC key, a server write MAC key, a
- // client write encryption key, and a server write encryption key. Each
- // of these is generated from the byte sequence in that order. Unused
- // values are empty. Some AEAD ciphers may additionally require a
- // client write IV and a server write IV (see Section 6.2.3.3).
- //
- // When keys and MAC keys are generated, the master secret is used as an
- // entropy source.
- //
- // To generate the key material, compute
- //
- // key_block = PRF(SecurityParameters.master_secret,
- // "key expansion",
- // SecurityParameters.server_random +
- // SecurityParameters.client_random);
- //
- // until enough output has been generated. Then, the key_block is
- // partitioned as follows:
- //
- // client_write_MAC_key[SecurityParameters.mac_key_length]
- // server_write_MAC_key[SecurityParameters.mac_key_length]
- // client_write_key[SecurityParameters.enc_key_length]
- // server_write_key[SecurityParameters.enc_key_length]
- // client_write_IV[SecurityParameters.fixed_iv_length]
- // server_write_IV[SecurityParameters.fixed_iv_length]
+ aes_setkey(&tls->aes_decrypt, tls->server_write_key, tls->key_size);
+ aes_setkey(&tls->aes_encrypt, tls->client_write_key, tls->key_size);
{
- uint8_t tmp64[64];
-
- /* make "server_rand32 + client_rand32" */
- memcpy(&tmp64[0] , &tls->hsd->client_and_server_rand32[32], 32);
- memcpy(&tmp64[32], &tls->hsd->client_and_server_rand32[0] , 32);
-
- prf_hmac_sha256(/*tls,*/
- tls->client_write_MAC_key, 2 * (tls->MAC_size + tls->key_size + tls->IV_size),
- // also fills:
- // server_write_MAC_key[]
- // client_write_key[]
- // server_write_key[]
- // client_write_IV[]
- // server_write_IV[]
- tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
- "key expansion",
- tmp64, 64
- );
- tls->client_write_key = tls->client_write_MAC_key + (2 * tls->MAC_size);
- tls->server_write_key = tls->client_write_key + tls->key_size;
- tls->client_write_IV = tls->server_write_key + tls->key_size;
- tls->server_write_IV = tls->client_write_IV + tls->IV_size;
- dump_hex("client_write_MAC_key:%s\n",
- tls->client_write_MAC_key, tls->MAC_size
- );
- dump_hex("client_write_key:%s\n",
- tls->client_write_key, tls->key_size
- );
- dump_hex("client_write_IV:%s\n",
- tls->client_write_IV, tls->IV_size
- );
-
- aes_setkey(&tls->aes_decrypt, tls->server_write_key, tls->key_size);
- aes_setkey(&tls->aes_encrypt, tls->client_write_key, tls->key_size);
- {
- uint8_t iv[AES_BLOCK_SIZE];
- memset(iv, 0, AES_BLOCK_SIZE);
- aes_encrypt_one_block(&tls->aes_encrypt, iv, tls->H);
- }
+ uint8_t iv[AES_BLOCK_SIZE];
+ memset(iv, 0, AES_BLOCK_SIZE);
+ aes_encrypt_one_block(&tls->aes_encrypt, iv, tls->H);
}
}
@@ -2070,7 +2096,7 @@ static void send_change_cipher_spec(tls_state_t *tls)
// suite. Any cipher suite which does not explicitly specify
// verify_data_length has a verify_data_length equal to 12. This
// includes all existing cipher suites.
-static void send_client_finished(tls_state_t *tls)
+static void send_finished(tls_state_t *tls, const char *msg_to_encrypt)
{
struct finished {
uint8_t type;
@@ -2088,7 +2114,7 @@ static void send_client_finished(tls_state_t *tls)
prf_hmac_sha256(/*tls,*/
record->prf_result, sizeof(record->prf_result),
tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
- "client finished",
+ msg_to_encrypt,
handshake_hash, len
);
dump_hex("from secret: %s\n", tls->hsd->master_secret, sizeof(tls->hsd->master_secret));
@@ -2100,6 +2126,51 @@ static void send_client_finished(tls_state_t *tls)
xwrite_encrypted(tls, sizeof(*record), RECORD_TYPE_HANDSHAKE);
}
+/* Receive and process ChangeCipherSpec */
+static void get_change_cipher_spec(tls_state_t *tls)
+{
+ int len;
+
+ /* Get CHANGE_CIPHER_SPEC */
+ len = tls_xread_record(tls, "switch to encrypted traffic");
+ if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0)
+ bad_record_die(tls, "switch to encrypted traffic", len);
+ dbg("<< CHANGE_CIPHER_SPEC\n");
+
+ /* Enable decryption for incoming packets */
+ if (ALLOW_RSA_NULL_SHA256
+ && tls->cipher_id == TLS_RSA_WITH_NULL_SHA256
+ ) {
+ tls->min_encrypted_len_on_read = tls->MAC_size;
+ } else
+ if (!(tls->flags & ENCRYPTION_AESGCM)) {
+ unsigned mac_blocks = (unsigned)(TLS_MAC_SIZE(tls) + AES_BLOCK_SIZE-1) / AES_BLOCK_SIZE;
+ /* all incoming packets now should be encrypted and have
+ * at least IV + (MAC padded to blocksize):
+ */
+ tls->min_encrypted_len_on_read = AES_BLOCK_SIZE + (mac_blocks * AES_BLOCK_SIZE);
+ } else {
+ tls->min_encrypted_len_on_read = 8 + AES_BLOCK_SIZE;
+ }
+ dbg("min_encrypted_len_on_read: %u\n", tls->min_encrypted_len_on_read);
+}
+
+/* Receive encrypted Finished message */
+static void get_finished(tls_state_t *tls, const char *expected)
+{
+ int len;
+
+ len = tls_xread_record(tls, expected);
+ if (len < 4 || tls->inbuf[RECHDR_LEN] != HANDSHAKE_FINISHED)
+ bad_record_die(tls, expected, len);
+ dbg("<< FINISHED\n");
+
+ /* TODO: Verify the Finished message contents */
+ /* The Finished message contains verify_data which is:
+ * PRF(master_secret, "client finished"/"server finished", SHA256(handshake_messages))
+ */
+}
+
void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
{
// Client RFC 5246 Server
@@ -2190,36 +2261,15 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
/* from now on we should send encrypted */
/* tls->write_seq64_be = 0; - already is */
tls->flags |= ENCRYPT_ON_WRITE;
+//TODO: ENCRYPT_ON_WRITE is unused, remove
- send_client_finished(tls);
-
- /* Get CHANGE_CIPHER_SPEC */
- len = tls_xread_record(tls, "switch to encrypted traffic");
- if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0)
- bad_record_die(tls, "switch to encrypted traffic", len);
- dbg("<< CHANGE_CIPHER_SPEC\n");
+ send_finished(tls, "client finished");
- if (ALLOW_RSA_NULL_SHA256
- && tls->cipher_id == TLS_RSA_WITH_NULL_SHA256
- ) {
- tls->min_encrypted_len_on_read = tls->MAC_size;
- } else
- if (!(tls->flags & ENCRYPTION_AESGCM)) {
- unsigned mac_blocks = (unsigned)(TLS_MAC_SIZE(tls) + AES_BLOCK_SIZE-1) / AES_BLOCK_SIZE;
- /* all incoming packets now should be encrypted and have
- * at least IV + (MAC padded to blocksize):
- */
- tls->min_encrypted_len_on_read = AES_BLOCK_SIZE + (mac_blocks * AES_BLOCK_SIZE);
- } else {
- tls->min_encrypted_len_on_read = 8 + AES_BLOCK_SIZE;
- }
- dbg("min_encrypted_len_on_read: %u\n", tls->min_encrypted_len_on_read);
+ get_change_cipher_spec(tls);
/* Get (encrypted) FINISHED from the server */
- len = tls_xread_record(tls, "'server finished'");
- if (len < 4 || tls->inbuf[RECHDR_LEN] != HANDSHAKE_FINISHED)
- bad_record_die(tls, "'server finished'", len);
- dbg("<< FINISHED\n");
+ get_finished(tls, "'server finished'");
+
/* application data can be sent/received */
/* free handshake data */
@@ -2371,11 +2421,383 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags)
/* =============== SERVER-SIDE CODE =============== */
+static void get_client_hello(tls_state_t *tls)
+{
+ struct client_hello {
+ uint8_t type;
+ uint8_t len24_hi, len24_mid, len24_lo;
+ uint8_t proto_maj, proto_min;
+ uint8_t rand32[32];
+ uint8_t session_id_len;
+ /* followed by session_id, cipher suites, compression methods, extensions */
+ };
+ struct client_hello *hp;
+ uint8_t *p;
+ unsigned cipher_list_len;
+ int len;
+
+ len = tls_xread_handshake_block(tls, sizeof(*hp));
+ /* NB: the recv'd block is already hashed by tls_xread_handshake_block() */
+ hp = (void*)(tls->inbuf + RECHDR_LEN);
+ if (hp->type != HANDSHAKE_CLIENT_HELLO
+ || hp->len24_hi != 0
+ || hp->len24_mid != 0
+ /* hp->len24_lo checked later */
+ || hp->proto_maj != TLS_MAJ
+///? || hp->proto_min != TLS_MIN
+ ) {
+ bad_record_die(tls, "'client hello'", len);
+ }
+ dbg("<< CLIENT_HELLO len:%d len24:%d\n", len, hp->len24_lo);
+
+ /* Save client random */
+ memcpy(tls->hsd->client_and_server_rand32, hp->rand32, 32);
+
+ /* Parse cipher suites to select one we support */
+ p = (uint8_t*)(hp + 1);
+
+ /* Skip session ID */
+ len -= RECHDR_LEN + sizeof(*hp);
+ if (len < hp->session_id_len) {
+ bb_simple_error_msg_and_die("malformed ClientHello");
+ }
+ p += hp->session_id_len;
+ len -= hp->session_id_len;
+
+ /* Parse cipher suite list */
+ if (len < 2) {
+ bb_simple_error_msg_and_die("malformed ClientHello");
+ }
+ cipher_list_len = (p[0] << 8) | p[1];
+ p += 2;
+ len -= 2;
+
+ if (len < cipher_list_len) {
+ bb_simple_error_msg_and_die("malformed ClientHello");
+ }
+
+//FIXME: proper cipher suite selection - see get_server_hello()
+ tls->cipher_id = TLS_RSA_WITH_AES_128_CBC_SHA256;
+ //tls->flags = 0; /* RSA mode, no ECDHE */
+ /* Set cipher parameters for TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003C) */
+ tls->key_size = AES128_KEYSIZE; /* 16 bytes */
+ tls->MAC_size = SHA256_OUTSIZE; /* 32 bytes */
+ //tls->IV_size = 0; /* For CBC mode, IV is sent with each encrypted record */
+
+ dbg("Selected cipher: %04x\n", tls->cipher_id);
+}
+
+static void send_server_hello(tls_state_t *tls)
+{
+ struct server_hello {
+ uint8_t type;
+ uint8_t len24_hi, len24_mid, len24_lo;
+ uint8_t proto_maj, proto_min;
+ uint8_t rand32[32];
+ uint8_t session_id_len;
+ uint8_t cipherid_hi, cipherid_lo;
+ uint8_t comprtype;
+ uint8_t extensions_len_hi, extensions_len_lo;
+ /* extensions follow */
+ uint8_t ext_reneg_info[5]; /* ff 01 00 01 00 */
+ };
+ struct server_hello *record;
+
+ record = tls_get_zeroed_outbuf(tls, sizeof(*record));
+
+ fill_handshake_record_hdr(record, HANDSHAKE_SERVER_HELLO, sizeof(*record));
+
+ record->proto_maj = TLS_MAJ;
+ record->proto_min = TLS_MIN;
+
+ /* Generate server random */
+ tls_get_random(record->rand32, sizeof(record->rand32));
+ memcpy(tls->hsd->client_and_server_rand32 + 32, record->rand32, 32);
+
+ /* No session ID */
+ //record->session_id_len = 0;
+
+ /* Selected cipher suite */
+ record->cipherid_hi = tls->cipher_id >> 8;
+ record->cipherid_lo = tls->cipher_id & 0xff;
+
+ /* No compression */
+ //record->comprtype = 0;
+
+ /* Extensions */
+ //record->extensions_len_hi = 0;
+ record->extensions_len_lo = 5; /* length of renegotiation_info extension */
+
+ /* Renegotiation info extension (RFC 5746) */
+ record->ext_reneg_info[0] = 0xff;
+ record->ext_reneg_info[1] = 0x01; /* extension type */
+ //record->ext_reneg_info[2] = 0x00;
+ record->ext_reneg_info[3] = 0x01; /* extension data length: 1 byte */
+ //record->ext_reneg_info[4] = 0x00; /* renegotiation info length: 0 (no previous connection) */
+
+ dbg(">> SERVER_HELLO\n");
+ xwrite_and_update_handshake_hash(tls, sizeof(*record));
+}
+
+static void send_server_certificate(tls_state_t *tls)
+{
+ struct certificate_msg {
+ uint8_t type;
+ uint8_t len24_hi, len24_mid, len24_lo;
+ uint8_t cert_chain_len24_hi, cert_chain_len24_mid, cert_chain_len24_lo;
+ uint8_t cert1_len24_hi, cert1_len24_mid, cert1_len24_lo;
+ /* followed by certificate DER data */
+ };
+ struct certificate_msg *record;
+ unsigned total_len, cert_len, chain_len;
+
+ cert_len = tls->hsd->server_cert_der_len;
+ total_len = sizeof(*record) + cert_len;
+
+ record = tls_get_zeroed_outbuf(tls, total_len);
+ fill_handshake_record_hdr(record, HANDSHAKE_CERTIFICATE, total_len);
+
+ /* Certificate chain length (just one cert for now) */
+ chain_len = cert_len + 3; /* 3 bytes for cert length */
+ record->cert_chain_len24_hi = chain_len >> 16;
+ record->cert_chain_len24_mid = (chain_len >> 8) & 0xff;
+ record->cert_chain_len24_lo = chain_len & 0xff;
+
+ /* First certificate length */
+ record->cert1_len24_hi = cert_len >> 16;
+ record->cert1_len24_mid = (cert_len >> 8) & 0xff;
+ record->cert1_len24_lo = cert_len & 0xff;
+
+ /* Copy certificate DER data */
+ memcpy(record + 1, tls->hsd->server_cert_der, cert_len);
+
+ dbg(">> CERTIFICATE (len=%u)\n", cert_len);
+ xwrite_and_update_handshake_hash(tls, total_len);
+}
+
+static void send_server_hello_done(tls_state_t *tls)
+{
+ struct server_hello_done {
+ uint8_t type;
+ uint8_t len24_hi, len24_mid, len24_lo;
+ };
+ struct server_hello_done *record;
+
+ record = tls_get_zeroed_outbuf(tls, sizeof(*record));
+ record->type = HANDSHAKE_SERVER_HELLO_DONE;
+ /* length is 0 */
+
+ dbg(">> SERVER_HELLO_DONE\n");
+ xwrite_and_update_handshake_hash(tls, sizeof(*record));
+}
+
+/* Receive and process ClientKeyExchange */
+static void get_client_key_exchange(tls_state_t *tls)
+{
+ struct client_key_exchange {
+ uint8_t type;
+ uint8_t len24_hi, len24_mid, len24_lo;
+ uint8_t enckey_len_hi, enckey_len_lo; /* RSA encrypted premaster length */
+ /* followed by RSA encrypted premaster secret */
+ };
+ struct client_key_exchange *record;
+ uint8_t premaster[RSA_PREMASTER_SIZE];
+ int len, enckey_len;
+ uint8_t *encrypted_premaster;
+
+ len = tls_xread_handshake_block(tls, 64);
+ record = (void*)(tls->inbuf + RECHDR_LEN);
+
+ if (record->type != HANDSHAKE_CLIENT_KEY_EXCHANGE) {
+ bad_record_die(tls, "'client key exchange'", len);
+ }
+ dbg("<< CLIENT_KEY_EXCHANGE\n");
+
+ /* Get the length of the encrypted premaster secret */
+ enckey_len = (record->enckey_len_hi << 8) | record->enckey_len_lo;
+ dbg("enckey_len:%d len:%d\n", enckey_len, len);
+
+ if (enckey_len < 128 || enckey_len > 512) {
+ bb_simple_error_msg_and_die("bad encrypted premaster length");
+ }
+
+ encrypted_premaster = (uint8_t*)(record + 1);
+
+ /* Decrypt the premaster secret using server's private RSA key */
+ {
+ int32 ret;
+ uint32 premaster_len;
+
+ premaster_len = RSA_PREMASTER_SIZE;
+ ret = psRsaDecryptPriv(NULL, &tls->hsd->server_rsa_priv_key,
+ encrypted_premaster, enckey_len,
+ premaster, premaster_len, NULL);
+
+ if (ret != RSA_PREMASTER_SIZE) {
+ bb_error_msg_and_die("RSA decrypt failed or wrong premaster size: %d", ret);
+ }
+
+ dbg("Decrypted premaster secret (%d bytes)\n", ret);
+
+ /* Verify premaster format: should start with version 0x03 0x03 (TLS 1.2) */
+ if (premaster[0] != 0x03 || premaster[1] != 0x03) {
+ bb_simple_error_msg_and_die("bad premaster secret version");
+ }
+ }
+
+ derive_master_secret_and_keys(tls, premaster, RSA_PREMASTER_SIZE);
+
+ /* Server decrypts with client_write_key, encrypts with server_write_key */
+ aes_setkey(&tls->aes_decrypt, tls->client_write_key, tls->key_size);
+ aes_setkey(&tls->aes_encrypt, tls->server_write_key, tls->key_size);
+ {
+ uint8_t iv[AES_BLOCK_SIZE];
+ memset(iv, 0, AES_BLOCK_SIZE);
+ aes_encrypt_one_block(&tls->aes_encrypt, iv, tls->H);
+ }
+ dbg("Derived key block\n");
+}
+
+/* Load RSA private key from DER file (supports PKCS#8 or PKCS#1)
+ * PKCS#8 PrivateKeyInfo ::= SEQUENCE {
+ * version INTEGER,
+ * algorithm AlgorithmIdentifier,
+ * privateKey OCTET STRING -- contains PKCS#1 RSAPrivateKey
+ * }
+ * PKCS#1 RSAPrivateKey ::= SEQUENCE {
+ * version INTEGER, -- 0
+ * modulus INTEGER, -- N
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- dP (d mod (p-1))
+ * exponent2 INTEGER, -- dQ (d mod (q-1))
+ * coefficient INTEGER -- qP ((inverse of q) mod p)
+ * }
+ */
+static NOINLINE /* don't inline - large stack use */
+void load_rsa_priv_key(psRsaKey_t *key, const char *filename)
+{
+ uint8_t buf[4*1024]; /* DER key files are usually ~1kbyte */
+ ssize_t sz;
+ uint8_t *der, *end;
+
+ sz = open_read_close(filename, buf, sizeof(buf));
+ if (sz < 0)
+ bb_perror_msg_and_die("can't read '%s'", filename);
+
+ der = buf;
+ end = der + sz;
+
+ /* Enter the outer SEQUENCE */
+ der = enter_der_item(der, &end);
+
+ /* Check if this is PKCS#8 or PKCS#1 format
+ * PKCS#8 starts with version 0 (02 01 00) followed by AlgorithmIdentifier (30 0d...)
+ * PKCS#1 starts with version 0 (02 01 00) followed by modulus (02 82...)
+ * We can distinguish by checking if the second element is a SEQUENCE (0x30) or INTEGER (0x02)
+ */
+ der = skip_der_item(der, end); /* Skip version */
+
+ if (*der == 0x30) {
+ /* PKCS#8 format - skip AlgorithmIdentifier and enter OCTET STRING */
+ dbg("Detected PKCS#8 private key format\n");
+ der = skip_der_item(der, end); /* Skip AlgorithmIdentifier */
+ der = enter_der_item(der, &end); /* Enter OCTET STRING containing PKCS#1 key */
+ der = enter_der_item(der, &end); /* Enter the PKCS#1 SEQUENCE */
+ der = skip_der_item(der, end); /* Skip version again */
+ } else {
+ /* PKCS#1 format - we already skipped the version */
+ dbg("Detected PKCS#1 private key format\n");
+ }
+
+ /* Read the key components */
+ der_binary_to_pstm(&key->N, der, end); /* modulus */
+ der = skip_der_item(der, end);
+
+ der_binary_to_pstm(&key->e, der, end); /* publicExponent */
+ der = skip_der_item(der, end);
+
+ der_binary_to_pstm(&key->d, der, end); /* privateExponent */
+ der = skip_der_item(der, end);
+
+ der_binary_to_pstm(&key->p, der, end); /* prime1 */
+ der = skip_der_item(der, end);
+
+ der_binary_to_pstm(&key->q, der, end); /* prime2 */
+ der = skip_der_item(der, end);
+
+ der_binary_to_pstm(&key->dP, der, end); /* exponent1 */
+ der = skip_der_item(der, end);
+
+ der_binary_to_pstm(&key->dQ, der, end); /* exponent2 */
+ der = skip_der_item(der, end);
+
+ der_binary_to_pstm(&key->qP, der, end); /* coefficient */
+
+ key->size = pstm_unsigned_bin_size(&key->N);
+ key->optimized = 1; /* We have CRT parameters */
+
+ dbg("Loaded RSA private key, size:%d\n", key->size);
+}
+
void FAST_FUNC tls_handshake_as_server(tls_state_t *tls,
const char *privkey_der_filename,
const char *cert_der_filename)
{
-//TODO
- exit(1 | !tls | !privkey_der_filename | !cert_der_filename);
+ dbg("Starting TLS server handshake\n");
+
+ /* Allocate handshake data */
+ tls->hsd = xzalloc(sizeof(*tls->hsd));
+
+ /* Load server private key */
+ tls->hsd->server_cert_der_len = 64*1024; /* sanity limit (don't load multi-megabyte "certificates") */
+ tls->hsd->server_cert_der = xmalloc_xopen_read_close(cert_der_filename, &tls->hsd->server_cert_der_len);
+
+ /* Load server certificate */
+ load_rsa_priv_key(&tls->hsd->server_rsa_priv_key, privkey_der_filename);
+ dbg("Loaded private key: %d bytes\n", tls->hsd->server_rsa_priv_key.size);
+
+ sha256_begin(&tls->hsd->handshake_hash_ctx);
+ tls->expecting_first_packet = 1;
+
+ /* Server handshake sequence (RSA mode):
+ * 1. Receive ClientHello
+ * 2. Send ServerHello
+ * 3. Send Certificate
+ * 4. [Send ServerKeyExchange] - only for DHE/ECDHE
+ * 5. [Send CertificateRequest] - optional, skip for now
+ * 6. Send ServerHelloDone
+ * 7. Receive ClientKeyExchange
+ * 8. Receive ChangeCipherSpec
+ * 9. Receive Finished (encrypted)
+ * 10. Send ChangeCipherSpec
+ * 11. Send Finished (encrypted)
+ */
+ get_client_hello(tls);
+ send_server_hello(tls);
+ send_server_certificate(tls);
+ send_server_hello_done(tls);
+
+ get_client_key_exchange(tls);
+ get_change_cipher_spec(tls);
+ /* Get (encrypted) FINISHED from the client */
+ get_finished(tls, "'cliend finished'");
+
+ send_change_cipher_spec(tls);
+ send_finished(tls, "server finished");
+
+ dbg("Server handshake complete\n");
+
+ /* application data can be sent/received */
+
+ /* free handshake data */
+ psRsaKey_clear(&tls->hsd->server_rsa_priv_key);
+ free(tls->hsd->server_cert_der);
+// if (PARANOIA)
+// memset(tls->hsd, 0, sizeof(*tls->hsd));
+ free(tls->hsd);
+ tls->hsd = NULL;
}
#endif
diff --git a/networking/tls_rsa.c b/networking/tls_rsa.c
index 2dd5a02f4..8a9c0c6db 100644
--- a/networking/tls_rsa.c
+++ b/networking/tls_rsa.c
@@ -211,3 +211,104 @@ int32 FAST_FUNC psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key,
}
return size;
}
+
+/* Remove PKCS#1 padding (Type 2) from decrypted data
+ * Format: 00 || 02 || PS || 00 || M
+ * Returns length of unpadded message, or negative on error
+ */
+#define pkcs1Unpad(in, inlen, out, outlen) \
+ pkcs1Unpad(in, inlen, out, outlen)
+static //bbox
+int32 pkcs1Unpad(unsigned char *in, uint32 inlen, unsigned char *out,
+ uint32 outlen)
+{
+ unsigned char *c, *end;
+ uint32 msglen;
+
+ if (inlen < 11) { /* Minimum: 00 02 [8 bytes PS] 00 */
+ psTraceCrypto("pkcs1Unpad: input too short\n");
+ return PS_FAILURE;
+ }
+
+ c = in;
+ end = in + inlen;
+
+ /* Check padding type byte */
+ if (*c++ != 0x00) {
+ psTraceCrypto("pkcs1Unpad: bad first byte\n");
+ return PS_FAILURE;
+ }
+ if (*c++ != 0x02) {
+ psTraceCrypto("pkcs1Unpad: bad padding type\n");
+ return PS_FAILURE;
+ }
+
+ /* Skip padding string (non-zero bytes) until we find 0x00 */
+ while (c < end && *c != 0x00) {
+ c++;
+ }
+
+ if (c >= end) {
+ psTraceCrypto("pkcs1Unpad: no 0x00 separator found\n");
+ return PS_FAILURE;
+ }
+
+ /* Skip the 0x00 separator */
+ c++;
+
+ /* Calculate message length */
+ msglen = (uint32)(end - c);
+
+ if (msglen > outlen) {
+ psTraceCrypto("pkcs1Unpad: output buffer too small\n");
+ return PS_FAILURE;
+ }
+
+ /* Copy message to output */
+ memcpy(out, c, msglen);
+
+ return msglen;
+}
+
+/* RSA private key decryption (PKCS#1 v1.5)
+ * Decrypts with private key and removes PKCS#1 padding
+ */
+#define psRsaDecryptPriv(pool, key, in, inlen, out, outlen, data) \
+ psRsaDecryptPriv( key, in, inlen, out, outlen)
+int32 FAST_FUNC psRsaDecryptPriv(psPool_t *pool, psRsaKey_t *key,
+ unsigned char *in, uint32 inlen,
+ unsigned char *out, uint32 outlen, void *data)
+{
+ int32 err;
+ uint32 size, ptLen;
+ unsigned char *tmp;
+
+ size = key->size;
+ if (inlen != size) {
+ psTraceCrypto("psRsaDecryptPriv: input size mismatch\n");
+ return PS_ARG_FAIL;
+ }
+
+ /* Allocate temp buffer for decrypted padded data */
+ tmp = xmalloc(size);
+
+ /* Perform RSA decryption */
+ ptLen = size;
+ if ((err = psRsaCrypt(pool, in, inlen, tmp, &ptLen, key,
+ PRIVKEY_TYPE, data)) < PS_SUCCESS) {
+ psTraceCrypto("Error performing psRsaDecryptPriv\n");
+ free(tmp);
+ return err;
+ }
+
+ /* Remove PKCS#1 padding */
+ err = pkcs1Unpad(tmp, ptLen, out, outlen);
+ free(tmp);
+
+ if (err < 0) {
+ psTraceCrypto("Error unpadding in psRsaDecryptPriv\n");
+ return PS_FAILURE;
+ }
+
+ return err; /* Return length of unpadded message */
+}
diff --git a/networking/tls_rsa.h b/networking/tls_rsa.h
index 82bea2a67..b63a64d92 100644
--- a/networking/tls_rsa.h
+++ b/networking/tls_rsa.h
@@ -30,3 +30,9 @@ static ALWAYS_INLINE void psRsaKey_clear(psRsaKey_t *key)
int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key,
unsigned char *in, uint32 inlen,
unsigned char *out, uint32 outlen, void *data) FAST_FUNC;
+
+#define psRsaDecryptPriv(pool, key, in, inlen, out, outlen, data) \
+ psRsaDecryptPriv( key, in, inlen, out, outlen)
+int32 psRsaDecryptPriv(psPool_t *pool, psRsaKey_t *key,
+ unsigned char *in, uint32 inlen,
+ unsigned char *out, uint32 outlen, void *data) FAST_FUNC;
More information about the busybox-cvs
mailing list