- /*
- * In case of record types for which we have 'fragment' storage, fill
- * that so that we can process the data at a fixed place.
- */
- {
- unsigned int k, dest_maxlen = 0;
- unsigned char *dest = NULL;
- unsigned int *dest_len = NULL;
-
- if (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) {
- dest_maxlen = sizeof s->rlayer.d->handshake_fragment;
- dest = s->rlayer.d->handshake_fragment;
- dest_len = &s->rlayer.d->handshake_fragment_len;
- } else if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) {
- dest_maxlen = sizeof(s->rlayer.d->alert_fragment);
- dest = s->rlayer.d->alert_fragment;
- dest_len = &s->rlayer.d->alert_fragment_len;
- }
-#ifndef OPENSSL_NO_HEARTBEATS
- else if (SSL3_RECORD_get_type(rr) == TLS1_RT_HEARTBEAT) {
- /* We allow a 0 return */
- if (dtls1_process_heartbeat(s, SSL3_RECORD_get_data(rr),
- SSL3_RECORD_get_length(rr)) < 0) {
- return -1;
- }
- /* Exit and notify application to read again */
- SSL3_RECORD_set_length(rr, 0);
- s->rwstate = SSL_READING;
- BIO_clear_retry_flags(SSL_get_rbio(s));
- BIO_set_retry_read(SSL_get_rbio(s));
- return (-1);
- }
-#endif
- /* else it's a CCS message, or application data or wrong */
- else if (SSL3_RECORD_get_type(rr) != SSL3_RT_CHANGE_CIPHER_SPEC) {
- /*
- * Application data while renegotiating is allowed. Try again
- * reading.
- */
- if (SSL3_RECORD_get_type(rr) == SSL3_RT_APPLICATION_DATA) {
- BIO *bio;
- s->s3->in_read_app_data = 2;
- bio = SSL_get_rbio(s);
- s->rwstate = SSL_READING;
- BIO_clear_retry_flags(bio);
- BIO_set_retry_read(bio);
- return (-1);
- }
-
- /* Not certain if this is the right error handling */
- al = SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD);
- goto f_err;
- }
-
- if (dest_maxlen > 0) {
- /*
- * XDTLS: In a pathalogical case, the Client Hello may be
- * fragmented--don't always expect dest_maxlen bytes
- */
- if (SSL3_RECORD_get_length(rr) < dest_maxlen) {
-#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
- /*
- * for normal alerts rr->length is 2, while
- * dest_maxlen is 7 if we were to handle this
- * non-existing alert...
- */
- FIX ME
-#endif
- s->rlayer.rstate = SSL_ST_READ_HEADER;
- SSL3_RECORD_set_length(rr, 0);
- goto start;
- }
-
- /* now move 'n' bytes: */
- for (k = 0; k < dest_maxlen; k++) {
- dest[k] = SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)];
- SSL3_RECORD_add_off(rr, 1);
- SSL3_RECORD_add_length(rr, -1);
- }
- *dest_len = dest_maxlen;
- }
- }
-
- /*-
- * s->rlayer.d->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE;
- * s->rlayer.d->alert_fragment_len == 7 iff rr->type == SSL3_RT_ALERT.
- * (Possibly rr is 'empty' now, i.e. rr->length may be 0.)
- */
-
- /* If we are a client, check for an incoming 'Hello Request': */
- if ((!s->server) &&
- (s->rlayer.d->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
- (s->rlayer.d->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
- (s->session != NULL) && (s->session->cipher != NULL)) {
- s->rlayer.d->handshake_fragment_len = 0;
-
- if ((s->rlayer.d->handshake_fragment[1] != 0) ||
- (s->rlayer.d->handshake_fragment[2] != 0) ||
- (s->rlayer.d->handshake_fragment[3] != 0)) {
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_BAD_HELLO_REQUEST);
- goto f_err;
+ if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) {
+ unsigned int alert_level, alert_descr;
+ unsigned char *alert_bytes = SSL3_RECORD_get_data(rr)
+ + SSL3_RECORD_get_off(rr);
+ PACKET alert;
+
+ if (!PACKET_buf_init(&alert, alert_bytes, SSL3_RECORD_get_length(rr))
+ || !PACKET_get_1(&alert, &alert_level)
+ || !PACKET_get_1(&alert, &alert_descr)
+ || PACKET_remaining(&alert) != 0) {
+ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_DTLS1_READ_BYTES,
+ SSL_R_INVALID_ALERT);
+ return -1;