From 28418076b2050fb463bdce922f444d5d043f48fa Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Thu, 15 Oct 2009 17:41:44 +0000 Subject: [PATCH] PR: 2069 Submitted by: Michael Tuexen Approved by: steve@openssl.org IPv6 support for DTLS. --- apps/s_cb.c | 118 +++++++++++++++++++++++++++++++++++++---- crypto/bio/bss_dgram.c | 86 ++++++++++++++++++++++-------- 2 files changed, 174 insertions(+), 30 deletions(-) diff --git a/apps/s_cb.c b/apps/s_cb.c index d92f43d52a..4b27c7f0f5 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -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 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; - +#endif + /* Initialize a random secret */ 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); /* 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_port); +#endif buffer = OPENSSL_malloc(length); 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"); return 0; } - - memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr)); - memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port)); + +#if OPENSSL_USE_IPV6 + 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 */ 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 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; - +#endif + /* If secret isn't initialized yet, the cookie can't be valid */ if (!cookie_initialized) 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); /* 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_port); +#endif buffer = OPENSSL_malloc(length); 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"); return 0; } - - memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr)); - memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port)); + +#if OPENSSL_USE_IPV6 + 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 */ HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, buffer, length, result, &resultlength); OPENSSL_free(buffer); - + if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0) return 1; diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c index 5cd6342598..cddabe1aaf 100644 --- a/crypto/bio/bss_dgram.c +++ b/crypto/bio/bss_dgram.c @@ -108,7 +108,11 @@ static BIO_METHOD methods_dgramp= 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 _errno; unsigned int mtu; @@ -274,7 +278,11 @@ static int dgram_read(BIO *b, char *out, int outl) int ret=0; 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); if (out != NULL) @@ -287,7 +295,7 @@ static int dgram_read(BIO *b, char *out, int outl) * compiler warnings. */ 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); 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; clear_socket_error(); - if ( data->connected ) - ret=writesocket(b->num,in,inl); - else + if ( data->connected ) + ret=writesocket(b->num,in,inl); + else +#if OPENSSL_USE_IPV6 + if (data->peer.ss_family == AF_INET) #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 - 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 BIO_clear_retry_flags(b); @@ -405,7 +428,11 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) else { #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 } #endif @@ -510,27 +537,44 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) if ( to != NULL) { 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 { 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; - case BIO_CTRL_DGRAM_GET_PEER: - to = (struct sockaddr *) ptr; + case BIO_CTRL_DGRAM_GET_PEER: + to = (struct sockaddr *) ptr; - memcpy(to, &(data->peer), sizeof(struct sockaddr)); - ret = sizeof(struct sockaddr); - break; - case BIO_CTRL_DGRAM_SET_PEER: - to = (struct sockaddr *) ptr; +#if OPENSSL_USE_IPV6 + memcpy(to, &(data->peer), sizeof(struct sockaddr_storage)); + ret = sizeof(struct sockaddr_storage); +#else + 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)); - break; +#if OPENSSL_USE_IPV6 + 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: - memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); + memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); break; #if defined(SO_RCVTIMEO) case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: -- 2.40.0