Refactoring BIO: Adapt BIO_s_datagram and all that depends on it

The control commands that previously took a struct sockaddr * have
been changed to take a BIO_ADDR * instead.

Reviewed-by: Kurt Roeckx <kurt@openssl.org>
This commit is contained in:
Richard Levitte 2016-02-03 00:27:44 +01:00
parent 75d5bd4e7d
commit d858c87653
4 changed files with 79 additions and 182 deletions

View File

@ -737,14 +737,9 @@ int generate_cookie_callback(SSL *ssl, unsigned char *cookie,
unsigned int *cookie_len) unsigned int *cookie_len)
{ {
unsigned char *buffer; unsigned char *buffer;
unsigned int length; size_t length;
union { unsigned short port;
struct sockaddr sa; BIO_ADDR *peer = NULL;
struct sockaddr_in s4;
#if OPENSSL_USE_IPV6
struct sockaddr_in6 s6;
#endif
} peer;
/* Initialize a random secret */ /* Initialize a random secret */
if (!cookie_initialized) { if (!cookie_initialized) {
@ -755,50 +750,31 @@ int generate_cookie_callback(SSL *ssl, unsigned char *cookie,
cookie_initialized = 1; cookie_initialized = 1;
} }
peer = BIO_ADDR_new();
if (peer == NULL) {
BIO_printf(bio_err, "memory full\n");
return 0;
}
/* Read peer information */ /* Read peer information */
(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 */
length = 0; BIO_ADDR_rawaddress(peer, NULL, &length);
switch (peer.sa.sa_family) { OPENSSL_assert(length != 0);
case AF_INET: port = BIO_ADDR_rawport(peer);
length += sizeof(struct in_addr); length += sizeof(port);
length += sizeof(peer.s4.sin_port);
break;
#if OPENSSL_USE_IPV6
case AF_INET6:
length += sizeof(struct in6_addr);
length += sizeof(peer.s6.sin6_port);
break;
#endif
default:
OPENSSL_assert(0);
break;
}
buffer = app_malloc(length, "cookie generate buffer"); buffer = app_malloc(length, "cookie generate buffer");
switch (peer.sa.sa_family) { memcpy(buffer, &port, sizeof(port));
case AF_INET: BIO_ADDR_rawaddress(peer, buffer + sizeof(port), NULL);
memcpy(buffer, &peer.s4.sin_port, sizeof(peer.s4.sin_port));
memcpy(buffer + sizeof(peer.s4.sin_port),
&peer.s4.sin_addr, sizeof(struct in_addr));
break;
#if OPENSSL_USE_IPV6
case AF_INET6:
memcpy(buffer, &peer.s6.sin6_port, sizeof(peer.s6.sin6_port));
memcpy(buffer + sizeof(peer.s6.sin6_port),
&peer.s6.sin6_addr, sizeof(struct in6_addr));
break;
#endif
default:
OPENSSL_assert(0);
break;
}
/* 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, cookie, cookie_len); buffer, length, cookie, cookie_len);
OPENSSL_free(buffer); OPENSSL_free(buffer);
BIO_ADDR_free(peer);
return 1; return 1;
} }

View File

@ -2432,12 +2432,15 @@ static int init_ssl_connection(SSL *con)
unsigned next_proto_neg_len; unsigned next_proto_neg_len;
#endif #endif
unsigned char *exportedkeymat; unsigned char *exportedkeymat;
#ifndef OPENSSL_NO_DTLS
struct sockaddr_storage client;
#endif
#ifndef OPENSSL_NO_DTLS #ifndef OPENSSL_NO_DTLS
if(dtlslisten) { if(dtlslisten) {
BIO_ADDR *client = NULL;
if ((client = BIO_ADDR_new()) == NULL) {
BIO_printf(bio_err, "ERROR - memory\n");
return 0;
}
i = DTLSv1_listen(con, &client); i = DTLSv1_listen(con, &client);
if (i > 0) { if (i > 0) {
BIO *wbio; BIO *wbio;
@ -2448,11 +2451,12 @@ static int init_ssl_connection(SSL *con)
BIO_get_fd(wbio, &fd); BIO_get_fd(wbio, &fd);
} }
if(!wbio || connect(fd, (struct sockaddr *)&client, if(!wbio || BIO_connect(fd, client, 0) == 0) {
sizeof(struct sockaddr_storage))) {
BIO_printf(bio_err, "ERROR - unable to connect\n"); BIO_printf(bio_err, "ERROR - unable to connect\n");
BIO_ADDR_free(client);
return 0; return 0;
} }
BIO_ADDR_free(client);
dtlslisten = 0; dtlslisten = 0;
i = SSL_accept(con); i = SSL_accept(con);
} }

View File

@ -58,10 +58,8 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#define USE_SOCKETS
#include "internal/cryptlib.h"
#include <openssl/bio.h> #include "bio_lcl.h"
#ifndef OPENSSL_NO_DGRAM #ifndef OPENSSL_NO_DGRAM
# if !(defined(_WIN32) || defined(OPENSSL_SYS_VMS)) # if !(defined(_WIN32) || defined(OPENSSL_SYS_VMS))
@ -156,13 +154,7 @@ static BIO_METHOD methods_dgramp_sctp = {
# endif # endif
typedef struct bio_dgram_data_st { typedef struct bio_dgram_data_st {
union { BIO_ADDR peer;
struct sockaddr sa;
struct sockaddr_in sa_in;
# if OPENSSL_USE_IPV6
struct sockaddr_in6 sa_in6;
# endif
} peer;
unsigned int connected; unsigned int connected;
unsigned int _errno; unsigned int _errno;
unsigned int mtu; unsigned int mtu;
@ -179,13 +171,7 @@ typedef struct bio_dgram_sctp_save_message_st {
} bio_dgram_sctp_save_message; } bio_dgram_sctp_save_message;
typedef struct bio_dgram_sctp_data_st { typedef struct bio_dgram_sctp_data_st {
union { BIO_ADDR peer;
struct sockaddr sa;
struct sockaddr_in sa_in;
# if OPENSSL_USE_IPV6
struct sockaddr_in6 sa_in6;
# endif
} peer;
unsigned int connected; unsigned int connected;
unsigned int _errno; unsigned int _errno;
unsigned int mtu; unsigned int mtu;
@ -369,40 +355,20 @@ static int dgram_read(BIO *b, char *out, int outl)
bio_dgram_data *data = (bio_dgram_data *)b->ptr; bio_dgram_data *data = (bio_dgram_data *)b->ptr;
int flags = 0; int flags = 0;
struct { BIO_ADDR peer;
/* socklen_t len = sizeof(peer);
* See commentary in b_sock.c. <appro>
*/
union {
size_t s;
int i;
} len;
union {
struct sockaddr sa;
struct sockaddr_in sa_in;
# if OPENSSL_USE_IPV6
struct sockaddr_in6 sa_in6;
# endif
} peer;
} sa;
sa.len.s = 0;
sa.len.i = sizeof(sa.peer);
if (out != NULL) { if (out != NULL) {
clear_socket_error(); clear_socket_error();
memset(&sa.peer, 0, sizeof(sa.peer)); memset(&peer, 0, sizeof(peer));
dgram_adjust_rcv_timeout(b); dgram_adjust_rcv_timeout(b);
if (data->peekmode) if (data->peekmode)
flags = MSG_PEEK; flags = MSG_PEEK;
ret = recvfrom(b->num, out, outl, flags, &sa.peer.sa, (void *)&sa.len); ret = recvfrom(b->num, out, outl, flags,
if (sizeof(sa.len.i) != sizeof(sa.len.s) && sa.len.i == 0) { BIO_ADDR_sockaddr_noconst(&peer), &len);
OPENSSL_assert(sa.len.s <= sizeof(sa.peer));
sa.len.i = (int)sa.len.s;
}
if (!data->connected && ret >= 0) if (!data->connected && ret >= 0)
BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer); BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer);
BIO_clear_retry_flags(b); BIO_clear_retry_flags(b);
if (ret < 0) { if (ret < 0) {
@ -426,18 +392,14 @@ static int dgram_write(BIO *b, const char *in, int inl)
if (data->connected) if (data->connected)
ret = writesocket(b->num, in, inl); ret = writesocket(b->num, in, inl);
else { else {
int peerlen = sizeof(data->peer); int peerlen = BIO_ADDR_sockaddr_size(&data->peer);
if (data->peer.sa.sa_family == AF_INET)
peerlen = sizeof(data->peer.sa_in);
# if OPENSSL_USE_IPV6
else if (data->peer.sa.sa_family == AF_INET6)
peerlen = sizeof(data->peer.sa_in6);
# endif
# if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK) # if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
ret = sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen); ret = sendto(b->num, (char *)in, inl, 0,
BIO_ADDR_sockaddr(&data->peer), peerlen);
# else # else
ret = sendto(b->num, in, inl, 0, &data->peer.sa, peerlen); ret = sendto(b->num, in, inl, 0,
BIO_ADDR_sockaddr(&data->peer), peerlen);
# endif # endif
} }
@ -455,17 +417,20 @@ static long dgram_get_mtu_overhead(bio_dgram_data *data)
{ {
long ret; long ret;
switch (data->peer.sa.sa_family) { switch (BIO_ADDR_family(&data->peer)) {
case AF_INET: case AF_INET:
/* /*
* Assume this is UDP - 20 bytes for IP, 8 bytes for UDP * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP
*/ */
ret = 28; ret = 28;
break; break;
# if OPENSSL_USE_IPV6 # ifdef AF_INET6
case AF_INET6: case AF_INET6:
{
# ifdef IN6_IS_ADDR_V4MAPPED # ifdef IN6_IS_ADDR_V4MAPPED
if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr)) struct in6_addr tmp_addr;
if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL)
&& IN6_IS_ADDR_V4MAPPED(&tmp_addr))
/* /*
* Assume this is UDP - 20 bytes for IP, 8 bytes for UDP * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP
*/ */
@ -476,6 +441,7 @@ static long dgram_get_mtu_overhead(bio_dgram_data *data)
* Assume this is UDP - 40 bytes for IP, 8 bytes for UDP * Assume this is UDP - 40 bytes for IP, 8 bytes for UDP
*/ */
ret = 48; ret = 48;
}
break; break;
# endif # endif
default: default:
@ -490,20 +456,13 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
{ {
long ret = 1; long ret = 1;
int *ip; int *ip;
struct sockaddr *to = NULL;
bio_dgram_data *data = NULL; bio_dgram_data *data = NULL;
int sockopt_val = 0; int sockopt_val = 0;
# if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU)) # if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU))
socklen_t sockopt_len; /* assume that system supporting IP_MTU is socklen_t sockopt_len; /* assume that system supporting IP_MTU is
* modern enough to define socklen_t */ * modern enough to define socklen_t */
socklen_t addr_len; socklen_t addr_len;
union { BIO_ADDR addr;
struct sockaddr sa;
struct sockaddr_in s4;
# if OPENSSL_USE_IPV6
struct sockaddr_in6 s6;
# endif
} addr;
# endif # endif
data = (bio_dgram_data *)b->ptr; data = (bio_dgram_data *)b->ptr;
@ -546,20 +505,7 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
ret = 1; ret = 1;
break; break;
case BIO_CTRL_DGRAM_CONNECT: case BIO_CTRL_DGRAM_CONNECT:
to = (struct sockaddr *)ptr; BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
switch (to->sa_family) {
case AF_INET:
memcpy(&data->peer, to, sizeof(data->peer.sa_in));
break;
# if OPENSSL_USE_IPV6
case AF_INET6:
memcpy(&data->peer, to, sizeof(data->peer.sa_in6));
break;
# endif
default:
memcpy(&data->peer, to, sizeof(data->peer.sa));
break;
}
break; break;
/* (Linux)kernel sets DF bit on outgoing IP packets */ /* (Linux)kernel sets DF bit on outgoing IP packets */
case BIO_CTRL_DGRAM_MTU_DISCOVER: case BIO_CTRL_DGRAM_MTU_DISCOVER:
@ -644,18 +590,22 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
break; break;
case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
ret = -dgram_get_mtu_overhead(data); ret = -dgram_get_mtu_overhead(data);
switch (data->peer.sa.sa_family) { switch (BIO_ADDR_family(&data->peer)) {
case AF_INET: case AF_INET:
ret += 576; ret += 576;
break; break;
# if OPENSSL_USE_IPV6 # if OPENSSL_USE_IPV6
case AF_INET6: case AF_INET6:
{
# ifdef IN6_IS_ADDR_V4MAPPED # ifdef IN6_IS_ADDR_V4MAPPED
if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr)) struct in6_addr tmp_addr;
if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL)
&& IN6_IS_ADDR_V4MAPPED(&tmp_addr))
ret += 576; ret += 576;
else else
# endif # endif
ret += 1280; ret += 1280;
}
break; break;
# endif # endif
default: default:
@ -670,61 +620,24 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
ret = num; ret = num;
break; break;
case BIO_CTRL_DGRAM_SET_CONNECTED: case BIO_CTRL_DGRAM_SET_CONNECTED:
to = (struct sockaddr *)ptr; if (ptr != NULL) {
if (to != NULL) {
data->connected = 1; data->connected = 1;
switch (to->sa_family) { BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
case AF_INET:
memcpy(&data->peer, to, sizeof(data->peer.sa_in));
break;
# if OPENSSL_USE_IPV6
case AF_INET6:
memcpy(&data->peer, to, sizeof(data->peer.sa_in6));
break;
# endif
default:
memcpy(&data->peer, to, sizeof(data->peer.sa));
break;
}
} else { } else {
data->connected = 0; data->connected = 0;
memset(&data->peer, 0, sizeof(data->peer)); memset(&data->peer, 0, sizeof(data->peer));
} }
break; break;
case BIO_CTRL_DGRAM_GET_PEER: case BIO_CTRL_DGRAM_GET_PEER:
switch (data->peer.sa.sa_family) { ret = BIO_ADDR_sockaddr_size(&data->peer);
case AF_INET: /* FIXME: if num < ret, we will only return part of an address.
ret = sizeof(data->peer.sa_in); That should bee an error, no? */
break;
# if OPENSSL_USE_IPV6
case AF_INET6:
ret = sizeof(data->peer.sa_in6);
break;
# endif
default:
ret = sizeof(data->peer.sa);
break;
}
if (num == 0 || num > ret) if (num == 0 || num > ret)
num = ret; num = ret;
memcpy(ptr, &data->peer, (ret = num)); memcpy(ptr, &data->peer, (ret = num));
break; break;
case BIO_CTRL_DGRAM_SET_PEER: case BIO_CTRL_DGRAM_SET_PEER:
to = (struct sockaddr *)ptr; BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
switch (to->sa_family) {
case AF_INET:
memcpy(&data->peer, to, sizeof(data->peer.sa_in));
break;
# if OPENSSL_USE_IPV6
case AF_INET6:
memcpy(&data->peer, to, sizeof(data->peer.sa_in6));
break;
# endif
default:
memcpy(&data->peer, to, sizeof(data->peer.sa));
break;
}
break; 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));

View File

@ -75,7 +75,7 @@
static void get_current_time(struct timeval *t); static void get_current_time(struct timeval *t);
static int dtls1_set_handshake_header(SSL *s, int type, unsigned long len); static int dtls1_set_handshake_header(SSL *s, int type, unsigned long len);
static int dtls1_handshake_write(SSL *s); static int dtls1_handshake_write(SSL *s);
int dtls1_listen(SSL *s, struct sockaddr *client); int dtls1_listen(SSL *s, BIO_ADDR *client);
static unsigned int dtls1_link_min_mtu(void); static unsigned int dtls1_link_min_mtu(void);
/* XDTLS: figure out the right values */ /* XDTLS: figure out the right values */
@ -484,7 +484,7 @@ static void get_current_time(struct timeval *t)
#define LISTEN_SEND_VERIFY_REQUEST 1 #define LISTEN_SEND_VERIFY_REQUEST 1
int dtls1_listen(SSL *s, struct sockaddr *client) int dtls1_listen(SSL *s, BIO_ADDR *client)
{ {
int next, n, ret = 0, clearpkt = 0; int next, n, ret = 0, clearpkt = 0;
unsigned char cookie[DTLS1_COOKIE_LENGTH]; unsigned char cookie[DTLS1_COOKIE_LENGTH];
@ -495,7 +495,7 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen; unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen;
BIO *rbio, *wbio; BIO *rbio, *wbio;
BUF_MEM *bufm; BUF_MEM *bufm;
struct sockaddr_storage tmpclient; BIO_ADDR *tmpclient = NULL;
PACKET pkt, msgpkt, msgpayload, session, cookiepkt; PACKET pkt, msgpkt, msgpayload, session, cookiepkt;
/* Ensure there is no state left over from a previous invocation */ /* Ensure there is no state left over from a previous invocation */
@ -805,11 +805,14 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
* This is unneccessary if rbio and wbio are one and the same - but * This is unneccessary if rbio and wbio are one and the same - but
* maybe they're not. * maybe they're not.
*/ */
if(BIO_dgram_get_peer(rbio, &tmpclient) <= 0 if ((tmpclient = BIO_ADDR_new()) == NULL
|| BIO_dgram_set_peer(wbio, &tmpclient) <= 0) { || BIO_dgram_get_peer(rbio, tmpclient) <= 0
|| BIO_dgram_set_peer(wbio, tmpclient) <= 0) {
SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR); SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR);
goto end; goto end;
} }
BIO_ADDR_free(tmpclient);
tmpclient = NULL;
if (BIO_write(wbio, buf, reclen) < (int)reclen) { if (BIO_write(wbio, buf, reclen) < (int)reclen) {
if(BIO_should_retry(wbio)) { if(BIO_should_retry(wbio)) {
@ -863,6 +866,7 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
ret = 1; ret = 1;
clearpkt = 0; clearpkt = 0;
end: end:
BIO_ADDR_free(tmpclient);
BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL); BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL);
if (clearpkt) { if (clearpkt) {
/* Dump this packet. Ignore return value */ /* Dump this packet. Ignore return value */