tls: a bit more work
authorDenys Vlasenko <vda.linux@googlemail.com>
Sat, 14 Jan 2017 12:57:16 +0000 (13:57 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sat, 14 Jan 2017 12:57:16 +0000 (13:57 +0100)
$ ./busybox tls kernel.org
insize:0 tail:0
got block len:74
got HANDSHAKE
got SERVER_HELLO
insize:79 tail:4406
got block len:4392
got HANDSHAKE
got CERTIFICATE
entered der @0x8f7e723:0x30 len:1452 inner_byte @0x8f7e727:0x30
entered der @0x8f7e727:0x30 len:1172 inner_byte @0x8f7e72b:0xa0
skipped der 0xa0, next byte 0x02
skipped der 0x02, next byte 0x30
skipped der 0x30, next byte 0x30
skipped der 0x30, next byte 0x30
skipped der 0x30, next byte 0x30
skipped der 0x30, next byte 0x30
entered der @0x8f7e830:0x30 len:418 inner_byte @0x8f7e834:0x30
skipped der 0x30, next byte 0x03
entered der @0x8f7e843:0x03 len:399 inner_byte @0x8f7e847:0x00
copying key bytes:399, first:0x00
insize:4397 tail:9
got block len:4
got SERVER_HELLO_DONE

Now need to teach it to send ClientKeyExchange...

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/tls.c

index 983ed507d44942d5d53c3ae3272595322ad682aa..3b6347ecc95e0ac49e58b9fec89addffa803f787 100644 (file)
 // (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 transport_hdr {
+struct record_hdr {
        uint8_t type;
        uint8_t proto_maj, proto_min;
        uint8_t len16_hi, len16_lo;
@@ -140,8 +140,6 @@ typedef struct tls_state {
        uint8_t *pubkey;
        int pubkey_len;
 
-       int insize;
-       int tail;
        // RFC 5246
        // |6.2.1. Fragmentation
        // |  The record layer fragments information blocks into TLSPlaintext
@@ -167,6 +165,8 @@ typedef struct tls_state {
        // |    The length MUST NOT exceed 2^14 + 1024.
        //
        // Since our buffer also contains 5-byte headers, make it a bit bigger:
+       int insize;
+       int tail;
        uint8_t inbuf[18*1024];
 } tls_state_t;
 
@@ -220,6 +220,7 @@ static void tls_error_die(tls_state_t *tls)
 
 static int xread_tls_block(tls_state_t *tls)
 {
+       struct record_hdr *xhdr;
        int len;
        int total;
        int target;
@@ -230,21 +231,28 @@ static int xread_tls_block(tls_state_t *tls)
        total = tls->tail;
        target = sizeof(tls->inbuf);
        for (;;) {
-               if (total >= sizeof(struct transport_hdr) && target == sizeof(tls->inbuf)) {
-                       struct transport_hdr *xhdr = (void*)tls->inbuf;
+               if (total >= sizeof(*xhdr) && target == sizeof(tls->inbuf)) {
+                       xhdr = (void*)tls->inbuf;
                        target = sizeof(*xhdr) + (0x100 * xhdr->len16_hi + xhdr->len16_lo);
+                       if (target >= sizeof(tls->inbuf)) {
+                               /* malformed input (too long): yell and die */
+                               tls->tail = 0;
+                               tls->insize = total;
+                               tls_error_die(tls);
+                       }
+                       // can also check type/proto_maj/proto_min here
                }
                /* if total >= target, we have a full packet (and possibly more)... */
-               if (target - total <= 0)
+               if (total - target >= 0)
                        break;
                len = safe_read(tls->fd, tls->inbuf + total, sizeof(tls->inbuf) - total);
                if (len <= 0)
                        bb_perror_msg_and_die("short read");
                total += len;
        }
-       tls->tail = -(target - total);
+       tls->tail = total - target;
        tls->insize = target;
-       target -= sizeof(struct transport_hdr);
+       target -= sizeof(*xhdr);
        dbg("got block len:%u\n", target);
        return target;
 }
@@ -252,7 +260,7 @@ static int xread_tls_block(tls_state_t *tls)
 static void send_client_hello(tls_state_t *tls)
 {
        struct client_hello {
-               struct transport_hdr xhdr;
+               struct record_hdr xhdr;
                uint8_t type;
                uint8_t len24_hi, len24_mid, len24_lo;
                uint8_t proto_maj, proto_min;
@@ -270,18 +278,18 @@ static void send_client_hello(tls_state_t *tls)
        hello.xhdr.type = RECORD_TYPE_HANDSHAKE;
        hello.xhdr.proto_maj = TLS_MAJ;
        hello.xhdr.proto_min = TLS_MIN;
-       hello.xhdr.len16_hi = (sizeof(hello) - sizeof(hello.xhdr)) >> 8;
+       //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_mid = (sizeof(hello) - sizeof(hello.xhdr) - 4) >> 8;
+       //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;
        hello.proto_min = TLS_MIN;
-       //fillrand(hello.rand32, sizeof(hello.rand32));
        open_read_close("/dev/urandom", hello.rand32, sizeof(hello.rand32));
        //hello.session_id_len = 0;
        //hello.cipherid_len16_hi = 0;
-       hello.cipherid_len16_lo = 2;
+       hello.cipherid_len16_lo = 2 * 1;
        hello.cipherid[0] = CIPHER_ID >> 8;
        hello.cipherid[1] = CIPHER_ID & 0xff;
        hello.comprtypes_len = 1;
@@ -293,7 +301,7 @@ static void send_client_hello(tls_state_t *tls)
 static void get_server_hello_or_die(tls_state_t *tls)
 {
        struct server_hello {
-               struct transport_hdr xhdr;
+               struct record_hdr xhdr;
                uint8_t type;
                uint8_t len24_hi, len24_mid, len24_lo;
                uint8_t proto_maj, proto_min;
@@ -319,8 +327,9 @@ static void get_server_hello_or_die(tls_state_t *tls)
                tls_error_die(tls);
        }
        dbg("got HANDSHAKE\n");
-       // 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
+       // 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
@@ -359,8 +368,8 @@ static unsigned get_der_len(uint8_t **bodyp, uint8_t *der, uint8_t *end)
                        xfunc_die();
                /* it's "ii 82 xx yy" */
                len = 0x100*der[2] + der[3];
-               if (len < 0x80)
-                       xfunc_die(); /* invalid DER: must use short len if can */
+//             if (len < 0x80)
+//                     xfunc_die(); /* invalid DER: must use short len if can */
 
                der += 2; /* skip [code]+[82]+[2byte_len] */
        }
@@ -395,7 +404,9 @@ static uint8_t *skip_der_item(uint8_t *der, uint8_t *end)
 
 static void *find_key_in_der_cert(int *key_len, uint8_t *der, int len)
 {
-/* Example: partial decode of kernel.org certificate in DER format.
+/* 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
+ * without parsing them. Example: partial decode of kernel.org certificate:
  *  SEQ 0x05ac/1452 bytes (Certificate): 308205ac
  *    SEQ 0x0494/1172 bytes (tbsCertificate): 30820494
  *      [ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0] 3 bytes: a003
@@ -425,8 +436,7 @@ static void *find_key_in_der_cert(int *key_len, uint8_t *der, int len)
  *        SET 32 bytes: 3120
  *          SEQ 30 bytes: 301e
  *            OID 3 bytes: 0603 550403
- *            Printable string "Gandi Standard SSL CA 2": 1317
- *                              47616e6469205374616e646172642053534c2043412032
+ *            Printable string "Gandi Standard SSL CA 2": 1317 47616e6469205374616e646172642053534c2043412032
  *      SEQ 30 bytes (validity): 301e
  *        TIME "161011000000Z": 170d 3136313031313030303030305a
  *        TIME "191011235959Z": 170d 3139313031313233353935395a
@@ -452,10 +462,6 @@ static void *find_key_in_der_cert(int *key_len, uint8_t *der, int len)
  *      [ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0x3] 0x01e5 bytes (X509v3 extensions): a38201e5
  *        SEQ 0x01e1 bytes: 308201e1
  *        ...
- * 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
- * without parsing them.
- *
  * Certificate is a sequence of three elements:
  *     tbsCertificate (SEQ)
  *     signatureAlgorithm (AlgorithmIdentifier)
@@ -475,7 +481,7 @@ static void *find_key_in_der_cert(int *key_len, uint8_t *der, int len)
  *     algorithm (AlgorithmIdentifier)
  *     publicKey (BIT STRING)
  *
- * Essentially, we want subjectPublicKeyInfo.publicKey
+ * We need Certificate.tbsCertificate.subjectPublicKeyInfo.publicKey
  */
        uint8_t *end = der + len;
 
@@ -510,7 +516,7 @@ static void *find_key_in_der_cert(int *key_len, uint8_t *der, int len)
 
 static void get_server_cert_or_die(tls_state_t *tls)
 {
-       struct transport_hdr *xhdr;
+       struct record_hdr *xhdr;
        uint8_t *certbuf;
        int len, len1;
 
@@ -528,16 +534,15 @@ static void get_server_cert_or_die(tls_state_t *tls)
        if (certbuf[0] != HANDSHAKE_CERTIFICATE)
                tls_error_die(tls);
        dbg("got CERTIFICATE\n");
-       // 0b   00|11|24 00|11|21 00|05|b0 30|82|05|ac|30|82|04|94|a0|03|02|01|02|02|11|00|9f|85|bf|66|4b|0c|dd|af|ca|50|86|79|50|1b|2b|e4|30|0d... (4392 bytes)
-       // Cert len=4388 ChainLen CertLen^ DER encoded X509 starts here. openssl x509 -in FILE -inform DER -noout -text
+       // 4392 bytes:
+       // 0b  00|11|24 00|11|21 00|05|b0 30|82|05|ac|30|82|04|94|a0|03|02|01|02|02|11|00|9f|85|bf|66|4b|0c|dd|af|ca|50|86|79|50|1b|2b|e4|30|0d...
+       //Cert len=4388 ChainLen CertLen^ DER encoded X509 starts here. openssl x509 -in FILE -inform DER -noout -text
        len1 = get24be(certbuf + 1);
        if (len1 > len - 4) tls_error_die(tls);
        len = len1;
-
        len1 = get24be(certbuf + 4);
        if (len1 > len - 3) tls_error_die(tls);
        len = len1;
-
        len1 = get24be(certbuf + 7);
        if (len1 > len - 3) tls_error_die(tls);
        len = len1;
@@ -601,8 +606,9 @@ static void tls_handshake(tls_state_t *tls)
        /* Next handshake type is not predetermined */
        switch (tls->inbuf[5]) {
        case HANDSHAKE_SERVER_KEY_EXCHANGE:
-               //0c    0001c7 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... 459 bytes
-               //SvKey len^^^
+               // 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^
                dbg("got SERVER_KEY_EXCHANGE\n");
                len = xread_tls_block(tls);
                break;