diff --git a/cyassl/internal.h b/cyassl/internal.h index dfc58559d..7081430eb 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -374,6 +374,7 @@ enum Misc { SEED_LEN = RAN_LEN * 2, /* tls prf seed length */ ID_LEN = 32, /* session id length */ MAX_COOKIE_LEN = 32, /* max dtls cookie size */ + COOKIE_SZ = 20, /* use a 20 byte cookie */ SUITE_LEN = 2, /* cipher suite sz length */ ENUM_LEN = 1, /* always a byte */ COMP_LEN = 1, /* compression length */ @@ -650,6 +651,8 @@ int SetCipherList(Suites*, const char* list); #endif #ifdef CYASSL_DTLS + CYASSL_LOCAL + int EmbedGenerateCookie(byte *buf, int sz, void *ctx); CYASSL_LOCAL int IsUDP(void*); #endif @@ -1127,6 +1130,7 @@ typedef struct Arrays { byte masterSecret[SECRET_LEN]; #ifdef CYASSL_DTLS byte cookie[MAX_COOKIE_LEN]; + byte cookieSz; #endif #ifndef NO_PSK char client_identity[MAX_PSK_ID_LEN]; diff --git a/src/internal.c b/src/internal.c index 86c8bfcc7..11f4df2a6 100644 --- a/src/internal.c +++ b/src/internal.c @@ -4398,6 +4398,7 @@ int SetCipherList(Suites* s, const char* list) #ifdef CYASSL_DTLS if (ssl->options.dtls) { length += ENUM_LEN; /* cookie */ + if (ssl->arrays.cookieSz != 0) length += ssl->arrays.cookieSz; sendSz = length + DTLS_HANDSHAKE_HEADER_SZ + DTLS_RECORD_HEADER_SZ; idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; } @@ -4442,7 +4443,13 @@ int SetCipherList(Suites* s, const char* list) /* then DTLS cookie */ #ifdef CYASSL_DTLS if (ssl->options.dtls) { - output[idx++] = 0; + byte cookieSz = ssl->arrays.cookieSz; + + output[idx++] = cookieSz; + if (cookieSz) { + XMEMCPY(&output[idx], ssl->arrays.cookie, cookieSz); + idx += cookieSz; + } } #endif /* then cipher suites */ @@ -4513,8 +4520,15 @@ int SetCipherList(Suites* s, const char* list) cookieSz = input[(*inOutIdx)++]; - if (cookieSz) - *inOutIdx += cookieSz; /* skip for now */ + if (cookieSz) { +#ifdef CYASSL_DTLS + if (cookieSz < MAX_COOKIE_LEN) { + XMEMCPY(ssl->arrays.cookie, input + *inOutIdx, cookieSz); + ssl->arrays.cookieSz = cookieSz; + } +#endif + *inOutIdx += cookieSz; + } ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE; return 0; @@ -6411,11 +6425,16 @@ int SetCipherList(Suites* s, const char* list) if (ssl->options.dtls) { b = input[i++]; if (b) { + byte cookie[MAX_COOKIE_LEN]; + byte cookieSz; + if (b > MAX_COOKIE_LEN) return BUFFER_ERROR; if (i + b > totalSz) return INCOMPLETE_DATA; - XMEMCPY(ssl->arrays.cookie, input + i, b); + cookieSz = EmbedGenerateCookie(cookie, COOKIE_SZ, ssl); + if ((b != cookieSz) || XMEMCMP(cookie, input + i, b) != 0) + return PARSE_ERROR; i += b; } } @@ -6604,11 +6623,12 @@ int SetCipherList(Suites* s, const char* list) return SendBuffered(ssl); } - +#ifdef CYASSL_DTLS int SendHelloVerifyRequest(CYASSL* ssl) { byte* output; - int length = VERSION_SZ + ENUM_LEN; + byte cookieSz = COOKIE_SZ; + int length = VERSION_SZ + ENUM_LEN + cookieSz; int idx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ; int sendSz = length + idx; int ret; @@ -6625,7 +6645,10 @@ int SetCipherList(Suites* s, const char* list) XMEMCPY(output + idx, &ssl->chVersion, VERSION_SZ); idx += VERSION_SZ; - output[idx++] = 0; /* no cookie for now */ + + output[idx++] = cookieSz; + if ((ret = EmbedGenerateCookie(output + idx, cookieSz, ssl)) < 0) + return ret; HashOutput(ssl, output, sendSz, 0); #ifdef CYASSL_CALLBACKS @@ -6641,7 +6664,7 @@ int SetCipherList(Suites* s, const char* list) return SendBuffered(ssl); } - +#endif static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32* inOutIdx) diff --git a/src/io.c b/src/io.c index 865a2486b..cf38c8a66 100644 --- a/src/io.c +++ b/src/io.c @@ -29,6 +29,7 @@ #endif #include +#include /* if user writes own I/O callbacks they can define CYASSL_USER_IO to remove automatic setting of default I/O functions EmbedSend() and EmbedReceive() @@ -200,6 +201,46 @@ int EmbedSend(char *buf, int sz, void *ctx) } +/* The DTLS Generate Cookie callback + * return : number of bytes copied into buf, or error + */ +int EmbedGenerateCookie(byte *buf, int sz, void *ctx) +{ + CYASSL* ssl = (CYASSL*)ctx; + int sd = ssl->wfd; + struct sockaddr_storage peer; + socklen_t peerSz = sizeof(peer); + byte cookieSrc[sizeof(struct in6_addr) + sizeof(int)]; + int cookieSrcSz = 0; + Sha sha; + + getpeername(sd, (struct sockaddr*)&peer, &peerSz); + + if (peer.ss_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in*)&peer; + + cookieSrcSz = sizeof(struct in_addr) + sizeof(s->sin_port); + XMEMCPY(cookieSrc, &s->sin_port, sizeof(s->sin_port)); + XMEMCPY(cookieSrc + sizeof(s->sin_port), + &s->sin_addr, sizeof(struct in_addr)); + } + else if (peer.ss_family == AF_INET6) { + struct sockaddr_in6 *s = (struct sockaddr_in6*)&peer; + + cookieSrcSz = sizeof(struct in6_addr) + sizeof(s->sin6_port); + XMEMCPY(cookieSrc, &s->sin6_port, sizeof(s->sin6_port)); + XMEMCPY(cookieSrc + sizeof(s->sin6_port), + &s->sin6_addr, sizeof(struct in6_addr)); + } + + InitSha(&sha); + ShaUpdate(&sha, cookieSrc, cookieSrcSz); + ShaFinal(&sha, buf); + + return SHA_DIGEST_SIZE; +} + + #endif /* CYASSL_USER_IO */ CYASSL_API void CyaSSL_SetIORecv(CYASSL_CTX *ctx, CallbackIORecv CBIORecv)