diff options
Diffstat (limited to 'crypto/openssl/ssl/d1_both.c')
-rw-r--r-- | crypto/openssl/ssl/d1_both.c | 286 |
1 files changed, 227 insertions, 59 deletions
diff --git a/crypto/openssl/ssl/d1_both.c b/crypto/openssl/ssl/d1_both.c index 4481c55..de8bab8 100644 --- a/crypto/openssl/ssl/d1_both.c +++ b/crypto/openssl/ssl/d1_both.c @@ -272,7 +272,7 @@ int dtls1_do_write(SSL *s, int type) (int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH); if (s->write_hash) - mac_size = EVP_MD_size(s->write_hash); + mac_size = EVP_MD_CTX_size(s->write_hash); else mac_size = 0; @@ -358,7 +358,7 @@ int dtls1_do_write(SSL *s, int type) const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; int xlen; - if (frag_off == 0 && s->client_version != DTLS1_BAD_VER) + if (frag_off == 0 && s->version != DTLS1_BAD_VER) { /* reconstruct message header is if it * is being sent in single fragment */ @@ -501,7 +501,7 @@ static int dtls1_preprocess_fragment(SSL *s,struct hm_header_st *msg_hdr,int max { /* msg_len is limited to 2^24, but is effectively checked * against max above */ - if (!BUF_MEM_grow_clean(s->init_buf,(int)msg_len+DTLS1_HM_HEADER_LENGTH)) + if (!BUF_MEM_grow_clean(s->init_buf,msg_len+DTLS1_HM_HEADER_LENGTH)) { SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,ERR_R_BUF_LIB); return SSL_AD_INTERNAL_ERROR; @@ -587,7 +587,7 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok) hm_fragment *frag = NULL; pitem *item = NULL; int i = -1, is_complete; - PQ_64BIT seq64; + unsigned char seq64be[8]; unsigned long frag_len = msg_hdr->frag_len, max_len; if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len) @@ -605,10 +605,10 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok) goto err; /* Try to find item in queue */ - pq_64bit_init(&seq64); - pq_64bit_assign_word(&seq64, msg_hdr->seq); - item = pqueue_find(s->d1->buffered_messages, seq64); - pq_64bit_free(&seq64); + memset(seq64be,0,sizeof(seq64be)); + seq64be[6] = (unsigned char) (msg_hdr->seq>>8); + seq64be[7] = (unsigned char) msg_hdr->seq; + item = pqueue_find(s->d1->buffered_messages, seq64be); if (item == NULL) { @@ -660,11 +660,11 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok) if (item == NULL) { - pq_64bit_init(&seq64); - pq_64bit_assign_word(&seq64, msg_hdr->seq); - item = pitem_new(seq64, frag); - pq_64bit_free(&seq64); + memset(seq64be,0,sizeof(seq64be)); + seq64be[6] = (unsigned char)(msg_hdr->seq>>8); + seq64be[7] = (unsigned char)(msg_hdr->seq); + item = pitem_new(seq64be, frag); if (item == NULL) { goto err; @@ -690,17 +690,17 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok) int i=-1; hm_fragment *frag = NULL; pitem *item = NULL; - PQ_64BIT seq64; + unsigned char seq64be[8]; unsigned long frag_len = msg_hdr->frag_len; if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len) goto err; /* Try to find item in queue, to prevent duplicate entries */ - pq_64bit_init(&seq64); - pq_64bit_assign_word(&seq64, msg_hdr->seq); - item = pqueue_find(s->d1->buffered_messages, seq64); - pq_64bit_free(&seq64); + memset(seq64be,0,sizeof(seq64be)); + seq64be[6] = (unsigned char) (msg_hdr->seq>>8); + seq64be[7] = (unsigned char) msg_hdr->seq; + item = pqueue_find(s->d1->buffered_messages, seq64be); /* If we already have an entry and this one is a fragment, * don't discard it and rather try to reassemble it. @@ -741,18 +741,18 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok) if (frag_len) { - /* read the body of the fragment (header has already been read) */ + /* read the body of the fragment (header has already been read */ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, frag->fragment,frag_len,0); if (i<=0 || (unsigned long)i!=frag_len) goto err; } - pq_64bit_init(&seq64); - pq_64bit_assign_word(&seq64, msg_hdr->seq); + memset(seq64be,0,sizeof(seq64be)); + seq64be[6] = (unsigned char)(msg_hdr->seq>>8); + seq64be[7] = (unsigned char)(msg_hdr->seq); - item = pitem_new(seq64, frag); - pq_64bit_free(&seq64); + item = pitem_new(seq64be, frag); if ( item == NULL) goto err; @@ -907,8 +907,6 @@ int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen) p= &(d[DTLS1_HM_HEADER_LENGTH]); i=s->method->ssl3_enc->final_finish_mac(s, - &(s->s3->finish_dgst1), - &(s->s3->finish_dgst2), sender,slen,s->s3->tmp.finish_md); s->s3->tmp.finish_md_len = i; memcpy(p, s->s3->tmp.finish_md, i); @@ -973,12 +971,11 @@ int dtls1_send_change_cipher_spec(SSL *s, int a, int b) s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; s->init_num=DTLS1_CCS_HEADER_LENGTH; - if (s->client_version == DTLS1_BAD_VER) - { + if (s->version == DTLS1_BAD_VER) { s->d1->next_handshake_write_seq++; s2n(s->d1->handshake_write_seq,p); s->init_num+=2; - } + } s->init_off=0; @@ -997,21 +994,21 @@ int dtls1_send_change_cipher_spec(SSL *s, int a, int b) static int dtls1_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x) { - int n; - unsigned char *p; + int n; + unsigned char *p; - n=i2d_X509(x,NULL); - if (!BUF_MEM_grow_clean(buf,(int)(n+(*l)+3))) - { - SSLerr(SSL_F_DTLS1_ADD_CERT_TO_BUF,ERR_R_BUF_LIB); - return 0; - } - p=(unsigned char *)&(buf->data[*l]); - l2n3(n,p); - i2d_X509(x,&p); - *l+=n+3; + n=i2d_X509(x,NULL); + if (!BUF_MEM_grow_clean(buf,(int)(n+(*l)+3))) + { + SSLerr(SSL_F_DTLS1_ADD_CERT_TO_BUF,ERR_R_BUF_LIB); + return 0; + } + p=(unsigned char *)&(buf->data[*l]); + l2n3(n,p); + i2d_X509(x,&p); + *l+=n+3; - return 1; + return 1; } unsigned long dtls1_output_cert_chain(SSL *s, X509 *x) { @@ -1030,7 +1027,7 @@ unsigned long dtls1_output_cert_chain(SSL *s, X509 *x) if (x != NULL) { X509_STORE_CTX xs_ctx; - + if (!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,x,NULL)) { SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_X509_LIB); @@ -1052,7 +1049,7 @@ unsigned long dtls1_output_cert_chain(SSL *s, X509 *x) } X509_STORE_CTX_cleanup(&xs_ctx); } - /* Thawte special :-) */ + /* Thawte special :-) */ for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++) { x=sk_X509_value(s->ctx->extra_certs,i); @@ -1087,7 +1084,11 @@ int dtls1_read_failed(SSL *s, int code) return code; } - if ( ! SSL_in_init(s)) /* done, no need to send a retransmit */ +#ifndef OPENSSL_NO_HEARTBEATS + if (!SSL_in_init(s) && !s->tlsext_hb_pending) /* done, no need to send a retransmit */ +#else + if (!SSL_in_init(s)) /* done, no need to send a retransmit */ +#endif { BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ); return code; @@ -1156,7 +1157,7 @@ dtls1_buffer_message(SSL *s, int is_ccs) { pitem *item; hm_fragment *frag; - PQ_64BIT seq64; + unsigned char seq64be[8]; /* this function is called immediately after a message has * been serialized */ @@ -1169,7 +1170,7 @@ dtls1_buffer_message(SSL *s, int is_ccs) if ( is_ccs) { OPENSSL_assert(s->d1->w_msg_hdr.msg_len + - DTLS1_CCS_HEADER_LENGTH <= (unsigned int)s->init_num); + ((s->version==DTLS1_VERSION)?DTLS1_CCS_HEADER_LENGTH:3) == (unsigned int)s->init_num); } else { @@ -1190,15 +1191,14 @@ dtls1_buffer_message(SSL *s, int is_ccs) frag->msg_header.saved_retransmit_state.compress = s->compress; frag->msg_header.saved_retransmit_state.session = s->session; frag->msg_header.saved_retransmit_state.epoch = s->d1->w_epoch; + + memset(seq64be,0,sizeof(seq64be)); + seq64be[6] = (unsigned char)(dtls1_get_queue_priority(frag->msg_header.seq, + frag->msg_header.is_ccs)>>8); + seq64be[7] = (unsigned char)(dtls1_get_queue_priority(frag->msg_header.seq, + frag->msg_header.is_ccs)); - pq_64bit_init(&seq64); - - pq_64bit_assign_word(&seq64, - dtls1_get_queue_priority(frag->msg_header.seq, - frag->msg_header.is_ccs)); - - item = pitem_new(seq64, frag); - pq_64bit_free(&seq64); + item = pitem_new(seq64be, frag); if ( item == NULL) { dtls1_hm_fragment_free(frag); @@ -1224,7 +1224,7 @@ dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, pitem *item; hm_fragment *frag ; unsigned long header_length; - PQ_64BIT seq64; + unsigned char seq64be[8]; struct dtls1_retransmit_state saved_state; unsigned char save_write_sequence[8]; @@ -1234,11 +1234,11 @@ dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, */ /* XDTLS: the requested message ought to be found, otherwise error */ - pq_64bit_init(&seq64); - pq_64bit_assign_word(&seq64, seq); + memset(seq64be,0,sizeof(seq64be)); + seq64be[6] = (unsigned char)(seq>>8); + seq64be[7] = (unsigned char)seq; - item = pqueue_find(s->d1->sent_messages, seq64); - pq_64bit_free(&seq64); + item = pqueue_find(s->d1->sent_messages, seq64be); if ( item == NULL) { fprintf(stderr, "retransmit: message %d non-existant\n", seq); @@ -1390,7 +1390,7 @@ dtls1_min_mtu(void) static unsigned int dtls1_guess_mtu(unsigned int curr_mtu) { - size_t i; + unsigned int i; if ( curr_mtu == 0 ) return g_probable_mtu[0] ; @@ -1421,3 +1421,171 @@ dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr) 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; + } + +#ifndef OPENSSL_NO_HEARTBEATS +int +dtls1_process_heartbeat(SSL *s) + { + unsigned char *p = &s->s3->rrec.data[0], *pl; + unsigned short hbtype; + unsigned int payload; + unsigned int padding = 16; /* Use minimum padding */ + + /* Read type and payload length first */ + hbtype = *p++; + n2s(p, payload); + pl = p; + + if (s->msg_callback) + s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT, + &s->s3->rrec.data[0], s->s3->rrec.length, + s, s->msg_callback_arg); + + if (hbtype == TLS1_HB_REQUEST) + { + unsigned char *buffer, *bp; + int r; + + /* Allocate memory for the response, size is 1 byte + * message type, plus 2 bytes payload length, plus + * payload, plus padding + */ + buffer = OPENSSL_malloc(1 + 2 + payload + padding); + bp = buffer; + + /* Enter response type, length and copy payload */ + *bp++ = TLS1_HB_RESPONSE; + s2n(payload, bp); + memcpy(bp, pl, payload); + bp += payload; + /* Random padding */ + RAND_pseudo_bytes(bp, padding); + + r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding); + + if (r >= 0 && s->msg_callback) + s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, + buffer, 3 + payload + padding, + s, s->msg_callback_arg); + + OPENSSL_free(buffer); + + if (r < 0) + return r; + } + 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; + } + +int +dtls1_heartbeat(SSL *s) + { + unsigned char *buf, *p; + int ret; + unsigned int payload = 18; /* Sequence number + random bytes */ + unsigned int padding = 16; /* Use minimum padding */ + + /* Only send if peer supports and accepts HB requests... */ + if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) || + s->tlsext_heartbeat & SSL_TLSEXT_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) || s->in_handshake) + { + SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_UNEXPECTED_MESSAGE); + return -1; + } + + /* Check if padding is too long, payload and padding + * must not exceed 2^14 - 3 = 16381 bytes in total. + */ + OPENSSL_assert(payload + padding <= 16381); + + /* Create HeartBeat message, we just use a sequence number + * as payload to distuingish different messages and add + * some random stuff. + * - Message Type, 1 byte + * - Payload Length, 2 bytes (unsigned int) + * - Payload, the sequence number (2 bytes uint) + * - Payload, random bytes (16 bytes uint) + * - Padding + */ + buf = OPENSSL_malloc(1 + 2 + payload + padding); + 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 */ + RAND_pseudo_bytes(p, 16); + p += 16; + /* Random padding */ + RAND_pseudo_bytes(p, padding); + + ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding); + if (ret >= 0) + { + if (s->msg_callback) + s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, + buf, 3 + payload + padding, + s, s->msg_callback_arg); + + dtls1_start_timer(s); + s->tlsext_hb_pending = 1; + } + + OPENSSL_free(buf); + + return ret; + } +#endif |