-#ifndef OPENSSL_NO_HEARTBEATS
-int tls1_process_heartbeat(SSL *s, unsigned char *p, unsigned int length)
-{
- unsigned char *pl;
- unsigned short hbtype;
- unsigned int payload;
- unsigned int padding = 16; /* Use minimum padding */
-
- if (s->msg_callback)
- s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
- p, length,
- s, s->msg_callback_arg);
-
- /* Read type and payload length first */
- if (1 + 2 + 16 > length)
- return 0; /* silently discard */
- hbtype = *p++;
- n2s(p, payload);
- if (1 + 2 + payload + 16 > length)
- return 0; /* silently discard per RFC 6520 sec. 4 */
- pl = p;
-
- if (hbtype == TLS1_HB_REQUEST) {
- unsigned char *buffer, *bp;
- int r;
-
- /*
- * Allocate memory for the response, size is 1 bytes message type,
- * plus 2 bytes payload length, plus payload, plus padding
- */
- buffer = OPENSSL_malloc(1 + 2 + payload + padding);
- if (buffer == NULL) {
- SSLerr(SSL_F_TLS1_PROCESS_HEARTBEAT, ERR_R_MALLOC_FAILURE);
- 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 = ssl3_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) {
- s->tlsext_hb_seq++;
- s->tlsext_hb_pending = 0;
- }
- }
-
- return 0;
-}
-
-int tls1_heartbeat(SSL *s)
-{
- unsigned char *buf, *p;
- int ret = -1;
- 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_TLS1_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_TLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PENDING);
- return -1;
- }
-
- /* ...and no handshake in progress. */
- if (SSL_in_init(s) || s->in_handshake) {
- SSLerr(SSL_F_TLS1_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);
- if (buf == NULL) {
- SSLerr(SSL_F_TLS1_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_TLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- p += 16;
- /* Random padding */
- if (RAND_bytes(p, padding) <= 0) {
- SSLerr(SSL_F_TLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- ret = ssl3_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);
-
- s->tlsext_hb_pending = 1;
- }
-
- err:
- OPENSSL_free(buf);
- return ret;
-}
-#endif
-