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]