diff --git a/configure.ac b/configure.ac index 5ecb76338c..6cc2e2e10e 100644 --- a/configure.ac +++ b/configure.ac @@ -349,6 +349,29 @@ AS_IF([test "x$ENABLED_SCTP" = "xyes"], ]) +# DTLS-MULTICAST +AC_ARG_ENABLE([mcast], + [AS_HELP_STRING([--enable-mcast],[Enable wolfSSL DTLS multicast support (default: disabled)])], + [ENABLED_MCAST=$enableval], + [ENABLED_MCAST=no]) + +AM_CONDITIONAL([BUILD_MCAST], [test "x$ENABLED_MCAST" = "xyes"]) + + +# RNG +AC_ARG_ENABLE([rng], + [AS_HELP_STRING([--enable-rng],[Enable compiling and using RNG (default: enabled)])], + [ ENABLED_RNG=$enableval ], + [ ENABLED_RNG=yes ] + ) + +if test "$ENABLED_RNG" = "no" +then + AM_CFLAGS="$AM_CFLAGS -DWC_NO_RNG" +fi +AM_CONDITIONAL([BUILD_RNG], [test "x$ENABLED_RNG" = "xyes"]) + + # OpenSSH compatibility Build AC_ARG_ENABLE([openssh], [AS_HELP_STRING([--enable-openssh],[Enable OpenSSH compatibility build (default: disabled)])], @@ -3532,12 +3555,21 @@ AS_IF([test "x$ENABLED_MAXSTRENGTH" = "xyes" && \ AS_IF([test "x$ENABLED_SCTP" = "xyes"], [AM_CFLAGS="-DWOLFSSL_SCTP $AM_CFLAGS"]) -# SCTP requires DTLS -AS_IF([test "x$ENABLED_DTLS" = "xno" && \ - test "x$ENABLED_SCTP" = "xyes"], +AS_IF([test "x$ENABLED_MCAST" = "xyes"], + [AM_CFLAGS="-DWOLFSSL_MULTICAST $AM_CFLAGS"]) + +# SCTP and Multicast require DTLS +AS_IF([(test "x$ENABLED_DTLS" = "xno") && \ + (test "x$ENABLED_SCTP" = "xyes" || test "x$ENABLED_MCAST" = "xyes")], [AM_CFLAGS="-DWOLFSSL_DTLS $AM_CFLAGS" ENABLED_DTLS=yes]) +# Multicast requires the null cipher +AS_IF([test "x$ENABLED_NULL_CIPHER" = "xno" && \ + test "x$ENABLED_MCAST" = "xyes"], + [AM_CFLAGS="-DHAVE_NULL_CIPHER $AM_CFLAGS" + ENABLED_NULL_CIPHER=yes]) + ################################################################################ # OPTIMIZE FLAGS @@ -3816,6 +3848,7 @@ echo " * NGINX: $ENABLED_NGINX" echo " * ERROR_STRINGS: $ENABLED_ERROR_STRINGS" echo " * DTLS: $ENABLED_DTLS" echo " * SCTP: $ENABLED_SCTP" +echo " * Multicast: $ENABLED_MCAST" echo " * Old TLS Versions: $ENABLED_OLD_TLS" echo " * SSL version 3.0: $ENABLED_SSLV3" echo " * TLS v1.3: $ENABLED_TLS13" diff --git a/examples/client/client.c b/examples/client/client.c index 52f1ab8285..0e6b0c5cca 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -752,8 +752,12 @@ static void Usage(void) #ifdef WOLFSSL_EARLY_DATA printf("-0 Early data sent to server (0-RTT handshake)\n"); #endif +#ifdef WOLFSSL_MULTICAST + printf("-3 Multicast, grpid < 256\n"); +#endif } + THREAD_RETURN WOLFSSL_THREAD client_test(void* args) { SOCKET_T sockfd = WOLFSSL_SOCKET_INVALID; @@ -793,6 +797,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) int doDTLS = 0; int dtlsUDP = 0; int dtlsSCTP = 0; + int doMcast = 0; int matchName = 0; int doPeerCheck = 1; int nonBlocking = 0; @@ -856,6 +861,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifdef WOLFSSL_EARLY_DATA int earlyData = 0; #endif +#ifdef WOLFSSL_MULTICAST + byte mcastID = 0; +#endif #ifdef HAVE_OCSP int useOcsp = 0; @@ -905,7 +913,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) while ((ch = mygetopt(argc, argv, "?" "ab:c:defgh:ijk:l:mnop:q:rstuv:wxyz" "A:B:CDE:F:GHIJKL:M:NO:PQRS:TUVW:XYZ:" - "0")) != -1) { + "03:")) != -1) { switch (ch) { case '?' : Usage(); @@ -1231,6 +1239,13 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif break; + case '3' : + #ifdef WOLFSSL_MULTICAST + doMcast = 1; + mcastID = (byte)(atoi(myoptarg) & 0xFF); + #endif + break; + default: Usage(); exit(MY_EX_USAGE); @@ -1660,6 +1675,16 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) wolfSSL_CTX_allow_post_handshake_auth(ctx); #endif + if (doMcast) { +#ifdef WOLFSSL_MULTICAST + wolfSSL_CTX_mcast_set_member_id(ctx, mcastID); + if (wolfSSL_CTX_set_cipher_list(ctx, "WDM-NULL-SHA256") != SSL_SUCCESS) { + wolfSSL_CTX_free(ctx); + err_sys("Couldn't set multicast cipher list."); + } +#endif + } + ssl = wolfSSL_new(ctx); if (ssl == NULL) { wolfSSL_CTX_free(ctx); @@ -1705,6 +1730,25 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) } #endif + if (doMcast) { +#ifdef WOLFSSL_MULTICAST + byte pms[512]; /* pre master secret */ + byte cr[32]; /* client random */ + byte sr[32]; /* server random */ + const byte suite[2] = {0, 0xfe}; /* WDM_WITH_NULL_SHA256 */ + + XMEMSET(pms, 0x23, sizeof(pms)); + XMEMSET(cr, 0xA5, sizeof(cr)); + XMEMSET(sr, 0x5A, sizeof(sr)); + + if (wolfSSL_set_secret(ssl, 1, pms, sizeof(pms), cr, sr, suite) + != SSL_SUCCESS) { + wolfSSL_CTX_free(ctx); + err_sys("unable to set mcast secret"); + } +#endif + } + #ifdef HAVE_SESSION_TICKET wolfSSL_set_SessionTicket_cb(ssl, sessionTicketCB, (void*)"initial session"); #endif diff --git a/examples/server/server.c b/examples/server/server.c index 2c85e4c4cc..60ee22007a 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -416,6 +416,9 @@ static void Usage(void) #ifdef WOLFSSL_EARLY_DATA printf("-0 Early data read from client (0-RTT handshake)\n"); #endif +#ifdef WOLFSSL_MULTICAST + printf("-3 Multicast, grpid < 256\n"); +#endif } THREAD_RETURN CYASSL_THREAD server_test(void* args) @@ -445,6 +448,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) int doDTLS = 0; int dtlsUDP = 0; int dtlsSCTP = 0; + int doMcast = 0; int needDH = 0; int useNtruKey = 0; int nonBlocking = 0; @@ -510,6 +514,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #ifdef WOLFSSL_SEND_HRR_COOKIE int hrrCookie = 0; #endif + byte mcastID = 0; #ifdef WOLFSSL_STATIC_MEMORY #if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \ @@ -546,6 +551,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) (void)crlFlags; (void)readySignal; (void)updateKeysIVs; + (void)mcastID; #ifdef CYASSL_TIRTOS fdOpenSession(Task_self()); @@ -558,7 +564,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) while ((ch = mygetopt(argc, argv, "?" "abc:defgijk:l:nop:q:rsuv:wx" "A:B:C:D:E:GHIJKL:NO:PQR:S:UYZ:" - "0")) != -1) { + "03:")) != -1) { switch (ch) { case '?' : Usage(); @@ -795,6 +801,13 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #endif break; + case '3' : + #ifdef WOLFSSL_MULTICAST + doMcast = 1; + mcastID = (byte)(atoi(myoptarg) & 0xFF); + #endif + break; + default: Usage(); exit(MY_EX_USAGE); @@ -1119,6 +1132,14 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) } #endif + if (doMcast) { +#ifdef WOLFSSL_MULTICAST + wolfSSL_CTX_mcast_set_member_id(ctx, mcastID); + if (wolfSSL_CTX_set_cipher_list(ctx, "WDM-NULL-SHA256") != SSL_SUCCESS) + err_sys("Couldn't set multicast cipher list."); +#endif + } + ssl = SSL_new(ctx); if (ssl == NULL) err_sys_ex(runWithErrors, "unable to get SSL"); @@ -1143,6 +1164,23 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) } #endif + if (doMcast) { +#ifdef WOLFSSL_MULTICAST + byte pms[512]; + byte cr[32]; + byte sr[32]; + const byte suite[2] = {0, 0xfe}; /* WDM_WITH_NULL_SHA256 */ + + XMEMSET(pms, 0x23, sizeof(pms)); + XMEMSET(cr, 0xA5, sizeof(cr)); + XMEMSET(sr, 0x5A, sizeof(sr)); + + if (wolfSSL_set_secret(ssl, 1, pms, sizeof(pms), cr, sr, suite) + != SSL_SUCCESS) + err_sys("unable to set mcast secret"); +#endif + } + #ifndef NO_HANDSHAKE_DONE_CB wolfSSL_SetHsDoneCb(ssl, myHsDoneCb, NULL); #endif diff --git a/src/internal.c b/src/internal.c index 009c968868..59b207fe3a 100755 --- a/src/internal.c +++ b/src/internal.c @@ -534,14 +534,14 @@ static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) c32toa(keys->sequence_number_hi, exp + idx); idx += OPAQUE32_LEN; c32toa(keys->sequence_number_lo, exp + idx); idx += OPAQUE32_LEN; - c16toa(keys->nextEpoch, exp + idx); idx += OPAQUE16_LEN; - c16toa(keys->nextSeq_hi, exp + idx); idx += OPAQUE16_LEN; - c32toa(keys->nextSeq_lo, exp + idx); idx += OPAQUE32_LEN; + c16toa(keys->peerSeq[0].nextEpoch, exp + idx); idx += OPAQUE16_LEN; + c16toa(keys->peerSeq[0].nextSeq_hi, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->peerSeq[0].nextSeq_lo, exp + idx); idx += OPAQUE32_LEN; c16toa(keys->curEpoch, exp + idx); idx += OPAQUE16_LEN; c16toa(keys->curSeq_hi, exp + idx); idx += OPAQUE16_LEN; c32toa(keys->curSeq_lo, exp + idx); idx += OPAQUE32_LEN; - c16toa(keys->prevSeq_hi, exp + idx); idx += OPAQUE16_LEN; - c32toa(keys->prevSeq_lo, exp + idx); idx += OPAQUE32_LEN; + c16toa(keys->peerSeq[0].prevSeq_hi, exp + idx); idx += OPAQUE16_LEN; + c32toa(keys->peerSeq[0].prevSeq_lo, exp + idx); idx += OPAQUE32_LEN; c16toa(keys->dtls_peer_handshake_number, exp + idx); idx += OPAQUE16_LEN; c16toa(keys->dtls_expected_peer_handshake_number, exp + idx); @@ -563,12 +563,12 @@ static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) c16toa(WOLFSSL_DTLS_WINDOW_WORDS, exp + idx); idx += OPAQUE16_LEN; for (i = 0; i < WOLFSSL_DTLS_WINDOW_WORDS; i++) { - c32toa(keys->window[i], exp + idx); + c32toa(keys->peerSeq[0].window[i], exp + idx); idx += OPAQUE32_LEN; } c16toa(WOLFSSL_DTLS_WINDOW_WORDS, exp + idx); idx += OPAQUE16_LEN; for (i = 0; i < WOLFSSL_DTLS_WINDOW_WORDS; i++) { - c32toa(keys->prevWindow[i], exp + idx); + c32toa(keys->peerSeq[0].prevWindow[i], exp + idx); idx += OPAQUE32_LEN; } } @@ -672,14 +672,14 @@ static int ImportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) ato32(exp + idx, &keys->sequence_number_hi); idx += OPAQUE32_LEN; ato32(exp + idx, &keys->sequence_number_lo); idx += OPAQUE32_LEN; - ato16(exp + idx, &keys->nextEpoch); idx += OPAQUE16_LEN; - ato16(exp + idx, &keys->nextSeq_hi); idx += OPAQUE16_LEN; - ato32(exp + idx, &keys->nextSeq_lo); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->peerSeq[0].nextEpoch); idx += OPAQUE16_LEN; + ato16(exp + idx, &keys->peerSeq[0].nextSeq_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->peerSeq[0].nextSeq_lo); idx += OPAQUE32_LEN; ato16(exp + idx, &keys->curEpoch); idx += OPAQUE16_LEN; ato16(exp + idx, &keys->curSeq_hi); idx += OPAQUE16_LEN; ato32(exp + idx, &keys->curSeq_lo); idx += OPAQUE32_LEN; - ato16(exp + idx, &keys->prevSeq_hi); idx += OPAQUE16_LEN; - ato32(exp + idx, &keys->prevSeq_lo); idx += OPAQUE32_LEN; + ato16(exp + idx, &keys->peerSeq[0].prevSeq_hi); idx += OPAQUE16_LEN; + ato32(exp + idx, &keys->peerSeq[0].prevSeq_lo); idx += OPAQUE32_LEN; ato16(exp + idx, &keys->dtls_peer_handshake_number); idx += OPAQUE16_LEN; ato16(exp + idx, &keys->dtls_expected_peer_handshake_number); @@ -708,9 +708,9 @@ static int ImportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) wordAdj = (WOLFSSL_DTLS_WINDOW_WORDS - wordCount) * sizeof(word32); } - XMEMSET(keys->window, 0xFF, DTLS_SEQ_SZ); + XMEMSET(keys->peerSeq[0].window, 0xFF, DTLS_SEQ_SZ); for (i = 0; i < wordCount; i++) { - ato32(exp + idx, &keys->window[i]); + ato32(exp + idx, &keys->peerSeq[0].window[i]); idx += OPAQUE32_LEN; } idx += wordAdj; @@ -724,9 +724,9 @@ static int ImportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver) wordAdj = (WOLFSSL_DTLS_WINDOW_WORDS - wordCount) * sizeof(word32); } - XMEMSET(keys->prevWindow, 0xFF, DTLS_SEQ_SZ); + XMEMSET(keys->peerSeq[0].prevWindow, 0xFF, DTLS_SEQ_SZ); for (i = 0; i < wordCount; i++) { - ato32(exp + idx, &keys->prevWindow[i]); + ato32(exp + idx, &keys->peerSeq[0].prevWindow[i]); idx += OPAQUE32_LEN; } idx += wordAdj; @@ -3725,7 +3725,10 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) byte haveAnon = 0; byte newSSL; byte haveRSA = 0; - (void) haveAnon; /* Squash unused var warnings */ + byte haveMcast = 0; + + (void)haveAnon; /* Squash unused var warnings */ + (void)haveMcast; if (!ssl || !ctx) return BAD_FUNC_ARG; @@ -3751,6 +3754,9 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) #ifdef HAVE_ANON haveAnon = ctx->haveAnon; #endif /* HAVE_ANON*/ +#ifdef WOLFSSL_MULTICAST + haveMcast = ctx->haveMcast; +#endif /* WOLFSSL_MULTICAST */ /* decrement previous CTX reference count if exists. * This should only happen if switching ctxs!*/ @@ -3885,11 +3891,12 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->options.haveStaticECC, ssl->options.side); #if !defined(NO_CERTS) && !defined(WOLFSSL_SESSION_EXPORT) - /* make sure server has cert and key unless using PSK or Anon - * This should be true even if just switching ssl ctx */ - if (ssl->options.side == WOLFSSL_SERVER_END && !havePSK && !haveAnon) + /* make sure server has cert and key unless using PSK, Anon, or + * Multicast. This should be true even if just switching ssl ctx */ + if (ssl->options.side == WOLFSSL_SERVER_END && + !havePSK && !haveAnon && !haveMcast) if (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer - || !ssl->buffers.key || !ssl->buffers.key->buffer) { + || !ssl->buffers.key || !ssl->buffers.key->buffer) { WOLFSSL_MSG("Server missing certificate and/or private key"); return NO_PRIVATE_KEY; } @@ -4281,6 +4288,28 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) #ifdef HAVE_SESSION_TICKET ssl->session.ticket = ssl->session.staticTicket; #endif + +#ifdef WOLFSSL_MULTICAST + if (ctx->haveMcast) { + int i; + + ssl->options.haveMcast = 1; + ssl->options.mcastID = ctx->mcastID; + + /* Force the state to look like handshake has completed. */ + /* Keying material is supplied externally. */ + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + ssl->options.connectState = SECOND_REPLY_DONE; + ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE; + ssl->options.handShakeState = HANDSHAKE_DONE; + ssl->options.handShakeDone = 1; + + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) + ssl->keys.peerSeq[i].peerId = INVALID_PEER_ID; + } +#endif + return 0; } @@ -4889,18 +4918,42 @@ static INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2]) { if (order == PREV_ORDER) { /* Previous epoch case */ - seq[0] = ((ssl->keys.dtls_epoch - 1) << 16) | - (ssl->keys.dtls_prev_sequence_number_hi & 0xFFFF); + if (ssl->options.haveMcast) { + #ifdef WOLFSSL_MULTICAST + seq[0] = ((ssl->keys.dtls_epoch - 1) << 16) | + (ssl->options.mcastID << 8) | + (ssl->keys.dtls_prev_sequence_number_hi & 0xFF); + #endif + } + else + seq[0] = ((ssl->keys.dtls_epoch - 1) << 16) | + (ssl->keys.dtls_prev_sequence_number_hi & 0xFFFF); seq[1] = ssl->keys.dtls_prev_sequence_number_lo; } else if (order == PEER_ORDER) { - seq[0] = (ssl->keys.curEpoch << 16) | - (ssl->keys.curSeq_hi & 0xFFFF); + if (ssl->options.haveMcast) { + #ifdef WOLFSSL_MULTICAST + seq[0] = (ssl->keys.curEpoch << 16) | + (ssl->keys.curPeerId << 8) | + (ssl->keys.curSeq_hi & 0xFF); + #endif + } + else + seq[0] = (ssl->keys.curEpoch << 16) | + (ssl->keys.curSeq_hi & 0xFFFF); seq[1] = ssl->keys.curSeq_lo; /* explicit from peer */ } else { - seq[0] = (ssl->keys.dtls_epoch << 16) | - (ssl->keys.dtls_sequence_number_hi & 0xFFFF); + if (ssl->options.haveMcast) { + #ifdef WOLFSSL_MULTICAST + seq[0] = (ssl->keys.dtls_epoch << 16) | + (ssl->options.mcastID << 8) | + (ssl->keys.dtls_sequence_number_hi & 0xFF); + #endif + } + else + seq[0] = (ssl->keys.dtls_epoch << 16) | + (ssl->keys.dtls_sequence_number_hi & 0xFFFF); seq[1] = ssl->keys.dtls_sequence_number_lo; } } @@ -6200,7 +6253,14 @@ static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, *inOutIdx += ENUM_LEN + VERSION_SZ; ato16(input + *inOutIdx, &ssl->keys.curEpoch); *inOutIdx += OPAQUE16_LEN; - ato16(input + *inOutIdx, &ssl->keys.curSeq_hi); + if (ssl->options.haveMcast) { + #ifdef WOLFSSL_MULTICAST + ssl->keys.curPeerId = input[*inOutIdx]; + ssl->keys.curSeq_hi = input[*inOutIdx+1]; + #endif + } + else + ato16(input + *inOutIdx, &ssl->keys.curSeq_hi); *inOutIdx += OPAQUE16_LEN; ato32(input + *inOutIdx, &ssl->keys.curSeq_lo); *inOutIdx += OPAQUE32_LEN; /* advance past rest of seq */ @@ -7060,6 +7120,10 @@ static int BuildFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) return 1; break; #endif +#ifdef WOLFSSL_MULTICAST + case WDM_WITH_NULL_SHA256 : + break; +#endif default: WOLFSSL_MSG("Unsupported cipher suite, CipherRequires"); @@ -9552,16 +9616,41 @@ static INLINE int DtlsCheckWindow(WOLFSSL* ssl) word16 cur_hi, next_hi; word32 cur_lo, next_lo, diff; int curLT; + WOLFSSL_DTLS_PEERSEQ* peerSeq = NULL; - if (ssl->keys.curEpoch == ssl->keys.nextEpoch) { - next_hi = ssl->keys.nextSeq_hi; - next_lo = ssl->keys.nextSeq_lo; - window = ssl->keys.window; + if (!ssl->options.haveMcast) + peerSeq = ssl->keys.peerSeq; + else { +#ifdef WOLFSSL_MULTICAST + WOLFSSL_DTLS_PEERSEQ* p; + int i; + + for (i = 0, p = ssl->keys.peerSeq; + i < WOLFSSL_DTLS_PEERSEQ_SZ; + i++, p++) { + + if (p->peerId == ssl->keys.curPeerId) { + peerSeq = p; + break; + } + } + + if (peerSeq == NULL) { + WOLFSSL_MSG("Couldn't find that peer ID to check window."); + return 0; + } +#endif } - else if (ssl->keys.curEpoch == ssl->keys.nextEpoch - 1) { - next_hi = ssl->keys.prevSeq_hi; - next_lo = ssl->keys.prevSeq_lo; - window = ssl->keys.prevWindow; + + if (ssl->keys.curEpoch == peerSeq->nextEpoch) { + next_hi = peerSeq->nextSeq_hi; + next_lo = peerSeq->nextSeq_lo; + window = peerSeq->window; + } + else if (ssl->keys.curEpoch == peerSeq->nextEpoch - 1) { + next_hi = peerSeq->prevSeq_hi; + next_lo = peerSeq->prevSeq_lo; + window = peerSeq->prevWindow; } else { return 0; @@ -9595,10 +9684,12 @@ static INLINE int DtlsCheckWindow(WOLFSSL* ssl) WOLFSSL_MSG("Current record sequence number from the past."); return 0; } +#ifndef WOLFSSL_DTLS_ALLOW_FUTURE else if (!curLT && (diff > DTLS_SEQ_BITS)) { WOLFSSL_MSG("Rejecting message too far into the future."); return 0; } +#endif else if (curLT) { word32 idx = diff / DTLS_WORD_BITS; word32 newDiff = diff % DTLS_WORD_BITS; @@ -9619,6 +9710,24 @@ static INLINE int DtlsCheckWindow(WOLFSSL* ssl) } +#ifdef WOLFSSL_MULTICAST +static INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, + word32 second, word32 max) +{ + word32 newCur = 0; + + if (cur < first) + newCur = first; + else if (cur < second) + newCur = second; + else if (cur < max) + newCur = max; + + return newCur; +} +#endif /* WOLFSSL_MULTICAST */ + + static INLINE int DtlsUpdateWindow(WOLFSSL* ssl) { word32* window; @@ -9627,21 +9736,63 @@ static INLINE int DtlsUpdateWindow(WOLFSSL* ssl) int curLT; word32 cur_lo, diff; word16 cur_hi; - - if (ssl->keys.curEpoch == ssl->keys.nextEpoch) { - next_hi = &ssl->keys.nextSeq_hi; - next_lo = &ssl->keys.nextSeq_lo; - window = ssl->keys.window; - } - else { - next_hi = &ssl->keys.prevSeq_hi; - next_lo = &ssl->keys.prevSeq_lo; - window = ssl->keys.prevWindow; - } + WOLFSSL_DTLS_PEERSEQ* peerSeq = ssl->keys.peerSeq; cur_hi = ssl->keys.curSeq_hi; cur_lo = ssl->keys.curSeq_lo; +#ifdef WOLFSSL_MULTICAST + if (ssl->options.haveMcast) { + WOLFSSL_DTLS_PEERSEQ* p; + int i; + + peerSeq = NULL; + for (i = 0, p = ssl->keys.peerSeq; + i < WOLFSSL_DTLS_PEERSEQ_SZ; + i++, p++) { + + if (p->peerId == ssl->keys.curPeerId) { + peerSeq = p; + break; + } + } + + if (peerSeq == NULL) { + WOLFSSL_MSG("Couldn't find that peer ID to update window."); + return 0; + } + + if (p->highwaterMark && cur_lo >= p->highwaterMark) { + int cbError = 0; + + if (ssl->ctx->mcastHwCb) + cbError = ssl->ctx->mcastHwCb(p->peerId, + ssl->ctx->mcastMaxSeq, + cur_lo, ssl->mcastHwCbCtx); + if (cbError) { + WOLFSSL_MSG("Multicast highwater callback returned an error."); + return MCAST_HIGHWATER_CB_E; + } + + p->highwaterMark = UpdateHighwaterMark(cur_lo, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + } +#endif + + if (ssl->keys.curEpoch == peerSeq->nextEpoch) { + next_hi = &peerSeq->nextSeq_hi; + next_lo = &peerSeq->nextSeq_lo; + window = peerSeq->window; + } + else { + next_hi = &peerSeq->prevSeq_hi; + next_lo = &peerSeq->prevSeq_lo; + window = peerSeq->prevWindow; + } + if (cur_hi == *next_hi) { curLT = cur_lo < *next_lo; diff = curLT ? *next_lo - cur_lo : cur_lo - *next_lo; @@ -10676,6 +10827,10 @@ static INLINE int Decrypt(WOLFSSL* ssl, byte* plain, const byte* input, if (ret == VERIFY_MAC_ERROR) { if (!ssl->options.dtls) SendAlert(ssl, alert_fatal, bad_record_mac); + + #ifdef WOLFSSL_DTLS_DROP_STATS + ssl->macDropCount++; + #endif /* WOLFSSL_DTLS_DROP_STATS */ } return ret; @@ -11401,6 +11556,9 @@ int ProcessReply(WOLFSSL* ssl) ssl->options.processReply = doProcessInit; ssl->buffers.inputBuffer.length = 0; ssl->buffers.inputBuffer.idx = 0; +#ifdef WOLFSSL_DTLS_DROP_STATS + ssl->replayDropCount++; +#endif /* WOLFSSL_DTLS_DROP_STATS */ if (IsDtlsNotSctpMode(ssl) && ssl->options.dtlsHsRetain) { ret = DtlsMsgPoolSend(ssl, 0); @@ -11539,6 +11697,9 @@ int ProcessReply(WOLFSSL* ssl) if (ret < 0) { WOLFSSL_MSG("VerifyMac failed"); WOLFSSL_ERROR(ret); + #ifdef WOLFSSL_DTLS_DROP_STATS + ssl->macDropCount++; + #endif /* WOLFSSL_DTLS_DROP_STATS */ return DECRYPT_ERROR; } } @@ -11670,20 +11831,33 @@ int ProcessReply(WOLFSSL* ssl) ssl->keys.encryptionOn = 1; /* setup decrypt keys for following messages */ + /* XXX This might not be what we want to do when + * receiving a CCS with multicast. We update the + * key when the application updates them. */ if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0) return ret; #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { + WOLFSSL_DTLS_PEERSEQ* peerSeq = ssl->keys.peerSeq; +#ifdef WOLFSSL_MULTICAST + if (ssl->options.haveMcast) { + peerSeq += ssl->keys.curPeerId; + peerSeq->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } +#endif DtlsMsgPoolReset(ssl); - ssl->keys.prevSeq_lo = ssl->keys.nextSeq_lo; - ssl->keys.prevSeq_hi = ssl->keys.nextSeq_hi; - XMEMCPY(ssl->keys.prevWindow, ssl->keys.window, + peerSeq->nextEpoch++; + peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; + peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; + peerSeq->nextSeq_lo = 0; + peerSeq->nextSeq_hi = 0; + XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); - ssl->keys.nextEpoch++; - ssl->keys.nextSeq_lo = 0; - ssl->keys.nextSeq_hi = 0; - XMEMSET(ssl->keys.window, 0, DTLS_SEQ_SZ); + XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); } #endif @@ -14064,6 +14238,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case HRR_COOKIE_ERROR: return "Cookie does not match one sent in HelloRetryRequest"; + case MCAST_HIGHWATER_CB_E: + return "Multicast highwater callback returned error"; + default : return "unknown error number"; } @@ -14540,6 +14717,9 @@ static const char* const cipher_names[] = "TLS13-AES128-CCM-8-SHA256", #endif +#ifdef BUILD_WDM_WITH_NULL_SHA256 + "WDM-NULL-SHA256", +#endif }; @@ -15007,6 +15187,9 @@ static int cipher_name_idx[] = TLS_AES_128_CCM_8_SHA256, #endif +#ifdef BUILD_WDM_WITH_NULL_SHA256 + WDM_WITH_NULL_SHA256, +#endif }; @@ -15495,6 +15678,10 @@ const char* wolfSSL_get_cipher_name_from_suite(const unsigned char cipherSuite, #ifdef BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA case TLS_DH_anon_WITH_AES_128_CBC_SHA : return "TLS_DH_anon_WITH_AES_128_CBC_SHA"; +#endif +#ifdef BUILD_WDM_WITH_NULL_SHA256 + case WDM_WITH_NULL_SHA256 : + return "WDM_WITH_NULL_SHA256"; #endif default: return "NONE"; diff --git a/src/io.c b/src/io.c index 6a904683c4..8e7ac14239 100644 --- a/src/io.c +++ b/src/io.c @@ -296,7 +296,7 @@ int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx) if (dtlsCtx->peer.sz > 0 && peerSz != (XSOCKLENT)dtlsCtx->peer.sz && XMEMCMP(&peer, dtlsCtx->peer.sa, peerSz) != 0) { - WOLFSSL_MSG("\tIgnored packet from invalid peer"); + WOLFSSL_MSG(" Ignored packet from invalid peer"); return WOLFSSL_CBIO_ERR_WANT_READ; } } @@ -354,6 +354,61 @@ int EmbedSendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx) } +#ifdef WOLFSSL_MULTICAST + +/* The alternate receive embedded callback for Multicast + * return : nb bytes read, or error + */ +int EmbedReceiveFromMcast(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + WOLFSSL_DTLS_CTX* dtlsCtx = (WOLFSSL_DTLS_CTX*)ctx; + int recvd; + int err; + int sd = dtlsCtx->rfd; + + WOLFSSL_ENTER("EmbedReceiveFromMcast()"); + + recvd = (int)RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags, NULL, NULL); + + recvd = TranslateReturnCode(recvd, sd); + + if (recvd < 0) { + err = LastError(); + WOLFSSL_MSG("Embed Receive From error"); + + if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) { + if (wolfSSL_get_using_nonblock(ssl)) { + WOLFSSL_MSG("\tWould block"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + WOLFSSL_MSG("\tSocket timeout"); + return WOLFSSL_CBIO_ERR_TIMEOUT; + } + } + else if (err == SOCKET_ECONNRESET) { + WOLFSSL_MSG("\tConnection reset"); + return WOLFSSL_CBIO_ERR_CONN_RST; + } + else if (err == SOCKET_EINTR) { + WOLFSSL_MSG("\tSocket interrupted"); + return WOLFSSL_CBIO_ERR_ISR; + } + else if (err == SOCKET_ECONNREFUSED) { + WOLFSSL_MSG("\tConnection refused"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + return recvd; +} +#endif /* WOLFSSL_MULTICAST */ + + /* The DTLS Generate Cookie callback * return : number of bytes copied into buf, or error */ @@ -362,7 +417,7 @@ int EmbedGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *ctx) int sd = ssl->wfd; SOCKADDR_S peer; XSOCKLENT peerSz = sizeof(peer); - byte digest[SHA_DIGEST_SIZE]; + byte digest[SHA256_DIGEST_SIZE]; int ret = 0; (void)ctx; @@ -373,12 +428,12 @@ int EmbedGenerateCookie(WOLFSSL* ssl, byte *buf, int sz, void *ctx) return GEN_COOKIE_E; } - ret = wc_ShaHash((byte*)&peer, peerSz, digest); + ret = wc_Sha256Hash((byte*)&peer, peerSz, digest); if (ret != 0) return ret; - if (sz > SHA_DIGEST_SIZE) - sz = SHA_DIGEST_SIZE; + if (sz > SHA256_DIGEST_SIZE) + sz = SHA256_DIGEST_SIZE; XMEMCPY(buf, digest, sz); return sz; diff --git a/src/keys.c b/src/keys.c index b8726d28a7..938387ec11 100644 --- a/src/keys.c +++ b/src/keys.c @@ -2083,6 +2083,19 @@ int SetCipherSpecs(WOLFSSL* ssl) break; #endif +#ifdef BUILD_WDM_WITH_NULL_SHA256 + case WDM_WITH_NULL_SHA256 : + ssl->specs.bulk_cipher_algorithm = wolfssl_cipher_null; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = no_kea; + ssl->specs.sig_algo = anonymous_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + + break; +#endif + default: WOLFSSL_MSG("Unsupported cipher suite, SetCipherSpecs"); return UNSUPPORTED_SUITE; @@ -3043,6 +3056,35 @@ int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side) } #endif /* HAVE_SECURE_RENEGOTIATION */ +#ifdef WOLFSSL_MULTICAST + if (ssl->options.haveMcast) { + /* Use the same keys for encrypt and decrypt. */ + if (ssl->specs.cipher_type != aead) { + sz = ssl->specs.hash_size; + XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz); + XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz); + i += sz; + } + sz = ssl->specs.key_size; + XMEMCPY(keys->client_write_key, &keyData[i], sz); + XMEMCPY(keys->server_write_key, &keyData[i], sz); + i += sz; + + sz = ssl->specs.iv_size; + XMEMCPY(keys->client_write_IV, &keyData[i], sz); + XMEMCPY(keys->server_write_IV, &keyData[i], sz); + +#ifdef HAVE_AEAD + if (ssl->specs.cipher_type == aead) { + /* Initialize the AES-GCM/CCM explicit IV to a zero. */ + XMEMSET(keys->aead_exp_IV, 0, AEAD_MAX_EXP_SZ); + } +#endif /* HAVE_AEAD */ + + return 0; + } +#endif /* WOLFSSL_MULTICAST */ + if (ssl->specs.cipher_type != aead) { sz = ssl->specs.hash_size; if (side & PROVISION_CLIENT) { diff --git a/src/ssl.c b/src/ssl.c index de055ce446..0944b0f113 100755 --- a/src/ssl.c +++ b/src/ssl.c @@ -843,6 +843,276 @@ int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) #endif /* WOLFSSL_DTLS && WOLFSSL_SCTP */ + +#ifdef WOLFSSL_DTLS_DROP_STATS + +int wolfSSL_dtls_get_drop_stats(WOLFSSL* ssl, + word32* macDropCount, word32* replayDropCount) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_dtls_get_drop_stats()"); + + if (ssl == NULL) + ret = BAD_FUNC_ARG; + else { + ret = SSL_SUCCESS; + if (macDropCount != NULL) + *macDropCount = ssl->macDropCount; + if (replayDropCount != NULL) + *replayDropCount = ssl->replayDropCount; + } + + WOLFSSL_LEAVE("wolfSSL_dtls_get_drop_stats()", ret); + return ret; +} + +#endif /* WOLFSSL_DTLS_DROP_STATS */ + + +#if defined(WOLFSSL_MULTICAST) + +int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX* ctx, word16 id) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_mcast_set_member_id()"); + + if (ctx == NULL || id > 255) + ret = BAD_FUNC_ARG; + + if (ret == 0) { + ctx->haveEMS = 0; + ctx->haveMcast = 1; + ctx->mcastID = id; +#ifndef WOLFSSL_USER_IO + ctx->CBIORecv = EmbedReceiveFromMcast; +#endif /* WOLFSSL_USER_IO */ + } + + if (ret == 0) + ret = SSL_SUCCESS; + WOLFSSL_LEAVE("wolfSSL_CTX_mcast_set_member_id()", ret); + return ret; +} + +int wolfSSL_mcast_get_max_peers(void) +{ + return WOLFSSL_MULTICAST_PEERS; +} + +#ifdef WOLFSSL_DTLS +static INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, + word32 second, word32 max) +{ + word32 newCur = 0; + + if (cur < first) + newCur = first; + else if (cur < second) + newCur = second; + else if (cur < max) + newCur = max; + + return newCur; +} +#endif /* WOLFSSL_DTLS */ + + +int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, + const byte* preMasterSecret, word32 preMasterSz, + const byte* clientRandom, const byte* serverRandom, + const byte* suite) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_set_secret()"); + + if (ssl == NULL || preMasterSecret == NULL || + preMasterSz == 0 || preMasterSz > ENCRYPT_LEN || + clientRandom == NULL || serverRandom == NULL || suite == NULL) { + + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); + ssl->arrays->preMasterSz = preMasterSz; + XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); + XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); + ssl->options.cipherSuite0 = suite[0]; + ssl->options.cipherSuite = suite[1]; + + ret = SetCipherSpecs(ssl); + } + + if (ret == 0) + ret = MakeTlsMasterSecret(ssl); + + if (ret == 0) { + ssl->keys.encryptionOn = 1; + ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); + } + + if (ret == 0) { + if (ssl->options.dtls) { + #ifdef WOLFSSL_DTLS + WOLFSSL_DTLS_PEERSEQ* peerSeq; + int i; + + ssl->keys.dtls_epoch = epoch; + for (i = 0, peerSeq = ssl->keys.peerSeq; + i < WOLFSSL_DTLS_PEERSEQ_SZ; + i++, peerSeq++) { + + peerSeq->nextEpoch = epoch; + peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; + peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; + peerSeq->nextSeq_lo = 0; + peerSeq->nextSeq_hi = 0; + XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); + XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); + peerSeq->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + #else + (void)epoch; + #endif + } + FreeHandshakeResources(ssl); + ret = SSL_SUCCESS; + } + else { + if (ssl) + ssl->error = ret; + ret = SSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_set_secret()", ret); + return ret; +} + + +#ifdef WOLFSSL_DTLS + +int wolfSSL_mcast_peer_add(WOLFSSL* ssl, word16 peerId, int remove) +{ + WOLFSSL_DTLS_PEERSEQ* p = NULL; + int ret = SSL_SUCCESS; + int i; + + WOLFSSL_ENTER("wolfSSL_mcast_peer_add()"); + if (ssl == NULL || peerId > 255) + return BAD_FUNC_ARG; + + if (!remove) { + /* Make sure it isn't already present, while keeping the first + * open spot. */ + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == INVALID_PEER_ID) + p = &ssl->keys.peerSeq[i]; + if (ssl->keys.peerSeq[i].peerId == peerId) { + WOLFSSL_MSG("Peer ID already in multicast peer list."); + p = NULL; + } + } + + if (p != NULL) { + XMEMSET(p, 0, sizeof(WOLFSSL_DTLS_PEERSEQ)); + p->peerId = peerId; + p->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + else { + WOLFSSL_MSG("No room in peer list."); + ret = -1; + } + } + else { + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == peerId) + p = &ssl->keys.peerSeq[i]; + } + + if (p != NULL) { + p->peerId = INVALID_PEER_ID; + } + else { + WOLFSSL_MSG("Peer not found in list."); + } + } + + WOLFSSL_LEAVE("wolfSSL_mcast_peer_add()", ret); + return ret; +} + + +/* If peerId is in the list of peers and its last sequence number is non-zero, + * return 1, otherwise return 0. */ +int wolfSSL_mcast_peer_known(WOLFSSL* ssl, unsigned short peerId) +{ + int known = 0; + int i; + + WOLFSSL_ENTER("wolfSSL_mcast_peer_known()"); + + if (ssl == NULL || peerId > 255) { + return BAD_FUNC_ARG; + } + + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == peerId) { + if (ssl->keys.peerSeq[i].nextSeq_hi || + ssl->keys.peerSeq[i].nextSeq_lo) { + + known = 1; + } + break; + } + } + + WOLFSSL_LEAVE("wolfSSL_mcast_peer_known()", known); + return known; +} + + +int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX* ctx, word32 maxSeq, + word32 first, word32 second, + CallbackMcastHighwater cb) +{ + if (ctx == NULL || (second && first > second) || + first > maxSeq || second > maxSeq || cb == NULL) { + + return BAD_FUNC_ARG; + } + + ctx->mcastHwCb = cb; + ctx->mcastFirstSeq = first; + ctx->mcastSecondSeq = second; + ctx->mcastMaxSeq = maxSeq; + + return SSL_SUCCESS; +} + + +int wolfSSL_mcast_set_highwater_ctx(WOLFSSL* ssl, void* ctx) +{ + if (ssl == NULL || ctx == NULL) + return BAD_FUNC_ARG; + + ssl->mcastHwCbCtx = ctx; + + return SSL_SUCCESS; +} + +#endif /* WOLFSSL_DTLS */ + +#endif /* WOLFSSL_MULTICAST */ + + #endif /* WOLFSSL_LEANPSK */ @@ -1452,6 +1722,25 @@ int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) } +#ifdef WOLFSSL_MULTICAST + +int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_mcast_read()"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ret = wolfSSL_read_internal(ssl, data, sz, FALSE); + if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) + *id = ssl->keys.curPeerId; + return ret; +} + +#endif /* WOLFSSL_MULTICAST */ + #ifdef WOLFSSL_ASYNC_CRYPT /* let's use async hardware, SSL_SUCCESS on ok */ @@ -8643,12 +8932,12 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, { word16 havePSK = 0; word16 haveAnon = 0; + word16 haveMcast = 0; #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) return wolfSSL_accept_TLSv13(ssl); #endif - WOLFSSL_ENTER("SSL_accept()"); #ifdef HAVE_ERRNO_H @@ -8665,6 +8954,11 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #endif (void)haveAnon; + #ifdef WOLFSSL_MULTICAST + haveMcast = ssl->options.haveMcast; + #endif + (void)haveMcast; + if (ssl->options.side != WOLFSSL_SERVER_END) { WOLFSSL_ERROR(ssl->error = SIDE_ERROR); return SSL_FATAL_ERROR; @@ -8672,7 +8966,7 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #ifndef NO_CERTS /* in case used set_accept_state after init */ - if (!havePSK && !haveAnon && + if (!havePSK && !haveAnon && !haveMcast && (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer || !ssl->buffers.key || diff --git a/tests/api.c b/tests/api.c index fccfd8e718..e8cb185786 100644 --- a/tests/api.c +++ b/tests/api.c @@ -2344,6 +2344,49 @@ static int test_wolfSSL_UseOCSPStaplingV2 (void) } /*END test_wolfSSL_UseOCSPStaplingV2*/ +/*----------------------------------------------------------------------------* + | Multicast Tests + *----------------------------------------------------------------------------*/ +static void test_wolfSSL_mcast(void) +{ +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) + WOLFSSL_CTX* ctx; + WOLFSSL* ssl; + int result; + byte preMasterSecret[512]; + byte clientRandom[32]; + byte serverRandom[32]; + byte suite[2] = {0, 0xfe}; /* WDM_WITH_NULL_SHA256 */ + byte buf[256]; + word16 newId; + + ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method()); + AssertNotNull(ctx); + + result = wolfSSL_CTX_mcast_set_member_id(ctx, 0); + AssertIntEQ(result, SSL_SUCCESS); + + ssl = wolfSSL_new(ctx); + AssertNotNull(ssl); + + XMEMSET(preMasterSecret, 0x23, sizeof(preMasterSecret)); + XMEMSET(clientRandom, 0xA5, sizeof(clientRandom)); + XMEMSET(serverRandom, 0x5A, sizeof(serverRandom)); + result = wolfSSL_set_secret(ssl, 23, + preMasterSecret, sizeof(preMasterSecret), + clientRandom, serverRandom, suite); + AssertIntEQ(result, SSL_SUCCESS); + + result = wolfSSL_mcast_read(ssl, &newId, buf, sizeof(buf)); + AssertIntLE(result, 0); + AssertIntLE(newId, 100); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif /* WOLFSSL_DTLS && WOLFSSL_MULTICAST */ +} + + /*----------------------------------------------------------------------------* | Wolfcrypt *----------------------------------------------------------------------------*/ @@ -9707,6 +9750,9 @@ void ApiTest(void) AssertIntEQ(test_wolfSSL_UseOCSPStapling(), SSL_SUCCESS); AssertIntEQ(test_wolfSSL_UseOCSPStaplingV2(), SSL_SUCCESS); + /* Multicast */ + test_wolfSSL_mcast(); + /* compatibility tests */ test_wolfSSL_DES(); test_wolfSSL_certs(); diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 09d8436993..f827d3acf0 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -161,6 +161,7 @@ enum wolfSSL_ErrorCodes { BAD_BINDER = -423, /* Binder does not match */ EXT_NOT_ALLOWED = -424, /* Extension not allowed in msg */ INVALID_PARAMETER = -425, /* Security parameter invalid */ + MCAST_HIGHWATER_CB_E = -426, /* Multicast highwater cb err */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d77da93de3..3875c47e79 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -657,6 +657,12 @@ typedef byte word24[3]; #endif #endif +#ifdef WOLFSSL_MULTICAST + #if defined(HAVE_NULL_CIPHER) && !defined(NO_SHA256) + #define BUILD_WDM_WITH_NULL_SHA256 + #endif +#endif + #if defined(BUILD_SSL_RSA_WITH_RC4_128_SHA) || \ defined(BUILD_SSL_RSA_WITH_RC4_128_MD5) #define BUILD_ARC4 @@ -794,6 +800,7 @@ enum { TLS_RSA_WITH_HC_128_MD5 = 0xFB, TLS_RSA_WITH_HC_128_SHA = 0xFC, TLS_RSA_WITH_RABBIT_SHA = 0xFD, + WDM_WITH_NULL_SHA256 = 0xFE, /* wolfSSL DTLS Multicast */ /* wolfSSL extension - Blake2b 256 */ TLS_RSA_WITH_AES_128_CBC_B2B256 = 0xF8, @@ -907,6 +914,21 @@ enum { #define DTLS_SEQ_BITS (WOLFSSL_DTLS_WINDOW_WORDS * DTLS_WORD_BITS) #define DTLS_SEQ_SZ (sizeof(word32) * WOLFSSL_DTLS_WINDOW_WORDS) +#ifndef WOLFSSL_MULTICAST + #define WOLFSSL_DTLS_PEERSEQ_SZ 1 +#else + #ifndef WOLFSSL_MULTICAST_PEERS + /* max allowed multicast group peers */ + #define WOLFSSL_MULTICAST_PEERS 100 + #endif + #define WOLFSSL_DTLS_PEERSEQ_SZ WOLFSSL_MULTICAST_PEERS +#endif /* WOLFSSL_MULTICAST */ + +#ifndef WOLFSSL_MAX_MTU + #define WOLFSSL_MAX_MTU 1500 +#endif /* WOLFSSL_MAX_MTU */ + + enum Misc { ECC_BYTE = 0xC0, /* ECC first cipher suite byte */ @@ -952,7 +974,7 @@ enum Misc { /* RECORD_HEADER_SZ + BLOCK_SZ (pad) + Max digest sz + BLOC_SZ (iv) + pad byte (1) */ MAX_COMP_EXTRA = 1024, /* max compression extra */ - MAX_MTU = 1500, /* max expected MTU */ + MAX_MTU = WOLFSSL_MAX_MTU, /* max expected MTU */ MAX_UDP_SIZE = 8192 - 100, /* was MAX_MTU - 100 */ MAX_DH_SZ = 1036, /* 4096 p, pub, g + 2 byte size for each */ MAX_STR_VERSION = 8, /* string rep of protocol version */ @@ -1150,6 +1172,8 @@ enum Misc { NO_COPY = 0, /* should we copy static buffer for write */ COPY = 1, /* should we copy static buffer for write */ + INVALID_PEER_ID = 0xFFFF, /* Initialize value for peer ID. */ + PREV_ORDER = -1, /* Sequence number is in previous epoch. */ PEER_ORDER = 1, /* Peer sequence number for verify. */ CUR_ORDER = 0 /* Current sequence number. */ @@ -1716,6 +1740,25 @@ typedef struct WOLFSSL_DTLS_CTX { } WOLFSSL_DTLS_CTX; +typedef struct WOLFSSL_DTLS_PEERSEQ { + word32 window[WOLFSSL_DTLS_WINDOW_WORDS]; + /* Sliding window for current epoch */ + word16 nextEpoch; /* Expected epoch in next record */ + word16 nextSeq_hi; /* Expected sequence in next record */ + word32 nextSeq_lo; + + word32 prevWindow[WOLFSSL_DTLS_WINDOW_WORDS]; + /* Sliding window for old epoch */ + word32 prevSeq_lo; + word16 prevSeq_hi; /* Next sequence in allowed old epoch */ + +#ifdef WOLFSSL_MULTICAST + word16 peerId; + word32 highwaterMark; +#endif +} WOLFSSL_DTLS_PEERSEQ; + + #define MAX_WRITE_IV_SZ 16 /* max size of client/server write_IV */ /* keys and secrets @@ -1739,20 +1782,13 @@ typedef struct Keys { word32 sequence_number_lo; #ifdef WOLFSSL_DTLS - word32 window[WOLFSSL_DTLS_WINDOW_WORDS]; - /* Sliding window for current epoch */ - word16 nextEpoch; /* Expected epoch in next record */ - word16 nextSeq_hi; /* Expected sequence in next record */ - word32 nextSeq_lo; - word16 curEpoch; /* Received epoch in current record */ word16 curSeq_hi; /* Received sequence in current record */ word32 curSeq_lo; - - word32 prevWindow[WOLFSSL_DTLS_WINDOW_WORDS]; - /* Sliding window for old epoch */ - word16 prevSeq_hi; /* Next sequence in allowed old epoch */ - word32 prevSeq_lo; +#ifdef WOLFSSL_MULTICAST + byte curPeerId; /* Received peer group ID in current record */ +#endif + WOLFSSL_DTLS_PEERSEQ peerSeq[WOLFSSL_DTLS_PEERSEQ_SZ]; word16 dtls_peer_handshake_number; word16 dtls_expected_peer_handshake_number; @@ -2232,6 +2268,10 @@ struct WOLFSSL_CTX { #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) byte postHandshakeAuth:1; /* Post-handshake auth supported. */ #endif +#ifdef WOLFSSL_MULTICAST + byte haveMcast; /* multicast requested */ + byte mcastID; /* multicast group ID */ +#endif #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) byte dtlsSctp; /* DTLS-over-SCTP mode */ word16 dtlsMtuSz; /* DTLS MTU size */ @@ -2299,6 +2339,12 @@ struct WOLFSSL_CTX { CallbackSniRecv sniRecvCb; void* sniRecvCbArg; #endif +#if defined(WOLFSSL_MULTICAST) && defined(WOLFSSL_DTLS) + CallbackMcastHighwater mcastHwCb; /* Sequence number highwater callback */ + word32 mcastFirstSeq; /* first trigger level */ + word32 mcastSecondSeq; /* second tigger level */ + word32 mcastMaxSeq; /* max level */ +#endif #ifdef HAVE_OCSP WOLFSSL_OCSP ocsp; #endif @@ -2813,6 +2859,7 @@ typedef struct Options { word16 saveArrays:1; /* save array Memory for user get keys or psk */ word16 weOwnRng:1; /* will be true unless CTX owns */ + word16 haveEMS:1; /* using extended master secret */ #ifdef HAVE_POLY1305 word16 oldPoly:1; /* set when to use old rfc way of poly*/ #endif @@ -2829,11 +2876,11 @@ typedef struct Options { #endif #ifdef WOLFSSL_DTLS word16 dtlsHsRetain:1; /* DTLS retaining HS data */ + word16 haveMcast:1; /* using multicast ? */ #ifdef WOLFSSL_SCTP word16 dtlsSctp:1; /* DTLS-over-SCTP mode */ #endif #endif - word16 haveEMS:1; /* using extended master secret */ #if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES) word16 userCurves:1; /* indicates user called wolfSSL_UseSupportedCurve */ #endif @@ -2860,6 +2907,9 @@ typedef struct Options { byte acceptState; /* nonblocking resume */ byte asyncState; /* sub-state for enum asyncState */ byte buildMsgState; /* sub-state for enum buildMsgState */ +#ifdef WOLFSSL_MULTICAST + word16 mcastID; /* Multicast group ID */ +#endif #ifndef NO_DH word16 minDhKeySz; /* minimum DH key size */ word16 dhKeySz; /* actual DH key size */ @@ -3296,7 +3346,14 @@ struct WOLFSSL { #ifdef WOLFSSL_SCTP word16 dtlsMtuSz; #endif /* WOLFSSL_SCTP */ -#endif +#ifdef WOLFSSL_MULTICAST + void* mcastHwCbCtx; /* Multicast highwater callback ctx */ +#endif /* WOLFSSL_MULTICAST */ +#ifdef WOLFSSL_DTLS_DROP_STATS + word32 macDropCount; + word32 replayDropCount; +#endif /* WOLFSSL_DTLS_DROP_STATS */ +#endif /* WOLFSSL_DTLS */ #ifdef WOLFSSL_CALLBACKS HandShakeInfo handShakeInfo; /* info saved during handshake */ TimeoutInfo timeoutInfo; /* info saved during handshake */ diff --git a/wolfssl/io.h b/wolfssl/io.h index c134194984..0bbb2d7835 100644 --- a/wolfssl/io.h +++ b/wolfssl/io.h @@ -298,6 +298,10 @@ WOLFSSL_API int wolfIO_Recv(SOCKET_T sd, char *buf, int sz, int rdFlags); WOLFSSL_API int EmbedSendTo(WOLFSSL* ssl, char* buf, int sz, void* ctx); WOLFSSL_API int EmbedGenerateCookie(WOLFSSL* ssl, unsigned char* buf, int sz, void*); + #ifdef WOLFSSL_MULTICAST + WOLFSSL_API int EmbedReceiveFromMcast(WOLFSSL* ssl, + char* buf, int sz, void*); + #endif /* WOLFSSL_MULTICAST */ #ifdef WOLFSSL_SESSION_EXPORT WOLFSSL_API int EmbedGetPeer(WOLFSSL* ssl, char* ip, int* ipSz, unsigned short* port, int* fam); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 8082aded27..4a31a94954 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -509,6 +509,27 @@ WOLFSSL_API int wolfSSL_dtls_set_sctp(WOLFSSL*); WOLFSSL_API int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX*, unsigned short); WOLFSSL_API int wolfSSL_dtls_set_mtu(WOLFSSL*, unsigned short); +WOLFSSL_API int wolfSSL_dtls_get_drop_stats(WOLFSSL*, + unsigned int*, unsigned int*); +WOLFSSL_API int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX*, unsigned short); +WOLFSSL_API int wolfSSL_set_secret(WOLFSSL*, unsigned short, + const unsigned char*, unsigned int, + const unsigned char*, const unsigned char*, + const unsigned char*); +WOLFSSL_API int wolfSSL_mcast_read(WOLFSSL*, unsigned short*, void*, int); +WOLFSSL_API int wolfSSL_mcast_peer_add(WOLFSSL*, unsigned short, int); +WOLFSSL_API int wolfSSL_mcast_peer_known(WOLFSSL*, unsigned short); +WOLFSSL_API int wolfSSL_mcast_get_max_peers(void); +typedef int (*CallbackMcastHighwater)(unsigned short peerId, + unsigned int maxSeq, + unsigned int curSeq, void* ctx); +WOLFSSL_API int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX*, + unsigned int, + unsigned int, + unsigned int, + CallbackMcastHighwater); +WOLFSSL_API int wolfSSL_mcast_set_highwater_ctx(WOLFSSL*, void*); + WOLFSSL_API int wolfSSL_ERR_GET_REASON(unsigned long err); WOLFSSL_API char* wolfSSL_ERR_error_string(unsigned long,char*); WOLFSSL_API void wolfSSL_ERR_error_string_n(unsigned long e, char* buf, diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 92bb3b2c01..58d1bd2c6b 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -153,7 +153,7 @@ #include #ifdef WOLFSSL_USER_SETTINGS - #include + #include "user_settings.h" #endif @@ -174,7 +174,10 @@ #endif #ifdef HAVE_NETX - #include "nx_api.h" + #ifdef NEED_THREADX_TYPES + #include + #endif + #include #endif #if defined(HAVE_LWIP_NATIVE) /* using LwIP native TCP socket */ diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 0c42240f0b..d10522cbf7 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -49,7 +49,10 @@ #endif #elif defined(THREADX) #ifndef SINGLE_THREADED - #include "tx_api.h" + #ifdef NEED_THREADX_TYPES + #include + #endif + #include #endif #elif defined(MICRIUM) /* do nothing, just don't pick Unix */