return len;
}
-static void send_client_hello(tls_state_t *tls)
-{
- struct client_hello {
- struct record_hdr xhdr;
- 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 session_id[]; */
- uint8_t cipherid_len16_hi, cipherid_len16_lo;
- uint8_t cipherid[2 * 1]; /* actually variable */
- uint8_t comprtypes_len;
- uint8_t comprtypes[1]; /* actually variable */
- };
- struct client_hello hello;
-
- memset(&hello, 0, sizeof(hello));
- hello.xhdr.type = RECORD_TYPE_HANDSHAKE;
- hello.xhdr.proto_maj = TLS_MAJ;
- hello.xhdr.proto_min = TLS_MIN;
- //zero: hello.xhdr.len16_hi = (sizeof(hello) - sizeof(hello.xhdr)) >> 8;
- hello.xhdr.len16_lo = (sizeof(hello) - sizeof(hello.xhdr));
- hello.type = HANDSHAKE_CLIENT_HELLO;
- //hello.len24_hi = 0;
- //zero: hello.len24_mid = (sizeof(hello) - sizeof(hello.xhdr) - 4) >> 8;
- hello.len24_lo = (sizeof(hello) - sizeof(hello.xhdr) - 4);
- hello.proto_maj = TLS_MAJ; /* the "requested" version of the protocol, */
- hello.proto_min = TLS_MIN; /* can be higher than one in record headers */
- tls_get_random(hello.rand32, sizeof(hello.rand32));
- //hello.session_id_len = 0;
- //hello.cipherid_len16_hi = 0;
- hello.cipherid_len16_lo = 2 * 1;
- hello.cipherid[0] = CIPHER_ID >> 8;
- hello.cipherid[1] = CIPHER_ID & 0xff;
- hello.comprtypes_len = 1;
- //hello.comprtypes[0] = 0;
-
- xwrite(tls->fd, &hello, sizeof(hello));
-}
-
-static void get_server_hello_or_die(tls_state_t *tls)
-{
- struct server_hello {
- struct record_hdr xhdr;
- uint8_t type;
- uint8_t len24_hi, len24_mid, len24_lo;
- uint8_t proto_maj, proto_min;
- uint8_t rand32[32]; /* first 4 bytes are unix time in BE format */
- uint8_t session_id_len;
- uint8_t session_id[32];
- uint8_t cipherid_hi, cipherid_lo;
- uint8_t comprtype;
- /* extensions may follow, but only those which client offered in its Hello */
- };
- struct server_hello *hp;
-
- xread_tls_handshake_block(tls, 74);
-
- hp = (void*)tls->inbuf;
- // 74 bytes:
- // 02 000046 03|03 58|78|cf|c1 50|a5|49|ee|7e|29|48|71|fe|97|fa|e8|2d|19|87|72|90|84|9d|37|a3|f0|cb|6f|5f|e3|3c|2f |20 |d8|1a|78|96|52|d6|91|01|24|b3|d6|5b|b7|d0|6c|b3|e1|78|4e|3c|95|de|74|a0|ba|eb|a7|3a|ff|bd|a2|bf |00|9c |00|
- //SvHl len=70 maj.min unixtime^^^ 28randbytes^^^^^^^^^^^^^^^^^^^^^^^^^^^^_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_^^^ slen sid32bytes^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cipSel comprSel
- if (hp->type != HANDSHAKE_SERVER_HELLO
- || hp->len24_hi != 0
- || hp->len24_mid != 0
- || hp->len24_lo != 70
- || hp->proto_maj != TLS_MAJ
- || hp->proto_min != TLS_MIN
- || hp->session_id_len != 32
- || hp->cipherid_hi != (CIPHER_ID >> 8)
- || hp->cipherid_lo != (CIPHER_ID & 0xff)
- || hp->comprtype != 0
- ) {
- tls_error_die(tls);
- }
- dbg("got SERVER_HELLO\n");
-}
-
static unsigned get_der_len(uint8_t **bodyp, uint8_t *der, uint8_t *end)
{
unsigned len, len1;
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)
+/*
+ * TLS Handshake routines
+ */
+static void send_client_hello(tls_state_t *tls)
+{
+ struct client_hello {
+ struct record_hdr xhdr;
+ 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 session_id[]; */
+ uint8_t cipherid_len16_hi, cipherid_len16_lo;
+ uint8_t cipherid[2 * 1]; /* actually variable */
+ uint8_t comprtypes_len;
+ uint8_t comprtypes[1]; /* actually variable */
+ };
+ struct client_hello hello;
+
+ memset(&hello, 0, sizeof(hello));
+ hello.xhdr.type = RECORD_TYPE_HANDSHAKE;
+ hello.xhdr.proto_maj = TLS_MAJ;
+ hello.xhdr.proto_min = TLS_MIN;
+ //zero: hello.xhdr.len16_hi = (sizeof(hello) - sizeof(hello.xhdr)) >> 8;
+ hello.xhdr.len16_lo = (sizeof(hello) - sizeof(hello.xhdr));
+ hello.type = HANDSHAKE_CLIENT_HELLO;
+ //hello.len24_hi = 0;
+ //zero: hello.len24_mid = (sizeof(hello) - sizeof(hello.xhdr) - 4) >> 8;
+ hello.len24_lo = (sizeof(hello) - sizeof(hello.xhdr) - 4);
+ hello.proto_maj = TLS_MAJ; /* the "requested" version of the protocol, */
+ hello.proto_min = TLS_MIN; /* can be higher than one in record headers */
+ tls_get_random(hello.rand32, sizeof(hello.rand32));
+ //hello.session_id_len = 0;
+ //hello.cipherid_len16_hi = 0;
+ hello.cipherid_len16_lo = 2 * 1;
+ hello.cipherid[0] = CIPHER_ID >> 8;
+ hello.cipherid[1] = CIPHER_ID & 0xff;
+ hello.comprtypes_len = 1;
+ //hello.comprtypes[0] = 0;
+
+ xwrite(tls->fd, &hello, sizeof(hello));
+#if 0 /* dump */
+ for (;;) {
+ uint8_t buf[16*1024];
+ sleep(2);
+ len = recv(tls->fd, buf, sizeof(buf), 0); //MSG_DONTWAIT);
+ if (len < 0) {
+ if (errno == EAGAIN)
+ continue;
+ bb_perror_msg_and_die("recv");
+ }
+ if (len == 0)
+ break;
+ dump(buf, len);
+ }
+#endif
+}
+
+static void get_server_hello(tls_state_t *tls)
+{
+ struct server_hello {
+ struct record_hdr xhdr;
+ uint8_t type;
+ uint8_t len24_hi, len24_mid, len24_lo;
+ uint8_t proto_maj, proto_min;
+ uint8_t rand32[32]; /* first 4 bytes are unix time in BE format */
+ uint8_t session_id_len;
+ uint8_t session_id[32];
+ uint8_t cipherid_hi, cipherid_lo;
+ uint8_t comprtype;
+ /* extensions may follow, but only those which client offered in its Hello */
+ };
+ struct server_hello *hp;
+
+ xread_tls_handshake_block(tls, 74);
+
+ hp = (void*)tls->inbuf;
+ // 74 bytes:
+ // 02 000046 03|03 58|78|cf|c1 50|a5|49|ee|7e|29|48|71|fe|97|fa|e8|2d|19|87|72|90|84|9d|37|a3|f0|cb|6f|5f|e3|3c|2f |20 |d8|1a|78|96|52|d6|91|01|24|b3|d6|5b|b7|d0|6c|b3|e1|78|4e|3c|95|de|74|a0|ba|eb|a7|3a|ff|bd|a2|bf |00|9c |00|
+ //SvHl len=70 maj.min unixtime^^^ 28randbytes^^^^^^^^^^^^^^^^^^^^^^^^^^^^_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_^^^ slen sid32bytes^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cipSel comprSel
+ if (hp->type != HANDSHAKE_SERVER_HELLO
+ || hp->len24_hi != 0
+ || hp->len24_mid != 0
+ || hp->len24_lo != 70
+ || hp->proto_maj != TLS_MAJ
+ || hp->proto_min != TLS_MIN
+ || hp->session_id_len != 32
+ || hp->cipherid_hi != (CIPHER_ID >> 8)
+ || hp->cipherid_lo != (CIPHER_ID & 0xff)
+ || hp->comprtype != 0
+ ) {
+ tls_error_die(tls);
+ }
+ dbg("got SERVER_HELLO\n");
+}
+
+static void get_server_cert(tls_state_t *tls)
{
struct record_hdr *xhdr;
uint8_t *certbuf;
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 key[384]; // size??
};
struct client_key_exchange record;
- uint8_t premaster[SSL_HS_RSA_PREMASTER_SIZE];
+ uint8_t rsa_premaster[SSL_HS_RSA_PREMASTER_SIZE];
memset(&record, 0, sizeof(record));
record.xhdr.type = RECORD_TYPE_HANDSHAKE;
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;
+ tls_get_random(rsa_premaster, sizeof(rsa_premaster));
+// RFC 5246
+// "Note: The version number in the PreMasterSecret is the version
+// offered by the client in the ClientHello.client_version, not the
+// version negotiated for the connection."
+ rsa_premaster[0] = TLS_MAJ;
+ rsa_premaster[1] = TLS_MIN;
psRsaEncryptPub(/*pool:*/ NULL,
/* psRsaKey_t* */ &tls->server_rsa_pub_key,
- premaster, /*inlen:*/ sizeof(premaster),
+ rsa_premaster, /*inlen:*/ sizeof(rsa_premaster),
record.key, sizeof(record.key),
data_param_ignored
);
xwrite(tls->fd, rec, sizeof(rec));
}
+static void send_client_finished(tls_state_t *tls)
+{
+// RFC 5246 on pseudorandom function (PRF):
+//
+// 5. HMAC and the Pseudorandom Function
+//...
+// In this section, we define one PRF, based on HMAC. This PRF with the
+// SHA-256 hash function is used for all cipher suites defined in this
+// document and in TLS documents published prior to this document when
+// TLS 1.2 is negotiated.
+//...
+// P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
+// HMAC_hash(secret, A(2) + seed) +
+// HMAC_hash(secret, A(3) + seed) + ...
+// where + indicates concatenation.
+// A() is defined as:
+// A(0) = seed
+// A(i) = HMAC_hash(secret, A(i-1))
+// P_hash can be iterated as many times as necessary to produce the
+// required quantity of data. For example, if P_SHA256 is being used to
+// create 80 bytes of data, it will have to be iterated three times
+// (through A(3)), creating 96 bytes of output data; the last 16 bytes
+// of the final iteration will then be discarded, leaving 80 bytes of
+// output data.
+//
+// TLS's PRF is created by applying P_hash to the secret as:
+//
+// PRF(secret, label, seed) = P_<hash>(secret, label + seed)
+//
+// The label is an ASCII string.
+
+ tls->fd = 0;
+
+// 7.4.9. Finished
+// A Finished message is always sent immediately after a change
+// cipher spec message to verify that the key exchange and
+// authentication processes were successful. It is essential that a
+// change cipher spec message be received between the other handshake
+// messages and the Finished message.
+//...
+// The Finished message is the first one protected with the just
+// negotiated algorithms, keys, and secrets. Recipients of Finished
+// messages MUST verify that the contents are correct. Once a side
+// has sent its Finished message and received and validated the
+// Finished message from its peer, it may begin to send and receive
+// application data over the connection.
+//...
+// struct {
+// opaque verify_data[verify_data_length];
+// } Finished;
+//
+// verify_data
+// PRF(master_secret, finished_label, Hash(handshake_messages))
+// [0..verify_data_length-1];
+//
+// finished_label
+// For Finished messages sent by the client, the string
+// "client finished". For Finished messages sent by the server,
+// the string "server finished".
+//
+// Hash denotes a Hash of the handshake messages. For the PRF
+// defined in Section 5, the Hash MUST be the Hash used as the basis
+// for the PRF. Any cipher suite which defines a different PRF MUST
+// also define the Hash to use in the Finished computation.
+//
+// In previous versions of TLS, the verify_data was always 12 octets
+// long. In the current version of TLS, it depends on the cipher
+// 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 get_change_cipher_spec(tls_state_t *tls)
+{
+ tls->fd = 0;
+}
+
+static void get_server_finished(tls_state_t *tls)
+{
+ tls->fd = 0;
+}
+
static void tls_handshake(tls_state_t *tls)
{
// Client RFC 5246 Server
int len;
send_client_hello(tls);
-#if 0 /* dump */
- for (;;) {
- uint8_t buf[16*1024];
- sleep(2);
- len = recv(tls->fd, buf, sizeof(buf), 0); //MSG_DONTWAIT);
- if (len < 0) {
- if (errno == EAGAIN)
- continue;
- bb_perror_msg_and_die("recv");
- }
- if (len == 0)
- break;
- dump(buf, len);
- }
-#endif
-
- get_server_hello_or_die(tls);
+ get_server_hello(tls);
//RFC 5246
// The server MUST send a Certificate message whenever the agreed-
//
// IOW: in practice, Certificate *always* follows.
// (for example, kernel.org does not even accept DH_anon cipher id)
- get_server_cert_or_die(tls);
+ get_server_cert(tls);
len = xread_tls_handshake_block(tls, 4);
if (tls->inbuf[5] == HANDSHAKE_SERVER_KEY_EXCHANGE) {
}
// if (tls->inbuf[5] == HANDSHAKE_CERTIFICATE_REQUEST) {
// dbg("got CERTIFICATE_REQUEST\n");
+//RFC 5246: (in response to this,) "If no suitable certificate is available,
+// the client MUST send a certificate message containing no
+// certificates. That is, the certificate_list structure has a
+// length of zero. ...
+// Client certificates are sent using the Certificate structure
+// defined in Section 7.4.2."
+// (i.e. the same format as server certs)
// xread_tls_handshake_block(tls, 4);
// }
if (tls->inbuf[5] == HANDSHAKE_SERVER_HELLO_DONE) {
send_client_key_exchange(tls);
send_change_cipher_spec(tls);
//we now should be able to send encrypted... as soon as we grok AES.
+ send_client_finished(tls);
+ get_change_cipher_spec(tls);
+ get_server_finished(tls);
+//we now should receive encrypted, and application data can be sent/received
} else {
tls_error_die(tls);
}
*/
#include "tls.h"
+/* The code below is taken from parts of
+ * matrixssl-3-7-2b-open/crypto/pubkey/pkcs.c
+ * matrixssl-3-7-2b-open/crypto/pubkey/rsa.c
+ * and (so far) almost not modified. Changes are flagged with ///bbox
+ */
+
#define pkcs1Pad(in, inlen, out, outlen, cryptType, userPtr) \
pkcs1Pad(in, inlen, out, outlen, cryptType)
static ///bbox
int32 pkcs1Pad(unsigned char *in, uint32 inlen, unsigned char *out,
- uint32 outlen, int32 cryptType, void *userPtr)
+ uint32 outlen, int32 cryptType, void *userPtr)
{
- unsigned char *c;
- int32 randomLen;
+ unsigned char *c;
+ int32 randomLen;
- randomLen = outlen - 3 - inlen;
- if (randomLen < 8) {
- psTraceCrypto("pkcs1Pad failure\n");
- return PS_LIMIT_FAIL;
- }
- c = out;
- *c = 0x00;
- c++;
- *c = (unsigned char)cryptType;
- c++;
- if (cryptType == PUBKEY_TYPE) {
- while (randomLen-- > 0) {
- *c++ = 0xFF;
- }
- } else {
- if (matrixCryptoGetPrngData(c, (uint32)randomLen, userPtr) < 0) {
- return PS_PLATFORM_FAIL;
- }
+ randomLen = outlen - 3 - inlen;
+ if (randomLen < 8) {
+ psTraceCrypto("pkcs1Pad failure\n");
+ return PS_LIMIT_FAIL;
+ }
+ c = out;
+ *c = 0x00;
+ c++;
+ *c = (unsigned char)cryptType;
+ c++;
+ if (cryptType == PUBKEY_TYPE) {
+ while (randomLen-- > 0) {
+ *c++ = 0xFF;
+ }
+ } else {
+ if (matrixCryptoGetPrngData(c, (uint32)randomLen, userPtr) < 0) {
+ return PS_PLATFORM_FAIL;
+ }
/*
- SECURITY: Read through the random data and change all 0x0 to 0x01.
- This is per spec that no random bytes should be 0
+ SECURITY: Read through the random data and change all 0x0 to 0x01.
+ This is per spec that no random bytes should be 0
*/
- while (randomLen-- > 0) {
- if (*c == 0x0) {
- *c = 0x01;
- }
- c++;
- }
- }
- *c = 0x00;
- c++;
- memcpy(c, in, inlen);
+ while (randomLen-- > 0) {
+ if (*c == 0x0) {
+ *c = 0x01;
+ }
+ c++;
+ }
+ }
+ *c = 0x00;
+ c++;
+ memcpy(c, in, inlen);
- return outlen;
+ return outlen;
}
#define psRsaCrypt(pool, in, inlen, out, outlen, key, type, data) \
}
int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key,
- unsigned char *in, uint32 inlen,
- unsigned char *out, uint32 outlen, void *data)
+ unsigned char *in, uint32 inlen,
+ unsigned char *out, uint32 outlen, void *data)
{
- int32 err;
- uint32 size;
+ int32 err;
+ uint32 size;
- size = key->size;
- if (outlen < size) {
- psTraceCrypto("Error on bad outlen parameter to psRsaEncryptPub\n");
- return PS_ARG_FAIL;
- }
+ size = key->size;
+ if (outlen < size) {
+ psTraceCrypto("Error on bad outlen parameter to psRsaEncryptPub\n");
+ return PS_ARG_FAIL;
+ }
- if ((err = pkcs1Pad(in, inlen, out, size, PRIVKEY_TYPE, data))
- < PS_SUCCESS) {
- psTraceCrypto("Error padding psRsaEncryptPub. Likely data too long\n");
- return err;
- }
- if ((err = psRsaCrypt(pool, out, size, out, (uint32*)&outlen, key,
- PUBKEY_TYPE, data)) < PS_SUCCESS) {
- psTraceCrypto("Error performing psRsaEncryptPub\n");
- return err;
- }
- if (outlen != size) {
- psTraceCrypto("Encrypted size error in psRsaEncryptPub\n");
- return PS_FAILURE;
- }
- return size;
+ if ((err = pkcs1Pad(in, inlen, out, size, PRIVKEY_TYPE, data))
+ < PS_SUCCESS) {
+ psTraceCrypto("Error padding psRsaEncryptPub. Likely data too long\n");
+ return err;
+ }
+ if ((err = psRsaCrypt(pool, out, size, out, (uint32*)&outlen, key,
+ PUBKEY_TYPE, data)) < PS_SUCCESS) {
+ psTraceCrypto("Error performing psRsaEncryptPub\n");
+ return err;
+ }
+ if (outlen != size) {
+ psTraceCrypto("Encrypted size error in psRsaEncryptPub\n");
+ return PS_FAILURE;
+ }
+ return size;
}