int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len) { 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) #endif { i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } } if (len > SSL3_RT_MAX_PLAIN_LENGTH) { SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES, SSL_R_DTLS_MESSAGE_TOO_BIG); return -1; } i = dtls1_write_bytes(s, type, buf_, len); return i; }
int dtls1_write_app_data(SSL *s, const void *buf_, int len) { int i; if (SSL_in_init(s) && !s->in_handshake) { i = s->handshake_func(s); if (i < 0) { return i; } if (i == 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } } if (len > SSL3_RT_MAX_PLAIN_LENGTH) { OPENSSL_PUT_ERROR(SSL, SSL_R_DTLS_MESSAGE_TOO_BIG); return -1; } i = dtls1_write_bytes(s, SSL3_RT_APPLICATION_DATA, buf_, len, dtls1_use_current_epoch); return i; }
int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, size_t len, size_t *written) { int i; if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s)) { i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } } if (len > SSL3_RT_MAX_PLAIN_LENGTH) { SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES, SSL_R_DTLS_MESSAGE_TOO_BIG); return -1; } return dtls1_write_bytes(s, type, buf_, len, written); }
/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */ int dtls1_do_write(SSL *s, int type) { int ret; int curr_mtu; unsigned int len, frag_off, mac_size, blocksize; /* AHA! Figure out the MTU, and stick to the right size */ if (s->d1->mtu < dtls1_min_mtu() && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) { s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); /* I've seen the kernel return bogus numbers when it doesn't know * (initial write), so just make sure we have a reasonable number */ if (s->d1->mtu < dtls1_min_mtu()) { s->d1->mtu = 0; s->d1->mtu = dtls1_guess_mtu(s->d1->mtu); BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, s->d1->mtu, NULL); } } #if 0 mtu = s->d1->mtu; fprintf(stderr, "using MTU = %d\n", mtu); mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH); curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s)); if ( curr_mtu > 0) mtu = curr_mtu; else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0) return ret; if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu) { ret = BIO_flush(SSL_get_wbio(s)); if ( ret <= 0) return ret; mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH); } #endif OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu()); /* should have something reasonable now */ if ( s->init_off == 0 && type == SSL3_RT_HANDSHAKE) OPENSSL_assert(s->init_num == (int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH); if (s->write_hash) mac_size = EVP_MD_size(s->write_hash); else mac_size = 0; if (s->enc_write_ctx && (EVP_CIPHER_mode( s->enc_write_ctx->cipher) & EVP_CIPH_CBC_MODE)) blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher); else blocksize = 0; frag_off = 0; while( s->init_num) { curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) - DTLS1_RT_HEADER_LENGTH - mac_size - blocksize; if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH) { /* grr.. we could get an error if MTU picked was wrong */ ret = BIO_flush(SSL_get_wbio(s)); if ( ret <= 0) return ret; curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH - mac_size - blocksize; } if ( s->init_num > curr_mtu) len = curr_mtu; else len = s->init_num; /* XDTLS: this function is too long. split out the CCS part */ if ( type == SSL3_RT_HANDSHAKE) { if ( s->init_off != 0) { OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH); s->init_off -= DTLS1_HM_HEADER_LENGTH; s->init_num += DTLS1_HM_HEADER_LENGTH; if ( s->init_num > curr_mtu) len = curr_mtu; else len = s->init_num; } dtls1_fix_message_header(s, frag_off, len - DTLS1_HM_HEADER_LENGTH); dtls1_write_message_header(s, (unsigned char *)&s->init_buf->data[s->init_off]); OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH); } ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off], len); if (ret < 0) { /* might need to update MTU here, but we don't know * which previous packet caused the failure -- so can't * really retransmit anything. continue as if everything * is fine and wait for an alert to handle the * retransmit */ if ( BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0 ) s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); else return(-1); } else { /* bad if this assert fails, only part of the handshake * message got sent. but why would this happen? */ OPENSSL_assert(len == (unsigned int)ret); if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting) { /* should not be done for 'Hello Request's, but in that case * we'll ignore the result anyway */ unsigned char *p = (unsigned char *)&s->init_buf->data[s->init_off]; const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; int xlen; if (frag_off == 0 && s->client_version != DTLS1_BAD_VER) { /* reconstruct message header is if it * is being sent in single fragment */ *p++ = msg_hdr->type; l2n3(msg_hdr->msg_len,p); s2n (msg_hdr->seq,p); l2n3(0,p); l2n3(msg_hdr->msg_len,p); p -= DTLS1_HM_HEADER_LENGTH; xlen = ret; } else { p += DTLS1_HM_HEADER_LENGTH; xlen = ret - DTLS1_HM_HEADER_LENGTH; } ssl3_finish_mac(s, p, xlen); } if (ret == s->init_num) { if (s->msg_callback) s->msg_callback(1, s->version, type, s->init_buf->data, (size_t)(s->init_off + s->init_num), s, s->msg_callback_arg); s->init_off = 0; /* done writing this message */ s->init_num = 0; return(1); } s->init_off+=ret; s->init_num-=ret; frag_off += (ret -= DTLS1_HM_HEADER_LENGTH); } } return(0); }
int dtls1_heartbeat(SSL *s) { unsigned char *buf, *p; int ret = -1; size_t payload = 18; /* Sequence number + random bytes */ size_t padding = 16; /* Use minimum padding */ size_t size, written; /* Only send if peer supports and accepts HB requests... */ if (!(s->tlsext_heartbeat & SSL_DTLSEXT_HB_ENABLED) || s->tlsext_heartbeat & SSL_DTLSEXT_HB_DONT_SEND_REQUESTS) { SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT); return -1; } /* ...and there is none in flight yet... */ if (s->tlsext_hb_pending) { SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PENDING); return -1; } /* ...and no handshake in progress. */ if (SSL_in_init(s) || ossl_statem_get_in_handshake(s)) { SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_UNEXPECTED_MESSAGE); return -1; } /*- * Create HeartBeat message, we just use a sequence number * as payload to distinguish different messages and add * some random stuff. */ size = HEARTBEAT_SIZE(payload, padding); buf = OPENSSL_malloc(size); if (buf == NULL) { SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_MALLOC_FAILURE); return -1; } p = buf; /* Message Type */ *p++ = TLS1_HB_REQUEST; /* Payload length (18 bytes here) */ s2n(payload, p); /* Sequence number */ s2n(s->tlsext_hb_seq, p); /* 16 random bytes */ if (RAND_bytes(p, 16) <= 0) { SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR); goto err; } p += 16; /* Random padding */ if (RAND_bytes(p, padding) <= 0) { SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR); goto err; } ret = dtls1_write_bytes(s, DTLS1_RT_HEARTBEAT, buf, size, &written); if (ret > 0) { if (s->msg_callback) s->msg_callback(1, s->version, DTLS1_RT_HEARTBEAT, buf, size, s, s->msg_callback_arg); dtls1_start_timer(s); s->tlsext_hb_pending = 1; } err: OPENSSL_free(buf); return ret; }
int dtls1_process_heartbeat(SSL *s, unsigned char *p, size_t length) { unsigned char *pl; unsigned short hbtype; unsigned int payload; unsigned int padding = 16; /* Use minimum padding */ size_t written; if (s->msg_callback) s->msg_callback(0, s->version, DTLS1_RT_HEARTBEAT, p, length, s, s->msg_callback_arg); /* Read type and payload length */ if (HEARTBEAT_SIZE_STD(0) > length) return 0; /* silently discard */ if (length > SSL3_RT_MAX_PLAIN_LENGTH) return 0; /* silently discard per RFC 6520 sec. 4 */ hbtype = *p++; n2s(p, payload); if (HEARTBEAT_SIZE_STD(payload) > length) return 0; /* silently discard per RFC 6520 sec. 4 */ pl = p; if (hbtype == TLS1_HB_REQUEST) { unsigned char *buffer, *bp; size_t write_length = HEARTBEAT_SIZE(payload, padding); int r; if (write_length > SSL3_RT_MAX_PLAIN_LENGTH) return 0; /* Allocate memory for the response. */ buffer = OPENSSL_malloc(write_length); if (buffer == NULL) return -1; bp = buffer; /* Enter response type, length and copy payload */ *bp++ = TLS1_HB_RESPONSE; s2n(payload, bp); memcpy(bp, pl, payload); bp += payload; /* Random padding */ if (RAND_bytes(bp, padding) <= 0) { OPENSSL_free(buffer); return -1; } r = dtls1_write_bytes(s, DTLS1_RT_HEARTBEAT, buffer, write_length, &written); if (r > 0 && s->msg_callback) s->msg_callback(1, s->version, DTLS1_RT_HEARTBEAT, buffer, write_length, s, s->msg_callback_arg); OPENSSL_free(buffer); if (r <= 0) return -1; } else if (hbtype == TLS1_HB_RESPONSE) { unsigned int seq; /* * We only send sequence numbers (2 bytes unsigned int), and 16 * random bytes, so we just try to read the sequence number */ n2s(pl, seq); if (payload == 18 && seq == s->tlsext_hb_seq) { dtls1_stop_timer(s); s->tlsext_hb_seq++; s->tlsext_hb_pending = 0; } } return 0; }
/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */ int dtls1_do_write(SSL *s, int type) { int ret; int curr_mtu; unsigned int len, frag_off; /* AHA! Figure out the MTU, and stick to the right size */ if ( ! (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) { s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); /* I've seen the kernel return bogus numbers when it doesn't know * (initial write), so just make sure we have a reasonable number */ if ( s->d1->mtu < dtls1_min_mtu()) { s->d1->mtu = 0; s->d1->mtu = dtls1_guess_mtu(s->d1->mtu); BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, s->d1->mtu, NULL); } } #if 0 mtu = s->d1->mtu; fprintf(stderr, "using MTU = %d\n", mtu); mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH); curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s)); if ( curr_mtu > 0) mtu = curr_mtu; else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0) return ret; if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu) { ret = BIO_flush(SSL_get_wbio(s)); if ( ret <= 0) return ret; mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH); } OPENSSL_assert(mtu > 0); /* should have something reasonable now */ #endif if ( s->init_off == 0 && type == SSL3_RT_HANDSHAKE) OPENSSL_assert(s->init_num == (int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH); frag_off = 0; while( s->init_num) { curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) - DTLS1_RT_HEADER_LENGTH; if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH) { /* grr.. we could get an error if MTU picked was wrong */ ret = BIO_flush(SSL_get_wbio(s)); if ( ret <= 0) return ret; curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH; } if ( s->init_num > curr_mtu) len = curr_mtu; else len = s->init_num; /* XDTLS: this function is too long. split out the CCS part */ if ( type == SSL3_RT_HANDSHAKE) { if ( s->init_off != 0) { OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH); s->init_off -= DTLS1_HM_HEADER_LENGTH; s->init_num += DTLS1_HM_HEADER_LENGTH; /* write atleast DTLS1_HM_HEADER_LENGTH bytes */ if ( len <= DTLS1_HM_HEADER_LENGTH) len += DTLS1_HM_HEADER_LENGTH; } dtls1_fix_message_header(s, frag_off, len - DTLS1_HM_HEADER_LENGTH); dtls1_write_message_header(s, (unsigned char *)&s->init_buf->data[s->init_off]); OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH); } ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off], len); if (ret < 0) { /* might need to update MTU here, but we don't know * which previous packet caused the failure -- so can't * really retransmit anything. continue as if everything * is fine and wait for an alert to handle the * retransmit */ if ( BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL)) s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); else return(-1); } else { /* bad if this assert fails, only part of the handshake * message got sent. but why would this happen? */ OPENSSL_assert(len == (unsigned int)ret); if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting) /* should not be done for 'Hello Request's, but in that case * we'll ignore the result anyway */ ssl3_finish_mac(s, (unsigned char *)&s->init_buf->data[s->init_off + DTLS1_HM_HEADER_LENGTH], ret - DTLS1_HM_HEADER_LENGTH); if (ret == s->init_num) { if (s->msg_callback) s->msg_callback(1, s->version, type, s->init_buf->data, (size_t)(s->init_off + s->init_num), s, s->msg_callback_arg); s->init_off = 0; /* done writing this message */ s->init_num = 0; return(1); } s->init_off+=ret; s->init_num-=ret; frag_off += (ret -= DTLS1_HM_HEADER_LENGTH); } } return(0); }