X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fbio%2Fbss_dgram.c;h=1b2b5c745554a1d835189e1aaf31c2cacb442a92;hp=78c437bcb568144c5dd1f3fbf47afa5e91c44ada;hb=617b49db14fa4c1211bfc5d0e88294d0f159c9a9;hpb=0f113f3ee4d629ef9a4a30911b22b224772085e5 diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c index 78c437bcb5..1b2b5c7455 100644 --- a/crypto/bio/bss_dgram.c +++ b/crypto/bio/bss_dgram.c @@ -1,77 +1,18 @@ -/* crypto/bio/bio_dgram.c */ /* - * DTLS implementation written by Nagendra Modadugu - * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. - */ -/* ==================================================================== - * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). + * Copyright 2005-2017 The OpenSSL Project Authors. All Rights Reserved. * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html */ #include #include -#define USE_SOCKETS -#include "cryptlib.h" -#include +#include "bio_lcl.h" #ifndef OPENSSL_NO_DGRAM -# if !(defined(_WIN32) || defined(OPENSSL_SYS_VMS)) -# include -# endif -# if defined(OPENSSL_SYS_VMS) -# include -# endif - # ifndef OPENSSL_NO_SCTP # include # include @@ -97,12 +38,6 @@ ((a)->s6_addr32[2] == htonl(0x0000ffff))) # endif -# ifdef WATT32 -# define sock_write SockWrite /* Watt-32 uses same names */ -# define sock_read SockRead -# define sock_puts SockPuts -# endif - static int dgram_write(BIO *h, const char *buf, int num); static int dgram_read(BIO *h, char *buf, int size); static int dgram_puts(BIO *h, const char *str); @@ -128,47 +63,50 @@ static int BIO_dgram_should_retry(int s); static void get_current_time(struct timeval *t); -static BIO_METHOD methods_dgramp = { +static const BIO_METHOD methods_dgramp = { BIO_TYPE_DGRAM, "datagram socket", + /* TODO: Convert to new style write function */ + bwrite_conv, dgram_write, + /* TODO: Convert to new style read function */ + bread_conv, dgram_read, dgram_puts, - NULL, /* dgram_gets, */ + NULL, /* dgram_gets, */ dgram_ctrl, dgram_new, dgram_free, - NULL, + NULL, /* dgram_callback_ctrl */ }; # ifndef OPENSSL_NO_SCTP -static BIO_METHOD methods_dgramp_sctp = { +static const BIO_METHOD methods_dgramp_sctp = { BIO_TYPE_DGRAM_SCTP, "datagram sctp socket", + /* TODO: Convert to new style write function */ + bwrite_conv, dgram_sctp_write, + /* TODO: Convert to new style write function */ + bread_conv, dgram_sctp_read, dgram_sctp_puts, - NULL, /* dgram_gets, */ + NULL, /* dgram_gets, */ dgram_sctp_ctrl, dgram_sctp_new, dgram_sctp_free, - NULL, + NULL, /* dgram_callback_ctrl */ }; # 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; struct timeval next_timeout; struct timeval socket_timeout; + unsigned int peekmode; } bio_dgram_data; # ifndef OPENSSL_NO_SCTP @@ -179,13 +117,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; @@ -199,13 +131,12 @@ typedef struct bio_dgram_sctp_data_st { int ccs_sent; int save_shutdown; int peer_auth_tested; - bio_dgram_sctp_save_message saved_message; } bio_dgram_sctp_data; # endif -BIO_METHOD *BIO_s_datagram(void) +const BIO_METHOD *BIO_s_datagram(void) { - return (&methods_dgramp); + return &methods_dgramp; } BIO *BIO_new_dgram(int fd, int close_flag) @@ -214,25 +145,19 @@ BIO *BIO_new_dgram(int fd, int close_flag) ret = BIO_new(BIO_s_datagram()); if (ret == NULL) - return (NULL); + return NULL; BIO_set_fd(ret, fd, close_flag); - return (ret); + return ret; } static int dgram_new(BIO *bi) { - bio_dgram_data *data = NULL; + bio_dgram_data *data = OPENSSL_zalloc(sizeof(*data)); - bi->init = 0; - bi->num = 0; - data = OPENSSL_malloc(sizeof(bio_dgram_data)); if (data == NULL) return 0; - memset(data, 0x00, sizeof(bio_dgram_data)); bi->ptr = data; - - bi->flags = 0; - return (1); + return 1; } static int dgram_free(BIO *a) @@ -240,29 +165,28 @@ static int dgram_free(BIO *a) bio_dgram_data *data; if (a == NULL) - return (0); + return 0; if (!dgram_clear(a)) return 0; data = (bio_dgram_data *)a->ptr; - if (data != NULL) - OPENSSL_free(data); + OPENSSL_free(data); - return (1); + return 1; } static int dgram_clear(BIO *a) { if (a == NULL) - return (0); + return 0; if (a->shutdown) { if (a->init) { - SHUTDOWN2(a->num); + BIO_closesocket(a->num); } a->init = 0; a->flags = 0; } - return (1); + return 1; } static void dgram_adjust_rcv_timeout(BIO *b) @@ -306,20 +230,21 @@ static void dgram_adjust_rcv_timeout(BIO *b) /* Calculate time left until timer expires */ memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval)); - timeleft.tv_sec -= timenow.tv_sec; - timeleft.tv_usec -= timenow.tv_usec; - if (timeleft.tv_usec < 0) { + if (timeleft.tv_usec < timenow.tv_usec) { + timeleft.tv_usec = 1000000 - timenow.tv_usec + timeleft.tv_usec; timeleft.tv_sec--; - timeleft.tv_usec += 1000000; + } else { + timeleft.tv_usec -= timenow.tv_usec; } - - if (timeleft.tv_sec < 0) { + if (timeleft.tv_sec < timenow.tv_sec) { timeleft.tv_sec = 0; timeleft.tv_usec = 1; + } else { + timeleft.tv_sec -= timenow.tv_sec; } /* - * Adjust socket timeout if next handhake message timer will expire + * Adjust socket timeout if next handshake message timer will expire * earlier. */ if ((data->socket_timeout.tv_sec == 0 @@ -373,39 +298,22 @@ static int dgram_read(BIO *b, char *out, int outl) { int ret = 0; bio_dgram_data *data = (bio_dgram_data *)b->ptr; + int flags = 0; - struct { - /* - * See commentary in b_sock.c. - */ - 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, 0x00, sizeof(sa.peer)); + memset(&peer, 0, sizeof(peer)); dgram_adjust_rcv_timeout(b); - ret = recvfrom(b->num, out, outl, 0, &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; - } + if (data->peekmode) + flags = MSG_PEEK; + 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) { @@ -417,7 +325,7 @@ static int dgram_read(BIO *b, char *out, int outl) dgram_reset_rcv_timeout(b); } - return (ret); + return ret; } static int dgram_write(BIO *b, const char *in, int inl) @@ -429,19 +337,10 @@ 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); -# else - ret = sendto(b->num, in, inl, 0, &data->peer.sa, peerlen); -# endif + ret = sendto(b->num, in, inl, 0, + BIO_ADDR_sockaddr(&data->peer), peerlen); } BIO_clear_retry_flags(b); @@ -449,43 +348,40 @@ static int dgram_write(BIO *b, const char *in, int inl) if (BIO_dgram_should_retry(ret)) { BIO_set_retry_write(b); data->_errno = get_last_socket_error(); - -# if 0 /* higher layers are responsible for querying - * MTU, if necessary */ - if (data->_errno == EMSGSIZE) - /* retrieve the new MTU */ - BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); -# endif } } - return (ret); + return ret; } 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)) - /* - * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP - */ - ret = 28; - else + 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 + */ + ret = 28; + else # endif /* * Assume this is UDP - 40 bytes for IP, 8 bytes for UDP */ ret = 48; + } break; # endif default: @@ -500,20 +396,14 @@ 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; + int d_errno; # 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; @@ -521,10 +411,8 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) switch (cmd) { case BIO_CTRL_RESET: num = 0; - case BIO_C_FILE_SEEK: ret = 0; break; - case BIO_C_FILE_TELL: case BIO_CTRL_INFO: ret = 0; break; @@ -558,35 +446,13 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) ret = 1; break; case BIO_CTRL_DGRAM_CONNECT: - to = (struct sockaddr *)ptr; -# if 0 - if (connect(b->num, to, sizeof(struct sockaddr)) < 0) { - perror("connect"); - ret = 0; - } else { -# endif - 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; - } -# if 0 - } -# endif + 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: # if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) addr_len = (socklen_t) sizeof(addr); - memset((void *)&addr, 0, sizeof(addr)); + memset(&addr, 0, sizeof(addr)); if (getsockname(b->num, &addr.sa, &addr_len) < 0) { ret = 0; break; @@ -617,7 +483,7 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) case BIO_CTRL_DGRAM_QUERY_MTU: # if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU) addr_len = (socklen_t) sizeof(addr); - memset((void *)&addr, 0, sizeof(addr)); + memset(&addr, 0, sizeof(addr)); if (getsockname(b->num, &addr.sa, &addr_len) < 0) { ret = 0; break; @@ -665,18 +531,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)) - ret += 576; - else + 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; + ret += 1280; + } break; # endif default: @@ -686,67 +556,29 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) break; case BIO_CTRL_DGRAM_GET_MTU: return data->mtu; - break; case BIO_CTRL_DGRAM_SET_MTU: data->mtu = num; 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), 0x00, sizeof(data->peer)); + 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)); @@ -869,11 +701,11 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) /* fall-through */ case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: # ifdef OPENSSL_SYS_WINDOWS - if (data->_errno == WSAETIMEDOUT) + d_errno = (data->_errno == WSAETIMEDOUT); # else - if (data->_errno == EAGAIN) + d_errno = (data->_errno == EAGAIN); # endif - { + if (d_errno) { ret = 1; data->_errno = 0; } else @@ -899,7 +731,7 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) perror("setsockopt"); ret = -1; } -# elif defined(OPENSSL_SYS_LINUX) && defined(IP_MTUDISCOVER) +# elif defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined (IP_PMTUDISC_PROBE) if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT), (ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, &sockopt_val, sizeof(sockopt_val))) < 0) { @@ -946,11 +778,23 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: ret = dgram_get_mtu_overhead(data); break; + + /* + * BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE is used here for compatibility + * reasons. When BIO_CTRL_DGRAM_SET_PEEK_MODE was first defined its value + * was incorrectly clashing with BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE. The + * value has been updated to a non-clashing value. However to preserve + * binary compatiblity we now respond to both the old value and the new one + */ + case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: + case BIO_CTRL_DGRAM_SET_PEEK_MODE: + data->peekmode = (unsigned int)num; + break; default: ret = 0; break; } - return (ret); + return ret; } static int dgram_puts(BIO *bp, const char *str) @@ -959,13 +803,13 @@ static int dgram_puts(BIO *bp, const char *str) n = strlen(str); ret = dgram_write(bp, str, n); - return (ret); + return ret; } # ifndef OPENSSL_NO_SCTP -BIO_METHOD *BIO_s_datagram_sctp(void) +const BIO_METHOD *BIO_s_datagram_sctp(void) { - return (&methods_dgramp_sctp); + return &methods_dgramp_sctp; } BIO *BIO_new_dgram_sctp(int fd, int close_flag) @@ -987,7 +831,7 @@ BIO *BIO_new_dgram_sctp(int fd, int close_flag) bio = BIO_new(BIO_s_datagram_sctp()); if (bio == NULL) - return (NULL); + return NULL; BIO_set_fd(bio, fd, close_flag); /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */ @@ -997,7 +841,9 @@ BIO *BIO_new_dgram_sctp(int fd, int close_flag) sizeof(struct sctp_authchunk)); if (ret < 0) { BIO_vfree(bio); - return (NULL); + BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); + ERR_add_error_data(1, "Ensure SCTP AUTH chunks are enabled in kernel"); + return NULL; } auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE; ret = @@ -1005,25 +851,29 @@ BIO *BIO_new_dgram_sctp(int fd, int close_flag) sizeof(struct sctp_authchunk)); if (ret < 0) { BIO_vfree(bio); - return (NULL); + BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); + ERR_add_error_data(1, "Ensure SCTP AUTH chunks are enabled in kernel"); + return NULL; } /* * Test if activation was successful. When using accept(), SCTP-AUTH has * to be activated for the listening socket already, otherwise the - * connected socket won't use it. + * connected socket won't use it. Similarly with connect(): the socket + * prior to connection must be activated for SCTP-AUTH */ sockopt_len = (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); - authchunks = OPENSSL_malloc(sockopt_len); - memset(authchunks, 0, sockopt_len); - ret = - getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, + authchunks = OPENSSL_zalloc(sockopt_len); + if (authchunks == NULL) { + BIO_vfree(bio); + return NULL; + } + ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, &sockopt_len); - if (ret < 0) { OPENSSL_free(authchunks); BIO_vfree(bio); - return (NULL); + return NULL; } for (p = (unsigned char *)authchunks->gauth_chunks; @@ -1037,12 +887,18 @@ BIO *BIO_new_dgram_sctp(int fd, int close_flag) OPENSSL_free(authchunks); - OPENSSL_assert(auth_data); - OPENSSL_assert(auth_forward); + if (!auth_data || !auth_forward) { + BIO_vfree(bio); + BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); + ERR_add_error_data(1, + "Ensure SCTP AUTH chunks are enabled on the " + "underlying socket"); + return NULL; + } # ifdef SCTP_AUTHENTICATION_EVENT # ifdef SCTP_EVENT - memset(&event, 0, sizeof(struct sctp_event)); + memset(&event, 0, sizeof(event)); event.se_assoc_id = 0; event.se_type = SCTP_AUTHENTICATION_EVENT; event.se_on = 1; @@ -1051,14 +907,14 @@ BIO *BIO_new_dgram_sctp(int fd, int close_flag) sizeof(struct sctp_event)); if (ret < 0) { BIO_vfree(bio); - return (NULL); + return NULL; } # else sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe); ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len); if (ret < 0) { BIO_vfree(bio); - return (NULL); + return NULL; } event.sctp_authentication_event = 1; @@ -1068,7 +924,7 @@ BIO *BIO_new_dgram_sctp(int fd, int close_flag) sizeof(struct sctp_event_subscribe)); if (ret < 0) { BIO_vfree(bio); - return (NULL); + return NULL; } # endif # endif @@ -1082,10 +938,10 @@ BIO *BIO_new_dgram_sctp(int fd, int close_flag) sizeof(optval)); if (ret < 0) { BIO_vfree(bio); - return (NULL); + return NULL; } - return (bio); + return bio; } int BIO_dgram_is_sctp(BIO *bio) @@ -1099,17 +955,16 @@ static int dgram_sctp_new(BIO *bi) bi->init = 0; bi->num = 0; - data = OPENSSL_malloc(sizeof(bio_dgram_sctp_data)); + data = OPENSSL_zalloc(sizeof(*data)); if (data == NULL) return 0; - memset(data, 0x00, sizeof(bio_dgram_sctp_data)); # ifdef SCTP_PR_SCTP_NONE data->prinfo.pr_policy = SCTP_PR_SCTP_NONE; # endif bi->ptr = data; bi->flags = 0; - return (1); + return 1; } static int dgram_sctp_free(BIO *a) @@ -1117,18 +972,15 @@ static int dgram_sctp_free(BIO *a) bio_dgram_sctp_data *data; if (a == NULL) - return (0); + return 0; if (!dgram_clear(a)) return 0; data = (bio_dgram_sctp_data *) a->ptr; - if (data != NULL) { - if (data->saved_message.data != NULL) - OPENSSL_free(data->saved_message.data); + if (data != NULL) OPENSSL_free(data); - } - return (1); + return 1; } # ifdef SCTP_AUTHENTICATION_EVENT @@ -1164,8 +1016,7 @@ static int dgram_sctp_read(BIO *b, char *out, int outl) clear_socket_error(); do { - memset(&data->rcvinfo, 0x00, - sizeof(struct bio_dgram_sctp_rcvinfo)); + memset(&data->rcvinfo, 0, sizeof(data->rcvinfo)); iov.iov_base = out; iov.iov_len = outl; msg.msg_name = NULL; @@ -1229,22 +1080,10 @@ static int dgram_sctp_read(BIO *b, char *out, int outl) struct sctp_event_subscribe event; socklen_t eventsize; # endif - /* - * If a message has been delayed until the socket is dry, - * it can be sent now. - */ - if (data->saved_message.length > 0) { - dgram_sctp_write(data->saved_message.bio, - data->saved_message.data, - data->saved_message.length); - OPENSSL_free(data->saved_message.data); - data->saved_message.data = NULL; - data->saved_message.length = 0; - } /* disable sender dry event */ # ifdef SCTP_EVENT - memset(&event, 0, sizeof(struct sctp_event)); + memset(&event, 0, sizeof(event)); event.se_assoc_id = 0; event.se_type = SCTP_SENDER_DRY_EVENT; event.se_on = 0; @@ -1350,6 +1189,10 @@ static int dgram_sctp_read(BIO *b, char *out, int outl) optlen = (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); authchunks = OPENSSL_malloc(optlen); + if (authchunks == NULL) { + BIOerr(BIO_F_DGRAM_SCTP_READ, ERR_R_MALLOC_FAILURE); + return -1; + } memset(authchunks, 0, optlen); ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, authchunks, &optlen); @@ -1374,9 +1217,17 @@ static int dgram_sctp_read(BIO *b, char *out, int outl) data->peer_auth_tested = 1; } } - return (ret); + return ret; } +/* + * dgram_sctp_write - send message on SCTP socket + * @b: BIO to write to + * @in: data to send + * @inl: amount of bytes in @in to send + * + * Returns -1 on error or the sent amount of bytes on success + */ static int dgram_sctp_write(BIO *b, const char *in, int inl) { int ret; @@ -1404,25 +1255,23 @@ static int dgram_sctp_write(BIO *b, const char *in, int inl) * parameters and flags. */ if (in[0] != 23) { - memset(&handshake_sinfo, 0x00, sizeof(struct bio_dgram_sctp_sndinfo)); + memset(&handshake_sinfo, 0, sizeof(handshake_sinfo)); # ifdef SCTP_SACK_IMMEDIATELY handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY; # endif sinfo = &handshake_sinfo; } - /* - * If we have to send a shutdown alert message and the socket is not dry - * yet, we have to save it and send it as soon as the socket gets dry. - */ - if (data->save_shutdown && !BIO_dgram_sctp_wait_for_dry(b)) { - data->saved_message.bio = b; - if (data->saved_message.data) - OPENSSL_free(data->saved_message.data); - data->saved_message.data = OPENSSL_malloc(inl); - memcpy(data->saved_message.data, in, inl); - data->saved_message.length = inl; - return inl; + /* We can only send a shutdown alert if the socket is dry */ + if (data->save_shutdown) { + ret = BIO_dgram_sctp_wait_for_dry(b); + if (ret < 0) + return -1; + if (ret == 0) { + BIO_clear_retry_flags(b); + BIO_set_retry_write(b); + return -1; + } } iov[0].iov_base = (char *)in; @@ -1440,7 +1289,7 @@ static int dgram_sctp_write(BIO *b, const char *in, int inl) cmsg->cmsg_type = SCTP_SNDINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg); - memset(sndinfo, 0, sizeof(struct sctp_sndinfo)); + memset(sndinfo, 0, sizeof(*sndinfo)); sndinfo->snd_sid = sinfo->snd_sid; sndinfo->snd_flags = sinfo->snd_flags; sndinfo->snd_ppid = sinfo->snd_ppid; @@ -1453,7 +1302,7 @@ static int dgram_sctp_write(BIO *b, const char *in, int inl) cmsg->cmsg_type = SCTP_PRINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg); - memset(prinfo, 0, sizeof(struct sctp_prinfo)); + memset(prinfo, 0, sizeof(*prinfo)); prinfo->pr_policy = pinfo->pr_policy; prinfo->pr_value = pinfo->pr_value; msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); @@ -1463,7 +1312,7 @@ static int dgram_sctp_write(BIO *b, const char *in, int inl) cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); - memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); + memset(sndrcvinfo, 0, sizeof(*sndrcvinfo)); sndrcvinfo->sinfo_stream = sinfo->snd_sid; sndrcvinfo->sinfo_flags = sinfo->snd_flags; # ifdef __FreeBSD__ @@ -1484,7 +1333,7 @@ static int dgram_sctp_write(BIO *b, const char *in, int inl) data->_errno = get_last_socket_error(); } } - return (ret); + return ret; } static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) @@ -1560,7 +1409,7 @@ static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) ret = -1; break; } - memset(authkey, 0x00, sockopt_len); + memset(authkey, 0, sockopt_len); authkey->sca_keynumber = authkeyid.scact_keynumber + 1; # ifndef __FreeBSD__ /* @@ -1609,6 +1458,7 @@ static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) * we need to deactivate an old key */ data->ccs_sent = 1; + /* fall-through */ case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD: /* Returns 0 on success, -1 otherwise. */ @@ -1719,7 +1569,7 @@ static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) ret = dgram_ctrl(b, cmd, num, ptr); break; } - return (ret); + return ret; } int BIO_dgram_sctp_notification_cb(BIO *b, @@ -1740,10 +1590,24 @@ int BIO_dgram_sctp_notification_cb(BIO *b, return 0; } +/* + * BIO_dgram_sctp_wait_for_dry - Wait for SCTP SENDER_DRY event + * @b: The BIO to check for the dry event + * + * Wait until the peer confirms all packets have been received, and so that + * our kernel doesn't have anything to send anymore. This is only received by + * the peer's kernel, not the application. + * + * Returns: + * -1 on error + * 0 when not dry yet + * 1 when dry + */ int BIO_dgram_sctp_wait_for_dry(BIO *b) { int is_dry = 0; - int n, sockflags, ret; + int sockflags = 0; + int n, ret; union sctp_notification snp; struct msghdr msg; struct iovec iov; @@ -1757,7 +1621,7 @@ int BIO_dgram_sctp_wait_for_dry(BIO *b) /* set sender dry event */ # ifdef SCTP_EVENT - memset(&event, 0, sizeof(struct sctp_event)); + memset(&event, 0, sizeof(event)); event.se_assoc_id = 0; event.se_type = SCTP_SENDER_DRY_EVENT; event.se_on = 1; @@ -1780,7 +1644,7 @@ int BIO_dgram_sctp_wait_for_dry(BIO *b) return -1; /* peek for notification */ - memset(&snp, 0x00, sizeof(union sctp_notification)); + memset(&snp, 0, sizeof(snp)); iov.iov_base = (char *)&snp; iov.iov_len = sizeof(union sctp_notification); msg.msg_name = NULL; @@ -1802,7 +1666,7 @@ int BIO_dgram_sctp_wait_for_dry(BIO *b) /* if we find a notification, process it and try again if necessary */ while (msg.msg_flags & MSG_NOTIFICATION) { - memset(&snp, 0x00, sizeof(union sctp_notification)); + memset(&snp, 0, sizeof(snp)); iov.iov_base = (char *)&snp; iov.iov_len = sizeof(union sctp_notification); msg.msg_name = NULL; @@ -1827,7 +1691,7 @@ int BIO_dgram_sctp_wait_for_dry(BIO *b) /* disable sender dry event */ # ifdef SCTP_EVENT - memset(&event, 0, sizeof(struct sctp_event)); + memset(&event, 0, sizeof(event)); event.se_assoc_id = 0; event.se_type = SCTP_SENDER_DRY_EVENT; event.se_on = 0; @@ -1861,7 +1725,7 @@ int BIO_dgram_sctp_wait_for_dry(BIO *b) (void *)&snp); /* found notification, peek again */ - memset(&snp, 0x00, sizeof(union sctp_notification)); + memset(&snp, 0, sizeof(snp)); iov.iov_base = (char *)&snp; iov.iov_len = sizeof(union sctp_notification); msg.msg_name = NULL; @@ -1907,7 +1771,7 @@ int BIO_dgram_sctp_msg_waiting(BIO *b) /* Check if there are any messages waiting to be read */ do { - memset(&snp, 0x00, sizeof(union sctp_notification)); + memset(&snp, 0, sizeof(snp)); iov.iov_base = (char *)&snp; iov.iov_len = sizeof(union sctp_notification); msg.msg_name = NULL; @@ -1930,7 +1794,7 @@ int BIO_dgram_sctp_msg_waiting(BIO *b) dgram_sctp_handle_auth_free_key_event(b, &snp); # endif - memset(&snp, 0x00, sizeof(union sctp_notification)); + memset(&snp, 0, sizeof(snp)); iov.iov_base = (char *)&snp; iov.iov_len = sizeof(union sctp_notification); msg.msg_name = NULL; @@ -1962,7 +1826,7 @@ static int dgram_sctp_puts(BIO *bp, const char *str) n = strlen(str); ret = dgram_sctp_write(bp, str, n); - return (ret); + return ret; } # endif @@ -1981,9 +1845,9 @@ static int BIO_dgram_should_retry(int i) */ # endif - return (BIO_dgram_non_fatal_error(err)); + return BIO_dgram_non_fatal_error(err); } - return (0); + return 0; } int BIO_dgram_non_fatal_error(int err) @@ -1993,12 +1857,6 @@ int BIO_dgram_non_fatal_error(int err) # if defined(WSAEWOULDBLOCK) case WSAEWOULDBLOCK: # endif - -# if 0 /* This appears to always be an error */ -# if defined(WSAENOTCONN) - case WSAENOTCONN: -# endif -# endif # endif # ifdef EWOULDBLOCK @@ -2033,12 +1891,11 @@ int BIO_dgram_non_fatal_error(int err) case EALREADY: # endif - return (1); - /* break; */ + return 1; default: break; } - return (0); + return 0; } static void get_current_time(struct timeval *t) @@ -2055,15 +1912,10 @@ static void get_current_time(struct timeval *t) # ifdef __MINGW32__ now.ul -= 116444736000000000ULL; # else - now.ul -= 116444736000000000U I64; /* re-bias to 1/1/1970 */ + now.ul -= 116444736000000000UI64; /* re-bias to 1/1/1970 */ # endif t->tv_sec = (long)(now.ul / 10000000); t->tv_usec = ((int)(now.ul % 10000000)) / 10; -# elif defined(OPENSSL_SYS_VMS) - struct timeb tb; - ftime(&tb); - t->tv_sec = (long)tb.time; - t->tv_usec = (long)tb.millitm * 1000; # else gettimeofday(t, NULL); # endif