Commit 07a9d1a2 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

PR: 2028

Submitted by: Robin Seggelmann <seggelmann@fh-muenster.de>
Approved by: steve@openssl.org

Fix DTLS cookie management bugs.
parent 88a3dd78
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -171,3 +171,6 @@ void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type,
					unsigned char *data, int len,
					void *arg);
#endif

int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len);
int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int cookie_len);
+88 −0
Original line number Diff line number Diff line
@@ -117,13 +117,18 @@
#undef NON_MAIN
#undef USE_SOCKETS
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include "s_apps.h"

#define	COOKIE_SECRET_LENGTH	16

int verify_depth=0;
int verify_error=X509_V_OK;
int verify_return_error=0;
unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
int cookie_initialized=0;

int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx)
	{
@@ -682,3 +687,86 @@ void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type,
	BIO_dump(bio, (char *)data, len);
	(void)BIO_flush(bio);
	}

int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
	{
	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
	unsigned int length, resultlength;
	struct sockaddr_in peer;
	
	/* Initialize a random secret */
	if (!cookie_initialized)
		{
		if (!RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH))
			{
			BIO_printf(bio_err,"error setting random cookie secret\n");
			return 0;
			}
		cookie_initialized = 1;
		}

	/* Read peer information */
	(void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

	/* Create buffer with peer's address and port */
	length = sizeof(peer.sin_addr);
	length += sizeof(peer.sin_port);
	buffer = OPENSSL_malloc(length);

	if (buffer == NULL)
		{
		BIO_printf(bio_err,"out of memory\n");
		return 0;
		}
	
	memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr));
	memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port));

	/* Calculate HMAC of buffer using the secret */
	HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
	     buffer, length, result, &resultlength);
	OPENSSL_free(buffer);

	memcpy(cookie, result, resultlength);
	*cookie_len = resultlength;

	return 1;
	}

int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int cookie_len)
	{
	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
	unsigned int length, resultlength;
	struct sockaddr_in peer;
	
	/* If secret isn't initialized yet, the cookie can't be valid */
	if (!cookie_initialized)
		return 0;

	/* Read peer information */
	(void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

	/* Create buffer with peer's address and port */
	length = sizeof(peer.sin_addr);
	length += sizeof(peer.sin_port);
	buffer = OPENSSL_malloc(length);
	
	if (buffer == NULL)
		{
		BIO_printf(bio_err,"out of memory\n");
		return 0;
		}
	
	memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr));
	memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port));

	/* Calculate HMAC of buffer using the secret */
	HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
	     buffer, length, result, &resultlength);
	OPENSSL_free(buffer);
	
	if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0)
		return 1;

	return 0;
	}
+4 −0
Original line number Diff line number Diff line
@@ -1654,6 +1654,10 @@ bad:
	SSL_CTX_set_session_id_context(ctx,(void*)&s_server_session_id_context,
		sizeof s_server_session_id_context);

	/* Set DTLS cookie generation and verification callbacks */
	SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie_callback);
	SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie_callback);

#ifndef OPENSSL_NO_TLSEXT
	if (ctx2)
		{
+3 −0
Original line number Diff line number Diff line
@@ -157,6 +157,7 @@ extern "C" {
					      * previous write
					      * operation */

#define BIO_CTRL_DGRAM_GET_PEER           46
#define BIO_CTRL_DGRAM_SET_PEER           44 /* Destination for the data */

#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT   45 /* Next DTLS handshake timeout to
@@ -538,6 +539,8 @@ int BIO_ctrl_reset_read_request(BIO *b);
         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP, 0, NULL)
#define BIO_dgram_send_timedout(b) \
         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP, 0, NULL)
#define BIO_dgram_get_peer(b,peer) \
         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_PEER, 0, (char *)peer)
#define BIO_dgram_set_peer(b,peer) \
         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, (char *)peer)

+9 −3
Original line number Diff line number Diff line
@@ -290,11 +290,11 @@ static int dgram_read(BIO *b, char *out, int outl)
		ret=recvfrom(b->num,out,outl,0,&peer,(void *)&peerlen);
		dgram_reset_rcv_timeout(b);

		if ( ! data->connected  && ret > 0)
			BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, &peer);
		if ( ! data->connected  && ret >= 0)
			BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer);

		BIO_clear_retry_flags(b);
		if (ret <= 0)
		if (ret < 0)
			{
			if (BIO_dgram_should_retry(ret))
				{
@@ -518,6 +518,12 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
			memset(&(data->peer), 0x00, sizeof(struct sockaddr));
			}
		break;
    case BIO_CTRL_DGRAM_GET_PEER:
        to = (struct sockaddr *) ptr;

        memcpy(to, &(data->peer), sizeof(struct sockaddr));
		ret = sizeof(struct sockaddr);
        break;
    case BIO_CTRL_DGRAM_SET_PEER:
        to = (struct sockaddr *) ptr;

Loading