[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