mirror of
https://git.busybox.net/busybox
synced 2026-02-15 22:16:09 +00:00
tls: fix cipher-id selection in server mode
ECDSA keys still don't work, and currently will be ignored function old new delta tls_handshake_as_server 824 1601 +777 .rodata 107764 108007 +243 set_cipher_parameters - 161 +161 packed_usage 36072 36146 +74 static.BLOCK_NAMES - 70 +70 client_hello_ciphers - 32 +32 ssl_server_main 288 279 -9 load_rsa_priv_key 329 282 -47 tls_handshake 1676 1530 -146 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 3/3 up/down: 1357/-202) Total: 1155 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
456abad825
commit
5a1bcdf036
3 changed files with 430 additions and 221 deletions
|
|
@ -928,8 +928,7 @@ static inline tls_state_t *new_tls_state(void)
|
|||
}
|
||||
void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni);
|
||||
void FAST_FUNC tls_handshake_as_server(tls_state_t *tls,
|
||||
const char *privkey_der_filename,
|
||||
const char *cert_der_filename);
|
||||
const char *pem_filename);
|
||||
#define TLSLOOP_EXIT_ON_LOCAL_EOF (1 << 0)
|
||||
void tls_run_copy_loop(tls_state_t *tls, unsigned flags) FAST_FUNC;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,9 +14,35 @@
|
|||
//kbuild:lib-$(CONFIG_SSL_SERVER) += ssl_server.o
|
||||
|
||||
//usage:#define ssl_server_trivial_usage
|
||||
//usage: "[-vv] -p PRIVKEY.der -c CERT.der PROG ARGS"
|
||||
//usage: "-f PRIVKEY_CERT.pem PROG ARGS"
|
||||
//usage:#define ssl_server_full_usage ""
|
||||
|
||||
//usage: "Inetd-style TLS server\n"
|
||||
//usage: "\n -f PEMFILE HAProxy-style CRT file"
|
||||
/*
|
||||
# Generate RSA key and certificate
|
||||
openssl req -x509 -newkey rsa:4096 \
|
||||
-keyout $HOSTNAME-rsa.key \
|
||||
-out $HOSTNAME-rsa.crt \
|
||||
-sha256 -days 9999 -nodes \
|
||||
-subj /CN=$HOSTNAME \
|
||||
-addext "subjectAltName=DNS:$HOSTNAME"
|
||||
# Generate ECDSA key and certificate
|
||||
openssl genpkey -algorithm EC \
|
||||
-pkeyopt ec_paramgen_curve:prime256v1 \
|
||||
-out $HOSTNAME-ecdsa.key
|
||||
fopenssl req -new -x509 \
|
||||
-key $HOSTNAME-ecdsa.key \
|
||||
-out $HOSTNAME-ecdsa.crt \
|
||||
-sha256 -days 9999 \
|
||||
-subj "/CN=$HOSTNAME" \
|
||||
-addext "subjectAltName=DNS:$HOSTNAME"
|
||||
# Concatenate all these files into PRIVKEY_CERT.pem
|
||||
{ cat $HOSTNAME-rsa.key
|
||||
cat $HOSTNAME-rsa.crt
|
||||
cat $HOSTNAME-ecdsa.key
|
||||
cat $HOSTNAME-ecdsa.crt
|
||||
} >PRIVKEY_CERT.pem
|
||||
*/
|
||||
#include "libbb.h"
|
||||
|
||||
/* TLS server applet.
|
||||
|
|
@ -42,18 +68,17 @@ int ssl_server_main(int argc UNUSED_PARAM, char **argv)
|
|||
struct fd_pair from_prog;
|
||||
pid_t pid;
|
||||
tls_state_t *tls;
|
||||
const char *privkey_in_der_format;
|
||||
const char *cert_in_der_format;
|
||||
const char *pem_file;
|
||||
unsigned opt;
|
||||
|
||||
tls = new_tls_state();
|
||||
|
||||
/* "+": stop on first non-option */
|
||||
opt = getopt32(argv, "+""vp:c:",
|
||||
&privkey_in_der_format, &cert_in_der_format
|
||||
opt = getopt32(argv, "+""vf:",
|
||||
&pem_file
|
||||
);
|
||||
argv += optind;
|
||||
if (!argv[0] || (opt >> 1) == 0)
|
||||
if (!argv[0] || !(opt & 2))
|
||||
bb_show_usage();
|
||||
|
||||
/* In inetd mode, stdin/stdout are the socket.
|
||||
|
|
@ -66,7 +91,7 @@ int ssl_server_main(int argc UNUSED_PARAM, char **argv)
|
|||
tls->ofd = 4;
|
||||
|
||||
/* This can abort on errors */
|
||||
tls_handshake_as_server(tls, privkey_in_der_format, cert_in_der_format);
|
||||
tls_handshake_as_server(tls, pem_file);
|
||||
|
||||
/* Run PROG, wrap its data in TLS and I/O to socket */
|
||||
xpiped_pair(to_prog);
|
||||
|
|
|
|||
607
networking/tls.c
607
networking/tls.c
|
|
@ -189,6 +189,76 @@
|
|||
#define TLS_MAX_CRYPTBLOCK_SIZE 16
|
||||
#define TLS_MAX_OUTBUF (1 << 14)
|
||||
|
||||
/* Cipher suites we support, in preference order (best first) */
|
||||
#define NUM_CIPHERS (0 \
|
||||
+ 4 * ENABLE_FEATURE_TLS_SHA1 \
|
||||
+ ALLOW_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 \
|
||||
+ ALLOW_ECDHE_RSA_WITH_AES_128_CBC_SHA256 \
|
||||
+ ALLOW_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 \
|
||||
+ ALLOW_ECDHE_RSA_WITH_AES_128_GCM_SHA256 \
|
||||
+ 2 * ENABLE_FEATURE_TLS_SHA1 \
|
||||
+ ALLOW_RSA_WITH_AES_128_CBC_SHA256 \
|
||||
+ ALLOW_RSA_WITH_AES_256_CBC_SHA256 \
|
||||
+ ALLOW_RSA_WITH_AES_128_GCM_SHA256 \
|
||||
+ ALLOW_RSA_NULL_SHA256 \
|
||||
)
|
||||
static const uint8_t client_hello_ciphers[] = {
|
||||
0x00,2 * (1 + NUM_CIPHERS), //len16_be
|
||||
0x00,0xFF, //not a cipher - TLS_EMPTY_RENEGOTIATION_INFO_SCSV
|
||||
/* ^^^^^^ RFC 5746 Renegotiation Indication Extension - some servers will refuse to work with us otherwise */
|
||||
#if ENABLE_FEATURE_TLS_SHA1
|
||||
0xC0,0x09, // 1 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - ok: wget https://is.gd/
|
||||
0xC0,0x0A, // 2 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - ok: wget https://is.gd/
|
||||
0xC0,0x13, // 3 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-SHA
|
||||
0xC0,0x14, // 4 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - ok: openssl s_server ... -cipher ECDHE-RSA-AES256-SHA (might fail with older openssl)
|
||||
// 0xC0,0x18, // TLS_ECDH_anon_WITH_AES_128_CBC_SHA
|
||||
// 0xC0,0x19, // TLS_ECDH_anon_WITH_AES_256_CBC_SHA
|
||||
#endif
|
||||
#if ALLOW_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
|
||||
0xC0,0x23, // 5 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - ok: wget https://is.gd/
|
||||
#endif
|
||||
// 0xC0,0x24, // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet
|
||||
#if ALLOW_ECDHE_RSA_WITH_AES_128_CBC_SHA256
|
||||
0xC0,0x27, // 6 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-SHA256
|
||||
#endif
|
||||
// 0xC0,0x28, // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet
|
||||
#if ALLOW_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
0xC0,0x2B, // 7 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - ok: wget https://is.gd/
|
||||
#endif
|
||||
// 0xC0,0x2C, // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - wget https://is.gd/: "TLS error from peer (alert code 20): bad MAC"
|
||||
//TODO: GCM_SHA384 ciphers can be supported, only need sha384-based PRF?
|
||||
#if ALLOW_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
0xC0,0x2F, // 8 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-GCM-SHA256
|
||||
#endif
|
||||
// 0xC0,0x30, // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - openssl s_server ... -cipher ECDHE-RSA-AES256-GCM-SHA384: "decryption failed or bad record mac"
|
||||
//possibly these too:
|
||||
#if ENABLE_FEATURE_TLS_SHA1
|
||||
// 0xC0,0x35, // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
|
||||
// 0xC0,0x36, // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
|
||||
#endif
|
||||
// 0xC0,0x37, // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
|
||||
// 0xC0,0x38, // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet
|
||||
#if ENABLE_FEATURE_TLS_SHA1
|
||||
0x00,0x2F, // 9 TLS_RSA_WITH_AES_128_CBC_SHA - ok: openssl s_server ... -cipher AES128-SHA
|
||||
0x00,0x35, //10 TLS_RSA_WITH_AES_256_CBC_SHA - ok: openssl s_server ... -cipher AES256-SHA
|
||||
#endif
|
||||
#if ALLOW_RSA_WITH_AES_128_CBC_SHA256
|
||||
0x00,0x3C, //11 TLS_RSA_WITH_AES_128_CBC_SHA256 - ok: openssl s_server ... -cipher AES128-SHA256
|
||||
#endif
|
||||
#if ALLOW_RSA_WITH_AES_256_CBC_SHA256
|
||||
0x00,0x3D, //12 TLS_RSA_WITH_AES_256_CBC_SHA256 - ok: openssl s_server ... -cipher AES256-SHA256
|
||||
#endif
|
||||
#if ALLOW_RSA_WITH_AES_128_GCM_SHA256
|
||||
0x00,0x9C, //13 TLS_RSA_WITH_AES_128_GCM_SHA256 - ok: openssl s_server ... -cipher AES128-GCM-SHA256
|
||||
#endif
|
||||
// 0x00,0x9D, // TLS_RSA_WITH_AES_256_GCM_SHA384 - openssl s_server ... -cipher AES256-GCM-SHA384: "decryption failed or bad record mac"
|
||||
#if ALLOW_RSA_NULL_SHA256
|
||||
0x00,0x3B, // TLS_RSA_WITH_NULL_SHA256
|
||||
#endif
|
||||
0x01,0x00, //not a cipher - comprtypes_len, comprtype
|
||||
};
|
||||
#define supported_ciphers (client_hello_ciphers + 4)
|
||||
|
||||
enum {
|
||||
AES128_KEYSIZE = 16,
|
||||
AES256_KEYSIZE = 32,
|
||||
|
|
@ -246,6 +316,67 @@ enum {
|
|||
ENCRYPTION_AESGCM = 1 << 5, // else AES-SHA (or NULL-SHA if ALLOW_RSA_NULL_SHA256=1)
|
||||
};
|
||||
|
||||
/* Note: return value matches KEY_RSA (0) / KEY_ECDSA (1) enum values */
|
||||
static int is_cipher_ECDSA(const uint8_t *cipherid)
|
||||
{
|
||||
uint8_t cipher_lo;
|
||||
if (cipherid[0] != 0xC0)
|
||||
return 0;
|
||||
/* ECDHE cipher - check if ECDSA or RSA */
|
||||
cipher_lo = cipherid[1];
|
||||
return (cipher_lo == 0x09 || cipher_lo == 0x0A
|
||||
|| cipher_lo == 0x23 || cipher_lo == 0x2B
|
||||
);
|
||||
}
|
||||
|
||||
/* Set cipher parameters based on selected cipher_id */
|
||||
static void set_cipher_parameters(tls_state_t *tls, const uint8_t *cipherid)
|
||||
{
|
||||
uint8_t cipherid1 = cipherid[1];
|
||||
|
||||
tls->cipher_id = 0x100 * cipherid[0] + cipherid1;
|
||||
|
||||
/* Set defaults for RSA with AES-256 */
|
||||
tls->key_size = AES256_KEYSIZE;
|
||||
tls->MAC_size = SHA256_OUTSIZE;
|
||||
tls->IV_size = 0;
|
||||
|
||||
if (cipherid[0] == 0xC0) {
|
||||
/* All C0xx are ECDHE */
|
||||
tls->flags |= NEED_EC_KEY;
|
||||
if (cipherid1 & 1) {
|
||||
/* Odd numbered C0xx use AES128 (even ones use AES256) */
|
||||
tls->key_size = AES128_KEYSIZE;
|
||||
}
|
||||
if (ENABLE_FEATURE_TLS_SHA1 && cipherid1 <= 0x19) {
|
||||
tls->MAC_size = SHA1_OUTSIZE;
|
||||
} else
|
||||
if (cipherid1 >= 0x2B && cipherid1 <= 0x30) {
|
||||
/* C02B,2C,2F,30 are AES-GCM */
|
||||
tls->flags |= ENCRYPTION_AESGCM;
|
||||
tls->MAC_size = 0;
|
||||
tls->IV_size = 4;
|
||||
}
|
||||
} else {
|
||||
/* All 00xx are RSA */
|
||||
if ((ENABLE_FEATURE_TLS_SHA1 && cipherid1 == 0x2F)
|
||||
|| cipherid1 == 0x3C
|
||||
|| cipherid1 == 0x9C
|
||||
) {
|
||||
tls->key_size = AES128_KEYSIZE;
|
||||
}
|
||||
if (ENABLE_FEATURE_TLS_SHA1 && cipherid1 <= 0x35) {
|
||||
tls->MAC_size = SHA1_OUTSIZE;
|
||||
} else
|
||||
if (cipherid1 == 0x9C /*|| cipherid1 == 0x9D*/) {
|
||||
/* 009C,9D are AES-GCM */
|
||||
tls->flags |= ENCRYPTION_AESGCM;
|
||||
tls->MAC_size = 0;
|
||||
tls->IV_size = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct record_hdr {
|
||||
uint8_t type;
|
||||
uint8_t proto_maj, proto_min;
|
||||
|
|
@ -273,14 +404,22 @@ struct tls_handshake_data {
|
|||
//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;
|
||||
/* Server certificate and key data */
|
||||
char *keys[2];
|
||||
char *certs[2];
|
||||
unsigned keysize[2];
|
||||
unsigned certsize[2];
|
||||
int key_type_chosen;
|
||||
psRsaKey_t rsa_priv_key;
|
||||
|
||||
///* For ECDHE: server's ephemeral EC private key */
|
||||
//uint8_t ecc_priv_key32[32];
|
||||
#endif
|
||||
};
|
||||
enum {
|
||||
KEY_RSA,
|
||||
KEY_ECDSA,
|
||||
};
|
||||
|
||||
static unsigned get24be(const uint8_t *p)
|
||||
{
|
||||
|
|
@ -1403,73 +1542,6 @@ static void *get_outbuf_fill_handshake_record(tls_state_t *tls, unsigned type, u
|
|||
|
||||
static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni)
|
||||
{
|
||||
#define NUM_CIPHERS (0 \
|
||||
+ 4 * ENABLE_FEATURE_TLS_SHA1 \
|
||||
+ ALLOW_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 \
|
||||
+ ALLOW_ECDHE_RSA_WITH_AES_128_CBC_SHA256 \
|
||||
+ ALLOW_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 \
|
||||
+ ALLOW_ECDHE_RSA_WITH_AES_128_GCM_SHA256 \
|
||||
+ 2 * ENABLE_FEATURE_TLS_SHA1 \
|
||||
+ ALLOW_RSA_WITH_AES_128_CBC_SHA256 \
|
||||
+ ALLOW_RSA_WITH_AES_256_CBC_SHA256 \
|
||||
+ ALLOW_RSA_WITH_AES_128_GCM_SHA256 \
|
||||
+ ALLOW_RSA_NULL_SHA256 \
|
||||
)
|
||||
static const uint8_t ciphers[] = {
|
||||
0x00,2 * (1 + NUM_CIPHERS), //len16_be
|
||||
0x00,0xFF, //not a cipher - TLS_EMPTY_RENEGOTIATION_INFO_SCSV
|
||||
/* ^^^^^^ RFC 5746 Renegotiation Indication Extension - some servers will refuse to work with us otherwise */
|
||||
#if ENABLE_FEATURE_TLS_SHA1
|
||||
0xC0,0x09, // 1 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - ok: wget https://is.gd/
|
||||
0xC0,0x0A, // 2 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - ok: wget https://is.gd/
|
||||
0xC0,0x13, // 3 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-SHA
|
||||
0xC0,0x14, // 4 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - ok: openssl s_server ... -cipher ECDHE-RSA-AES256-SHA (might fail with older openssl)
|
||||
// 0xC0,0x18, // TLS_ECDH_anon_WITH_AES_128_CBC_SHA
|
||||
// 0xC0,0x19, // TLS_ECDH_anon_WITH_AES_256_CBC_SHA
|
||||
#endif
|
||||
#if ALLOW_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
|
||||
0xC0,0x23, // 5 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - ok: wget https://is.gd/
|
||||
#endif
|
||||
// 0xC0,0x24, // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet
|
||||
#if ALLOW_ECDHE_RSA_WITH_AES_128_CBC_SHA256
|
||||
0xC0,0x27, // 6 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-SHA256
|
||||
#endif
|
||||
// 0xC0,0x28, // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet
|
||||
#if ALLOW_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
0xC0,0x2B, // 7 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - ok: wget https://is.gd/
|
||||
#endif
|
||||
// 0xC0,0x2C, // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - wget https://is.gd/: "TLS error from peer (alert code 20): bad MAC"
|
||||
//TODO: GCM_SHA384 ciphers can be supported, only need sha384-based PRF?
|
||||
#if ALLOW_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
0xC0,0x2F, // 8 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-GCM-SHA256
|
||||
#endif
|
||||
// 0xC0,0x30, // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - openssl s_server ... -cipher ECDHE-RSA-AES256-GCM-SHA384: "decryption failed or bad record mac"
|
||||
//possibly these too:
|
||||
#if ENABLE_FEATURE_TLS_SHA1
|
||||
// 0xC0,0x35, // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
|
||||
// 0xC0,0x36, // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
|
||||
#endif
|
||||
// 0xC0,0x37, // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
|
||||
// 0xC0,0x38, // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet
|
||||
#if ENABLE_FEATURE_TLS_SHA1
|
||||
0x00,0x2F, // 9 TLS_RSA_WITH_AES_128_CBC_SHA - ok: openssl s_server ... -cipher AES128-SHA
|
||||
0x00,0x35, //10 TLS_RSA_WITH_AES_256_CBC_SHA - ok: openssl s_server ... -cipher AES256-SHA
|
||||
#endif
|
||||
#if ALLOW_RSA_WITH_AES_128_CBC_SHA256
|
||||
0x00,0x3C, //11 TLS_RSA_WITH_AES_128_CBC_SHA256 - ok: openssl s_server ... -cipher AES128-SHA256
|
||||
#endif
|
||||
#if ALLOW_RSA_WITH_AES_256_CBC_SHA256
|
||||
0x00,0x3D, //12 TLS_RSA_WITH_AES_256_CBC_SHA256 - ok: openssl s_server ... -cipher AES256-SHA256
|
||||
#endif
|
||||
#if ALLOW_RSA_WITH_AES_128_GCM_SHA256
|
||||
0x00,0x9C, //13 TLS_RSA_WITH_AES_128_GCM_SHA256 - ok: openssl s_server ... -cipher AES128-GCM-SHA256
|
||||
#endif
|
||||
// 0x00,0x9D, // TLS_RSA_WITH_AES_256_GCM_SHA384 - openssl s_server ... -cipher AES256-GCM-SHA384: "decryption failed or bad record mac"
|
||||
#if ALLOW_RSA_NULL_SHA256
|
||||
0x00,0x3B, // TLS_RSA_WITH_NULL_SHA256
|
||||
#endif
|
||||
0x01,0x00, //not a cipher - comprtypes_len, comprtype
|
||||
};
|
||||
struct client_hello {
|
||||
uint8_t type;
|
||||
uint8_t len24_hi, len24_mid, len24_lo;
|
||||
|
|
@ -1556,8 +1628,8 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni)
|
|||
memset(record->rand32, 0x11, sizeof(record->rand32));
|
||||
/* record->session_id_len = 0; - already is */
|
||||
|
||||
BUILD_BUG_ON(sizeof(ciphers) != 2 * (1 + 1 + NUM_CIPHERS + 1));
|
||||
memcpy(&record->cipherid_len16_hi, ciphers, sizeof(ciphers));
|
||||
BUILD_BUG_ON(sizeof(client_hello_ciphers) != 2 * (1 + 1 + NUM_CIPHERS + 1));
|
||||
memcpy(&record->cipherid_len16_hi, client_hello_ciphers, sizeof(client_hello_ciphers));
|
||||
|
||||
ptr = (void*)(record + 1);
|
||||
*ptr++ = ext_len >> 8;
|
||||
|
|
@ -1612,7 +1684,6 @@ static void get_server_hello(tls_state_t *tls)
|
|||
|
||||
struct server_hello *hp;
|
||||
uint8_t *cipherid;
|
||||
uint8_t cipherid1;
|
||||
int len, len24;
|
||||
|
||||
len = tls_xread_handshake_block(tls, 74 - 32);
|
||||
|
|
@ -1651,74 +1722,7 @@ static void get_server_hello(tls_state_t *tls)
|
|||
|
||||
memcpy(tls->hsd->client_and_server_rand32 + 32, hp->rand32, sizeof(hp->rand32));
|
||||
|
||||
/* Set up encryption params based on selected cipher */
|
||||
#if 0
|
||||
0xC0,0x09, // 1 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - ok: wget https://is.gd/
|
||||
0xC0,0x0A, // 2 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - ok: wget https://is.gd/
|
||||
0xC0,0x13, // 3 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-SHA
|
||||
0xC0,0x14, // 4 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - ok: openssl s_server ... -cipher ECDHE-RSA-AES256-SHA (might fail with older openssl)
|
||||
// 0xC0,0x18, // TLS_ECDH_anon_WITH_AES_128_CBC_SHA
|
||||
// 0xC0,0x19, // TLS_ECDH_anon_WITH_AES_256_CBC_SHA
|
||||
0xC0,0x23, // 5 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - ok: wget https://is.gd/
|
||||
// 0xC0,0x24, // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet
|
||||
0xC0,0x27, // 6 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-SHA256
|
||||
// 0xC0,0x28, // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet
|
||||
0xC0,0x2B, // 7 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - ok: wget https://is.gd/
|
||||
// 0xC0,0x2C, // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - wget https://is.gd/: "TLS error from peer (alert code 20): bad MAC"
|
||||
0xC0,0x2F, // 8 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-GCM-SHA256
|
||||
// 0xC0,0x30, // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - openssl s_server ... -cipher ECDHE-RSA-AES256-GCM-SHA384: "decryption failed or bad record mac"
|
||||
//possibly these too:
|
||||
// 0xC0,0x35, // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
|
||||
// 0xC0,0x36, // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
|
||||
// 0xC0,0x37, // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
|
||||
// 0xC0,0x38, // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet
|
||||
0x00,0x2F, // 9 TLS_RSA_WITH_AES_128_CBC_SHA - ok: openssl s_server ... -cipher AES128-SHA
|
||||
0x00,0x35, //10 TLS_RSA_WITH_AES_256_CBC_SHA - ok: openssl s_server ... -cipher AES256-SHA
|
||||
0x00,0x3C, //11 TLS_RSA_WITH_AES_128_CBC_SHA256 - ok: openssl s_server ... -cipher AES128-SHA256
|
||||
0x00,0x3D, //12 TLS_RSA_WITH_AES_256_CBC_SHA256 - ok: openssl s_server ... -cipher AES256-SHA256
|
||||
0x00,0x9C, //13 TLS_RSA_WITH_AES_128_GCM_SHA256 - ok: openssl s_server ... -cipher AES128-GCM-SHA256
|
||||
// 0x00,0x9D, // TLS_RSA_WITH_AES_256_GCM_SHA384 - openssl s_server ... -cipher AES256-GCM-SHA384: "decryption failed or bad record mac"
|
||||
0x00,0x3B, // TLS_RSA_WITH_NULL_SHA256
|
||||
#endif
|
||||
cipherid1 = cipherid[1];
|
||||
tls->cipher_id = 0x100 * cipherid[0] + cipherid1;
|
||||
tls->key_size = AES256_KEYSIZE;
|
||||
tls->MAC_size = SHA256_OUTSIZE;
|
||||
/*tls->IV_size = 0; - already is */
|
||||
if (cipherid[0] == 0xC0) {
|
||||
/* All C0xx are ECDHE */
|
||||
tls->flags |= NEED_EC_KEY;
|
||||
if (cipherid1 & 1) {
|
||||
/* Odd numbered C0xx use AES128 (even ones use AES256) */
|
||||
tls->key_size = AES128_KEYSIZE;
|
||||
}
|
||||
if (ENABLE_FEATURE_TLS_SHA1 && cipherid1 <= 0x19) {
|
||||
tls->MAC_size = SHA1_OUTSIZE;
|
||||
} else
|
||||
if (cipherid1 >= 0x2B && cipherid1 <= 0x30) {
|
||||
/* C02B,2C,2F,30 are AES-GCM */
|
||||
tls->flags |= ENCRYPTION_AESGCM;
|
||||
tls->MAC_size = 0;
|
||||
tls->IV_size = 4;
|
||||
}
|
||||
} else {
|
||||
/* All 00xx are RSA */
|
||||
if ((ENABLE_FEATURE_TLS_SHA1 && cipherid1 == 0x2F)
|
||||
|| cipherid1 == 0x3C
|
||||
|| cipherid1 == 0x9C
|
||||
) {
|
||||
tls->key_size = AES128_KEYSIZE;
|
||||
}
|
||||
if (ENABLE_FEATURE_TLS_SHA1 && cipherid1 <= 0x35) {
|
||||
tls->MAC_size = SHA1_OUTSIZE;
|
||||
} else
|
||||
if (cipherid1 == 0x9C /*|| cipherid1 == 0x9D*/) {
|
||||
/* 009C,9D are AES-GCM */
|
||||
tls->flags |= ENCRYPTION_AESGCM;
|
||||
tls->MAC_size = 0;
|
||||
tls->IV_size = 4;
|
||||
}
|
||||
}
|
||||
set_cipher_parameters(tls, cipherid);
|
||||
dbg("server chose cipher %04x", tls->cipher_id);
|
||||
dbg("key_size:%u MAC_size:%u IV_size:%u", tls->key_size, tls->MAC_size, tls->IV_size);
|
||||
|
||||
|
|
@ -2424,6 +2428,7 @@ static void get_client_hello(tls_state_t *tls)
|
|||
uint8_t session_id_len;
|
||||
/* followed by session_id, cipher suites, compression methods, extensions */
|
||||
};
|
||||
unsigned i, j;
|
||||
struct client_hello *hp;
|
||||
uint8_t *p;
|
||||
unsigned cipher_list_len;
|
||||
|
|
@ -2434,14 +2439,13 @@ static void get_client_hello(tls_state_t *tls)
|
|||
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->len24_mid,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", len, hp->len24_lo);
|
||||
dbg("<< CLIENT_HELLO len:%d len24:%d", len, (hp->len24_mid << 8) | hp->len24_lo);
|
||||
|
||||
/* Save client random */
|
||||
memcpy(tls->hsd->client_and_server_rand32, hp->rand32, 32);
|
||||
|
|
@ -2469,15 +2473,49 @@ static void get_client_hello(tls_state_t *tls)
|
|||
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 */
|
||||
/* Select cipher + cert pair from client's list, preferring our ciphers in order */
|
||||
for (i = 0; i < NUM_CIPHERS*2; i += 2) {
|
||||
const uint8_t *our_cipher = &supported_ciphers[i];
|
||||
int key_type;
|
||||
|
||||
dbg("Selected cipher: %04x", tls->cipher_id);
|
||||
/* Skip all ECDHE ciphers (0xC0xx) - we don't support server-side ephemeral
|
||||
* EC key generation yet. ECDHE_RSA uses RSA certificates (which we have)
|
||||
* but still requires generating ephemeral EC keys for the key exchange.
|
||||
* We only support plain RSA key exchange (0x00xx) on the server side.
|
||||
*/
|
||||
if (our_cipher[0] == 0xC0) {
|
||||
//TODO: implement server-side ECDHE
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Determine required key type for this cipher */
|
||||
key_type = is_cipher_ECDSA(our_cipher);
|
||||
if (key_type == KEY_ECDSA) {
|
||||
if (!tls->hsd->keys[KEY_ECDSA])
|
||||
/* No ECDSA cert configured, can't choose this */
|
||||
continue;
|
||||
//TODO: ECDSA not supported yet at all
|
||||
continue;
|
||||
} else {
|
||||
if (!tls->hsd->keys[KEY_RSA])
|
||||
/* No RSA cert configured, can't choose this */
|
||||
continue;
|
||||
/* We _can_ choose this! */
|
||||
}
|
||||
|
||||
/* Check if this cipher is in client's list */
|
||||
for (j = 0; j < cipher_list_len; j += 2) {
|
||||
if (p[j] == our_cipher[0] && p[j + 1] == our_cipher[1]) {
|
||||
/* Found a match! */
|
||||
set_cipher_parameters(tls, our_cipher);
|
||||
dbg("Selected cipher: %04x", tls->cipher_id);
|
||||
tls->hsd->key_type_chosen = key_type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* try our next cipherid */
|
||||
}
|
||||
bb_simple_error_msg_and_die("no common cipher suites");
|
||||
}
|
||||
|
||||
static void send_server_hello(tls_state_t *tls)
|
||||
|
|
@ -2510,7 +2548,7 @@ static void send_server_hello(tls_state_t *tls)
|
|||
|
||||
/* Selected cipher suite */
|
||||
record->cipherid_hi = tls->cipher_id >> 8;
|
||||
record->cipherid_lo = tls->cipher_id & 0xff;
|
||||
record->cipherid_lo = tls->cipher_id; /* & 0xff implicit */
|
||||
|
||||
/* No compression */
|
||||
//record->comprtype = 0;
|
||||
|
|
@ -2532,37 +2570,14 @@ static void send_server_hello(tls_state_t *tls)
|
|||
|
||||
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;
|
||||
void *record;
|
||||
int n = tls->hsd->key_type_chosen;
|
||||
int sz = tls->hsd->certsize[n];
|
||||
|
||||
cert_len = tls->hsd->server_cert_der_len;
|
||||
total_len = sizeof(*record) + cert_len;
|
||||
|
||||
record = get_outbuf_fill_handshake_record(tls, 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)", cert_len);
|
||||
xwrite_and_update_handshake_hash(tls, total_len);
|
||||
record = tls_get_outbuf(tls, sz);
|
||||
memcpy(record, tls->hsd->certs[n], sz);
|
||||
dbg(">> CERTIFICATE");
|
||||
xwrite_and_update_handshake_hash(tls, sz);
|
||||
}
|
||||
|
||||
static void send_server_hello_done(tls_state_t *tls)
|
||||
|
|
@ -2615,9 +2630,10 @@ static void get_client_key_exchange(tls_state_t *tls)
|
|||
{
|
||||
int32 ret;
|
||||
uint32 premaster_len;
|
||||
psRsaKey_t *key = &tls->hsd->rsa_priv_key;
|
||||
|
||||
premaster_len = RSA_PREMASTER_SIZE;
|
||||
ret = psRsaDecryptPriv(NULL, &tls->hsd->server_rsa_priv_key,
|
||||
ret = psRsaDecryptPriv(NULL, key,
|
||||
encrypted_premaster, enckey_len,
|
||||
premaster, premaster_len, NULL);
|
||||
|
||||
|
|
@ -2665,16 +2681,10 @@ static void get_client_key_exchange(tls_state_t *tls)
|
|||
* }
|
||||
*/
|
||||
static NOINLINE /* don't inline - large stack use */
|
||||
void load_rsa_priv_key(psRsaKey_t *key, const char *filename)
|
||||
void load_rsa_priv_key(psRsaKey_t *key, uint8_t *buf, ssize_t sz)
|
||||
{
|
||||
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;
|
||||
|
||||
|
|
@ -2690,15 +2700,12 @@ void load_rsa_priv_key(psRsaKey_t *key, const char *filename)
|
|||
|
||||
if (*der == 0x30) {
|
||||
/* PKCS#8 format - skip AlgorithmIdentifier and enter OCTET STRING */
|
||||
dbg("Detected PKCS#8 private key format");
|
||||
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");
|
||||
}
|
||||
/* else: PKCS#1 format - we already skipped the version */
|
||||
|
||||
/* Read the key components */
|
||||
der_binary_to_pstm(&key->N, der, end); /* modulus */
|
||||
|
|
@ -2726,26 +2733,203 @@ void load_rsa_priv_key(psRsaKey_t *key, const char *filename)
|
|||
|
||||
key->size = pstm_unsigned_bin_size(&key->N);
|
||||
key->optimized = 1; /* We have CRT parameters */
|
||||
}
|
||||
|
||||
dbg("Loaded RSA private key, size:%d", key->size);
|
||||
static char *decode_base64_or_die(char *dst, const char *src)
|
||||
{
|
||||
char *dst_end = decode_base64(dst, &src);
|
||||
if (*src != '\0')
|
||||
bb_error_msg_and_die("base64 decode error");
|
||||
return dst_end;
|
||||
}
|
||||
|
||||
/* Parse PEM file and extract key + cert chain pairs
|
||||
* Returns number of pairs loaded
|
||||
*/
|
||||
static void load_pem_key_cert_pairs(tls_state_t *tls, const char *pem_filename)
|
||||
{
|
||||
static const char BLOCK_NAMES[] ALIGN1 =
|
||||
"EC PARAMETERS" "\0"
|
||||
"CERTIFICATE" "\0"
|
||||
"EC PRIVATE KEY" "\0"
|
||||
"PRIVATE KEY" "\0"
|
||||
"RSA PRIVATE KEY""\0"
|
||||
;
|
||||
enum {
|
||||
str_EC_PARAMETERS = 0,
|
||||
str_CERTIFICATE = 1,
|
||||
str_EC_KEY = 2,
|
||||
};
|
||||
char *p;
|
||||
char *pem_data;
|
||||
size_t pem_size;
|
||||
char *der_data;
|
||||
unsigned der_size;
|
||||
int keyidx;
|
||||
|
||||
/* Read PEM file */
|
||||
pem_size = 64 * 1024; /* sanity limit */
|
||||
pem_data = xmalloc_xopen_read_close(pem_filename, &pem_size);
|
||||
|
||||
der_data = NULL;
|
||||
der_size = 0;
|
||||
keyidx = -1; /* "we did not see any KEY yet" */
|
||||
|
||||
p = pem_data;
|
||||
while (1) {
|
||||
unsigned n;
|
||||
char *block_end;
|
||||
char *block_type_end;
|
||||
|
||||
/* Find next PEM block */
|
||||
p = skip_whitespace(p);
|
||||
if (*p == '\0')
|
||||
break; /* end of file */
|
||||
p = is_prefixed_with(p, "-----BEGIN ");
|
||||
if (!p)
|
||||
goto err;
|
||||
block_type_end = strstr(p, "-----\n");
|
||||
if (!block_type_end)
|
||||
goto err;
|
||||
block_type_end += 5;
|
||||
block_end = strstr(block_type_end, "\n-----END ");
|
||||
if (!block_end)
|
||||
goto err;
|
||||
*block_end = '\0';
|
||||
block_end += 10;
|
||||
//-----BEGIN PRIVATE KEY-----\n
|
||||
// ^p ^block_type_end
|
||||
//BASE64HERE-BASE64HERE
|
||||
//-----END PRIVATE KEY-----
|
||||
// ^block_end
|
||||
/* The headers must match */
|
||||
*block_type_end = '\0';
|
||||
if (!is_prefixed_with(block_end, p))
|
||||
goto err;
|
||||
/* Truncate trailing dashes from block type name */
|
||||
block_type_end[-5] = '\0';
|
||||
|
||||
block_end += (block_type_end - p);
|
||||
block_type_end++;
|
||||
//BASE64HERE-BASE64HERE
|
||||
//^block_type_end
|
||||
//-----END PRIVATE KEY-----
|
||||
// ^block_end
|
||||
n = index_in_strings(BLOCK_NAMES, p);
|
||||
if ((int)n < 0)
|
||||
bb_error_msg_and_die("'%s': unknown PEM block '%s'", pem_filename, p);
|
||||
|
||||
/* Note: may point to "\n" or even NUL */
|
||||
p = block_end;
|
||||
|
||||
/* What block do we see? */
|
||||
|
||||
if (n == str_EC_PARAMETERS) {
|
||||
/* "openssl ecparam -genkey" generates these, skip silently */
|
||||
continue; /* skip */
|
||||
}
|
||||
|
||||
if (n == str_CERTIFICATE) {
|
||||
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 */
|
||||
/* followed by cert2_len24, cert2 DER data, ... */
|
||||
};
|
||||
struct certificate_msg *cert_msg;
|
||||
unsigned start;
|
||||
|
||||
if (keyidx < 0)
|
||||
bb_error_msg_and_die("'%s': certificate must be after key", pem_filename);
|
||||
|
||||
/* We create or update a full HANDSHAKE_CERTIFICATE message */
|
||||
if (der_size == 0) {
|
||||
der_size = sizeof(*cert_msg);
|
||||
der_data = xzalloc(der_size);
|
||||
cert_msg = (void*)der_data;
|
||||
cert_msg->type = HANDSHAKE_CERTIFICATE;
|
||||
} else {
|
||||
/* We are here when we decode second or later cert */
|
||||
der_size += 3; /* for len24 */
|
||||
}
|
||||
|
||||
/* Decode BASE64 */
|
||||
start = der_size;
|
||||
der_size += block_end - block_type_end; /* worst case size */
|
||||
der_data = xrealloc(der_data, der_size);
|
||||
der_size = decode_base64_or_die(der_data + start, block_type_end) - der_data;
|
||||
der_data = xrealloc(der_data, der_size);
|
||||
|
||||
/* Fill last cert's len24 */
|
||||
n = der_size - start;
|
||||
der_data[start - 3] = n >> 16;
|
||||
der_data[start - 2] = n >> 8;
|
||||
der_data[start - 1] = n;
|
||||
/* Update sizes in header */
|
||||
cert_msg = (void*)der_data;
|
||||
n = der_size - 4;
|
||||
cert_msg->len24_hi = n >> 16;
|
||||
cert_msg->len24_mid = n >> 8;
|
||||
cert_msg->len24_lo = n;
|
||||
n -= 3;
|
||||
cert_msg->cert_chain_len24_hi = n >> 16;
|
||||
cert_msg->cert_chain_len24_mid = n >> 8;
|
||||
cert_msg->cert_chain_len24_lo = n;
|
||||
|
||||
tls->hsd->certs[keyidx] = der_data;
|
||||
tls->hsd->certsize[keyidx] = der_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We see a key */
|
||||
|
||||
/* Decode BASE64 */
|
||||
der_size = block_end - block_type_end; /* worst case size */
|
||||
der_data = xmalloc(der_size);
|
||||
der_size = decode_base64_or_die(der_data, block_type_end) - der_data;
|
||||
der_data = xrealloc(der_data, der_size);
|
||||
|
||||
keyidx = (n == str_EC_KEY) ? KEY_ECDSA : KEY_RSA;
|
||||
if (tls->hsd->keys[keyidx])
|
||||
bb_error_msg_and_die("'%s': more than one key", pem_filename);
|
||||
tls->hsd->keys[keyidx] = der_data;
|
||||
tls->hsd->keysize[keyidx] = der_size;
|
||||
|
||||
der_data = NULL;
|
||||
der_size = 0;
|
||||
} /* while (parsing PEM) */
|
||||
free(pem_data);
|
||||
|
||||
if (!tls->hsd->keys[KEY_RSA] && !tls->hsd->keys[KEY_ECDSA])
|
||||
bb_error_msg_and_die("'%s': no private keys", pem_filename);
|
||||
|
||||
if (tls->hsd->keys[KEY_RSA]) {
|
||||
if (!tls->hsd->certs[KEY_RSA])
|
||||
bb_error_msg_and_die("'%s': key with no cert", pem_filename);
|
||||
/* Parse RSA key from DER */
|
||||
load_rsa_priv_key(&tls->hsd->rsa_priv_key, (uint8_t*)tls->hsd->keys[KEY_RSA], tls->hsd->keysize[KEY_RSA]);
|
||||
}
|
||||
if (tls->hsd->keys[KEY_ECDSA]) {
|
||||
if (!tls->hsd->certs[KEY_ECDSA])
|
||||
bb_error_msg_and_die("'%s': key with no cert", pem_filename);
|
||||
bb_error_msg("'%s': ECDSA keys not supported", pem_filename);
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
bb_error_msg_and_die("malformed PEM file at '%.*s'", (int)(skip_whitespace(p) - p), p);
|
||||
}
|
||||
|
||||
void FAST_FUNC tls_handshake_as_server(tls_state_t *tls,
|
||||
const char *privkey_der_filename,
|
||||
const char *cert_der_filename)
|
||||
const char *pem_filename)
|
||||
{
|
||||
dbg("Starting TLS server handshake");
|
||||
|
||||
/* 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", tls->hsd->server_rsa_priv_key.size);
|
||||
/* Load server key(s) and certificate(s) from PEM file */
|
||||
load_pem_key_cert_pairs(tls, pem_filename);
|
||||
|
||||
sha256_begin(&tls->hsd->handshake_hash_ctx);
|
||||
tls->expecting_first_packet = 1;
|
||||
|
|
@ -2776,13 +2960,14 @@ void FAST_FUNC tls_handshake_as_server(tls_state_t *tls,
|
|||
send_change_cipher_spec(tls);
|
||||
send_finished(tls, "server finished");
|
||||
|
||||
dbg("Server handshake complete");
|
||||
|
||||
/* application data can be sent/received */
|
||||
|
||||
/* free handshake data */
|
||||
psRsaKey_clear(&tls->hsd->server_rsa_priv_key);
|
||||
free(tls->hsd->server_cert_der);
|
||||
psRsaKey_clear(&tls->hsd->rsa_priv_key);
|
||||
free(tls->hsd->keys[0]);
|
||||
free(tls->hsd->keys[1]);
|
||||
free(tls->hsd->certs[0]);
|
||||
free(tls->hsd->certs[1]);
|
||||
// if (PARANOIA)
|
||||
// memset(tls->hsd, 0, sizeof(*tls->hsd));
|
||||
free(tls->hsd);
|
||||
|
|
|
|||
Loading…
Reference in a new issue