--- Configure 2009-07-08 10:50:52.000000000 +0200 +++ Configure 2009-07-24 16:25:05.000000000 +0200 @@ -10,7 +10,7 @@ # see INSTALL for instructions. -my $usage="Usage: Configure [no- ...] [enable- ...] [experimental- ...] [-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- ...] [enable- ...] [experimental- ...] [-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: # @@ -56,6 +56,7 @@ # [no-]zlib [don't] compile support for zlib compression. # 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. +# sctp include SCTP support # 386 generate 80386 code # no-sse2 disables IA-32 SSE2 code, above option implies no-sse2 # no- build without specified algorithm (rsa, idea, rc5, ...) @@ -628,6 +629,7 @@ my $no_asm=0; my $no_dso=0; my $no_gmp=0; +my $sctp=0; my @skip=(); my $Makefile="Makefile"; my $des_locl="crypto/des/des_locl.h"; @@ -802,6 +804,10 @@ # The check for the option is there so scripts aren't # broken } + elsif (/^sctp$/) + { + $sctp = 1; + } elsif (/^[-+]/) { if (/^-[lL](.*)$/ or /^-Wl,/) @@ -1275,6 +1281,30 @@ } } +if ($sctp) + { + $openssl_other_defines .= "#define SCTP\n"; + + if ($target =~ /^darwin/) + { + $lflags = "$lflags -lsctp"; + } + if ($target =~ /^debug-darwin/) + { + $lflags = "$lflags -lsctp"; + } + + if ($target =~ /^linux/) + { + $lflags = "$lflags -lsctp"; + } + + if ($target =~ /^solaris/) + { + $lflags = "$lflags -lsctp"; + } + } + $cpuid_obj.=" uplink.o uplink-cof.o" if ($cflags =~ /\-DOPENSSL_USE_APPLINK/); # @@ -1739,6 +1769,7 @@ print "RC2 uses u$type[$rc2_int]\n" if $rc2_int != $def_int; print "BF_PTR used\n" if $bf_ptr == 1; print "BF_PTR2 used\n" if $bf_ptr == 2; +print "SCTP used\n" if $sctp; if($IsMK1MF) { open (OUT,">crypto/buildinf.h") || die "Can't open buildinf.h"; --- crypto/bio/bio.h 2009-06-25 19:11:48.000000000 +0200 +++ crypto/bio/bio.h 2009-07-24 16:25:05.000000000 +0200 @@ -95,6 +95,9 @@ #define BIO_TYPE_BIO (19|0x0400) /* (half a) BIO pair */ #define BIO_TYPE_LINEBUFFER (20|0x0200) /* filter */ #define BIO_TYPE_DGRAM (21|0x0400|0x0100) +#ifdef SCTP +#define BIO_TYPE_DGRAM_SCTP (24|0x0400|0x0100) +#endif #define BIO_TYPE_ASN1 (22|0x0200) /* filter */ #define BIO_TYPE_COMP (23|0x0200) /* filter */ @@ -162,6 +165,22 @@ #define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT 45 /* Next DTLS handshake timeout to * adjust socket timeouts */ +/* SCTP stuff */ +#ifdef SCTP +#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 55 +#define BIO_CTRL_DGRAM_SCTP_SET_SNDINFO 56 +#define BIO_CTRL_DGRAM_SCTP_GET_RCVINFO 57 +#define BIO_CTRL_DGRAM_SCTP_SET_RCVINFO 58 +#define BIO_CTRL_DGRAM_SCTP_GET_SNDFLAGS 59 +#define BIO_CTRL_DGRAM_SCTP_SET_SNDFLAGS 60 +#define BIO_CTRL_DGRAM_SCTP_GET_RCVFLAGS 61 +#define BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN 62 +#endif + /* modifiers */ #define BIO_FP_READ 0x02 #define BIO_FP_WRITE 0x04 @@ -616,6 +635,9 @@ BIO_METHOD *BIO_f_nbio_test(void); #ifndef OPENSSL_NO_DGRAM BIO_METHOD *BIO_s_datagram(void); +#ifdef SCTP +BIO_METHOD *BIO_s_datagram_sctp(void); +#endif #endif /* BIO_METHOD *BIO_f_ber(void); */ @@ -658,6 +680,12 @@ BIO *BIO_new_socket(int sock, int close_flag); BIO *BIO_new_dgram(int fd, int close_flag); +#ifdef SCTP +BIO *BIO_new_dgram_sctp(int fd, int close_flag); +int BIO_dgram_sctp_notification_cb(BIO *b, void (*handle_notifications)(BIO *bio, void *buf)); +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_connect(char *host_port); BIO *BIO_new_accept(char *host_port); --- crypto/bio/bss_dgram.c 2009-07-24 16:24:38.000000000 +0200 +++ crypto/bio/bss_dgram.c 2009-07-24 16:20:20.000000000 +0200 @@ -70,6 +70,11 @@ #include #endif +#ifdef SCTP +#include +#include +#endif + #ifdef OPENSSL_SYS_LINUX #define IP_MTU 14 /* linux is lame */ #endif @@ -88,6 +93,15 @@ static int dgram_free(BIO *data); static int dgram_clear(BIO *bio); +#ifdef 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); +#endif + static int BIO_dgram_should_retry(int s); static void get_current_time(struct timeval *t); @@ -106,6 +120,22 @@ NULL, }; +#ifdef 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 { struct sockaddr peer; @@ -116,11 +146,45 @@ struct timeval socket_timeout; } bio_dgram_data; +#ifdef 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 + { + struct sockaddr peer; + unsigned int connected; + unsigned int _errno; + unsigned int mtu; + struct sctp_sndrcvinfo sndinfo; + struct sctp_sndrcvinfo rcvinfo; + int sndflags; + int rcvflags; + void (*handle_notifications)(BIO *bio, void *buf); + int in_handshake; + int ccs_rcvd; + int ccs_sent; + int save_shutdown; + bio_dgram_sctp_save_message saved_message; + } bio_dgram_sctp_data; +#endif + BIO_METHOD *BIO_s_datagram(void) { return(&methods_dgramp); } +#ifdef SCTP +BIO_METHOD *BIO_s_datagram_sctp(void) + { + return(&methods_dgramp_sctp); + } +#endif + BIO *BIO_new_dgram(int fd, int close_flag) { BIO *ret; @@ -131,6 +195,38 @@ return(ret); } +#ifdef SCTP +BIO *BIO_new_dgram_sctp(int fd, int close_flag) + { + BIO *ret; + struct sctp_authchunk auth; + struct sctp_event_subscribe event; + socklen_t eventsize; + + ret=BIO_new(BIO_s_datagram_sctp()); + if (ret == NULL) return(NULL); + BIO_set_fd(ret,fd,close_flag); + + auth.sauth_chunk = SCTP_DATA; + setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk)); + auth.sauth_chunk = SCTP_SELECTIVE_ACK; + setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk)); + auth.sauth_chunk = SCTP_FORWARD_CUM_TSN; + setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk)); + + eventsize = sizeof(struct sctp_event_subscribe); + if (getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize) != 0) + perror("get event failed"); + + event.sctp_authentication_event = 1; + + if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) + perror("set event failed"); + + return(ret); + } +#endif + static int dgram_new(BIO *bi) { bio_dgram_data *data = NULL; @@ -147,6 +243,24 @@ return(1); } +#ifdef 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)); + bi->ptr = data; + + bi->flags=0; + return(1); + } +#endif + static int dgram_free(BIO *a) { bio_dgram_data *data; @@ -161,6 +275,22 @@ return(1); } +#ifdef SCTP +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); + } +#endif + static int dgram_clear(BIO *a) { if (a == NULL) return(0); @@ -290,6 +420,108 @@ ret=recvfrom(b->num,out,outl,0,&peer,(void *)&peerlen); dgram_reset_rcv_timeout(b); + if ( ! data->connected && ret >= 0) + BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, &peer); + + 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(); + } + } + } + return(ret); + } + +#ifdef SCTP +void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp) + { + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; + unsigned int sockopt_len = 0; + 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); + if (setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, + &authkeyid, sockopt_len) < 0) + perror("delete sctp auth key"); + } + } + +static int dgram_sctp_read(BIO *b, char *out, int outl) + { + int ret=0, n=0; + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; + struct sockaddr peer; + int peerlen = sizeof(peer); + union sctp_notification *snp; + + if (out != NULL) + { + clear_socket_error(); + /* Last arg in recvfrom is signed on some platforms and + * unsigned on others. It is of type socklen_t on some + * but this is not universal. Cast to (void *) to avoid + * compiler warnings. + */ + memset(&peer, 0x00, peerlen); + memset(&data->rcvinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); + data->rcvflags = 0; + n=sctp_recvmsg(b->num,(void*)out,outl,&peer,(void*)&peerlen,&data->rcvinfo,&data->rcvflags); + + while (!(data->rcvflags & MSG_EOR) || (data->rcvflags & MSG_NOTIFICATION)) + { + if (data->rcvflags & MSG_NOTIFICATION) + { + snp = (union sctp_notification*) out; + if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT) + { + struct sctp_event_subscribe event; + socklen_t eventsize; + /* 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); + free(data->saved_message.data); + data->saved_message.length = 0; + } + + /* disable sender dry event */ + eventsize = sizeof(struct sctp_event_subscribe); + if (getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize) != 0) + perror("get event failed"); + + event.sctp_sender_dry_event = 0; + + if (setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) + perror("set event failed"); + } + + if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) + dgram_sctp_handle_auth_free_key_event(b, snp); + + if (data->handle_notifications != NULL) + data->handle_notifications(b, (void*) out); + } + else + ret += n; + + memset(&data->rcvinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); + data->rcvflags = 0; + n=sctp_recvmsg(b->num,(void*)(out+ret),(outl-ret),&peer,(void*)&peerlen,&data->rcvinfo,&data->rcvflags); + } + ret += n; + if ( ! data->connected && ret > 0) BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, &peer); @@ -305,6 +537,7 @@ } return(ret); } +#endif static int dgram_write(BIO *b, const char *in, int inl) { @@ -339,6 +572,68 @@ return(ret); } +#ifdef SCTP +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 sctp_sndrcvinfo *sinfo = &data->sndinfo; + struct sctp_sndrcvinfo handshake_sinfo; + + sinfo->sinfo_flags = data->sndflags; + clear_socket_error(); + + /* If we're still handshaking, disable all parameters and flags */ + if (data->in_handshake > 0) { + memset(&handshake_sinfo, 0x00, sizeof(struct sctp_sndrcvinfo)); +#ifdef SCTP_SACK_IMMEDIATELY + handshake_sinfo.sinfo_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 = (char*) malloc(inl); + memcpy(data->saved_message.data, in, inl); + return inl; + } + + if ( data->connected ) + { + ret = sctp_sendmsg(b->num, (const void *) in, inl, NULL, 0, + sinfo->sinfo_ppid, sinfo->sinfo_flags, sinfo->sinfo_stream, + sinfo->sinfo_timetolive, sinfo->sinfo_context); + } + else + { + ret = sctp_sendmsg(b->num, (const void *) in, inl, (const struct sockaddr *) &data->peer, sizeof(data->peer), + sinfo->sinfo_ppid, sinfo->sinfo_flags, sinfo->sinfo_stream, + sinfo->sinfo_timetolive, sinfo->sinfo_context); + } + + if (ret < 0) + perror("sctp_sendmsg"); + + BIO_clear_retry_flags(b); + if (ret <= 0) + { + if (BIO_sock_should_retry(ret)) + { + BIO_set_retry_write(b); + data->_errno = get_last_socket_error(); + } + } + return(ret); + } +#endif + static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) { long ret=1; @@ -631,6 +926,320 @@ return(ret); } +#ifdef SCTP +static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) + { + long ret=1; + int *ip; + struct sockaddr *to = NULL; + bio_dgram_sctp_data *data = NULL; + long sockopt_val = 0; + unsigned int sockopt_len = 0; + struct sctp_authkeyid authkeyid; + struct sctp_authkey *authkey; + struct sctp_authchunk auth; + + data = (bio_dgram_sctp_data *)b->ptr; + + switch (cmd) + { + case BIO_CTRL_DGRAM_QUERY_MTU: + /* Set to maximum (2^14 + 2048 + 5) + * and ignore user input to enable transport + * protocol fragmentation + */ + data->mtu = 18437; + ret = data->mtu; + break; + case BIO_CTRL_DGRAM_SET_MTU: + /* Set to maximum (2^14 + 2048 + 5) + * and ignore input to enable transport + * protocol fragmentation + */ + data->mtu = 18437; + ret = data->mtu; + break; + case BIO_CTRL_DGRAM_CONNECT: + to = (struct sockaddr *)ptr; + memcpy(&(data->peer),to, sizeof(struct sockaddr)); + break; + case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: + /* SCTP doesn't need the DTLS timer */ + break; + case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: + if (num > 0) + data->in_handshake = 1; + else + data->in_handshake = 0; + + 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 */ + + /* Get active key */ + sockopt_len = sizeof(struct sctp_authkeyid); + if (sctp_opt_info(b->num, 0, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, &sockopt_len) < 0) + perror("get sctp auth active key"); + + /* Add new key */ + authkey = malloc(sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t)); + authkey->sca_keynumber = authkeyid.scact_keynumber + 1; + memset(&authkey->sca_key[0], 0x00, 65 * sizeof(uint8_t)); + memcpy(&authkey->sca_key[0], ptr, 32 * sizeof(uint8_t)); + + sockopt_len = sizeof(struct sctp_authkey) + 63 * sizeof(uint8_t); + if (setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, + authkey, sockopt_len) < 0) + perror("add sctp auth key"); + + /* Reset active key */ + if (setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, sizeof(struct sctp_authkeyid)) < 0) + perror("set sctp auth active key"); + + break; + case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY: + /* Get active key */ + sockopt_len = sizeof(struct sctp_authkeyid); + if (sctp_opt_info(b->num, 0, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, &sockopt_len) < 0) + perror("get sctp auth active key"); + + /* Set active key */ + authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1; + if (setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, sizeof(struct sctp_authkeyid)) < 0) + perror("set sctp auth active key"); + + /* 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: + + /* 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); + if (sctp_opt_info(b->num, 0, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, &sockopt_len) < 0) + perror("get sctp auth active key"); + + /* deactivate key */ + authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; + sockopt_len = sizeof(struct sctp_authkeyid); + if (setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY, + &authkeyid, sockopt_len) < 0) + perror("deactivate sctp auth key"); + + data->ccs_rcvd = 0; + data->ccs_sent = 0; + } + break; + case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO: + if (num > sizeof(struct sctp_sndrcvinfo)) + num = sizeof(struct sctp_sndrcvinfo); + + memcpy(ptr, &(data->sndinfo), num); + ret = num; + break; + case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO: + if (num > sizeof(struct sctp_sndrcvinfo)) + num = sizeof(struct sctp_sndrcvinfo); + + memcpy(&(data->sndinfo), ptr, num); + break; + case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO: + if (num > sizeof(struct sctp_sndrcvinfo)) + num = sizeof(struct sctp_sndrcvinfo); + + memcpy(ptr, &data->rcvinfo, num); + + ret = num; + break; + case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO: + if (num > sizeof(struct sctp_sndrcvinfo)) + num = sizeof(struct sctp_sndrcvinfo); + + memcpy(&(data->rcvinfo), ptr, num); + break; + case BIO_CTRL_DGRAM_SCTP_GET_SNDFLAGS: + if (num > sizeof(int)) + num = sizeof(int); + + memcpy(ptr, &(data->sndflags), num); + ret = num; + break; + case BIO_CTRL_DGRAM_SCTP_SET_SNDFLAGS: + if (num > sizeof(int)) + num = sizeof(int); + + memcpy(&(data->sndflags), ptr, num); + break; + case BIO_CTRL_DGRAM_SCTP_GET_RCVFLAGS: + if (num > sizeof(int)) + num = sizeof(int); + + memcpy(ptr, &(data->rcvflags), num); + ret = num; + break; + case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN: + 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 *buf)) + { + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + + if (handle_notifications != NULL) + data->handle_notifications = handle_notifications; + else + return -1; + + return 0; + } + +int BIO_dgram_sctp_wait_for_dry(BIO *b) +{ + int flags, is_dry = 0; + int n, sockflags; + struct sockaddr peer; + int peerlen = sizeof(peer); + union sctp_notification snp; + struct sctp_event_subscribe event; + socklen_t eventsize; + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; + + /* set sender dry event */ + eventsize = sizeof(struct sctp_event_subscribe); + if (getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize) != 0) + perror("get event failed"); + + event.sctp_sender_dry_event = 1; + + if (setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) + perror("set event failed"); + + /* peek for notification */ + flags = MSG_PEEK; + sctp_recvmsg(b->num,(void*)&snp,sizeof(union sctp_notification),&peer,(void*)&peerlen,0,&flags); + + /* if we find a notification, process it and try again if necessary */ + while (flags & MSG_NOTIFICATION) + { + if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) + { + is_dry = 1; + + /* disable sender dry event */ + eventsize = sizeof(struct sctp_event_subscribe); + if (getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize) != 0) + perror("get event failed"); + + event.sctp_sender_dry_event = 0; + + if (setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) + perror("set event failed"); + } + + if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) + dgram_sctp_handle_auth_free_key_event(b, &snp); + + memset(&snp, 0x00, sizeof(union sctp_notification)); + flags = 0; + sctp_recvmsg(b->num,(void*)&snp,sizeof(union sctp_notification),&peer,(void*)&peerlen,0,&flags); + + if (data->handle_notifications != NULL) + data->handle_notifications(b, (void*) &snp); + + if (is_dry == 1) + { + /* check for more notifications */ + sockflags = fcntl(b->num, F_GETFL, 0); + fcntl(b->num, F_SETFL, O_NONBLOCK); + flags = MSG_PEEK; + n = sctp_recvmsg(b->num,(void*)&snp,sizeof(union sctp_notification),&peer,(void*)&peerlen,0,&flags); + fcntl(b->num, F_SETFL, sockflags); + + /* if nothing is waiting just quit. otherwise read again. */ + if (n <= 0) + return 1; + } + + /* found notification but no dry event, peek again */ + memset(&snp, 0x00, sizeof(union sctp_notification)); + flags = MSG_PEEK; + sctp_recvmsg(b->num,(void*)&snp,sizeof(union sctp_notification),&peer,(void*)&peerlen,0,&flags); + } + + /* read anything else */ + return is_dry; +} + +int BIO_dgram_sctp_msg_waiting(BIO *b) + { + int n, sockflags, flags; + struct sockaddr peer; + int peerlen = sizeof(peer); + union sctp_notification snp; + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; + + /* Check if there are messages waiting */ + do + { + sockflags = fcntl(b->num, F_GETFL, 0); + fcntl(b->num, F_SETFL, O_NONBLOCK); + flags = MSG_PEEK; + n = sctp_recvmsg(b->num,(void*)&snp,sizeof(union sctp_notification),&peer,(void*)&peerlen,0,&flags); + fcntl(b->num, F_SETFL, sockflags); + + /* if notification, process and try again */ + if (n > 0 && flags & MSG_NOTIFICATION) + { + if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) + dgram_sctp_handle_auth_free_key_event(b, &snp); + + flags = 0; + n = sctp_recvmsg(b->num,(void*)&snp,sizeof(union sctp_notification),&peer,(void*)&peerlen,0,&flags); + if (n < 0) + perror("sctp_recvmsg"); + + if (data->handle_notifications != NULL) + data->handle_notifications(b, (void*) &snp); + + memset(&snp, 0x00, sizeof(union sctp_notification)); + } + + } while (flags & MSG_NOTIFICATION); + + if (n > 0) + return 1; + else + return 0; + } +#endif + static int dgram_puts(BIO *bp, const char *str) { int n,ret; @@ -640,6 +1249,17 @@ return(ret); } +#ifdef SCTP +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) { int err; --- ssl/d1_both.c 2009-07-15 13:32:57.000000000 +0200 +++ ssl/d1_both.c 2009-07-24 16:25:05.000000000 +0200 @@ -1256,3 +1256,19 @@ ccs_hdr->type = *(data++); } + +int dtls1_shutdown(SSL *s) + { + int ret; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP && + !BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s))) + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1, NULL); +#endif + ret = ssl3_shutdown(s); +#ifdef SCTP + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL); +#endif + return ret; + } + --- ssl/d1_clnt.c 2009-07-24 16:24:42.000000000 +0200 +++ ssl/d1_clnt.c 2009-07-24 16:25:05.000000000 +0200 @@ -152,6 +152,10 @@ void (*cb)(const SSL *ssl,int type,int val)=NULL; int ret= -1; int new_state,state,skip=0;; +#ifdef SCTP + unsigned char sctpauthkey[64]; + unsigned char labelbuffer[25], contextbuffer[8]; +#endif RAND_add(&Time,sizeof(Time),0); ERR_clear_error(); @@ -165,6 +169,14 @@ s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); +#ifdef 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 (;;) { state=s->state; @@ -227,6 +239,39 @@ s->hit = 0; break; +#ifdef 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 */ + + if (!BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(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->d1->next_state; + break; +#endif + case SSL3_ST_CW_CLNT_HELLO_A: case SSL3_ST_CW_CLNT_HELLO_B: @@ -249,9 +294,17 @@ s->init_num=0; - /* turn on buffering for the next lot of output */ - if (s->bbio != s->wbio) - s->wbio=BIO_push(s->bbio,s->wbio); +#ifdef SCTP + /* Disable buffering for SCTP */ + if (SSL_get_wbio(s)->method->type != BIO_TYPE_DGRAM_SCTP) + { +#endif + /* turn on buffering for the next lot of output */ + if (s->bbio != s->wbio) + s->wbio=BIO_push(s->bbio,s->wbio); +#ifdef SCTP + } +#endif break; @@ -263,7 +316,24 @@ { dtls1_stop_timer(s); if (s->hit) + { +#ifdef SCTP + /* Add new shared key for SCTP-Auth, + * will be ignored if no SCTP used. + */ + snprintf((char*) labelbuffer, 25, "EXTRACTOR_dtlssctpauthkey"); + snprintf((char*) contextbuffer, 8, "dtlssctp"); + + SSL_tls1_key_extractor(s, labelbuffer, sizeof(labelbuffer), + contextbuffer, sizeof(contextbuffer), + sctpauthkey, sizeof(sctpauthkey)); + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); +#endif + s->state=SSL3_ST_CR_FINISHED_A; + } else s->state=DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A; } @@ -328,11 +398,18 @@ ret=ssl3_get_server_done(s); if (ret <= 0) goto end; if (s->s3->tmp.cert_req) - s->state=SSL3_ST_CW_CERT_A; + s->s3->tmp.next_state=SSL3_ST_CW_CERT_A; else - s->state=SSL3_ST_CW_KEY_EXCH_A; + s->s3->tmp.next_state=SSL3_ST_CW_KEY_EXCH_A; s->init_num=0; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP && + state == SSL_ST_RENEGOTIATE) + s->state=DTLS1_SCTP_ST_CR_READ_SOCK; + else +#endif + s->state=s->s3->tmp.next_state; break; case SSL3_ST_CW_CERT_A: @@ -351,6 +428,22 @@ dtls1_start_timer(s); ret=dtls1_send_client_key_exchange(s); if (ret <= 0) goto end; + +#ifdef SCTP + /* Add new shared key for SCTP-Auth, + * will be ignored if no SCTP used. + */ + snprintf((char*) labelbuffer, 25, "EXTRACTOR_dtlssctpauthkey"); + snprintf((char*) contextbuffer, 8, "dtlssctp"); + + SSL_tls1_key_extractor(s, labelbuffer, sizeof(labelbuffer), + contextbuffer, sizeof(contextbuffer), + sctpauthkey, sizeof(sctpauthkey)); + + 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 * sent back */ /* For TLS, cert_req is set to 2, so a cert chain @@ -361,7 +454,15 @@ } else { - s->state=SSL3_ST_CW_CHANGE_A; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP) + { + 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->s3->change_cipher_spec=0; } @@ -373,7 +474,15 @@ dtls1_start_timer(s); ret=dtls1_send_client_verify(s); if (ret <= 0) goto end; - s->state=SSL3_ST_CW_CHANGE_A; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP) + { + 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->init_num=0; s->s3->change_cipher_spec=0; break; @@ -384,6 +493,14 @@ ret=dtls1_send_change_cipher_spec(s, SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); if (ret <= 0) goto end; + +#ifdef 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->init_num=0; @@ -428,9 +545,23 @@ if (s->hit) { s->s3->tmp.next_state=SSL_ST_OK; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP) + { + 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) { s->state=SSL_ST_OK; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP) + { + 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->delay_buf_pop_ret=0; } @@ -454,6 +585,16 @@ s->state=SSL3_ST_CW_CHANGE_A; else s->state=SSL_ST_OK; + +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP && + state == SSL_ST_RENEGOTIATE) + { + s->d1->next_state=s->state; + s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK; + } +#endif + s->init_num=0; break; @@ -536,6 +677,15 @@ } end: s->in_handshake--; + +#ifdef 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) BUF_MEM_free(buf); if (cb != NULL) --- ssl/d1_lib.c 2009-05-31 19:11:24.000000000 +0200 +++ ssl/d1_lib.c 2009-07-24 16:25:05.000000000 +0200 @@ -210,6 +210,15 @@ void dtls1_start_timer(SSL *s) { +#ifdef SCTP + /* Disable timer for SCTP */ + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP) + { + memset(&(s->d1->next_timeout), 0, sizeof(struct timeval)); + return; + } +#endif + /* 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) { --- ssl/d1_pkt.c 2009-07-24 16:24:42.000000000 +0200 +++ ssl/d1_pkt.c 2009-07-24 16:25:05.000000000 +0200 @@ -229,6 +229,14 @@ item->data = rdata; +#ifdef SCTP + /* Store sctp_sndrcvinfo struct */ + if (SSL_get_rbio(s)->method->type == BIO_TYPE_DGRAM_SCTP && + (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 */ if (pqueue_insert(queue->q, item) == NULL) { @@ -648,13 +656,21 @@ goto again; /* get another record */ } - /* check whether this is a repeat, or aged record */ - if ( ! dtls1_record_replay_check(s, bitmap)) - { - rr->length = 0; - s->packet_length=0; /* dump this record */ - goto again; /* get another record */ - } +#ifdef SCTP + /* Only do replay check if no SCTP bio */ + if (SSL_get_rbio(s)->method->type != BIO_TYPE_DGRAM_SCTP) + { +#endif + /* check whether this is a repeat, or aged record */ + if ( ! dtls1_record_replay_check(s, bitmap)) + { + rr->length = 0; + s->packet_length=0; /* dump this record */ + goto again; /* get another record */ + } +#ifdef SCTP + } +#endif /* just read a 0 length packet */ if (rr->length == 0) goto again; @@ -734,7 +750,17 @@ /* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */ +#ifdef SCTP + /* Continue handshake if it had to be interrupted to read + * app data with SCTP. + */ + if ((!s->in_handshake && SSL_in_init(s)) || + (SSL_get_rbio(s)->method->type == BIO_TYPE_DGRAM_SCTP && + (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)) +#endif { /* type == SSL3_RT_APPLICATION_DATA */ i=s->handshake_func(s); @@ -765,6 +791,15 @@ item = pqueue_pop(s->d1->buffered_app_data.q); if (item) { +#ifdef SCTP + /* Restore sctp_sndrcvinfo struct */ + if (SSL_get_rbio(s)->method->type == BIO_TYPE_DGRAM_SCTP) + { + 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); OPENSSL_free(item->data); @@ -850,6 +885,31 @@ rr->off=0; } } + +#ifdef SCTP + /* We were about to renegotiate but had to read + * belated application data first, so retry. + */ + if (SSL_get_rbio(s)->method->type == BIO_TYPE_DGRAM_SCTP && + 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 (SSL_get_rbio(s)->method->type == BIO_TYPE_DGRAM_SCTP && + s->d1->shutdown_received && !BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) + { + s->shutdown |= SSL_RECEIVED_SHUTDOWN; + return(0); + } +#endif return(n); } @@ -900,6 +960,7 @@ goto f_err; } + if (dest_maxlen > 0) { /* XDTLS: In a pathalogical case, the Client Hello @@ -1022,6 +1083,21 @@ s->s3->warn_alert = alert_descr; if (alert_descr == SSL_AD_CLOSE_NOTIFY) { +#ifdef 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 (SSL_get_rbio(s)->method->type == BIO_TYPE_DGRAM_SCTP && + 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; return(0); } @@ -1128,6 +1204,15 @@ if (s->version == DTLS1_BAD_VER) s->d1->handshake_read_seq++; +#ifdef 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; } @@ -1144,7 +1229,7 @@ rr->length = 0; goto start; } - + /* If we are server, we may have a repeated FINISHED of the * client here, then retransmit our CCS and FINISHED. */ @@ -1264,7 +1349,16 @@ unsigned int n,tot; int i; - if (SSL_in_init(s) && !s->in_handshake) +#ifdef 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) || + (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP && + (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) +#endif { i=s->handshake_func(s); if (i < 0) return(i); --- ssl/d1_srvr.c 2009-07-24 16:24:42.000000000 +0200 +++ ssl/d1_srvr.c 2009-07-24 16:25:05.000000000 +0200 @@ -151,6 +151,10 @@ unsigned long alg_k; int ret= -1; int new_state,state,skip=0; +#ifdef SCTP + unsigned char sctpauthkey[64]; + unsigned char labelbuffer[25], contextbuffer[8]; +#endif RAND_add(&Time,sizeof(Time),0); ERR_clear_error(); @@ -165,6 +169,14 @@ s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); +#ifdef 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) { SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_NO_CERTIFICATE_SET); @@ -223,8 +235,12 @@ { /* Ok, we now need to push on a buffering BIO so that * the output is sent in a way that TCP likes :-) + * ...but not with SCTP :-) */ - if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; } +#ifdef SCTP + if (SSL_get_wbio(s)->method->type != BIO_TYPE_DGRAM_SCTP) +#endif + if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; } ssl3_init_finished_mac(s); s->state=SSL3_ST_SR_CLNT_HELLO_A; @@ -296,6 +312,40 @@ ssl3_init_finished_mac(s); break; +#ifdef 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: + if (!BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s))) + { + 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_B: dtls1_start_timer(s); @@ -303,7 +353,23 @@ if (ret <= 0) goto end; if (s->hit) + { +#ifdef SCTP + /* Add new shared key for SCTP-Auth, + * will be ignored if no SCTP used. + */ + snprintf((char*) labelbuffer, 25, "EXTRACTOR_dtlssctpauthkey"); + snprintf((char*) contextbuffer, 8, "dtlssctp"); + + SSL_tls1_key_extractor(s, labelbuffer, sizeof(labelbuffer), + contextbuffer, sizeof(contextbuffer), + sctpauthkey, sizeof(sctpauthkey)); + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); +#endif s->state=SSL3_ST_SW_CHANGE_A; + } else s->state=SSL3_ST_SW_CERT_A; s->init_num=0; @@ -399,6 +465,13 @@ skip=1; s->s3->tmp.cert_request=0; s->state=SSL3_ST_SW_SRVR_DONE_A; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP) + { + s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A; + s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK; + } +#endif } else { @@ -408,9 +481,23 @@ if (ret <= 0) goto end; #ifndef NETSCAPE_HANG_BUG s->state=SSL3_ST_SW_SRVR_DONE_A; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP) + { + s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A; + s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK; + } +#endif #else s->state=SSL3_ST_SW_FLUSH; s->s3->tmp.next_state=SSL3_ST_SR_CERT_A; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP) + { + s->d1->next_state = s->s3->tmp.next_state; + s->s3->tmp.next_state=DTLS1_SCTP_ST_SW_WRITE_SOCK; + } +#endif #endif s->init_num=0; } @@ -465,6 +552,21 @@ ret=ssl3_get_client_key_exchange(s); if (ret <= 0) goto end; dtls1_stop_timer(s); +#ifdef SCTP + /* Add new shared key for SCTP-Auth, + * will be ignored if no SCTP used. + */ + snprintf((char *) labelbuffer, 25, "EXTRACTOR_dtlssctpauthkey"); + snprintf((char *) contextbuffer, 8, "dtlssctp"); + + SSL_tls1_key_extractor(s, labelbuffer, sizeof(labelbuffer), + contextbuffer, sizeof(contextbuffer), + sctpauthkey, sizeof(sctpauthkey)); + + 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->init_num=0; @@ -503,7 +605,13 @@ if (ret <= 0) goto end; dtls1_stop_timer(s); - s->state=SSL3_ST_SR_FINISHED_A; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP && + state == SSL_ST_RENEGOTIATE) + s->state=DTLS1_SCTP_ST_SR_READ_SOCK; + else +#endif + s->state=SSL3_ST_SR_FINISHED_A; s->init_num=0; break; @@ -532,6 +640,14 @@ SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B); if (ret <= 0) goto end; + +#ifdef 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->init_num=0; @@ -556,7 +672,16 @@ if (s->hit) s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A; else + { s->s3->tmp.next_state=SSL_ST_OK; +#ifdef SCTP + if (SSL_get_wbio(s)->method->type == BIO_TYPE_DGRAM_SCTP) + { + 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; break; @@ -630,6 +755,14 @@ /* BIO_flush(s->wbio); */ s->in_handshake--; +#ifdef 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) cb(s,SSL_CB_ACCEPT_EXIT,ret); return(ret); --- ssl/dtls1.h 2009-06-17 13:38:26.000000000 +0200 +++ ssl/dtls1.h 2009-07-24 16:25:05.000000000 +0200 @@ -70,6 +70,9 @@ #else #include #endif +#ifdef SCTP +#include +#endif #ifdef __cplusplus extern "C" { @@ -235,6 +238,13 @@ unsigned int retransmitting; unsigned int change_cipher_spec_ok; +#ifdef SCTP + /* used when SSL_ST_XX_FLUSH is entered */ + int next_state; + + int shutdown_received; +#endif + } DTLS1_STATE; typedef struct dtls1_record_data_st @@ -243,6 +253,9 @@ unsigned int packet_length; SSL3_BUFFER rbuf; SSL3_RECORD rrec; +#ifdef SCTP + struct sctp_sndrcvinfo recordinfo; +#endif } DTLS1_RECORD_DATA; --- ssl/ssl3.h 2009-06-16 18:39:20.000000000 +0200 +++ ssl/ssl3.h 2009-07-24 16:25:05.000000000 +0200 @@ -510,6 +510,10 @@ /*client */ /* extra state */ #define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT) +#ifdef 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 */ #define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT) #define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT) @@ -552,6 +556,10 @@ /* server */ /* extra state */ #define SSL3_ST_SW_FLUSH (0x100|SSL_ST_ACCEPT) +#ifdef 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 */ /* Do not change the number values, they do matter */ #define SSL3_ST_SR_CLNT_HELLO_A (0x110|SSL_ST_ACCEPT)