Re: DTLS clue requested: epoch numbers

2008-09-28 Thread David Woodhouse
On Fri, 2008-09-26 at 13:46 -0700, David Woodhouse wrote:
 At the worst, I should be able to reverse-engineer the library I have.

The first failure seems to have been a discrepancy in epoch numbers.

Comparing behaviour of their library and 0.9.8e, I find that theirs is
adding '00 01 00 00 00 00 00 00' to a digest at some point, while 0.9.8e
adds '00 00 00 00 00 00 00 00'. This is called from tls1_mac(), when
it's adding the 8 bytes of ssl-s3-read_sequence to the MAC.

The 0.9.8e library then rejects the Server Hello because of the MAC
failure, which was the original failure mode I was observing.

If I hack EVP_DigestUpdate() to fix that single byte for that one
call, then the MAC check in dtls1_process_record() succeeds, although
fairly unsurprisingly I get a later failure -- in ssl3_get_finished()
when s-s3-tmp.peer_finish_md doesn't contain what it should:
12778:error:1408C095:SSL routines:SSL3_GET_FINISHED:digest check 
failed:s3_both.c:235:

I'm still entirely clueless about the protocol, but it seems the top 16
bits of ssl-s3-read_sequence are supposed to be an epoch number. But
it's getting set to all zeroes in dtls1_reset_seq_numbers() even when
the epoch is non-zero.

Having narrowed it down that far, does anyone remember a change which
might have caused this?

I tried removing my hack from EVP_DigestUpdate and instead hacking
dtls1_reset_seq_numbers() to call s2n(epoch, seq) to put the epoch in
place after the memset. That makes no difference -- I still get the same
later failure. Which I'll now investigate, but it's probably going to
turn out to be due to the wrongness of my 'fix' for the epoch thing. As
I said, I'm fairly clueless.

I've converted the OpenSSL CVS history into git so that I can try to
look through it, but I don't see anything which jumps out as being
relevant. There's a commit entitled 'Liberate dtls from BN dependency.
Fix bug in replay/update.' which helpfully hides an unspecified bug fix
in amongst 300-odd lines of more cosmetic changes in one commit, but
that doesn't seem to be it.

As before, my test case is http://david.woodhou.se/dtls-test.c -- and
needs to be run against a version of OpenSSL which still uses 0x100 for
DTLS1_VERSION.

-- 
dwmw2

__
OpenSSL Project http://www.openssl.org
User Support Mailing Listopenssl-users@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: DTLS clue requested: epoch numbers

2008-09-28 Thread David Woodhouse
On Sun, 2008-09-28 at 18:56 +0100, David Woodhouse wrote:
 On Fri, 2008-09-26 at 13:46 -0700, David Woodhouse wrote:
  At the worst, I should be able to reverse-engineer the library I
 have.
 
 The first failure seems to have been a discrepancy in epoch numbers.

And the others are due to patches which were committed to OpenSSL later
-- in particular, 'RFC4347 says HelloVerifyRequest resets Finished MAC',
which moves a call to ssl3_init_finished_mac(), and Make DTLS1 record
layer MAC calculation RFC compliant, which sets the appropriate version
numbers in the packet in tls1_mac().

The full patch against 0.9.8e which makes this work (or at least
successfully negotiate and pass _some_ traffic -- I don't vouch for
later epoch changes) is below.

Next step would be to make it work in something newer. And preferably
with the RFC-defined version of the protocol instead of the old one.
Their client does seem to respond with the 'real' DTLS1 version if we
try that instead of using DTLS1_BAD_VER. And it has a CCS header length
of only 1 byte its responses, so it really is doing something different
and not just parrotting the version number. But just taking 0.9.8f and
setting the epoch in dtls1_reset_seq_numbers() as in the patch below
isn't sufficient -- I get the same record mac failure that I started
with.

This time it's going to be a little harder to guess what variant of the
new protocol they're using, because I don't have any implementation of
that -- and I'm not even sure it's _working_ on the server side. So I
suspect my best course of action now would be to somehow make it
possible to use the older version of DTLS in a current OpenSSL, for
compatibility? It's likely to be the only thing that's _tested_ against
Cisco servers anyway.

Index: ssl/d1_clnt.c
===
RCS file: /home/dwmw2/openssl-cvs/openssl/ssl/d1_clnt.c,v
retrieving revision 1.3.2.6
diff -u -p -r1.3.2.6 d1_clnt.c
--- ssl/d1_clnt.c   5 Dec 2005 17:32:19 -   1.3.2.6
+++ ssl/d1_clnt.c   28 Sep 2008 23:49:54 -
@@ -214,8 +214,6 @@ int dtls1_connect(SSL *s)
 
/* don't push the buffering BIO quite yet */
 
-   ssl3_init_finished_mac(s);
-
s-state=SSL3_ST_CW_CLNT_HELLO_A;
s-ctx-stats.sess_connect++;
s-init_num=0;
@@ -225,6 +223,10 @@ int dtls1_connect(SSL *s)
case SSL3_ST_CW_CLNT_HELLO_B:
 
s-shutdown=0;
+
+   /* HelloVerifyRequest resets Finished MAC */
+   ssl3_init_finished_mac(s);
+
ret=dtls1_client_hello(s);
if (ret = 0) goto end;
 
Index: ssl/d1_pkt.c
===
RCS file: /home/dwmw2/openssl-cvs/openssl/ssl/d1_pkt.c,v
retrieving revision 1.4.2.5
diff -u -p -r1.4.2.5 d1_pkt.c
--- ssl/d1_pkt.c29 Nov 2006 14:45:13 -  1.4.2.5
+++ ssl/d1_pkt.c28 Sep 2008 23:53:18 -
@@ -1718,12 +1718,12 @@ dtls1_reset_seq_numbers(SSL *s, int rw)
{
unsigned char *seq;
unsigned int seq_bytes = sizeof(s-s3-read_sequence);
+   int epoch;
 
if ( rw  SSL3_CC_READ)
{
seq = s-s3-read_sequence;
-   s-d1-r_epoch++;
-
+   epoch = ++s-d1-r_epoch;
pq_64bit_assign((s-d1-bitmap.map), 
(s-d1-next_bitmap.map));
s-d1-bitmap.length = s-d1-next_bitmap.length;
pq_64bit_assign((s-d1-bitmap.max_seq_num), 
@@ -1738,10 +1738,11 @@ dtls1_reset_seq_numbers(SSL *s, int rw)
else
{
seq = s-s3-write_sequence;
-   s-d1-w_epoch++;
+   epoch = ++s-d1-w_epoch;
}
 
memset(seq, 0x00, seq_bytes);
+   s2n(epoch,seq);
}
 
 #if PQ_64BIT_IS_INTEGER
Index: ssl/t1_enc.c
===
RCS file: /home/dwmw2/openssl-cvs/openssl/ssl/t1_enc.c,v
retrieving revision 1.35.2.3
diff -u -p -r1.35.2.3 t1_enc.c
--- ssl/t1_enc.c16 Feb 2007 20:40:07 -  1.35.2.3
+++ ssl/t1_enc.c28 Sep 2008 23:43:45 -
@@ -738,8 +738,8 @@ int tls1_mac(SSL *ssl, unsigned char *md
md_size=EVP_MD_size(hash);
 
buf[0]=rec-type;
-   buf[1]=TLS1_VERSION_MAJOR;
-   buf[2]=TLS1_VERSION_MINOR;
+   buf[1]=(unsigned char)(ssl-version  8);
+   buf[2]=(unsigned char)(ssl-version  0xff);
buf[3]=rec-length8;
buf[4]=rec-length0xff;
 

-- 
dwmw2

__
OpenSSL Project http://www.openssl.org
User Support Mailing Listopenssl-users@openssl.org
Automated List Manager   [EMAIL PROTECTED]