/* Provenance: OpenSSL tls1_process_heartbeat after Heartbleed bounds check. * repo: openssl/openssl * commit: 96db9023b881d7cd9f379b0c154650d6c108e9a3 * parent: 0d7717fc9c83dafab8153cbd5e2180e6e04cc802 * commit_url: https://github.com/openssl/openssl/commit/96db9023b881d7cd9f379b0c154650d6c108e9a3 * cve: CVE-2014-0160 * license: OpenSSL License * function: tls1_process_heartbeat * relpath: ssl/t1_lib.c */ #include #include typedef struct ssl_st { struct { struct { unsigned char *data; unsigned int length; } rrec; } *s3; int version; void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, void *ssl, void *arg); void *msg_callback_arg; unsigned int tlsext_hb_seq; unsigned int tlsext_hb_pending; } SSL; #define TLS1_RT_HEARTBEAT 24 #define TLS1_HB_REQUEST 1 #define TLS1_HB_RESPONSE 2 #define n2s(c, s) ((s = (((unsigned int)((c)[0])) << 8) | (((unsigned int)((c)[1])))), (c) += 2) #define s2n(s, c) (((c)[0] = (unsigned char)(((s) >> 8) & 0xff), (c)[1] = (unsigned char)(((s)) & 0xff)), (c) += 2) static unsigned char *OPENSSL_malloc(unsigned int n) { return (unsigned char *)malloc(n); } static void OPENSSL_free(void *p) { free(p); } static int RAND_pseudo_bytes(unsigned char *buf, unsigned int n) { (void)buf; (void)n; return 1; } static int ssl3_write_bytes(SSL *s, int type, unsigned char *buf, unsigned int len) { (void)s; (void)type; (void)buf; return (int)len; } int tls1_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 */ 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); /* Read type and payload length first */ if (1 + 2 + 16 > s->s3->rrec.length) return 0; /* silently discard */ hbtype = *p++; n2s(p, payload); if (1 + 2 + payload + 16 > s->s3->rrec.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); 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 = 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; }