提交 7e159e01 编写于 作者: D Dr. Stephen Henson

PR: 2535

Submitted by: Robin Seggelmann <seggelmann@fh-muenster.de>
Reviewed by: steve

Add SCTP support for DTLS (RFC 6083).
上级 b9e14888
...@@ -10,7 +10,7 @@ use strict; ...@@ -10,7 +10,7 @@ use strict;
# see INSTALL for instructions. # see INSTALL for instructions.
my $usage="Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [experimental-<cipher> ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-dso] [no-krb5] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--test-sanity] os/compiler[:flags]\n"; my $usage="Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [experimental-<cipher> ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-dso] [no-krb5] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--test-sanity] os/compiler[:flags]\n";
# Options: # Options:
# #
...@@ -56,6 +56,7 @@ my $usage="Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [experimenta ...@@ -56,6 +56,7 @@ my $usage="Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [experimenta
# [no-]zlib [don't] compile support for zlib compression. # [no-]zlib [don't] compile support for zlib compression.
# zlib-dynamic Like "zlib", but the zlib library is expected to be a shared # zlib-dynamic Like "zlib", but the zlib library is expected to be a shared
# library and will be loaded in run-time by the OpenSSL library. # library and will be loaded in run-time by the OpenSSL library.
# sctp include SCTP support
# 386 generate 80386 code # 386 generate 80386 code
# no-sse2 disables IA-32 SSE2 code, above option implies no-sse2 # no-sse2 disables IA-32 SSE2 code, above option implies no-sse2
# no-<cipher> build without specified algorithm (rsa, idea, rc5, ...) # no-<cipher> build without specified algorithm (rsa, idea, rc5, ...)
...@@ -709,6 +710,7 @@ my %disabled = ( # "what" => "comment" [or special keyword "experimental ...@@ -709,6 +710,7 @@ my %disabled = ( # "what" => "comment" [or special keyword "experimental
"md2" => "default", "md2" => "default",
"rc5" => "default", "rc5" => "default",
"rfc3779" => "default", "rfc3779" => "default",
"sctp" => "default",
"shared" => "default", "shared" => "default",
"store" => "experimental", "store" => "experimental",
"zlib" => "default", "zlib" => "default",
...@@ -791,6 +793,7 @@ PROCESS_ARGS: ...@@ -791,6 +793,7 @@ PROCESS_ARGS:
# rewrite some options in "enable-..." form # rewrite some options in "enable-..." form
s /^-?-?shared$/enable-shared/; s /^-?-?shared$/enable-shared/;
s /^sctp$/enable-sctp/;
s /^threads$/enable-threads/; s /^threads$/enable-threads/;
s /^zlib$/enable-zlib/; s /^zlib$/enable-zlib/;
s /^zlib-dynamic$/enable-zlib-dynamic/; s /^zlib-dynamic$/enable-zlib-dynamic/;
...@@ -1445,6 +1448,14 @@ if (!$IsMK1MF) ...@@ -1445,6 +1448,14 @@ if (!$IsMK1MF)
} }
} }
if (!defined($disabled{"sctp"}))
{
if ($target =~ /^solaris/)
{
$cflags = "$cflags -D_XPG4_2 -D__EXTENSIONS__";
}
}
$cpuid_obj.=" uplink.o uplink-x86.o" if ($cflags =~ /\-DOPENSSL_USE_APPLINK/); $cpuid_obj.=" uplink.o uplink-x86.o" if ($cflags =~ /\-DOPENSSL_USE_APPLINK/);
# #
......
...@@ -68,6 +68,10 @@ ...@@ -68,6 +68,10 @@
#include <openssl/crypto.h> #include <openssl/crypto.h>
#ifndef OPENSSL_NO_SCTP
#include <stdint.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
...@@ -95,6 +99,9 @@ extern "C" { ...@@ -95,6 +99,9 @@ extern "C" {
#define BIO_TYPE_BIO (19|0x0400) /* (half a) BIO pair */ #define BIO_TYPE_BIO (19|0x0400) /* (half a) BIO pair */
#define BIO_TYPE_LINEBUFFER (20|0x0200) /* filter */ #define BIO_TYPE_LINEBUFFER (20|0x0200) /* filter */
#define BIO_TYPE_DGRAM (21|0x0400|0x0100) #define BIO_TYPE_DGRAM (21|0x0400|0x0100)
#ifndef OPENSSL_NO_SCTP
#define BIO_TYPE_DGRAM_SCTP (24|0x0400|0x0100)
#endif
#define BIO_TYPE_ASN1 (22|0x0200) /* filter */ #define BIO_TYPE_ASN1 (22|0x0200) /* filter */
#define BIO_TYPE_COMP (23|0x0200) /* filter */ #define BIO_TYPE_COMP (23|0x0200) /* filter */
...@@ -163,6 +170,21 @@ extern "C" { ...@@ -163,6 +170,21 @@ extern "C" {
#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT 45 /* Next DTLS handshake timeout to #define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT 45 /* Next DTLS handshake timeout to
* adjust socket timeouts */ * adjust socket timeouts */
#ifndef OPENSSL_NO_SCTP
/* SCTP stuff */
#define BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE 50
#define BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY 51
#define BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY 52
#define BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD 53
#define BIO_CTRL_DGRAM_SCTP_GET_SNDINFO 60
#define BIO_CTRL_DGRAM_SCTP_SET_SNDINFO 61
#define BIO_CTRL_DGRAM_SCTP_GET_RCVINFO 62
#define BIO_CTRL_DGRAM_SCTP_SET_RCVINFO 63
#define BIO_CTRL_DGRAM_SCTP_GET_PRINFO 64
#define BIO_CTRL_DGRAM_SCTP_SET_PRINFO 65
#define BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN 70
#endif
/* modifiers */ /* modifiers */
#define BIO_FP_READ 0x02 #define BIO_FP_READ 0x02
#define BIO_FP_WRITE 0x04 #define BIO_FP_WRITE 0x04
...@@ -331,6 +353,34 @@ typedef struct bio_f_buffer_ctx_struct ...@@ -331,6 +353,34 @@ typedef struct bio_f_buffer_ctx_struct
/* Prefix and suffix callback in ASN1 BIO */ /* Prefix and suffix callback in ASN1 BIO */
typedef int asn1_ps_func(BIO *b, unsigned char **pbuf, int *plen, void *parg); typedef int asn1_ps_func(BIO *b, unsigned char **pbuf, int *plen, void *parg);
#ifndef OPENSSL_NO_SCTP
/* SCTP parameter structs */
struct bio_dgram_sctp_sndinfo
{
uint16_t snd_sid;
uint16_t snd_flags;
uint32_t snd_ppid;
uint32_t snd_context;
};
struct bio_dgram_sctp_rcvinfo
{
uint16_t rcv_sid;
uint16_t rcv_ssn;
uint16_t rcv_flags;
uint32_t rcv_ppid;
uint32_t rcv_tsn;
uint32_t rcv_cumtsn;
uint32_t rcv_context;
};
struct bio_dgram_sctp_prinfo
{
uint16_t pr_policy;
uint32_t pr_value;
};
#endif
/* connect BIO stuff */ /* connect BIO stuff */
#define BIO_CONN_S_BEFORE 1 #define BIO_CONN_S_BEFORE 1
#define BIO_CONN_S_GET_IP 2 #define BIO_CONN_S_GET_IP 2
...@@ -628,6 +678,9 @@ BIO_METHOD *BIO_f_linebuffer(void); ...@@ -628,6 +678,9 @@ BIO_METHOD *BIO_f_linebuffer(void);
BIO_METHOD *BIO_f_nbio_test(void); BIO_METHOD *BIO_f_nbio_test(void);
#ifndef OPENSSL_NO_DGRAM #ifndef OPENSSL_NO_DGRAM
BIO_METHOD *BIO_s_datagram(void); BIO_METHOD *BIO_s_datagram(void);
#ifndef OPENSSL_NO_SCTP
BIO_METHOD *BIO_s_datagram_sctp(void);
#endif
#endif #endif
/* BIO_METHOD *BIO_f_ber(void); */ /* BIO_METHOD *BIO_f_ber(void); */
...@@ -670,6 +723,15 @@ int BIO_set_tcp_ndelay(int sock,int turn_on); ...@@ -670,6 +723,15 @@ int BIO_set_tcp_ndelay(int sock,int turn_on);
BIO *BIO_new_socket(int sock, int close_flag); BIO *BIO_new_socket(int sock, int close_flag);
BIO *BIO_new_dgram(int fd, int close_flag); BIO *BIO_new_dgram(int fd, int close_flag);
#ifndef OPENSSL_NO_SCTP
BIO *BIO_new_dgram_sctp(int fd, int close_flag);
int BIO_dgram_is_sctp(BIO *bio);
int BIO_dgram_sctp_notification_cb(BIO *b,
void (*handle_notifications)(BIO *bio, void *context, void *buf),
void *context);
int BIO_dgram_sctp_wait_for_dry(BIO *b);
int BIO_dgram_sctp_msg_waiting(BIO *b);
#endif
BIO *BIO_new_fd(int fd, int close_flag); BIO *BIO_new_fd(int fd, int close_flag);
BIO *BIO_new_connect(char *host_port); BIO *BIO_new_connect(char *host_port);
BIO *BIO_new_accept(char *host_port); BIO *BIO_new_accept(char *host_port);
......
...@@ -70,6 +70,13 @@ ...@@ -70,6 +70,13 @@
#include <sys/timeb.h> #include <sys/timeb.h>
#endif #endif
#ifndef OPENSSL_NO_SCTP
#include <netinet/sctp.h>
#include <fcntl.h>
#define OPENSSL_SCTP_DATA_CHUNK_TYPE 0x00
#define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0
#endif
#ifdef OPENSSL_SYS_LINUX #ifdef OPENSSL_SYS_LINUX
#define IP_MTU 14 /* linux is lame */ #define IP_MTU 14 /* linux is lame */
#endif #endif
...@@ -88,6 +95,18 @@ static int dgram_new(BIO *h); ...@@ -88,6 +95,18 @@ static int dgram_new(BIO *h);
static int dgram_free(BIO *data); static int dgram_free(BIO *data);
static int dgram_clear(BIO *bio); static int dgram_clear(BIO *bio);
#ifndef OPENSSL_NO_SCTP
static int dgram_sctp_write(BIO *h, const char *buf, int num);
static int dgram_sctp_read(BIO *h, char *buf, int size);
static int dgram_sctp_puts(BIO *h, const char *str);
static long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2);
static int dgram_sctp_new(BIO *h);
static int dgram_sctp_free(BIO *data);
#ifdef SCTP_AUTHENTICATION_EVENT
static void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp);
#endif
#endif
static int BIO_dgram_should_retry(int s); static int BIO_dgram_should_retry(int s);
static void get_current_time(struct timeval *t); static void get_current_time(struct timeval *t);
...@@ -106,6 +125,22 @@ static BIO_METHOD methods_dgramp= ...@@ -106,6 +125,22 @@ static BIO_METHOD methods_dgramp=
NULL, NULL,
}; };
#ifndef OPENSSL_NO_SCTP
static BIO_METHOD methods_dgramp_sctp=
{
BIO_TYPE_DGRAM_SCTP,
"datagram sctp socket",
dgram_sctp_write,
dgram_sctp_read,
dgram_sctp_puts,
NULL, /* dgram_gets, */
dgram_sctp_ctrl,
dgram_sctp_new,
dgram_sctp_free,
NULL,
};
#endif
typedef struct bio_dgram_data_st typedef struct bio_dgram_data_st
{ {
union { union {
...@@ -122,6 +157,40 @@ typedef struct bio_dgram_data_st ...@@ -122,6 +157,40 @@ typedef struct bio_dgram_data_st
struct timeval socket_timeout; struct timeval socket_timeout;
} bio_dgram_data; } bio_dgram_data;
#ifndef OPENSSL_NO_SCTP
typedef struct bio_dgram_sctp_save_message_st
{
BIO *bio;
char *data;
int length;
} 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;
unsigned int connected;
unsigned int _errno;
unsigned int mtu;
struct bio_dgram_sctp_sndinfo sndinfo;
struct bio_dgram_sctp_rcvinfo rcvinfo;
struct bio_dgram_sctp_prinfo prinfo;
void (*handle_notifications)(BIO *bio, void *context, void *buf);
void* notification_context;
int in_handshake;
int ccs_rcvd;
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) BIO_METHOD *BIO_s_datagram(void)
{ {
return(&methods_dgramp); return(&methods_dgramp);
...@@ -738,6 +807,912 @@ static int dgram_puts(BIO *bp, const char *str) ...@@ -738,6 +807,912 @@ static int dgram_puts(BIO *bp, const char *str)
return(ret); return(ret);
} }
#ifndef OPENSSL_NO_SCTP
BIO_METHOD *BIO_s_datagram_sctp(void)
{
return(&methods_dgramp_sctp);
}
BIO *BIO_new_dgram_sctp(int fd, int close_flag)
{
BIO *bio;
int ret, optval = 20000;
int auth_data = 0, auth_forward = 0;
unsigned char *p;
struct sctp_authchunk auth;
struct sctp_authchunks *authchunks;
socklen_t sockopt_len;
#ifdef SCTP_AUTHENTICATION_EVENT
#ifdef SCTP_EVENT
struct sctp_event event;
#else
struct sctp_event_subscribe event;
#endif
#endif
bio=BIO_new(BIO_s_datagram_sctp());
if (bio == NULL) return(NULL);
BIO_set_fd(bio,fd,close_flag);
/* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */
auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE;
ret = setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk));
OPENSSL_assert(ret >= 0);
auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE;
ret = setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk));
OPENSSL_assert(ret >= 0);
/* 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. */
sockopt_len = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
authchunks = OPENSSL_malloc(sockopt_len);
memset(authchunks, 0, sizeof(sockopt_len));
ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, &sockopt_len);
OPENSSL_assert(ret >= 0);
for (p = (unsigned char*) authchunks + sizeof(sctp_assoc_t);
p < (unsigned char*) authchunks + sockopt_len;
p += sizeof(uint8_t))
{
if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1;
if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1;
}
OPENSSL_free(authchunks);
OPENSSL_assert(auth_data);
OPENSSL_assert(auth_forward);
#ifdef SCTP_AUTHENTICATION_EVENT
#ifdef SCTP_EVENT
memset(&event, 0, sizeof(struct sctp_event));
event.se_assoc_id = 0;
event.se_type = SCTP_AUTHENTICATION_EVENT;
event.se_on = 1;
ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
OPENSSL_assert(ret >= 0);
#else
sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe);
ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len);
OPENSSL_assert(ret >= 0);
event.sctp_authentication_event = 1;
ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
OPENSSL_assert(ret >= 0);
#endif
#endif
/* Disable partial delivery by setting the min size
* larger than the max record size of 2^14 + 2048 + 13
*/
ret = setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval, sizeof(optval));
OPENSSL_assert(ret >= 0);
return(bio);
}
int BIO_dgram_is_sctp(BIO *bio)
{
return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP);
}
static int dgram_sctp_new(BIO *bi)
{
bio_dgram_sctp_data *data = NULL;
bi->init=0;
bi->num=0;
data = OPENSSL_malloc(sizeof(bio_dgram_sctp_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);
}
static int dgram_sctp_free(BIO *a)
{
bio_dgram_sctp_data *data;
if (a == NULL) return(0);
if ( ! dgram_clear(a))
return 0;
data = (bio_dgram_sctp_data *)a->ptr;
if(data != NULL) OPENSSL_free(data);
return(1);
}
#ifdef SCTP_AUTHENTICATION_EVENT
void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp)
{
unsigned int sockopt_len = 0;
int ret;
struct sctp_authkey_event* authkeyevent = &snp->sn_auth_event;
if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY)
{
struct sctp_authkeyid authkeyid;
/* delete key */
authkeyid.scact_keynumber = authkeyevent->auth_keynumber;
sockopt_len = sizeof(struct sctp_authkeyid);
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY,
&authkeyid, sockopt_len);
}
}
#endif
static int dgram_sctp_read(BIO *b, char *out, int outl)
{
int ret = 0, n = 0, i, optval;
socklen_t optlen;
bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
union sctp_notification *snp;
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;
char cmsgbuf[512];
if (out != NULL)
{
clear_socket_error();
do
{
memset(&data->rcvinfo, 0x00, sizeof(struct bio_dgram_sctp_rcvinfo));
iov.iov_base = out;
iov.iov_len = outl;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = 512;
msg.msg_flags = 0;
n = recvmsg(b->num, &msg, 0);
if (msg.msg_controllen > 0)
{
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
{
if (cmsg->cmsg_level != IPPROTO_SCTP)
continue;
#ifdef SCTP_RCVINFO
if (cmsg->cmsg_type == SCTP_RCVINFO)
{
struct sctp_rcvinfo *rcvinfo;
rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
data->rcvinfo.rcv_sid = rcvinfo->rcv_sid;
data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn;
data->rcvinfo.rcv_flags = rcvinfo->rcv_flags;
data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid;
data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn;
data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn;
data->rcvinfo.rcv_context = rcvinfo->rcv_context;
}
#endif
#ifdef SCTP_SNDRCV
if (cmsg->cmsg_type == SCTP_SNDRCV)
{
struct sctp_sndrcvinfo *sndrcvinfo;
sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream;
data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn;
data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags;
data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid;
data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn;
data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn;
data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context;
}
#endif
}
}
if (n <= 0)
{
if (n < 0)
ret = n;
break;
}
if (msg.msg_flags & MSG_NOTIFICATION)
{
snp = (union sctp_notification*) out;
if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT)
{
#ifdef SCTP_EVENT
struct sctp_event event;
#else
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.length = 0;
}
/* disable sender dry event */
#ifdef SCTP_EVENT
memset(&event, 0, sizeof(struct sctp_event));
event.se_assoc_id = 0;
event.se_type = SCTP_SENDER_DRY_EVENT;
event.se_on = 0;
i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
OPENSSL_assert(i >= 0);
#else
eventsize = sizeof(struct sctp_event_subscribe);
i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
OPENSSL_assert(i >= 0);
event.sctp_sender_dry_event = 0;
i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
OPENSSL_assert(i >= 0);
#endif
}
#ifdef SCTP_AUTHENTICATION_EVENT
if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
dgram_sctp_handle_auth_free_key_event(b, snp);
#endif
if (data->handle_notifications != NULL)
data->handle_notifications(b, data->notification_context, (void*) out);
memset(out, 0, outl);
}
else
ret += n;
}
while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR) && (ret < outl));
if (ret > 0 && !(msg.msg_flags & MSG_EOR))
{
/* Partial message read, this should never happen! */
/* The buffer was too small, this means the peer sent
* a message that was larger than allowed. */
if (ret == outl)
return -1;
/* Test if socket buffer can handle max record
* size (2^14 + 2048 + 13)
*/
optlen = (socklen_t) sizeof(int);
ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen);
OPENSSL_assert(ret >= 0);
OPENSSL_assert(optval >= 18445);
/* Test if SCTP doesn't partially deliver below
* max record size (2^14 + 2048 + 13)
*/
optlen = (socklen_t) sizeof(int);
ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
&optval, &optlen);
OPENSSL_assert(ret >= 0);
OPENSSL_assert(optval >= 18445);
/* Partially delivered notification??? Probably a bug.... */
OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION));
/* Everything seems ok till now, so it's most likely
* a message dropped by PR-SCTP.
*/
memset(out, 0, outl);
BIO_set_retry_read(b);
return -1;
}
BIO_clear_retry_flags(b);
if (ret < 0)
{
if (BIO_dgram_should_retry(ret))
{
BIO_set_retry_read(b);
data->_errno = get_last_socket_error();
}
}
/* Test if peer uses SCTP-AUTH before continuing */
if (!data->peer_auth_tested)
{
int ii, auth_data = 0, auth_forward = 0;
unsigned char *p;
struct sctp_authchunks *authchunks;
optlen = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
authchunks = OPENSSL_malloc(optlen);
memset(authchunks, 0, sizeof(optlen));
ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, authchunks, &optlen);
OPENSSL_assert(ii >= 0);
for (p = (unsigned char*) authchunks + sizeof(sctp_assoc_t);
p < (unsigned char*) authchunks + optlen;
p += sizeof(uint8_t))
{
if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1;
if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1;
}
OPENSSL_free(authchunks);
if (!auth_data || !auth_forward)
{
BIOerr(BIO_F_BIO_READ,BIO_R_CONNECT_ERROR);
return -1;
}
data->peer_auth_tested = 1;
}
}
return(ret);
}
static int dgram_sctp_write(BIO *b, const char *in, int inl)
{
int ret;
bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo);
struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo);
struct bio_dgram_sctp_sndinfo handshake_sinfo;
struct iovec iov[1];
struct msghdr msg;
struct cmsghdr *cmsg;
#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + CMSG_SPACE(sizeof(struct sctp_prinfo))];
struct sctp_sndinfo *sndinfo;
struct sctp_prinfo *prinfo;
#else
char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
struct sctp_sndrcvinfo *sndrcvinfo;
#endif
clear_socket_error();
/* If we're send anything else than application data,
* disable all user parameters and flags.
*/
if (in[0] != 23) {
memset(&handshake_sinfo, 0x00, sizeof(struct bio_dgram_sctp_sndinfo));
#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;
data->saved_message.length = inl;
data->saved_message.data = OPENSSL_malloc(inl);
memcpy(data->saved_message.data, in, inl);
return inl;
}
iov[0].iov_base = (char *)in;
iov[0].iov_len = inl;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)cmsgbuf;
msg.msg_controllen = 0;
msg.msg_flags = 0;
#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
cmsg = (struct cmsghdr *)cmsgbuf;
cmsg->cmsg_level = IPPROTO_SCTP;
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));
sndinfo->snd_sid = sinfo->snd_sid;
sndinfo->snd_flags = sinfo->snd_flags;
sndinfo->snd_ppid = sinfo->snd_ppid;
sndinfo->snd_context = sinfo->snd_context;
msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
cmsg = (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))];
cmsg->cmsg_level = IPPROTO_SCTP;
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));
prinfo->pr_policy = pinfo->pr_policy;
prinfo->pr_value = pinfo->pr_value;
msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
#else
cmsg = (struct cmsghdr *)cmsgbuf;
cmsg->cmsg_level = IPPROTO_SCTP;
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));
sndrcvinfo->sinfo_stream = sinfo->snd_sid;
sndrcvinfo->sinfo_flags = sinfo->snd_flags;
#ifdef __FreeBSD__
sndrcvinfo->sinfo_flags |= pinfo->pr_policy;
#endif
sndrcvinfo->sinfo_ppid = sinfo->snd_ppid;
sndrcvinfo->sinfo_context = sinfo->snd_context;
sndrcvinfo->sinfo_timetolive = pinfo->pr_value;
msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
#endif
ret = sendmsg(b->num, &msg, 0);
BIO_clear_retry_flags(b);
if (ret <= 0)
{
if (BIO_dgram_should_retry(ret))
{
BIO_set_retry_write(b);
data->_errno = get_last_socket_error();
}
}
return(ret);
}
static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr)
{
long ret=1;
bio_dgram_sctp_data *data = NULL;
unsigned int sockopt_len = 0;
struct sctp_authkeyid authkeyid;
struct sctp_authkey *authkey;
data = (bio_dgram_sctp_data *)b->ptr;
switch (cmd)
{
case BIO_CTRL_DGRAM_QUERY_MTU:
/* Set to maximum (2^14)
* and ignore user input to enable transport
* protocol fragmentation.
* Returns always 2^14.
*/
data->mtu = 16384;
ret = data->mtu;
break;
case BIO_CTRL_DGRAM_SET_MTU:
/* Set to maximum (2^14)
* and ignore input to enable transport
* protocol fragmentation.
* Returns always 2^14.
*/
data->mtu = 16384;
ret = data->mtu;
break;
case BIO_CTRL_DGRAM_SET_CONNECTED:
case BIO_CTRL_DGRAM_CONNECT:
/* Returns always -1. */
ret = -1;
break;
case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
/* SCTP doesn't need the DTLS timer
* Returns always 1.
*/
break;
case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE:
if (num > 0)
data->in_handshake = 1;
else
data->in_handshake = 0;
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY, &data->in_handshake, sizeof(int));
break;
case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY:
/* New shared key for SCTP AUTH.
* Returns 0 on success, -1 otherwise.
*/
/* Get active key */
sockopt_len = sizeof(struct sctp_authkeyid);
ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len);
if (ret < 0) break;
/* Add new key */
sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t);
authkey = OPENSSL_malloc(sockopt_len);
memset(authkey, 0x00, sockopt_len);
authkey->sca_keynumber = authkeyid.scact_keynumber + 1;
#ifndef __FreeBSD__
/* This field is missing in FreeBSD 8.2 and earlier,
* and FreeBSD 8.3 and higher work without it.
*/
authkey->sca_keylength = 64;
#endif
memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t));
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey, sockopt_len);
if (ret < 0) break;
/* Reset active key */
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
&authkeyid, sizeof(struct sctp_authkeyid));
if (ret < 0) break;
break;
case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY:
/* Returns 0 on success, -1 otherwise. */
/* Get active key */
sockopt_len = sizeof(struct sctp_authkeyid);
ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len);
if (ret < 0) break;
/* Set active key */
authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1;
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY,
&authkeyid, sizeof(struct sctp_authkeyid));
if (ret < 0) break;
/* CCS has been sent, so remember that and fall through
* to check if we need to deactivate an old key
*/
data->ccs_sent = 1;
case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD:
/* Returns 0 on success, -1 otherwise. */
/* Has this command really been called or is this just a fall-through? */
if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD)
data->ccs_rcvd = 1;
/* CSS has been both, received and sent, so deactivate an old key */
if (data->ccs_rcvd == 1 && data->ccs_sent == 1)
{
/* Get active key */
sockopt_len = sizeof(struct sctp_authkeyid);
ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len);
if (ret < 0) break;
/* Deactivate key or delete second last key if
* SCTP_AUTHENTICATION_EVENT is not available.
*/
authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1;
#ifdef SCTP_AUTH_DEACTIVATE_KEY
sockopt_len = sizeof(struct sctp_authkeyid);
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY,
&authkeyid, sockopt_len);
if (ret < 0) break;
#endif
#ifndef SCTP_AUTHENTICATION_EVENT
if (authkeyid.scact_keynumber > 0)
{
authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1;
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY,
&authkeyid, sizeof(struct sctp_authkeyid));
if (ret < 0) break;
}
#endif
data->ccs_rcvd = 0;
data->ccs_sent = 0;
}
break;
case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO:
/* Returns the size of the copied struct. */
if (num > (long) sizeof(struct bio_dgram_sctp_sndinfo))
num = sizeof(struct bio_dgram_sctp_sndinfo);
memcpy(ptr, &(data->sndinfo), num);
ret = num;
break;
case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO:
/* Returns the size of the copied struct. */
if (num > (long) sizeof(struct bio_dgram_sctp_sndinfo))
num = sizeof(struct bio_dgram_sctp_sndinfo);
memcpy(&(data->sndinfo), ptr, num);
break;
case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO:
/* Returns the size of the copied struct. */
if (num > (long) sizeof(struct bio_dgram_sctp_rcvinfo))
num = sizeof(struct bio_dgram_sctp_rcvinfo);
memcpy(ptr, &data->rcvinfo, num);
ret = num;
break;
case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO:
/* Returns the size of the copied struct. */
if (num > (long) sizeof(struct bio_dgram_sctp_rcvinfo))
num = sizeof(struct bio_dgram_sctp_rcvinfo);
memcpy(&(data->rcvinfo), ptr, num);
break;
case BIO_CTRL_DGRAM_SCTP_GET_PRINFO:
/* Returns the size of the copied struct. */
if (num > (long) sizeof(struct bio_dgram_sctp_prinfo))
num = sizeof(struct bio_dgram_sctp_prinfo);
memcpy(ptr, &(data->prinfo), num);
ret = num;
break;
case BIO_CTRL_DGRAM_SCTP_SET_PRINFO:
/* Returns the size of the copied struct. */
if (num > (long) sizeof(struct bio_dgram_sctp_prinfo))
num = sizeof(struct bio_dgram_sctp_prinfo);
memcpy(&(data->prinfo), ptr, num);
break;
case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN:
/* Returns always 1. */
if (num > 0)
data->save_shutdown = 1;
else
data->save_shutdown = 0;
break;
default:
/* Pass to default ctrl function to
* process SCTP unspecific commands
*/
ret=dgram_ctrl(b, cmd, num, ptr);
break;
}
return(ret);
}
int BIO_dgram_sctp_notification_cb(BIO *b,
void (*handle_notifications)(BIO *bio, void *context, void *buf),
void *context)
{
bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr;
if (handle_notifications != NULL)
{
data->handle_notifications = handle_notifications;
data->notification_context = context;
}
else
return -1;
return 0;
}
int BIO_dgram_sctp_wait_for_dry(BIO *b)
{
int is_dry = 0;
int n, sockflags, ret;
union sctp_notification snp;
struct msghdr msg;
struct iovec iov;
#ifdef SCTP_EVENT
struct sctp_event event;
#else
struct sctp_event_subscribe event;
socklen_t eventsize;
#endif
bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
/* set sender dry event */
#ifdef SCTP_EVENT
memset(&event, 0, sizeof(struct sctp_event));
event.se_assoc_id = 0;
event.se_type = SCTP_SENDER_DRY_EVENT;
event.se_on = 1;
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
#else
eventsize = sizeof(struct sctp_event_subscribe);
ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
if (ret < 0)
return -1;
event.sctp_sender_dry_event = 1;
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
#endif
if (ret < 0)
return -1;
/* peek for notification */
memset(&snp, 0x00, sizeof(union sctp_notification));
iov.iov_base = (char *)&snp;
iov.iov_len = sizeof(union sctp_notification);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
n = recvmsg(b->num, &msg, MSG_PEEK);
if (n <= 0)
{
if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK))
return -1;
else
return 0;
}
/* 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));
iov.iov_base = (char *)&snp;
iov.iov_len = sizeof(union sctp_notification);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
n = recvmsg(b->num, &msg, 0);
if (n <= 0)
{
if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK))
return -1;
else
return is_dry;
}
if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT)
{
is_dry = 1;
/* disable sender dry event */
#ifdef SCTP_EVENT
memset(&event, 0, sizeof(struct sctp_event));
event.se_assoc_id = 0;
event.se_type = SCTP_SENDER_DRY_EVENT;
event.se_on = 0;
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event));
#else
eventsize = (socklen_t) sizeof(struct sctp_event_subscribe);
ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize);
if (ret < 0)
return -1;
event.sctp_sender_dry_event = 0;
ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe));
#endif
if (ret < 0)
return -1;
}
#ifdef SCTP_AUTHENTICATION_EVENT
if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
dgram_sctp_handle_auth_free_key_event(b, &snp);
#endif
if (data->handle_notifications != NULL)
data->handle_notifications(b, data->notification_context, (void*) &snp);
/* found notification, peek again */
memset(&snp, 0x00, sizeof(union sctp_notification));
iov.iov_base = (char *)&snp;
iov.iov_len = sizeof(union sctp_notification);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
/* if we have seen the dry already, don't wait */
if (is_dry)
{
sockflags = fcntl(b->num, F_GETFL, 0);
fcntl(b->num, F_SETFL, O_NONBLOCK);
}
n = recvmsg(b->num, &msg, MSG_PEEK);
if (is_dry)
{
fcntl(b->num, F_SETFL, sockflags);
}
if (n <= 0)
{
if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK))
return -1;
else
return is_dry;
}
}
/* read anything else */
return is_dry;
}
int BIO_dgram_sctp_msg_waiting(BIO *b)
{
int n, sockflags;
union sctp_notification snp;
struct msghdr msg;
struct iovec iov;
bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
/* Check if there are any messages waiting to be read */
do
{
memset(&snp, 0x00, sizeof(union sctp_notification));
iov.iov_base = (char *)&snp;
iov.iov_len = sizeof(union sctp_notification);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
sockflags = fcntl(b->num, F_GETFL, 0);
fcntl(b->num, F_SETFL, O_NONBLOCK);
n = recvmsg(b->num, &msg, MSG_PEEK);
fcntl(b->num, F_SETFL, sockflags);
/* if notification, process and try again */
if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION))
{
#ifdef SCTP_AUTHENTICATION_EVENT
if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT)
dgram_sctp_handle_auth_free_key_event(b, &snp);
#endif
memset(&snp, 0x00, sizeof(union sctp_notification));
iov.iov_base = (char *)&snp;
iov.iov_len = sizeof(union sctp_notification);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
n = recvmsg(b->num, &msg, 0);
if (data->handle_notifications != NULL)
data->handle_notifications(b, data->notification_context, (void*) &snp);
}
} while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION));
/* Return 1 if there is a message to be read, return 0 otherwise. */
if (n > 0)
return 1;
else
return 0;
}
static int dgram_sctp_puts(BIO *bp, const char *str)
{
int n,ret;
n=strlen(str);
ret=dgram_sctp_write(bp,str,n);
return(ret);
}
#endif
static int BIO_dgram_should_retry(int i) static int BIO_dgram_should_retry(int i)
{ {
int err; int err;
......
...@@ -1417,3 +1417,24 @@ dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr) ...@@ -1417,3 +1417,24 @@ dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr)
ccs_hdr->type = *(data++); ccs_hdr->type = *(data++);
} }
int dtls1_shutdown(SSL *s)
{
int ret;
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
!(s->shutdown & SSL_SENT_SHUTDOWN))
{
ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
if (ret < 0) return -1;
if (ret == 0)
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1, NULL);
}
#endif
ret = ssl3_shutdown(s);
#ifndef OPENSSL_NO_SCTP
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL);
#endif
return ret;
}
...@@ -151,7 +151,11 @@ int dtls1_connect(SSL *s) ...@@ -151,7 +151,11 @@ int dtls1_connect(SSL *s)
unsigned long Time=(unsigned long)time(NULL); unsigned long Time=(unsigned long)time(NULL);
void (*cb)(const SSL *ssl,int type,int val)=NULL; void (*cb)(const SSL *ssl,int type,int val)=NULL;
int ret= -1; int ret= -1;
int new_state,state,skip=0;; int new_state,state,skip=0;
#ifndef OPENSSL_NO_SCTP
unsigned char sctpauthkey[64];
char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
#endif
RAND_add(&Time,sizeof(Time),0); RAND_add(&Time,sizeof(Time),0);
ERR_clear_error(); ERR_clear_error();
...@@ -165,6 +169,14 @@ int dtls1_connect(SSL *s) ...@@ -165,6 +169,14 @@ int dtls1_connect(SSL *s)
s->in_handshake++; s->in_handshake++;
if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
#ifndef OPENSSL_NO_SCTP
/* Notify SCTP BIO socket to enter handshake
* mode and prevent stream identifier other
* than 0. Will be ignored if no SCTP is used.
*/
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
#endif
for (;;) for (;;)
{ {
state=s->state; state=s->state;
...@@ -227,6 +239,42 @@ int dtls1_connect(SSL *s) ...@@ -227,6 +239,42 @@ int dtls1_connect(SSL *s)
s->hit = 0; s->hit = 0;
break; break;
#ifndef OPENSSL_NO_SCTP
case DTLS1_SCTP_ST_CR_READ_SOCK:
if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
{
s->s3->in_read_app_data=2;
s->rwstate=SSL_READING;
BIO_clear_retry_flags(SSL_get_rbio(s));
BIO_set_retry_read(SSL_get_rbio(s));
ret = -1;
goto end;
}
s->state=s->s3->tmp.next_state;
break;
case DTLS1_SCTP_ST_CW_WRITE_SOCK:
/* read app data until dry event */
ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
if (ret < 0) goto end;
if (ret == 0)
{
s->s3->in_read_app_data=2;
s->rwstate=SSL_READING;
BIO_clear_retry_flags(SSL_get_rbio(s));
BIO_set_retry_read(SSL_get_rbio(s));
ret = -1;
goto end;
}
s->state=s->d1->next_state;
break;
#endif
case SSL3_ST_CW_CLNT_HELLO_A: case SSL3_ST_CW_CLNT_HELLO_A:
case SSL3_ST_CW_CLNT_HELLO_B: case SSL3_ST_CW_CLNT_HELLO_B:
...@@ -249,9 +297,17 @@ int dtls1_connect(SSL *s) ...@@ -249,9 +297,17 @@ int dtls1_connect(SSL *s)
s->init_num=0; s->init_num=0;
#ifndef OPENSSL_NO_SCTP
/* Disable buffering for SCTP */
if (!BIO_dgram_is_sctp(SSL_get_wbio(s)))
{
#endif
/* turn on buffering for the next lot of output */ /* turn on buffering for the next lot of output */
if (s->bbio != s->wbio) if (s->bbio != s->wbio)
s->wbio=BIO_push(s->bbio,s->wbio); s->wbio=BIO_push(s->bbio,s->wbio);
#ifndef OPENSSL_NO_SCTP
}
#endif
break; break;
...@@ -263,7 +319,24 @@ int dtls1_connect(SSL *s) ...@@ -263,7 +319,24 @@ int dtls1_connect(SSL *s)
{ {
dtls1_stop_timer(s); dtls1_stop_timer(s);
if (s->hit) if (s->hit)
{
#ifndef OPENSSL_NO_SCTP
/* Add new shared key for SCTP-Auth,
* will be ignored if no SCTP used.
*/
snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
DTLS1_SCTP_AUTH_LABEL);
SSL_export_keying_material(s, sctpauthkey,
sizeof(sctpauthkey), labelbuffer,
sizeof(labelbuffer), NULL, 0, 0);
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
sizeof(sctpauthkey), sctpauthkey);
#endif
s->state=SSL3_ST_CR_FINISHED_A; s->state=SSL3_ST_CR_FINISHED_A;
}
else else
s->state=DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A; s->state=DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
} }
...@@ -356,11 +429,18 @@ int dtls1_connect(SSL *s) ...@@ -356,11 +429,18 @@ int dtls1_connect(SSL *s)
ret=ssl3_get_server_done(s); ret=ssl3_get_server_done(s);
if (ret <= 0) goto end; if (ret <= 0) goto end;
if (s->s3->tmp.cert_req) if (s->s3->tmp.cert_req)
s->state=SSL3_ST_CW_CERT_A; s->s3->tmp.next_state=SSL3_ST_CW_CERT_A;
else else
s->state=SSL3_ST_CW_KEY_EXCH_A; s->s3->tmp.next_state=SSL3_ST_CW_KEY_EXCH_A;
s->init_num=0; s->init_num=0;
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
state == SSL_ST_RENEGOTIATE)
s->state=DTLS1_SCTP_ST_CR_READ_SOCK;
else
#endif
s->state=s->s3->tmp.next_state;
break; break;
case SSL3_ST_CW_CERT_A: case SSL3_ST_CW_CERT_A:
...@@ -379,6 +459,22 @@ int dtls1_connect(SSL *s) ...@@ -379,6 +459,22 @@ int dtls1_connect(SSL *s)
dtls1_start_timer(s); dtls1_start_timer(s);
ret=dtls1_send_client_key_exchange(s); ret=dtls1_send_client_key_exchange(s);
if (ret <= 0) goto end; if (ret <= 0) goto end;
#ifndef OPENSSL_NO_SCTP
/* Add new shared key for SCTP-Auth,
* will be ignored if no SCTP used.
*/
snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
DTLS1_SCTP_AUTH_LABEL);
SSL_export_keying_material(s, sctpauthkey,
sizeof(sctpauthkey), labelbuffer,
sizeof(labelbuffer), NULL, 0, 0);
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
sizeof(sctpauthkey), sctpauthkey);
#endif
/* EAY EAY EAY need to check for DH fix cert /* EAY EAY EAY need to check for DH fix cert
* sent back */ * sent back */
/* For TLS, cert_req is set to 2, so a cert chain /* For TLS, cert_req is set to 2, so a cert chain
...@@ -389,6 +485,14 @@ int dtls1_connect(SSL *s) ...@@ -389,6 +485,14 @@ int dtls1_connect(SSL *s)
} }
else else
{ {
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
{
s->d1->next_state=SSL3_ST_CW_CHANGE_A;
s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK;
}
else
#endif
s->state=SSL3_ST_CW_CHANGE_A; s->state=SSL3_ST_CW_CHANGE_A;
s->s3->change_cipher_spec=0; s->s3->change_cipher_spec=0;
} }
...@@ -401,6 +505,14 @@ int dtls1_connect(SSL *s) ...@@ -401,6 +505,14 @@ int dtls1_connect(SSL *s)
dtls1_start_timer(s); dtls1_start_timer(s);
ret=dtls1_send_client_verify(s); ret=dtls1_send_client_verify(s);
if (ret <= 0) goto end; if (ret <= 0) goto end;
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
{
s->d1->next_state=SSL3_ST_CW_CHANGE_A;
s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK;
}
else
#endif
s->state=SSL3_ST_CW_CHANGE_A; s->state=SSL3_ST_CW_CHANGE_A;
s->init_num=0; s->init_num=0;
s->s3->change_cipher_spec=0; s->s3->change_cipher_spec=0;
...@@ -413,6 +525,14 @@ int dtls1_connect(SSL *s) ...@@ -413,6 +525,14 @@ int dtls1_connect(SSL *s)
ret=dtls1_send_change_cipher_spec(s, ret=dtls1_send_change_cipher_spec(s,
SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
if (ret <= 0) goto end; if (ret <= 0) goto end;
#ifndef OPENSSL_NO_SCTP
/* Change to new shared key of SCTP-Auth,
* will be ignored if no SCTP used.
*/
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL);
#endif
s->state=SSL3_ST_CW_FINISHED_A; s->state=SSL3_ST_CW_FINISHED_A;
s->init_num=0; s->init_num=0;
...@@ -458,9 +578,23 @@ int dtls1_connect(SSL *s) ...@@ -458,9 +578,23 @@ int dtls1_connect(SSL *s)
if (s->hit) if (s->hit)
{ {
s->s3->tmp.next_state=SSL_ST_OK; s->s3->tmp.next_state=SSL_ST_OK;
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
{
s->d1->next_state = s->s3->tmp.next_state;
s->s3->tmp.next_state=DTLS1_SCTP_ST_CW_WRITE_SOCK;
}
#endif
if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED) if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED)
{ {
s->state=SSL_ST_OK; s->state=SSL_ST_OK;
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
{
s->d1->next_state = SSL_ST_OK;
s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK;
}
#endif
s->s3->flags|=SSL3_FLAGS_POP_BUFFER; s->s3->flags|=SSL3_FLAGS_POP_BUFFER;
s->s3->delay_buf_pop_ret=0; s->s3->delay_buf_pop_ret=0;
} }
...@@ -509,6 +643,16 @@ int dtls1_connect(SSL *s) ...@@ -509,6 +643,16 @@ int dtls1_connect(SSL *s)
s->state=SSL3_ST_CW_CHANGE_A; s->state=SSL3_ST_CW_CHANGE_A;
else else
s->state=SSL_ST_OK; s->state=SSL_ST_OK;
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
state == SSL_ST_RENEGOTIATE)
{
s->d1->next_state=s->state;
s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK;
}
#endif
s->init_num=0; s->init_num=0;
break; break;
...@@ -516,6 +660,13 @@ int dtls1_connect(SSL *s) ...@@ -516,6 +660,13 @@ int dtls1_connect(SSL *s)
s->rwstate=SSL_WRITING; s->rwstate=SSL_WRITING;
if (BIO_flush(s->wbio) <= 0) if (BIO_flush(s->wbio) <= 0)
{ {
/* If the write error was fatal, stop trying */
if (!BIO_should_retry(s->wbio))
{
s->rwstate=SSL_NOTHING;
s->state=s->s3->tmp.next_state;
}
ret= -1; ret= -1;
goto end; goto end;
} }
...@@ -589,6 +740,15 @@ int dtls1_connect(SSL *s) ...@@ -589,6 +740,15 @@ int dtls1_connect(SSL *s)
} }
end: end:
s->in_handshake--; s->in_handshake--;
#ifndef OPENSSL_NO_SCTP
/* Notify SCTP BIO socket to leave handshake
* mode and allow stream identifier other
* than 0. Will be ignored if no SCTP is used.
*/
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
#endif
if (buf != NULL) if (buf != NULL)
BUF_MEM_free(buf); BUF_MEM_free(buf);
if (cb != NULL) if (cb != NULL)
......
...@@ -292,6 +292,15 @@ const SSL_CIPHER *dtls1_get_cipher(unsigned int u) ...@@ -292,6 +292,15 @@ const SSL_CIPHER *dtls1_get_cipher(unsigned int u)
void dtls1_start_timer(SSL *s) void dtls1_start_timer(SSL *s)
{ {
#ifndef OPENSSL_NO_SCTP
/* Disable timer for SCTP */
if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
{
memset(&(s->d1->next_timeout), 0, sizeof(struct timeval));
return;
}
#endif
/* If timer is not set, initialize duration with 1 second */ /* If timer is not set, initialize duration with 1 second */
if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
{ {
......
...@@ -232,6 +232,14 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority) ...@@ -232,6 +232,14 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
item->data = rdata; item->data = rdata;
#ifndef OPENSSL_NO_SCTP
/* Store bio_dgram_sctp_rcvinfo struct */
if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
(s->state == SSL3_ST_SR_FINISHED_A || s->state == SSL3_ST_CR_FINISHED_A)) {
BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_GET_RCVINFO, sizeof(rdata->recordinfo), &rdata->recordinfo);
}
#endif
/* insert should not fail, since duplicates are dropped */ /* insert should not fail, since duplicates are dropped */
if (pqueue_insert(queue->q, item) == NULL) if (pqueue_insert(queue->q, item) == NULL)
{ {
...@@ -638,6 +646,11 @@ again: ...@@ -638,6 +646,11 @@ again:
goto again; /* get another record */ goto again; /* get another record */
} }
#ifndef OPENSSL_NO_SCTP
/* Only do replay check if no SCTP bio */
if (!BIO_dgram_is_sctp(SSL_get_rbio(s)))
{
#endif
/* Check whether this is a repeat, or aged record. /* Check whether this is a repeat, or aged record.
* Don't check if we're listening and this message is * Don't check if we're listening and this message is
* a ClientHello. They can look as if they're replayed, * a ClientHello. They can look as if they're replayed,
...@@ -652,6 +665,9 @@ again: ...@@ -652,6 +665,9 @@ again:
s->packet_length=0; /* dump this record */ s->packet_length=0; /* dump this record */
goto again; /* get another record */ goto again; /* get another record */
} }
#ifndef OPENSSL_NO_SCTP
}
#endif
/* just read a 0 length packet */ /* just read a 0 length packet */
if (rr->length == 0) goto again; if (rr->length == 0) goto again;
...@@ -737,7 +753,17 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) ...@@ -737,7 +753,17 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
/* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */ /* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
#ifndef OPENSSL_NO_SCTP
/* Continue handshake if it had to be interrupted to read
* app data with SCTP.
*/
if ((!s->in_handshake && SSL_in_init(s)) ||
(BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
(s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK) &&
s->s3->in_read_app_data != 2))
#else
if (!s->in_handshake && SSL_in_init(s)) if (!s->in_handshake && SSL_in_init(s))
#endif
{ {
/* type == SSL3_RT_APPLICATION_DATA */ /* type == SSL3_RT_APPLICATION_DATA */
i=s->handshake_func(s); i=s->handshake_func(s);
...@@ -768,6 +794,15 @@ start: ...@@ -768,6 +794,15 @@ start:
item = pqueue_pop(s->d1->buffered_app_data.q); item = pqueue_pop(s->d1->buffered_app_data.q);
if (item) if (item)
{ {
#ifndef OPENSSL_NO_SCTP
/* Restore bio_dgram_sctp_rcvinfo struct */
if (BIO_dgram_is_sctp(SSL_get_rbio(s)))
{
DTLS1_RECORD_DATA *rdata = (DTLS1_RECORD_DATA *) item->data;
BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_SET_RCVINFO, sizeof(rdata->recordinfo), &rdata->recordinfo);
}
#endif
dtls1_copy_record(s, item); dtls1_copy_record(s, item);
OPENSSL_free(item->data); OPENSSL_free(item->data);
...@@ -850,6 +885,31 @@ start: ...@@ -850,6 +885,31 @@ start:
rr->off=0; rr->off=0;
} }
} }
#ifndef OPENSSL_NO_SCTP
/* We were about to renegotiate but had to read
* belated application data first, so retry.
*/
if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
rr->type == SSL3_RT_APPLICATION_DATA &&
(s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK))
{
s->rwstate=SSL_READING;
BIO_clear_retry_flags(SSL_get_rbio(s));
BIO_set_retry_read(SSL_get_rbio(s));
}
/* We might had to delay a close_notify alert because
* of reordered app data. If there was an alert and there
* is no message to read anymore, finally set shutdown.
*/
if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
s->d1->shutdown_received && !BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
{
s->shutdown |= SSL_RECEIVED_SHUTDOWN;
return(0);
}
#endif
return(n); return(n);
} }
...@@ -1022,6 +1082,21 @@ start: ...@@ -1022,6 +1082,21 @@ start:
s->s3->warn_alert = alert_descr; s->s3->warn_alert = alert_descr;
if (alert_descr == SSL_AD_CLOSE_NOTIFY) if (alert_descr == SSL_AD_CLOSE_NOTIFY)
{ {
#ifndef OPENSSL_NO_SCTP
/* With SCTP and streams the socket may deliver app data
* after a close_notify alert. We have to check this
* first so that nothing gets discarded.
*/
if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
{
s->d1->shutdown_received = 1;
s->rwstate=SSL_READING;
BIO_clear_retry_flags(SSL_get_rbio(s));
BIO_set_retry_read(SSL_get_rbio(s));
return -1;
}
#endif
s->shutdown |= SSL_RECEIVED_SHUTDOWN; s->shutdown |= SSL_RECEIVED_SHUTDOWN;
return(0); return(0);
} }
...@@ -1128,6 +1203,15 @@ start: ...@@ -1128,6 +1203,15 @@ start:
if (s->version == DTLS1_BAD_VER) if (s->version == DTLS1_BAD_VER)
s->d1->handshake_read_seq++; s->d1->handshake_read_seq++;
#ifndef OPENSSL_NO_SCTP
/* Remember that a CCS has been received,
* so that an old key of SCTP-Auth can be
* deleted when a CCS is sent. Will be ignored
* if no SCTP is used
*/
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD, 1, NULL);
#endif
goto start; goto start;
} }
...@@ -1264,7 +1348,16 @@ dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len) ...@@ -1264,7 +1348,16 @@ dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
{ {
int i; int i;
#ifndef OPENSSL_NO_SCTP
/* Check if we have to continue an interrupted handshake
* for reading belated app data with SCTP.
*/
if ((SSL_in_init(s) && !s->in_handshake) ||
(BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
(s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK)))
#else
if (SSL_in_init(s) && !s->in_handshake) if (SSL_in_init(s) && !s->in_handshake)
#endif
{ {
i=s->handshake_func(s); i=s->handshake_func(s);
if (i < 0) return(i); if (i < 0) return(i);
......
...@@ -151,6 +151,10 @@ int dtls1_accept(SSL *s) ...@@ -151,6 +151,10 @@ int dtls1_accept(SSL *s)
int ret= -1; int ret= -1;
int new_state,state,skip=0; int new_state,state,skip=0;
int listen; int listen;
#ifndef OPENSSL_NO_SCTP
unsigned char sctpauthkey[64];
char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
#endif
RAND_add(&Time,sizeof(Time),0); RAND_add(&Time,sizeof(Time),0);
ERR_clear_error(); ERR_clear_error();
...@@ -168,6 +172,13 @@ int dtls1_accept(SSL *s) ...@@ -168,6 +172,13 @@ int dtls1_accept(SSL *s)
if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
s->d1->listen = listen; s->d1->listen = listen;
#ifndef OPENSSL_NO_SCTP
/* Notify SCTP BIO socket to enter handshake
* mode and prevent stream identifier other
* than 0. Will be ignored if no SCTP is used.
*/
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
#endif
if (s->cert == NULL) if (s->cert == NULL)
{ {
...@@ -227,7 +238,11 @@ int dtls1_accept(SSL *s) ...@@ -227,7 +238,11 @@ int dtls1_accept(SSL *s)
{ {
/* Ok, we now need to push on a buffering BIO so that /* Ok, we now need to push on a buffering BIO so that
* the output is sent in a way that TCP likes :-) * the output is sent in a way that TCP likes :-)
* ...but not with SCTP :-)
*/ */
#ifndef OPENSSL_NO_SCTP
if (!BIO_dgram_is_sctp(SSL_get_wbio(s)))
#endif
if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; } if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }
ssl3_init_finished_mac(s); ssl3_init_finished_mac(s);
...@@ -313,6 +328,43 @@ int dtls1_accept(SSL *s) ...@@ -313,6 +328,43 @@ int dtls1_accept(SSL *s)
ssl3_init_finished_mac(s); ssl3_init_finished_mac(s);
break; break;
#ifndef OPENSSL_NO_SCTP
case DTLS1_SCTP_ST_SR_READ_SOCK:
if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
{
s->s3->in_read_app_data=2;
s->rwstate=SSL_READING;
BIO_clear_retry_flags(SSL_get_rbio(s));
BIO_set_retry_read(SSL_get_rbio(s));
ret = -1;
goto end;
}
s->state=SSL3_ST_SR_FINISHED_A;
break;
case DTLS1_SCTP_ST_SW_WRITE_SOCK:
ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
if (ret < 0) goto end;
if (ret == 0)
{
if (s->d1->next_state != SSL_ST_OK)
{
s->s3->in_read_app_data=2;
s->rwstate=SSL_READING;
BIO_clear_retry_flags(SSL_get_rbio(s));
BIO_set_retry_read(SSL_get_rbio(s));
ret = -1;
goto end;
}
}
s->state=s->d1->next_state;
break;
#endif
case SSL3_ST_SW_SRVR_HELLO_A: case SSL3_ST_SW_SRVR_HELLO_A:
case SSL3_ST_SW_SRVR_HELLO_B: case SSL3_ST_SW_SRVR_HELLO_B:
s->renegotiate = 2; s->renegotiate = 2;
...@@ -320,18 +372,31 @@ int dtls1_accept(SSL *s) ...@@ -320,18 +372,31 @@ int dtls1_accept(SSL *s)
ret=dtls1_send_server_hello(s); ret=dtls1_send_server_hello(s);
if (ret <= 0) goto end; if (ret <= 0) goto end;
#ifndef OPENSSL_NO_TLSEXT
if (s->hit) if (s->hit)
{ {
#ifndef OPENSSL_NO_SCTP
/* Add new shared key for SCTP-Auth,
* will be ignored if no SCTP used.
*/
snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
DTLS1_SCTP_AUTH_LABEL);
SSL_export_keying_material(s, sctpauthkey,
sizeof(sctpauthkey), labelbuffer,
sizeof(labelbuffer), NULL, 0, 0);
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
sizeof(sctpauthkey), sctpauthkey);
#endif
#ifndef OPENSSL_NO_TLSEXT
if (s->tlsext_ticket_expected) if (s->tlsext_ticket_expected)
s->state=SSL3_ST_SW_SESSION_TICKET_A; s->state=SSL3_ST_SW_SESSION_TICKET_A;
else else
s->state=SSL3_ST_SW_CHANGE_A; s->state=SSL3_ST_SW_CHANGE_A;
}
#else #else
if (s->hit)
s->state=SSL3_ST_SW_CHANGE_A; s->state=SSL3_ST_SW_CHANGE_A;
#endif #endif
}
else else
s->state=SSL3_ST_SW_CERT_A; s->state=SSL3_ST_SW_CERT_A;
s->init_num=0; s->init_num=0;
...@@ -441,6 +506,13 @@ int dtls1_accept(SSL *s) ...@@ -441,6 +506,13 @@ int dtls1_accept(SSL *s)
skip=1; skip=1;
s->s3->tmp.cert_request=0; s->s3->tmp.cert_request=0;
s->state=SSL3_ST_SW_SRVR_DONE_A; s->state=SSL3_ST_SW_SRVR_DONE_A;
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
{
s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
}
#endif
} }
else else
{ {
...@@ -450,9 +522,23 @@ int dtls1_accept(SSL *s) ...@@ -450,9 +522,23 @@ int dtls1_accept(SSL *s)
if (ret <= 0) goto end; if (ret <= 0) goto end;
#ifndef NETSCAPE_HANG_BUG #ifndef NETSCAPE_HANG_BUG
s->state=SSL3_ST_SW_SRVR_DONE_A; s->state=SSL3_ST_SW_SRVR_DONE_A;
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
{
s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A;
s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK;
}
#endif
#else #else
s->state=SSL3_ST_SW_FLUSH; s->state=SSL3_ST_SW_FLUSH;
s->s3->tmp.next_state=SSL3_ST_SR_CERT_A; s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
{
s->d1->next_state = s->s3->tmp.next_state;
s->s3->tmp.next_state=DTLS1_SCTP_ST_SW_WRITE_SOCK;
}
#endif
#endif #endif
s->init_num=0; s->init_num=0;
} }
...@@ -472,6 +558,13 @@ int dtls1_accept(SSL *s) ...@@ -472,6 +558,13 @@ int dtls1_accept(SSL *s)
s->rwstate=SSL_WRITING; s->rwstate=SSL_WRITING;
if (BIO_flush(s->wbio) <= 0) if (BIO_flush(s->wbio) <= 0)
{ {
/* If the write error was fatal, stop trying */
if (!BIO_should_retry(s->wbio))
{
s->rwstate=SSL_NOTHING;
s->state=s->s3->tmp.next_state;
}
ret= -1; ret= -1;
goto end; goto end;
} }
...@@ -504,6 +597,21 @@ int dtls1_accept(SSL *s) ...@@ -504,6 +597,21 @@ int dtls1_accept(SSL *s)
ret=ssl3_get_client_key_exchange(s); ret=ssl3_get_client_key_exchange(s);
if (ret <= 0) goto end; if (ret <= 0) goto end;
dtls1_stop_timer(s); dtls1_stop_timer(s);
#ifndef OPENSSL_NO_SCTP
/* Add new shared key for SCTP-Auth,
* will be ignored if no SCTP used.
*/
snprintf((char *) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
DTLS1_SCTP_AUTH_LABEL);
SSL_export_keying_material(s, sctpauthkey,
sizeof(sctpauthkey), labelbuffer,
sizeof(labelbuffer), NULL, 0, 0);
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
sizeof(sctpauthkey), sctpauthkey);
#endif
s->state=SSL3_ST_SR_CERT_VRFY_A; s->state=SSL3_ST_SR_CERT_VRFY_A;
s->init_num=0; s->init_num=0;
...@@ -541,7 +649,12 @@ int dtls1_accept(SSL *s) ...@@ -541,7 +649,12 @@ int dtls1_accept(SSL *s)
ret=ssl3_get_cert_verify(s); ret=ssl3_get_cert_verify(s);
if (ret <= 0) goto end; if (ret <= 0) goto end;
dtls1_stop_timer(s); dtls1_stop_timer(s);
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
state == SSL_ST_RENEGOTIATE)
s->state=DTLS1_SCTP_ST_SR_READ_SOCK;
else
#endif
s->state=SSL3_ST_SR_FINISHED_A; s->state=SSL3_ST_SR_FINISHED_A;
s->init_num=0; s->init_num=0;
break; break;
...@@ -594,6 +707,14 @@ int dtls1_accept(SSL *s) ...@@ -594,6 +707,14 @@ int dtls1_accept(SSL *s)
SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B); SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);
if (ret <= 0) goto end; if (ret <= 0) goto end;
#ifndef OPENSSL_NO_SCTP
/* Change to new shared key of SCTP-Auth,
* will be ignored if no SCTP used.
*/
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL);
#endif
s->state=SSL3_ST_SW_FINISHED_A; s->state=SSL3_ST_SW_FINISHED_A;
s->init_num=0; s->init_num=0;
...@@ -618,7 +739,16 @@ int dtls1_accept(SSL *s) ...@@ -618,7 +739,16 @@ int dtls1_accept(SSL *s)
if (s->hit) if (s->hit)
s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A; s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
else else
{
s->s3->tmp.next_state=SSL_ST_OK; s->s3->tmp.next_state=SSL_ST_OK;
#ifndef OPENSSL_NO_SCTP
if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
{
s->d1->next_state = s->s3->tmp.next_state;
s->s3->tmp.next_state=DTLS1_SCTP_ST_SW_WRITE_SOCK;
}
#endif
}
s->init_num=0; s->init_num=0;
break; break;
...@@ -690,6 +820,14 @@ end: ...@@ -690,6 +820,14 @@ end:
/* BIO_flush(s->wbio); */ /* BIO_flush(s->wbio); */
s->in_handshake--; s->in_handshake--;
#ifndef OPENSSL_NO_SCTP
/* Notify SCTP BIO socket to leave handshake
* mode and prevent stream identifier other
* than 0. Will be ignored if no SCTP is used.
*/
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
#endif
if (cb != NULL) if (cb != NULL)
cb(s,SSL_CB_ACCEPT_EXIT,ret); cb(s,SSL_CB_ACCEPT_EXIT,ret);
return(ret); return(ret);
......
...@@ -111,6 +111,9 @@ extern "C" { ...@@ -111,6 +111,9 @@ extern "C" {
#ifndef OPENSSL_NO_SSL_INTERN #ifndef OPENSSL_NO_SSL_INTERN
#ifndef OPENSSL_NO_SCTP
#define DTLS1_SCTP_AUTH_LABEL "EXPORTER_DTLS_OVER_SCTP"
#endif
typedef struct dtls1_bitmap_st typedef struct dtls1_bitmap_st
{ {
...@@ -249,6 +252,13 @@ typedef struct dtls1_state_st ...@@ -249,6 +252,13 @@ typedef struct dtls1_state_st
unsigned int retransmitting; unsigned int retransmitting;
unsigned int change_cipher_spec_ok; unsigned int change_cipher_spec_ok;
#ifndef OPENSSL_NO_SCTP
/* used when SSL_ST_XX_FLUSH is entered */
int next_state;
int shutdown_received;
#endif
} DTLS1_STATE; } DTLS1_STATE;
typedef struct dtls1_record_data_st typedef struct dtls1_record_data_st
...@@ -257,6 +267,9 @@ typedef struct dtls1_record_data_st ...@@ -257,6 +267,9 @@ typedef struct dtls1_record_data_st
unsigned int packet_length; unsigned int packet_length;
SSL3_BUFFER rbuf; SSL3_BUFFER rbuf;
SSL3_RECORD rrec; SSL3_RECORD rrec;
#ifndef OPENSSL_NO_SCTP
struct bio_dgram_sctp_rcvinfo recordinfo;
#endif
} DTLS1_RECORD_DATA; } DTLS1_RECORD_DATA;
#endif #endif
......
...@@ -533,6 +533,10 @@ typedef struct ssl3_state_st ...@@ -533,6 +533,10 @@ typedef struct ssl3_state_st
/*client */ /*client */
/* extra state */ /* extra state */
#define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT) #define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT)
#ifndef OPENSSL_NO_SCTP
#define DTLS1_SCTP_ST_CW_WRITE_SOCK (0x310|SSL_ST_CONNECT)
#define DTLS1_SCTP_ST_CR_READ_SOCK (0x320|SSL_ST_CONNECT)
#endif
/* write to server */ /* write to server */
#define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT) #define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT)
#define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT) #define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT)
...@@ -579,6 +583,10 @@ typedef struct ssl3_state_st ...@@ -579,6 +583,10 @@ typedef struct ssl3_state_st
/* server */ /* server */
/* extra state */ /* extra state */
#define SSL3_ST_SW_FLUSH (0x100|SSL_ST_ACCEPT) #define SSL3_ST_SW_FLUSH (0x100|SSL_ST_ACCEPT)
#ifndef OPENSSL_NO_SCTP
#define DTLS1_SCTP_ST_SW_WRITE_SOCK (0x310|SSL_ST_ACCEPT)
#define DTLS1_SCTP_ST_SR_READ_SOCK (0x320|SSL_ST_ACCEPT)
#endif
/* read from client */ /* read from client */
/* Do not change the number values, they do matter */ /* Do not change the number values, they do matter */
#define SSL3_ST_SR_CLNT_HELLO_A (0x110|SSL_ST_ACCEPT) #define SSL3_ST_SR_CLNT_HELLO_A (0x110|SSL_ST_ACCEPT)
......
...@@ -772,7 +772,7 @@ const SSL_METHOD *func_name(void) \ ...@@ -772,7 +772,7 @@ const SSL_METHOD *func_name(void) \
ssl3_read, \ ssl3_read, \
ssl3_peek, \ ssl3_peek, \
ssl3_write, \ ssl3_write, \
ssl3_shutdown, \ dtls1_shutdown, \
ssl3_renegotiate, \ ssl3_renegotiate, \
ssl3_renegotiate_check, \ ssl3_renegotiate_check, \
dtls1_get_message, \ dtls1_get_message, \
...@@ -1039,6 +1039,7 @@ int dtls1_connect(SSL *s); ...@@ -1039,6 +1039,7 @@ int dtls1_connect(SSL *s);
void dtls1_free(SSL *s); void dtls1_free(SSL *s);
void dtls1_clear(SSL *s); void dtls1_clear(SSL *s);
long dtls1_ctrl(SSL *s,int cmd, long larg, void *parg); long dtls1_ctrl(SSL *s,int cmd, long larg, void *parg);
int dtls1_shutdown(SSL *s);
long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok); long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok);
int dtls1_get_record(SSL *s); int dtls1_get_record(SSL *s);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册