DTLS to use recvfrom and sendto in embed recv and send callbacks. Added support for storing dtls peer address.

This commit is contained in:
John Safranek 2012-10-02 09:15:50 -07:00
parent bd849ea9d7
commit 6d1e485ef4
9 changed files with 255 additions and 20 deletions

View File

@ -220,7 +220,8 @@ enum {
DYNAMIC_TYPE_CIPHER = 31,
DYNAMIC_TYPE_RNG = 32,
DYNAMIC_TYPE_ARRAYS = 33,
DYNAMIC_TYPE_DTLS_POOL = 34
DYNAMIC_TYPE_DTLS_POOL = 34,
DYNAMIC_TYPE_SOCKADDR = 35
};
/* stack protection */

View File

@ -671,6 +671,10 @@ int SetCipherList(Suites*, const char* list);
#endif
#ifdef CYASSL_DTLS
CYASSL_LOCAL
int EmbedReceiveFrom(CYASSL *ssl, char *buf, int sz, void *ctx);
CYASSL_LOCAL
int EmbedSendTo(CYASSL *ssl, char *buf, int sz, void *ctx);
CYASSL_LOCAL
int EmbedGenerateCookie(byte *buf, int sz, void *ctx);
CYASSL_LOCAL
@ -789,6 +793,18 @@ struct CYASSL_CERT_MANAGER {
};
/* CyaSSL Sock Addr */
struct CYASSL_SOCKADDR {
unsigned int sz; /* sockaddr size */
void* sa; /* pointer to the sockaddr_in or sockaddr_in6 */
};
typedef struct CYASSL_DTLS_CTX {
CYASSL_SOCKADDR peer;
int fd;
} CYASSL_DTLS_CTX;
/* CyaSSL context type */
struct CYASSL_CTX {
CYASSL_METHOD* method;
@ -1113,6 +1129,7 @@ typedef struct Buffers {
buffer dtlsHandshake; /* DTLS handshake defragment buf */
word32 dtlsUsed; /* DTLS bytes used in buffer */
byte dtlsType; /* DTLS handshake frag type */
CYASSL_DTLS_CTX dtlsCtx; /* DTLS connection context */
#endif
} Buffers;

View File

@ -66,6 +66,7 @@ typedef struct CYASSL_X509_NAME CYASSL_X509_NAME;
typedef struct CYASSL_X509_CHAIN CYASSL_X509_CHAIN;
typedef struct CYASSL_CERT_MANAGER CYASSL_CERT_MANAGER;
typedef struct CYASSL_SOCKADDR CYASSL_SOCKADDR;
/* redeclare guard */
#define CYASSL_TYPES_DEFINED
@ -222,6 +223,9 @@ CYASSL_API int CyaSSL_dtls_get_current_timeout(CYASSL* ssl);
CYASSL_API int CyaSSL_dtls_got_timeout(CYASSL* ssl);
CYASSL_API int CyaSSL_dtls(CYASSL* ssl);
CYASSL_API int CyaSSL_dtls_set_peer(CYASSL*, void*, unsigned int);
CYASSL_API int CyaSSL_dtls_get_peer(CYASSL*, void*, unsigned int*);
CYASSL_API int CyaSSL_ERR_GET_REASON(int err);
CYASSL_API char* CyaSSL_ERR_error_string(unsigned long,char*);
CYASSL_API void CyaSSL_ERR_error_string_n(unsigned long e, char* buf,

View File

@ -304,8 +304,8 @@ static INLINE void showPeer(CYASSL* ssl)
}
static INLINE void tcp_socket(SOCKET_T* sockfd, SOCKADDR_IN_T* addr,
const char* peer, word16 port, int udp)
static INLINE void build_addr(SOCKADDR_IN_T* addr,
const char* peer, word16 port)
{
#ifndef TEST_IPV6
const char* host = peer;
@ -326,10 +326,6 @@ static INLINE void tcp_socket(SOCKET_T* sockfd, SOCKADDR_IN_T* addr,
}
#endif
if (udp)
*sockfd = socket(AF_INET_V, SOCK_DGRAM, 0);
else
*sockfd = socket(AF_INET_V, SOCK_STREAM, 0);
memset(addr, 0, sizeof(SOCKADDR_IN_T));
#ifndef TEST_IPV6
@ -344,6 +340,15 @@ static INLINE void tcp_socket(SOCKET_T* sockfd, SOCKADDR_IN_T* addr,
addr->sin6_port = htons(port);
addr->sin6_addr = in6addr_loopback;
#endif
}
static INLINE void tcp_socket(SOCKET_T* sockfd, int udp)
{
if (udp)
*sockfd = socket(AF_INET_V, SOCK_DGRAM, 0);
else
*sockfd = socket(AF_INET_V, SOCK_STREAM, 0);
#ifndef USE_WINDOWS_API
#ifdef SO_NOSIGPIPE
@ -374,9 +379,19 @@ static INLINE void tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port,
int udp)
{
SOCKADDR_IN_T addr;
tcp_socket(sockfd, &addr, ip, port, udp);
build_addr(&addr, ip, port);
tcp_socket(sockfd, udp);
if (connect(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
if (!udp) {
if (connect(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
err_sys("tcp connect failed");
}
}
static INLINE void udp_connect(SOCKET_T* sockfd, void* addr, int addrSz)
{
if (connect(*sockfd, (const struct sockaddr*)addr, addrSz) != 0)
err_sys("tcp connect failed");
}
@ -388,10 +403,8 @@ static INLINE void tcp_listen(SOCKET_T* sockfd, int port, int useAnyAddr,
/* don't use INADDR_ANY by default, firewall may block, make user switch
on */
if (useAnyAddr)
tcp_socket(sockfd, &addr, INADDR_ANY, port, udp);
else
tcp_socket(sockfd, &addr, yasslIP, port, udp);
build_addr(&addr, (useAnyAddr ? INADDR_ANY : yasslIP), port);
tcp_socket(sockfd, udp);
#ifndef USE_WINDOWS_API
{
@ -434,8 +447,9 @@ static INLINE void udp_accept(SOCKET_T* sockfd, int* clientfd, func_args* args)
{
SOCKADDR_IN_T addr;
(void)args;
tcp_socket(sockfd, &addr, yasslIP, yasslPort, 1);
(void)args;
build_addr(&addr, yasslIP, yasslPort);
tcp_socket(sockfd, 1);
#ifndef USE_WINDOWS_API

View File

@ -342,10 +342,18 @@ void client_test(void* args)
exit(EXIT_SUCCESS);
}
tcp_connect(&sockfd, host, port, doDTLS);
ssl = CyaSSL_new(ctx);
if (ssl == NULL)
err_sys("unable to get SSL object");
if (doDTLS) {
SOCKADDR_IN_T addr;
build_addr(&addr, host, port);
CyaSSL_dtls_set_peer(ssl, &addr, sizeof(addr));
tcp_socket(&sockfd, 1);
}
else {
tcp_connect(&sockfd, host, port, 0);
}
CyaSSL_set_fd(ssl, sockfd);
#ifdef HAVE_CRL
if (CyaSSL_EnableCRL(ssl, CYASSL_CRL_CHECKALL) != SSL_SUCCESS)

View File

@ -70,8 +70,6 @@ void echoclient_test(void* args)
doDTLS = 1;
#endif
tcp_connect(&sockfd, yasslIP, yasslPort, doDTLS);
#if defined(CYASSL_DTLS)
method = DTLSv1_client_method();
#elif !defined(NO_TLS)
@ -102,6 +100,16 @@ void echoclient_test(void* args)
#endif
ssl = SSL_new(ctx);
if (doDTLS) {
SOCKADDR_IN_T addr;
build_addr(&addr, yasslIP, yasslPort);
CyaSSL_dtls_set_peer(ssl, &addr, sizeof(addr));
tcp_socket(&sockfd, 1);
}
else {
tcp_connect(&sockfd, yasslIP, yasslPort, 0);
}
SSL_set_fd(ssl, sockfd);
#if defined(USE_WINDOWS_API) && defined(CYASSL_DTLS) && defined(NO_MAIN_DRIVER)
/* let echoserver bind first, TODO: add Windows signal like pthreads does */

View File

@ -344,6 +344,13 @@ int InitSSL_Ctx(CYASSL_CTX* ctx, CYASSL_METHOD* method)
#ifndef CYASSL_USER_IO
ctx->CBIORecv = EmbedReceive;
ctx->CBIOSend = EmbedSend;
#ifdef CYASSL_DTLS
if (method->version.major == DTLS_MAJOR
&& method->version.minor == DTLS_MINOR) {
ctx->CBIORecv = EmbedReceiveFrom;
ctx->CBIOSend = EmbedSendTo;
}
#endif
#else
/* user will set */
ctx->CBIORecv = NULL;
@ -1000,7 +1007,10 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx)
ssl->heap = ctx->heap; /* defaults to self */
ssl->options.tls = 0;
ssl->options.tls1_1 = 0;
ssl->options.dtls = 0;
if (ssl->version.major == DTLS_MAJOR && ssl->version.minor == DTLS_MINOR)
ssl->options.dtls = 1;
else
ssl->options.dtls = 0;
ssl->options.partialWrite = ctx->partialWrite;
ssl->options.quietShutdown = ctx->quietShutdown;
ssl->options.certOnly = 0;
@ -1024,6 +1034,9 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx)
ssl->buffers.dtlsHandshake.length = 0;
ssl->buffers.dtlsHandshake.buffer = NULL;
ssl->buffers.dtlsType = 0;
ssl->buffers.dtlsCtx.fd = -1;
ssl->buffers.dtlsCtx.peer.sa = NULL;
ssl->buffers.dtlsCtx.peer.sz = 0;
#endif
#ifdef OPENSSL_EXTRA
@ -1181,6 +1194,8 @@ void SSL_ResourceFree(CYASSL* ssl)
DtlsPoolReset(ssl);
XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_NONE);
}
XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR);
ssl->buffers.dtlsCtx.peer.sa = NULL;
#endif
#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
XFREE(ssl->peerCert.derCert.buffer, ssl->heap, DYNAMIC_TYPE_CERT);

124
src/io.c
View File

@ -86,7 +86,7 @@
#define WSAEPIPE -12345
#endif
#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
#define SOCKET_EAGAIN WSAEWOULDBLOCK
#define SOCKET_EAGAIN WSAETIMEDOUT
#define SOCKET_ECONNRESET WSAECONNRESET
#define SOCKET_EINTR WSAEINTR
#define SOCKET_EPIPE WSAEPIPE
@ -255,6 +255,128 @@ int EmbedSend(CYASSL* ssl, char *buf, int sz, void *ctx)
#define XSOCKLENT socklen_t
#endif
#define SENDTO_FUNCTION sendto
#define RECVFROM_FUNCTION recvfrom
/* The receive embedded callback
* return : nb bytes read, or error
*/
int EmbedReceiveFrom(CYASSL *ssl, char *buf, int sz, void *ctx)
{
CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
int recvd;
int err;
int sd = dtlsCtx->fd;
int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
struct sockaddr_in peer;
XSOCKLENT peerSz = sizeof(peer);
CYASSL_ENTER("EmbedReceiveFrom()");
if (!CyaSSL_get_using_nonblock(ssl) && dtls_timeout != 0) {
#ifdef USE_WINDOWS_API
DWORD timeout = dtls_timeout;
#else
struct timeval timeout = {dtls_timeout, 0};
#endif
setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO,
(char*)&timeout, sizeof(timeout));
}
recvd = RECVFROM_FUNCTION(sd, (char *)buf, sz, 0,
(struct sockaddr*)&peer, &peerSz);
if (recvd < 0) {
err = LastError();
CYASSL_MSG("Embed Receive From error");
if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
if (CyaSSL_get_using_nonblock(ssl)) {
CYASSL_MSG(" Would block");
return IO_ERR_WANT_READ;
}
else {
CYASSL_MSG(" Socket timeout");
return IO_ERR_TIMEOUT;
}
}
else if (err == SOCKET_ECONNRESET) {
CYASSL_MSG(" Connection reset");
return IO_ERR_CONN_RST;
}
else if (err == SOCKET_EINTR) {
CYASSL_MSG(" Socket interrupted");
return IO_ERR_ISR;
}
else if (err == SOCKET_ECONNREFUSED) {
CYASSL_MSG(" Connection refused");
return IO_ERR_WANT_READ;
}
else {
CYASSL_MSG(" General error");
return IO_ERR_GENERAL;
}
}
else {
if (dtlsCtx != NULL
&& dtlsCtx->peer.sz > 0
&& peerSz != dtlsCtx->peer.sz
&& memcmp(&peer, dtlsCtx->peer.sa, peerSz) != 0) {
CYASSL_MSG(" Ignored packet from invalid peer");
return IO_ERR_WANT_READ;
}
}
return recvd;
}
/* The send embedded callback
* return : nb bytes sent, or error
*/
int EmbedSendTo(CYASSL* ssl, char *buf, int sz, void *ctx)
{
CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
int sd = dtlsCtx->fd;
int sent;
int len = sz;
int err;
(void)ssl;
CYASSL_ENTER("EmbedSendTo()");
sent = SENDTO_FUNCTION(sd, &buf[sz - len], len, 0,
dtlsCtx->peer.sa, dtlsCtx->peer.sz);
if (sent < 0) {
err = LastError();
CYASSL_MSG("Embed Send To error");
if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
CYASSL_MSG(" Would Block");
return IO_ERR_WANT_WRITE;
}
else if (err == SOCKET_ECONNRESET) {
CYASSL_MSG(" Connection reset");
return IO_ERR_CONN_RST;
}
else if (err == SOCKET_EINTR) {
CYASSL_MSG(" Socket interrupted");
return IO_ERR_ISR;
}
else if (err == SOCKET_EPIPE) {
CYASSL_MSG(" Socket EPIPE");
return IO_ERR_CONN_CLOSE;
}
else {
CYASSL_MSG(" General error");
return IO_ERR_GENERAL;
}
}
return sent;
}
/* The DTLS Generate Cookie callback
* return : number of bytes copied into buf, or error

View File

@ -172,6 +172,14 @@ int CyaSSL_set_fd(CYASSL* ssl, int fd)
ssl->IOCB_ReadCtx = &ssl->rfd;
ssl->IOCB_WriteCtx = &ssl->wfd;
#ifdef CYASSL_DTLS
if (ssl->options.dtls) {
ssl->IOCB_ReadCtx = &ssl->buffers.dtlsCtx;
ssl->IOCB_WriteCtx = &ssl->buffers.dtlsCtx;
ssl->buffers.dtlsCtx.fd = fd;
}
#endif
CYASSL_LEAVE("SSL_set_fd", SSL_SUCCESS);
return SSL_SUCCESS;
}
@ -206,6 +214,44 @@ int CyaSSL_dtls(CYASSL* ssl)
}
int CyaSSL_dtls_set_peer(CYASSL* ssl, void* peer, unsigned int peerSz)
{
#ifdef CYASSL_DTLS
void* sa = (void*)XMALLOC(peerSz, ssl->heap, DYNAMIC_TYPE_SOCKADDR);
if (sa != NULL) {
XMEMCPY(sa, peer, peerSz);
ssl->buffers.dtlsCtx.peer.sa = sa;
ssl->buffers.dtlsCtx.peer.sz = peerSz;
return SSL_SUCCESS;
}
return SSL_FAILURE;
#else
(void)ssl;
(void)peer;
(void)peerSz;
return SSL_NOT_IMPLEMENTED;
#endif
}
int CyaSSL_dtls_get_peer(CYASSL* ssl, void* peer, unsigned int* peerSz)
{
#ifdef CYASSL_DTLS
if (peer != NULL && peerSz != NULL
&& *peerSz >= ssl->buffers.dtlsCtx.peer.sz) {
*peerSz = ssl->buffers.dtlsCtx.peer.sz;
XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz);
return SSL_SUCCESS;
}
return SSL_FAILURE;
#else
(void)ssl;
(void)peer;
(void)peerSz;
return SSL_NOT_IMPLEMENTED;
#endif
}
int CyaSSL_negotiate(CYASSL* ssl)
{
int err = SSL_FATAL_ERROR;