Hi David, unfortunately I've been out of touch with the developments
to DTLS for some time.  I forwarded your message to Eric Rescorla
who worked with Cisco to get their implementation working.

I suspect that Cisco has proprietary patches that they haven't disclosed
(or don't know how to).

nagendra

* David Woodhouse <[EMAIL PROTECTED]> [2008-09-23 22:31:29 -0700]:

> I'm working on a VPN client compatible with Cisco's AnyConnect, which
> uses SSL + DTLS. My code so far is at git:// or
> http://git.infradead.org/users/dwmw2/anyconnect.git
> 
> It's mostly going quite well, but I'm having trouble with DTLS
> compatibility and would massively appreciate some help from someone a
> little more clueful about DTLS.
> 
> I can only actually get a successful handshake with their server when I
> use the libssl.so.0.9.8 which is shipped as part Cisco's own client -- I
> can't get it working with any version of OpenSSL that I build myself. My
> library always rejects the ServerHello packet:
> 
> 12293:error:14101119:SSL routines:DTLS1_PROCESS_RECORD:decryption failed or 
> bad record mac:d1_pkt.c:466:
> 
> Their library seems to be (contains the strings):
>       OpenSSL 0.9.8f 11 Oct 2007
> 
> However, the traffic I see on the wire is the pre-RFC version of DTLS
> (DTLS1_BAD_VER). But OpenSSL 0.9.8f postdates RFC4347 and had already
> been updated to the official protocol version number -- so whatever
> they're shipping, it's certainly not a pristine OpenSSL 0.9.8f.
> 
> I've tried using the last release of OpenSSL which actually supported
> that version of the DTLS protocol (0.9.8e), and I've tried 0.9.8f and
> newer versions. None of them work. The only thing that works is using
> LD_LIBRARY_PATH to run my client against _their_ build of the library.
> 
> I suspect that they haven't done anything particularly _exciting_ in
> their version of the library -- they've probably just reverted some of
> the updates in 0.9.8f which change to the the new behaviour defined in
> RFC4347. And maybe back-ported some later bug fixes. I've tried starting
> with 0.9.8f and reverting individual changes to see if I could get it to
> work, and I've tried some intermediate points between 0.9.8e and 0.9.8f,
> but haven't really had much luck and I'm mostly clueless about the
> details -- I would really appreciate some input from someone who
> actually knows the protocol a little better. I'm kind of hoping it's
> immediately obvious to someone.
> 
> Although their own client uses the old version (DTLS1_BAD_VER) of the
> protocol, their server does actually seem to respond to the new version
> too. Its responses are slightly different (two extra bytes) according to
> whether I use DTLS1_BAD_VER or DTLS1_VERSION, so it does seem to be
> adapting to what the client sends rather than just echoing the version
> number. But the ultimate result in both cases is exactly the same. I
> send a Client Hello, get a Hello Verify Request. I send the Client Hello
> again, get a Server Hello. And then I send a 'Bad Record MAC' alert and
> the connection is over.
> 
> I've made a simple test case, by capturing the traffic during a _failed_
> session with OpenSSL-0.9.8e. The captured packets _work_ when I play
> them back against their library, but obviously fail when run against my
> build of OpenSSL-0.9.8e. This capture is using DTLS1_BAD_VER, of course.
> 
> I _could_ do a capture using a newer version of OpenSSL and thus with
> DTLS1_VERSION, but the server side of that might be broken anyway -- I
> have no reason to believe there are _any_ working clients using that
> version of the protocol. And I wouldn't be able to show that test case
> working, either. So I think it's best to work with the old version of
> the protocol to start with, and work out what's going on.
> 
> The test program is at http://david.woodhou.se/dtls-test.c and also
> below, and their version of libssl.so.0.9.8 is next to it on the web
> server (sha1 21a5704ea4f66dd48ea2b9d6c5b8ab85d4e16d89).
> 
> [EMAIL PROTECTED] anyconnect]$ LD_LIBRARY_PATH=/opt/cisco/vpn/lib ./dtls-test
> Found AES128-SHA cipher at 28
> SSL_SESSION is 200 bytes
> Child done.
> Success
> [EMAIL PROTECTED] anyconnect]$ 
> LD_LIBRARY_PATH=/home/dwmw2/working/openssl-0.9.8e ./dtls-test
> Found AES128-SHA cipher at 29
> SSL_SESSION is 200 bytes
>  < ... lots of debugging that I added, which didn't enlighten me at all ... >
> DTLS connection returned 0
> 12994:error:14101119:SSL routines:DTLS1_PROCESS_RECORD:decryption failed or 
> bad record mac:d1_pkt.c:466:
> Child done.
> 
> 
> This is the test case....
> /*
>  * Open AnyConnect (SSL + DTLS) client
>  *
>  * © 2008 David Woodhouse <[EMAIL PROTECTED]>
>  *
>  * Permission to use, copy, modify, and/or distribute this software
>  * for any purpose with or without fee is hereby granted, provided
>  * that the above copyright notice and this permission notice appear
>  * in all copies.
>  *
>  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
>  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
>  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
>  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
>  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
>  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
>  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>  */
> 
> #include <errno.h>
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <netdb.h>
> #include <unistd.h>
> #include <openssl/ssl.h>
> #include <openssl/err.h>
> #include <fcntl.h>
> 
> #include <time.h>
> 
> /* We want it to be reproducible */
> time_t time(time_t *t)
> {
>       time_t x = 0x3ab2d948;
>       
>       if (t) *t = x;
>       
>       return x;
> }
> 
> int RAND_pseudo_bytes(char *buf, int len)
> {
>       memset(buf, 0x5a, len);
>       return 1;
>       
> }
> int RAND_bytes(char *buf, int len)
> {
>       memset(buf, 0x5b, len);
>       return 1;
> }
> 
> char master_secret[48];
> 
> #if 0 /* Test case recorded when _working_ */
> char session_id[] = {
>       0x60, 0x1E, 0xF8, 0x4A, 0xB7, 0x93, 0x48, 0xBB,
>       0x4A, 0xF9, 0x98, 0x40, 0x5E, 0x89, 0xA5, 0x8A,
>       0xD7, 0xC6, 0x14, 0x7A, 0xCE, 0x62, 0x4D, 0xEB,
>       0xB3, 0x8D, 0x15, 0x42, 0x87, 0x62, 0xD9, 0x07
> };
> 
> unsigned char verify_request[] = {
>       0x16, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
>       0x00, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0x00,
>       0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
>       0x03, 0x01, 0x00, 0x00
> };
> 
> unsigned char server_hello[] = {
>       0x16, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
>       0x00, 0x00, 0x01, 0x00, 0x52, 0x02, 0x00, 0x00,
>       0x46, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
>       0x46, 0x01, 0x00, 0x48, 0xd9, 0xb2, 0xf2, 0x0f,
>       0x9a, 0x91, 0x28, 0x56, 0x77, 0x36, 0xce, 0x1b,
>       0x26, 0x6b, 0x9b, 0xcf, 0x77, 0x95, 0x20, 0xa6,
>       0x67, 0x4d, 0x29, 0x62, 0x19, 0x69, 0xec, 0x0a,
>       0xf3, 0x36, 0x34, 0x20, 0x60, 0x1e, 0xf8, 0x4a,
>       0xb7, 0x93, 0x48, 0xbb, 0x4a, 0xf9, 0x98, 0x40,
>       0x5e, 0x89, 0xa5, 0x8a, 0xd7, 0xc6, 0x14, 0x7a,
>       0xce, 0x62, 0x4d, 0xeb, 0xb3, 0x8d, 0x15, 0x42,
>       0x87, 0x62, 0xd9, 0x07, 0x00, 0x2f, 0x00, 0x14,
>       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>       0x00, 0x02, 0x00, 0x03, 0x01, 0x00, 0x02, 0x16,
>       0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
>       0x00, 0x00, 0x00, 0x40, 0x0d, 0x9d, 0x2e, 0x90,
>       0x9f, 0x80, 0xb6, 0x2c, 0x55, 0x24, 0x46, 0xa8,
>       0xf4, 0xf7, 0xd3, 0x8e, 0x86, 0xac, 0x15, 0xf2,
>       0xfe, 0x91, 0xc4, 0x2e, 0xce, 0x47, 0xbc, 0x23,
>       0x0b, 0xa9, 0xc7, 0x36, 0x03, 0x07, 0xd8, 0xfc,
>       0xcb, 0x10, 0x2f, 0xe5, 0xa0, 0xb8, 0x67, 0x6a,
>       0xc1, 0xc2, 0xe9, 0xcd, 0xdd, 0xcb, 0x12, 0xdd,
>       0x57, 0x95, 0xe1, 0xbb, 0x74, 0xac, 0x05, 0x00,
>       0xea, 0xf8, 0x71, 0x59
> };
> #else 
> /* This one was captured with OpenSSL 0.9.8e on the client side,
>    which rejected the ServerHello. Yet it works fine with Cisco's
>    build of the library */
>    
> char session_id[] = {
>       0x60, 0x1E, 0xF8, 0x4A, 0xB7, 0x93, 0x48, 0xBB,
>       0x4A, 0xF9, 0x98, 0x40, 0x5E, 0x89, 0xA5, 0x8A,
>       0xD7, 0xC6, 0x14, 0x7A, 0xCE, 0x62, 0x4D, 0xEB,
>       0xB3, 0x8D, 0x15, 0x42, 0x87, 0x62, 0xD9, 0x07 
> };
> 
> unsigned char verify_request[] = {
>       0x16, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>       0x00, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0x00,
>       0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>       0x03, 0x01, 0x00, 0x00
> };
> 
> unsigned char server_hello[] = {
>       0x16, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>       0x00, 0x00, 0x01, 0x00, 0x52, 0x02, 0x00, 0x00,
>       0x46, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
>       0x46, 0x01, 0x00, 0x48, 0xd9, 0xc9, 0xae, 0x12,
>       0x1d, 0x7a, 0x84, 0x85, 0x4b, 0x0f, 0x2f, 0x75,
>       0x09, 0xf3, 0x20, 0xd2, 0x0a, 0xf5, 0x4e, 0x82,
>       0x9f, 0xb2, 0x60, 0x50, 0xda, 0x91, 0x34, 0x21,
>       0xd9, 0x32, 0xc0, 0x20, 0x60, 0x1e, 0xf8, 0x4a,
>       0xb7, 0x93, 0x48, 0xbb, 0x4a, 0xf9, 0x98, 0x40,
>       0x5e, 0x89, 0xa5, 0x8a, 0xd7, 0xc6, 0x14, 0x7a,
>       0xce, 0x62, 0x4d, 0xeb, 0xb3, 0x8d, 0x15, 0x42,
>       0x87, 0x62, 0xd9, 0x07, 0x00, 0x2f, 0x00, 0x14,
>       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>       0x00, 0x02, 0x00, 0x03, 0x01, 0x00, 0x02, 0x16,
>       0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
>       0x00, 0x00, 0x00, 0x40, 0xf8, 0x31, 0xa0, 0x7c,
>       0x83, 0xb3, 0x9e, 0x7d, 0xbb, 0x23, 0xee, 0x6c,
>       0x41, 0xdb, 0x70, 0xc2, 0x60, 0x19, 0xc1, 0xc4,
>       0x82, 0x57, 0x81, 0x52, 0x43, 0x78, 0xb4, 0x7b,
>       0x7d, 0x5c, 0xd0, 0x57, 0xee, 0xa3, 0x5b, 0x6c,
>       0xba, 0xa7, 0x8c, 0x2d, 0x76, 0x43, 0x3e, 0xa7,
>       0x93, 0x2e, 0xbe, 0xba, 0xbe, 0x1f, 0x42, 0x1f,
>       0x39, 0xb9, 0x40, 0x4e, 0x8a, 0xa1, 0xa0, 0x0b, 
>       0x50, 0x3e, 0x99, 0x85
> };
> #endif
> int dump_traffic = 0;
> void hexdump(unsigned char *buf, int len)
> {
>         int i;
> 
>         for (i=0; i<len; i++) {
>                 if (!(i&15))
>                         printf("\n%04x: ", i);
>                 printf("%02x ", buf[i]);
>         }
>         printf("\n");
> }
> 
> void feed_responses(int fd)
> {
>       char buf[2000];
>       int len;
> 
>       len = read(fd, buf, 2000);
>       if (len < 0) {
>               perror("read 1");
>               exit(1);
>       }
>       if (dump_traffic) {
>               printf("Received packet 1:");
>               hexdump(buf, len);
>       }
>       
>       len = write(fd, verify_request, sizeof(verify_request));
>       if (dump_traffic)
>               printf("Wrote %d bytes of Hello Verify\n", len);
> 
>       
>       len = read(fd, buf, 2000);
>       if (len < 0) {
>               perror("read 2");
>               exit(1);
>       }
>       if (dump_traffic) {
>               printf("Received packet 2:");
>               hexdump(buf, len);
>       }
>       
>       len = write(fd, server_hello, sizeof(server_hello));
>       if (dump_traffic)
>               printf("Wrote %d bytes of Server Hello\n", len);
> 
> 
>       len = read(fd, buf, 2000);
>       if (len < 0) {
>               perror("read 3");
>               exit(1);
>       }
>       if (dump_traffic) {
>               printf("Received packet 3:");
>               hexdump(buf, len);
>       }
> }
> extern SSL_CIPHER ssl3_ciphers[];
> 
> int main(void)
> {
>       int sockets[2];
>       pid_t child_pid;
>       int cipher;
>         SSL_METHOD *dtls_method;
>         SSL_CTX *dtls_ctx;
>         SSL_SESSION *dtls_session;
>         SSL_CIPHER *https_cipher;
>         SSL *dtls_ssl;
>         BIO *dtls_bio;
>         int ret;
>       int aes128_cipher;
> 
>       if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets)) {
>               perror("socketpair");
>               return 1;
>       }
> 
>       child_pid = fork();
>       if (child_pid < 0) {
>               perror("fork");
>               return 1;
>       }
>       if (!child_pid) {
>               close(sockets[1]);
>               feed_responses(sockets[0]);
>               printf("Child done.\n");
>               exit(1);
>       }
>       close(sockets[0]);
> 
>       /* Not really very random. */
>       RAND_bytes(master_secret, 48);
> 
>       /* Normally we go do an HTTPS exchange here with the server; we
>          tell it our master secret, and it gives us the session-id.
>          Then we "resume" a DTLS session... */
>         SSL_library_init ();
>         ERR_clear_error ();
>         SSL_load_error_strings ();
>         OpenSSL_add_all_algorithms ();
> 
>       dtls_method = DTLSv1_client_method();
>       dtls_ctx = SSL_CTX_new(dtls_method);
>       SSL_CTX_set_read_ahead(dtls_ctx, 1);
> 
>       dtls_ssl = SSL_new(dtls_ctx);
>       SSL_set_connect_state(dtls_ssl);
> 
>       /* Normally we use the same cipher as the HTTPS session. */
> //    https_cipher = SSL_get_current_cipher(vpninfo->https_ssl);
> 
>       while (ssl3_ciphers[aes128_cipher].id != 0x0300002f)
>               aes128_cipher++;
> 
>       printf("Found %s cipher at %d\n", ssl3_ciphers[aes128_cipher].name,
>              aes128_cipher);
> 
>       SSL_set_cipher_list(dtls_ssl, "AES128-SHA");
> 
>       printf("SSL_SESSION is %d bytes\n", sizeof(*dtls_session));
>       if (sizeof(*dtls_session) != 200) {
>               printf("WARNING: The version of OpenSSL you're building against 
> is\n");
>               printf("not ABI-compatible with Cisco's build of 
> libssl.0.9.8.\n");
>       }
> 
>       dtls_session = SSL_SESSION_new();
> 
>       dtls_session->ssl_version = DTLS1_BAD_VER;
>       
>       dtls_session->master_key_length = sizeof(master_secret);
>       memcpy(dtls_session->master_key, master_secret, sizeof(master_secret));
> 
>       dtls_session->session_id_length = sizeof(session_id);
>       memcpy(dtls_session->session_id, session_id, sizeof(session_id));
> 
>       dtls_session->cipher = &ssl3_ciphers[aes128_cipher];
>       dtls_session->cipher_id = 0x0300002f;
> 
>       if (!SSL_set_session(dtls_ssl, dtls_session)) {
>               printf("SSL_set_session() failed.\n");
>               return -EINVAL;
>       }
>       if (!SSL_CTX_add_session(dtls_ctx, dtls_session))
>               printf("SSL_CTX_add_session() failed\n");
> 
> 
>       dtls_bio = BIO_new_socket(sockets[1], BIO_NOCLOSE);
>       SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio);
> 
>       ret = SSL_do_handshake(dtls_ssl);
>       
>       if (ret != 1) {
>               fprintf(stderr, "DTLS connection returned %d\n", ret);
>               if (ret < 0)
>                       fprintf(stderr, "DTLS handshake error: %d\n", 
> SSL_get_error(dtls_ssl, ret));
>               ERR_print_errors_fp(stderr);
>               SSL_free(dtls_ssl);
>               SSL_CTX_free(dtls_ctx);
>               close(sockets[1]);
>               exit(1);
>               
>               return -EINVAL;
>       }
> 
> 
>       printf("Success\n");
>       return 0;
> }
> 
> 
> -- 
> dwmw2
> 
> ______________________________________________________________________
> OpenSSL Project                                 http://www.openssl.org
> User Support Mailing List                    openssl-users@openssl.org
> Automated List Manager                           [EMAIL PROTECTED]
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to