diff options
Diffstat (limited to 'networking/tls.c')
-rw-r--r-- | networking/tls.c | 225 |
1 files changed, 188 insertions, 37 deletions
diff --git a/networking/tls.c b/networking/tls.c index 69c81b5..b0a4f7e 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -1,7 +1,7 @@ /* - * Licensed under GPLv2, see file LICENSE in this source tree. - * * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. */ //config:config TLS //config: bool "tls (debugging)" @@ -10,6 +10,11 @@ //applet:IF_TLS(APPLET(tls, BB_DIR_USR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_TLS) += tls.o +//kbuild:lib-$(CONFIG_TLS) += tls_pstm.o +//kbuild:lib-$(CONFIG_TLS) += tls_pstm_montgomery_reduce.o +//kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o +//kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o +//kbuild:lib-$(CONFIG_TLS) += tls_rsa.o ////kbuild:lib-$(CONFIG_TLS) += tls_ciphers.o ////kbuild:lib-$(CONFIG_TLS) += tls_aes.o ////kbuild:lib-$(CONFIG_TLS) += tls_aes_gcm.o @@ -18,9 +23,7 @@ //usage: "HOST[:PORT]" //usage:#define tls_full_usage "\n\n" -#include "libbb.h" -//#include "tls_cryptoapi.h" -//#include "tls_ciphers.h" +#include "tls.h" #if 1 # define dbg(...) fprintf(stderr, __VA_ARGS__) @@ -28,23 +31,26 @@ # define dbg(...) ((void)0) #endif -#define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 -#define RECORD_TYPE_ALERT 21 -#define RECORD_TYPE_HANDSHAKE 22 -#define RECORD_TYPE_APPLICATION_DATA 23 - -#define HANDSHAKE_HELLO_REQUEST 0 -#define HANDSHAKE_CLIENT_HELLO 1 -#define HANDSHAKE_SERVER_HELLO 2 -#define HANDSHAKE_HELLO_VERIFY_REQUEST 3 -#define HANDSHAKE_NEW_SESSION_TICKET 4 -#define HANDSHAKE_CERTIFICATE 11 -#define HANDSHAKE_SERVER_KEY_EXCHANGE 12 -#define HANDSHAKE_CERTIFICATE_REQUEST 13 -#define HANDSHAKE_SERVER_HELLO_DONE 14 -#define HANDSHAKE_CERTIFICATE_VERIFY 15 -#define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 -#define HANDSHAKE_FINISHED 20 +#define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 +#define RECORD_TYPE_ALERT 21 +#define RECORD_TYPE_HANDSHAKE 22 +#define RECORD_TYPE_APPLICATION_DATA 23 + +#define HANDSHAKE_HELLO_REQUEST 0 +#define HANDSHAKE_CLIENT_HELLO 1 +#define HANDSHAKE_SERVER_HELLO 2 +#define HANDSHAKE_HELLO_VERIFY_REQUEST 3 +#define HANDSHAKE_NEW_SESSION_TICKET 4 +#define HANDSHAKE_CERTIFICATE 11 +#define HANDSHAKE_SERVER_KEY_EXCHANGE 12 +#define HANDSHAKE_CERTIFICATE_REQUEST 13 +#define HANDSHAKE_SERVER_HELLO_DONE 14 +#define HANDSHAKE_CERTIFICATE_VERIFY 15 +#define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 +#define HANDSHAKE_FINISHED 20 + +#define SSL_HS_RANDOM_SIZE 32 +#define SSL_HS_RSA_PREMASTER_SIZE 48 #define SSL_NULL_WITH_NULL_NULL 0x0000 #define SSL_RSA_WITH_NULL_MD5 0x0001 @@ -112,6 +118,7 @@ //TLS 1.2 #define TLS_MAJ 3 #define TLS_MIN 3 +//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // ok, recvs SERVER_KEY_EXCHANGE *** matrixssl uses this on my box //#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE // All GCMs: //#define CIPHER_ID TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 // SSL_ALERT_HANDSHAKE_FAILURE @@ -123,9 +130,9 @@ //#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 //#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE //#define CIPHER_ID TLS_RSA_WITH_AES_256_GCM_SHA384 // ok, no SERVER_KEY_EXCHANGE -#define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE +#define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE *** select this? //#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE -// (tested b/c this one doesn't req server certs... no luck) +//^^^^^^^^^^^^^^^^^^^^^^^ (tested b/c this one doesn't req server certs... no luck) //test TLS_RSA_WITH_AES_128_CBC_SHA, in tls 1.2 it's mandated to be always supported struct record_hdr { @@ -137,8 +144,7 @@ struct record_hdr { typedef struct tls_state { int fd; - uint8_t *pubkey; - int pubkey_len; + psRsaKey_t server_rsa_pub_key; // RFC 5246 // |6.2.1. Fragmentation @@ -170,6 +176,12 @@ typedef struct tls_state { uint8_t inbuf[18*1024]; } tls_state_t; +void tls_get_random(void *buf, unsigned len) +{ + if (len != open_read_close("/dev/urandom", buf, len)) + xfunc_die(); +} + static tls_state_t *new_tls_state(void) { @@ -286,7 +298,7 @@ static void send_client_hello(tls_state_t *tls) hello.len24_lo = (sizeof(hello) - sizeof(hello.xhdr) - 4); hello.proto_maj = TLS_MAJ; hello.proto_min = TLS_MIN; - open_read_close("/dev/urandom", hello.rand32, sizeof(hello.rand32)); + tls_get_random(hello.rand32, sizeof(hello.rand32)); //hello.session_id_len = 0; //hello.cipherid_len16_hi = 0; hello.cipherid_len16_lo = 2 * 1; @@ -407,7 +419,18 @@ static uint8_t *skip_der_item(uint8_t *der, uint8_t *end) return new_der; } -static void *find_key_in_der_cert(int *key_len, uint8_t *der, int len) +static void der_binary_to_pstm(pstm_int *pstm_n, uint8_t *der, uint8_t *end) +{ + uint8_t *bin_ptr; + unsigned len = get_der_len(&bin_ptr, der, end); + + dbg("binary bytes:%u, first:0x%02x\n", len, bin_ptr[0]); + pstm_init_for_read_unsigned_bin(/*pool:*/ NULL, pstm_n, len); + pstm_read_unsigned_bin(pstm_n, bin_ptr, len); + //return bin + len; +} + +static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len) { /* Certificate is a DER-encoded data structure. Each DER element has a length, * which makes it easy to skip over large compound elements of any complexity @@ -504,19 +527,43 @@ static void *find_key_in_der_cert(int *key_len, uint8_t *der, int len) der = skip_der_item(der, end); /* validity */ der = skip_der_item(der, end); /* subject */ - /* enter "subjectPublicKeyInfo" */ + /* enter subjectPublicKeyInfo */ der = enter_der_item(der, &end); - - /* skip "subjectPublicKeyInfo.algorithm" */ + { /* check subjectPublicKeyInfo.algorithm */ + static const uint8_t expected[] = { + 0x30,0x0d, // SEQ 13 bytes + 0x06,0x09, 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, // OID RSA_KEY_ALG 42.134.72.134.247.13.1.1.1 + //0x05,0x00, // NULL + }; + if (memcmp(der, expected, sizeof(expected)) != 0) + bb_error_msg_and_die("not RSA key"); + } + /* skip subjectPublicKeyInfo.algorithm */ der = skip_der_item(der, end); - /* enter "subjectPublicKeyInfo.publicKey" */ + /* enter subjectPublicKeyInfo.publicKey */ // die_if_not_this_der_type(der, end, 0x03); /* must be BITSTRING */ der = enter_der_item(der, &end); - /* return a copy */ - *key_len = end - der; - dbg("copying key bytes:%u, first:0x%02x\n", *key_len, der[0]); - return xmemdup(der, *key_len); + /* parse RSA key: */ +//based on getAsnRsaPubKey(), pkcs1ParsePrivBin() is also of note + dbg("key bytes:%u, first:0x%02x\n", (int)(end - der), der[0]); + if (end - der < 14) xfunc_die(); + /* example format: + * ignore bits: 00 + * SEQ 0x018a/394 bytes: 3082018a + * INTEGER 0x0181/385 bytes (modulus): 02820181 XX...XXX + * INTEGER 3 bytes (exponent): 0203 010001 + */ + if (*der != 0) /* "ignore bits", should be 0 */ + xfunc_die(); + der++; + der = enter_der_item(der, &end); /* enter SEQ */ + //memset(tls->server_rsa_pub_key, 0, sizeof(tls->server_rsa_pub_key)); + der_binary_to_pstm(&tls->server_rsa_pub_key.N, der, end); /* modulus */ + der = skip_der_item(der, end); + der_binary_to_pstm(&tls->server_rsa_pub_key.e, der, end); /* exponent */ + tls->server_rsa_pub_key.size = pstm_unsigned_bin_size(&tls->server_rsa_pub_key.N); + dbg("server_rsa_pub_key.size:%d\n", tls->server_rsa_pub_key.size); } static void get_server_cert_or_die(tls_state_t *tls) @@ -553,7 +600,107 @@ static void get_server_cert_or_die(tls_state_t *tls) len = len1; if (len) - tls->pubkey = find_key_in_der_cert(&tls->pubkey_len, certbuf + 10, len); + find_key_in_der_cert(tls, certbuf + 10, len); +} + +static void send_client_key_exchange(tls_state_t *tls) +{ +#if 0 //matrixssl code snippets: + int32 csRsaEncryptPub(psPool_t *pool, psPubKey_t *key, + unsigned char *in, uint32 inlen, unsigned char *out, uint32 outlen, + void *data) + { + psAssert(key->type == PS_RSA); + return psRsaEncryptPub(pool, (psRsaKey_t*)key->key, in, inlen, out, outlen, + data); + } +... + /* pkaAfter.user is buffer len */ + if ((rc = csRsaEncryptPub(pka->pool, &ssl->sec.cert->publicKey, + ssl->sec.premaster, ssl->sec.premasterSize, pka->outbuf, + pka->user, pka->data)) < 0) { + if (rc == PS_PENDING) { + /* For these ClientKeyExchange paths, we do want to come + back through nowDoCkePka for a double pass so each + case can manage its own pkaAfter and to make sure + psX509FreeCert and sslCreateKeys() are hit below. */ + return rc; + } + psTraceIntInfo("csRsaEncryptPub in CKE failed %d\n", rc); + return MATRIXSSL_ERROR; + } + /* RSA closed the pool on second pass */ + pka->pool = NULL; + clearPkaAfter(ssl); +... +#ifdef USE_RSA_CIPHER_SUITE +/* + Standard RSA suite +*/ + ssl->sec.premasterSize = SSL_HS_RSA_PREMASTER_SIZE; + ssl->sec.premaster = psMalloc(ssl->hsPool, + SSL_HS_RSA_PREMASTER_SIZE); + if (ssl->sec.premaster == NULL) { + return SSL_MEM_ERROR; + } + + ssl->sec.premaster[0] = ssl->reqMajVer; + ssl->sec.premaster[1] = ssl->reqMinVer; + if (matrixCryptoGetPrngData(ssl->sec.premaster + 2, + SSL_HS_RSA_PREMASTER_SIZE - 2, ssl->userPtr) < 0) { + return MATRIXSSL_ERROR; + } + + /* Shedule RSA encryption. Put tmp pool under control of After */ + pkaAfter->type = PKA_AFTER_RSA_ENCRYPT; + pkaAfter->outbuf = c; + pkaAfter->data = pkiData; + pkaAfter->pool = pkiPool; + pkaAfter->user = (uint32)(end - c); /* Available space */ + + c += keyLen; +#endif +#endif // 0 + + struct client_key_exchange { + struct record_hdr xhdr; + uint8_t type; + uint8_t len24_hi, len24_mid, len24_lo; + uint8_t keylen16_hi, keylen16_lo; /* exist for RSA, but not for some other key types */ +//had a bug when had no keylen: we: +//write(3, "\x16\x03\x03\x01\x84\x10\x00\x01\x80\xXX\xXX\xXX\xXX\xXX\xXX...", 393) = 393 +//openssl: +//write to 0xe9a090 [0xf9ac20] (395 bytes => 395 (0x18B)) +//0000 - 16 03 03 01 86 10 00 01 -82 01 80 xx xx xx xx xx + uint8_t key[384]; // size?? + }; + struct client_key_exchange record; + uint8_t premaster[SSL_HS_RSA_PREMASTER_SIZE]; + + memset(&record, 0, sizeof(record)); + record.xhdr.type = RECORD_TYPE_HANDSHAKE; + record.xhdr.proto_maj = TLS_MAJ; + record.xhdr.proto_min = TLS_MIN; + record.xhdr.len16_hi = (sizeof(record) - sizeof(record.xhdr)) >> 8; + record.xhdr.len16_lo = (sizeof(record) - sizeof(record.xhdr)) & 0xff; + record.type = HANDSHAKE_CLIENT_KEY_EXCHANGE; + //record.len24_hi = 0; + record.len24_mid = (sizeof(record) - sizeof(record.xhdr) - 4) >> 8; + record.len24_lo = (sizeof(record) - sizeof(record.xhdr) - 4) & 0xff; + record.keylen16_hi = (sizeof(record) - sizeof(record.xhdr) - 6) >> 8; + record.keylen16_lo = (sizeof(record) - sizeof(record.xhdr) - 6) & 0xff; + + tls_get_random(premaster, sizeof(premaster)); + premaster[0] = TLS_MAJ; + premaster[1] = TLS_MIN; + psRsaEncryptPub(/*pool:*/ NULL, + /* psRsaKey_t* */ &tls->server_rsa_pub_key, + premaster, /*inlen:*/ sizeof(premaster), + record.key, sizeof(record.key), + data_param_ignored + ); + + xwrite(tls->fd, &record, sizeof(record)); } static void tls_handshake(tls_state_t *tls) @@ -614,6 +761,8 @@ static void tls_handshake(tls_state_t *tls) // 459 bytes: // 0c 00|01|c7 03|00|17|41|04|87|94|2e|2f|68|d0|c9|f4|97|a8|2d|ef|ed|67|ea|c6|f3|b3|56|47|5d|27|b6|bd|ee|70|25|30|5e|b0|8e|f6|21|5a... //SvKey len=455^ + // with TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: 461 bytes: + // 0c 00|01|c9 03|00|17|41|04|cd|9b|b4|29|1f|f6|b0|c2|84|82|7f|29|6a|47|4e|ec|87|0b|c1|9c|69|e1|f8|c6|d0|53|e9|27|90|a5|c8|02|15|75... dbg("got SERVER_KEY_EXCHANGE\n"); len = xread_tls_block(tls); break; @@ -624,6 +773,8 @@ static void tls_handshake(tls_state_t *tls) case HANDSHAKE_SERVER_HELLO_DONE: // 0e 000000 (len:0) dbg("got SERVER_HELLO_DONE\n"); + send_client_key_exchange(tls); + len = xread_tls_block(tls); break; default: tls_error_die(tls); |