Commit d858c876 authored by Richard Levitte's avatar Richard Levitte
Browse files

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: default avatarKurt Roeckx <kurt@openssl.org>
parent 75d5bd4e
Loading
Loading
Loading
Loading
+18 −42
Original line number Diff line number Diff line
@@ -737,14 +737,9 @@ int generate_cookie_callback(SSL *ssl, unsigned char *cookie,
                             unsigned int *cookie_len)
{
    unsigned char *buffer;
    unsigned int length;
    union {
        struct sockaddr sa;
        struct sockaddr_in s4;
#if OPENSSL_USE_IPV6
        struct sockaddr_in6 s6;
#endif
    } peer;
    size_t length;
    unsigned short port;
    BIO_ADDR *peer = NULL;

    /* Initialize a random secret */
    if (!cookie_initialized) {
@@ -755,50 +750,31 @@ int generate_cookie_callback(SSL *ssl, unsigned char *cookie,
        cookie_initialized = 1;
    }

    peer = BIO_ADDR_new();
    if (peer == NULL) {
        BIO_printf(bio_err, "memory full\n");
        return 0;
    }

    /* 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 */
    length = 0;
    switch (peer.sa.sa_family) {
    case AF_INET:
        length += sizeof(struct in_addr);
        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;
    }
    BIO_ADDR_rawaddress(peer, NULL, &length);
    OPENSSL_assert(length != 0);
    port = BIO_ADDR_rawport(peer);
    length += sizeof(port);
    buffer = app_malloc(length, "cookie generate buffer");

    switch (peer.sa.sa_family) {
    case AF_INET:
        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;
    }
    memcpy(buffer, &port, sizeof(port));
    BIO_ADDR_rawaddress(peer, buffer + sizeof(port), NULL);

    /* Calculate HMAC of buffer using the secret */
    HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
         buffer, length, cookie, cookie_len);

    OPENSSL_free(buffer);
    BIO_ADDR_free(peer);

    return 1;
}
+9 −5
Original line number Diff line number Diff line
@@ -2432,12 +2432,15 @@ static int init_ssl_connection(SSL *con)
    unsigned next_proto_neg_len;
#endif
    unsigned char *exportedkeymat;
#ifndef OPENSSL_NO_DTLS
    struct sockaddr_storage client;
#endif

#ifndef OPENSSL_NO_DTLS
    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);
        if (i > 0) {
            BIO *wbio;
@@ -2448,11 +2451,12 @@ static int init_ssl_connection(SSL *con)
                BIO_get_fd(wbio, &fd);
            }

            if(!wbio || connect(fd, (struct sockaddr *)&client,
                                sizeof(struct sockaddr_storage))) {
            if(!wbio || BIO_connect(fd, client, 0) == 0) {
                BIO_printf(bio_err, "ERROR - unable to connect\n");
                BIO_ADDR_free(client);
                return 0;
            }
            BIO_ADDR_free(client);
            dtlslisten = 0;
            i = SSL_accept(con);
        }
+43 −130
Original line number Diff line number Diff line
@@ -58,10 +58,8 @@

#include <stdio.h>
#include <errno.h>
#define USE_SOCKETS
#include "internal/cryptlib.h"

#include <openssl/bio.h>
#include "bio_lcl.h"
#ifndef OPENSSL_NO_DGRAM

# if !(defined(_WIN32) || defined(OPENSSL_SYS_VMS))
@@ -156,13 +154,7 @@ static BIO_METHOD methods_dgramp_sctp = {
# endif

typedef struct bio_dgram_data_st {
    union {
        struct sockaddr sa;
        struct sockaddr_in sa_in;
# if OPENSSL_USE_IPV6
        struct sockaddr_in6 sa_in6;
# endif
    } peer;
    BIO_ADDR peer;
    unsigned int connected;
    unsigned int _errno;
    unsigned int mtu;
@@ -179,13 +171,7 @@ typedef struct bio_dgram_sctp_save_message_st {
} bio_dgram_sctp_save_message;

typedef struct bio_dgram_sctp_data_st {
    union {
        struct sockaddr sa;
        struct sockaddr_in sa_in;
#  if OPENSSL_USE_IPV6
        struct sockaddr_in6 sa_in6;
#  endif
    } peer;
    BIO_ADDR peer;
    unsigned int connected;
    unsigned int _errno;
    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;
    int flags = 0;

    struct {
        /*
         * 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);
    BIO_ADDR peer;
    socklen_t len = sizeof(peer);

    if (out != NULL) {
        clear_socket_error();
        memset(&sa.peer, 0, sizeof(sa.peer));
        memset(&peer, 0, sizeof(peer));
        dgram_adjust_rcv_timeout(b);
        if (data->peekmode)
            flags = MSG_PEEK;
        ret = recvfrom(b->num, out, outl, flags, &sa.peer.sa, (void *)&sa.len);
        if (sizeof(sa.len.i) != sizeof(sa.len.s) && sa.len.i == 0) {
            OPENSSL_assert(sa.len.s <= sizeof(sa.peer));
            sa.len.i = (int)sa.len.s;
        }
        ret = recvfrom(b->num, out, outl, flags,
                       BIO_ADDR_sockaddr_noconst(&peer), &len);

        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);
        if (ret < 0) {
@@ -426,18 +392,14 @@ static int dgram_write(BIO *b, const char *in, int inl)
    if (data->connected)
        ret = writesocket(b->num, in, inl);
    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)
        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
        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
    }

@@ -455,17 +417,20 @@ static long dgram_get_mtu_overhead(bio_dgram_data *data)
{
    long ret;

    switch (data->peer.sa.sa_family) {
    switch (BIO_ADDR_family(&data->peer)) {
    case AF_INET:
        /*
         * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP
         */
        ret = 28;
        break;
# if OPENSSL_USE_IPV6
# ifdef AF_INET6
    case AF_INET6:
        {
#  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
                 */
@@ -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
             */
            ret = 48;
        }
        break;
# endif
    default:
@@ -490,20 +456,13 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
{
    long ret = 1;
    int *ip;
    struct sockaddr *to = NULL;
    bio_dgram_data *data = NULL;
    int sockopt_val = 0;
# if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU))
    socklen_t sockopt_len;      /* assume that system supporting IP_MTU is
                                 * modern enough to define socklen_t */
    socklen_t addr_len;
    union {
        struct sockaddr sa;
        struct sockaddr_in s4;
#  if OPENSSL_USE_IPV6
        struct sockaddr_in6 s6;
#  endif
    } addr;
    BIO_ADDR addr;
# endif

    data = (bio_dgram_data *)b->ptr;
@@ -546,20 +505,7 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
        ret = 1;
        break;
    case BIO_CTRL_DGRAM_CONNECT:
        to = (struct sockaddr *)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;
        }
        BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
        break;
        /* (Linux)kernel sets DF bit on outgoing IP packets */
    case BIO_CTRL_DGRAM_MTU_DISCOVER:
@@ -644,18 +590,22 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
        break;
    case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
        ret = -dgram_get_mtu_overhead(data);
        switch (data->peer.sa.sa_family) {
        switch (BIO_ADDR_family(&data->peer)) {
        case AF_INET:
            ret += 576;
            break;
# if OPENSSL_USE_IPV6
        case AF_INET6:
            {
#  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;
                else
#  endif
                    ret += 1280;
            }
            break;
# endif
        default:
@@ -670,61 +620,24 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
        ret = num;
        break;
    case BIO_CTRL_DGRAM_SET_CONNECTED:
        to = (struct sockaddr *)ptr;

        if (to != NULL) {
        if (ptr != NULL) {
            data->connected = 1;
            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;
            }
            BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
        } else {
            data->connected = 0;
            memset(&data->peer, 0, sizeof(data->peer));
        }
        break;
    case BIO_CTRL_DGRAM_GET_PEER:
        switch (data->peer.sa.sa_family) {
        case AF_INET:
            ret = sizeof(data->peer.sa_in);
            break;
# if OPENSSL_USE_IPV6
        case AF_INET6:
            ret = sizeof(data->peer.sa_in6);
            break;
# endif
        default:
            ret = sizeof(data->peer.sa);
            break;
        }
        ret = BIO_ADDR_sockaddr_size(&data->peer);
        /* FIXME: if num < ret, we will only return part of an address.
           That should bee an error, no? */
        if (num == 0 || num > ret)
            num = ret;
        memcpy(ptr, &data->peer, (ret = num));
        break;
    case BIO_CTRL_DGRAM_SET_PEER:
        to = (struct sockaddr *)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;
        }
        BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
        break;
    case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
        memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
+9 −5
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@
static void get_current_time(struct timeval *t);
static int dtls1_set_handshake_header(SSL *s, int type, unsigned long len);
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);

/* XDTLS:  figure out the right values */
@@ -484,7 +484,7 @@ static void get_current_time(struct timeval *t)
#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;
    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;
    BIO *rbio, *wbio;
    BUF_MEM *bufm;
    struct sockaddr_storage tmpclient;
    BIO_ADDR *tmpclient = NULL;
    PACKET pkt, msgpkt, msgpayload, session, cookiepkt;

    /* 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
             * maybe they're not.
             */
            if(BIO_dgram_get_peer(rbio, &tmpclient) <= 0
               || BIO_dgram_set_peer(wbio, &tmpclient) <= 0) {
            if ((tmpclient = BIO_ADDR_new()) == NULL
                || BIO_dgram_get_peer(rbio, tmpclient) <= 0
                || BIO_dgram_set_peer(wbio, tmpclient) <= 0) {
                SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR);
                goto end;
            }
            BIO_ADDR_free(tmpclient);
            tmpclient = NULL;

            if (BIO_write(wbio, buf, reclen) < (int)reclen) {
                if(BIO_should_retry(wbio)) {
@@ -863,6 +866,7 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
    ret = 1;
    clearpkt = 0;
end:
    BIO_ADDR_free(tmpclient);
    BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL);
    if (clearpkt) {
        /* Dump this packet. Ignore return value */