Submitted by: Michael Tuexen <tuexen@fh-muenster.de>
Approved by: steve@openssl.org

IPv6 support for DTLS.
This commit is contained in:
Dr. Stephen Henson 2009-10-15 17:41:44 +00:00
parent abdfdb029e
commit 28418076b2
2 changed files with 174 additions and 30 deletions

View File

@ -692,8 +692,16 @@ int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsign
{ {
unsigned char *buffer, result[EVP_MAX_MD_SIZE]; unsigned char *buffer, result[EVP_MAX_MD_SIZE];
unsigned int length, resultlength; unsigned int length, resultlength;
#if OPENSSL_USE_IPV6
union {
struct sockaddr_storage ss;
struct sockaddr_in6 s6;
struct sockaddr_in s4;
} peer;
#else
struct sockaddr_in peer; struct sockaddr_in peer;
#endif
/* Initialize a random secret */ /* Initialize a random secret */
if (!cookie_initialized) if (!cookie_initialized)
{ {
@ -709,8 +717,25 @@ int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsign
(void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
/* Create buffer with peer's address and port */ /* Create buffer with peer's address and port */
#if OPENSSL_USE_IPV6
length = 0;
switch (peer.ss.ss_family)
{
case AF_INET:
length += sizeof(struct in_addr);
break;
case AF_INET6:
length += sizeof(struct in6_addr);
break;
default:
OPENSSL_assert(0);
break;
}
length += sizeof(in_port_t);
#else
length = sizeof(peer.sin_addr); length = sizeof(peer.sin_addr);
length += sizeof(peer.sin_port); length += sizeof(peer.sin_port);
#endif
buffer = OPENSSL_malloc(length); buffer = OPENSSL_malloc(length);
if (buffer == NULL) if (buffer == NULL)
@ -718,9 +743,34 @@ int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsign
BIO_printf(bio_err,"out of memory\n"); BIO_printf(bio_err,"out of memory\n");
return 0; return 0;
} }
memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr)); #if OPENSSL_USE_IPV6
memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port)); switch (peer.ss.ss_family)
{
case AF_INET:
memcpy(buffer,
&peer.s4.sin_port,
sizeof(in_port_t));
memcpy(buffer + sizeof(in_port_t),
&peer.s4.sin_addr,
sizeof(struct in_addr));
break;
case AF_INET6:
memcpy(buffer,
&peer.s6.sin6_port,
sizeof(in_port_t));
memcpy(buffer + sizeof(in_port_t),
&peer.s6.sin6_addr,
sizeof(struct in6_addr));
break;
default:
OPENSSL_assert(0);
break;
}
#else
memcpy(buffer, &peer.sin_port, sizeof(peer.sin_port));
memcpy(buffer + sizeof(peer.sin_port), &peer.sin_addr, sizeof(peer.sin_addr));
#endif
/* Calculate HMAC of buffer using the secret */ /* Calculate HMAC of buffer using the secret */
HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
@ -737,8 +787,16 @@ int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned
{ {
unsigned char *buffer, result[EVP_MAX_MD_SIZE]; unsigned char *buffer, result[EVP_MAX_MD_SIZE];
unsigned int length, resultlength; unsigned int length, resultlength;
#if OPENSSL_USE_IPV6
union {
struct sockaddr_storage ss;
struct sockaddr_in6 s6;
struct sockaddr_in s4;
} peer;
#else
struct sockaddr_in peer; struct sockaddr_in peer;
#endif
/* If secret isn't initialized yet, the cookie can't be valid */ /* If secret isn't initialized yet, the cookie can't be valid */
if (!cookie_initialized) if (!cookie_initialized)
return 0; return 0;
@ -747,8 +805,25 @@ int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned
(void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
/* Create buffer with peer's address and port */ /* Create buffer with peer's address and port */
#if OPENSSL_USE_IPV6
length = 0;
switch (peer.ss.ss_family)
{
case AF_INET:
length += sizeof(struct in_addr);
break;
case AF_INET6:
length += sizeof(struct in6_addr);
break;
default:
OPENSSL_assert(0);
break;
}
length += sizeof(in_port_t);
#else
length = sizeof(peer.sin_addr); length = sizeof(peer.sin_addr);
length += sizeof(peer.sin_port); length += sizeof(peer.sin_port);
#endif
buffer = OPENSSL_malloc(length); buffer = OPENSSL_malloc(length);
if (buffer == NULL) if (buffer == NULL)
@ -756,15 +831,40 @@ int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned
BIO_printf(bio_err,"out of memory\n"); BIO_printf(bio_err,"out of memory\n");
return 0; return 0;
} }
memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr)); #if OPENSSL_USE_IPV6
memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port)); switch (peer.ss.ss_family)
{
case AF_INET:
memcpy(buffer,
&peer.s4.sin_port,
sizeof(in_port_t));
memcpy(buffer + sizeof(in_port_t),
&peer.s4.sin_addr,
sizeof(struct in_addr));
break;
case AF_INET6:
memcpy(buffer,
&peer.s6.sin6_port,
sizeof(in_port_t));
memcpy(buffer + sizeof(in_port_t),
&peer.s6.sin6_addr,
sizeof(struct in6_addr));
break;
default:
OPENSSL_assert(0);
break;
}
#else
memcpy(buffer, &peer.sin_port, sizeof(peer.sin_port));
memcpy(buffer + sizeof(peer.sin_port), &peer.sin_addr, sizeof(peer.sin_addr));
#endif
/* Calculate HMAC of buffer using the secret */ /* Calculate HMAC of buffer using the secret */
HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
buffer, length, result, &resultlength); buffer, length, result, &resultlength);
OPENSSL_free(buffer); OPENSSL_free(buffer);
if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0) if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0)
return 1; return 1;

View File

@ -108,7 +108,11 @@ static BIO_METHOD methods_dgramp=
typedef struct bio_dgram_data_st typedef struct bio_dgram_data_st
{ {
struct sockaddr peer; #if OPENSSL_USE_IPV6
struct sockaddr_storage peer;
#else
struct sockaddr_in peer;
#endif
unsigned int connected; unsigned int connected;
unsigned int _errno; unsigned int _errno;
unsigned int mtu; unsigned int mtu;
@ -274,7 +278,11 @@ static int dgram_read(BIO *b, char *out, int outl)
int ret=0; int ret=0;
bio_dgram_data *data = (bio_dgram_data *)b->ptr; bio_dgram_data *data = (bio_dgram_data *)b->ptr;
struct sockaddr peer; #if OPENSSL_USE_IPV6
struct sockaddr_storage peer;
#else
struct sockaddr_in peer;
#endif
int peerlen = sizeof(peer); int peerlen = sizeof(peer);
if (out != NULL) if (out != NULL)
@ -287,7 +295,7 @@ static int dgram_read(BIO *b, char *out, int outl)
* compiler warnings. * compiler warnings.
*/ */
dgram_adjust_rcv_timeout(b); dgram_adjust_rcv_timeout(b);
ret=recvfrom(b->num,out,outl,0,&peer,(void *)&peerlen); ret=recvfrom(b->num,out,outl,0,(struct sockaddr *)&peer,(void *)&peerlen);
dgram_reset_rcv_timeout(b); dgram_reset_rcv_timeout(b);
if ( ! data->connected && ret >= 0) if ( ! data->connected && ret >= 0)
@ -312,13 +320,28 @@ static int dgram_write(BIO *b, const char *in, int inl)
bio_dgram_data *data = (bio_dgram_data *)b->ptr; bio_dgram_data *data = (bio_dgram_data *)b->ptr;
clear_socket_error(); clear_socket_error();
if ( data->connected ) if ( data->connected )
ret=writesocket(b->num,in,inl); ret=writesocket(b->num,in,inl);
else else
#if OPENSSL_USE_IPV6
if (data->peer.ss_family == AF_INET)
#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK) #if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
ret=sendto(b->num, (char *)in, inl, 0, &data->peer, sizeof(data->peer)); ret=sendto(b->num, (char *)in, inl, 0, (const struct sockaddr *)&data->peer, sizeof(struct sockaddr_in));
#else #else
ret=sendto(b->num, in, inl, 0, &data->peer, sizeof(data->peer)); ret=sendto(b->num, in, inl, 0, (const struct sockaddr *)&data->peer, sizeof(struct sockaddr_in));
#endif
else
#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
ret=sendto(b->num, (char *)in, inl, 0, (const struct sockaddr *)&data->peer, sizeof(struct sockaddr_in6));
#else
ret=sendto(b->num, in, inl, 0, (const struct sockaddr *)&data->peer, sizeof(struct sockaddr_in6));
#endif
#else
#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
ret=sendto(b->num, (char *)in, inl, 0, (const struct sockaddr *)&data->peer, sizeof(struct sockaddr_in));
#else
ret=sendto(b->num, in, inl, 0, (const struct sockaddr *)&data->peer, sizeof(struct sockaddr_in));
#endif
#endif #endif
BIO_clear_retry_flags(b); BIO_clear_retry_flags(b);
@ -405,7 +428,11 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
else else
{ {
#endif #endif
memcpy(&(data->peer),to, sizeof(struct sockaddr)); #if OPENSSL_USE_IPV6
memcpy(&(data->peer),to, sizeof(struct sockaddr_storage));
#else
memcpy(&(data->peer),to, sizeof(struct sockaddr_in));
#endif
#if 0 #if 0
} }
#endif #endif
@ -510,27 +537,44 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
if ( to != NULL) if ( to != NULL)
{ {
data->connected = 1; data->connected = 1;
memcpy(&(data->peer),to, sizeof(struct sockaddr)); #if OPENSSL_USE_IPV6
memcpy(&(data->peer),to, sizeof(struct sockaddr_storage));
#else
memcpy(&(data->peer),to, sizeof(struct sockaddr_in));
#endif
} }
else else
{ {
data->connected = 0; data->connected = 0;
memset(&(data->peer), 0x00, sizeof(struct sockaddr)); #if OPENSSL_USE_IPV6
memset(&(data->peer), 0x00, sizeof(struct sockaddr_storage));
#else
memset(&(data->peer), 0x00, sizeof(struct sockaddr_in));
#endif
} }
break; break;
case BIO_CTRL_DGRAM_GET_PEER: case BIO_CTRL_DGRAM_GET_PEER:
to = (struct sockaddr *) ptr; to = (struct sockaddr *) ptr;
memcpy(to, &(data->peer), sizeof(struct sockaddr)); #if OPENSSL_USE_IPV6
ret = sizeof(struct sockaddr); memcpy(to, &(data->peer), sizeof(struct sockaddr_storage));
break; ret = sizeof(struct sockaddr_storage);
case BIO_CTRL_DGRAM_SET_PEER: #else
to = (struct sockaddr *) ptr; memcpy(to, &(data->peer), sizeof(struct sockaddr_in));
ret = sizeof(struct sockaddr_in);
#endif
break;
case BIO_CTRL_DGRAM_SET_PEER:
to = (struct sockaddr *) ptr;
memcpy(&(data->peer), to, sizeof(struct sockaddr)); #if OPENSSL_USE_IPV6
break; memcpy(&(data->peer), to, sizeof(struct sockaddr_storage));
#else
memcpy(&(data->peer), to, sizeof(struct sockaddr_in));
#endif
break;
case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
break; break;
#if defined(SO_RCVTIMEO) #if defined(SO_RCVTIMEO)
case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: