From 64602d19698870aa36d69ba091f6718ec431ded7 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 21 May 2015 10:11:21 -0700 Subject: [PATCH] added check for allowed minimum DH key size --- certs/test/catalog.txt | 6 ++++++ certs/test/dh1024.der | Bin 0 -> 138 bytes certs/test/dh1024.pem | 17 +++++++++++++++++ certs/test/dh512.der | Bin 0 -> 72 bytes certs/test/dh512.pem | 12 ++++++++++++ examples/client/client.c | 22 +++++++++++++++++++++- examples/server/server.c | 33 +++++++++++++++++++++++++++++++-- src/internal.c | 27 +++++++++++++++++++++++++++ src/ssl.c | 35 +++++++++++++++++++++++++++++++++++ wolfssl/error-ssl.h | 2 ++ wolfssl/internal.h | 21 +++++++++++++++++++++ wolfssl/ssl.h | 4 ++++ wolfssl/test.h | 5 +++++ 13 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 certs/test/dh1024.der create mode 100644 certs/test/dh1024.pem create mode 100644 certs/test/dh512.der create mode 100644 certs/test/dh512.pem diff --git a/certs/test/catalog.txt b/certs/test/catalog.txt index dcc1393d4..a1f77b4b3 100644 --- a/certs/test/catalog.txt +++ b/certs/test/catalog.txt @@ -1,3 +1,9 @@ crit-cert.pem: Simple self-signed certificate with critical Basic Constraints and Key Usage extensions. +dh512.pem, dh512.der: + 512-bit DH parameters. Used for testing the rejection of lower-bit sized DH + keys. +dh1024.pem, dh1024.der: + 1024-bit DH parameters. Used for testing the rejection of lower-bit sized DH + keys. diff --git a/certs/test/dh1024.der b/certs/test/dh1024.der new file mode 100644 index 0000000000000000000000000000000000000000..1a3ff399f733d01722161352eee93f06dae5dcd6 GIT binary patch literal 138 zcmXqLY-eh0WO!G+Z1TR9JK}?O&bhLJzxU^cV9k}PYi&jd@#vTqkyuhoMnTe4J0Mcng9smFU literal 0 HcmV?d00001 diff --git a/certs/test/dh1024.pem b/certs/test/dh1024.pem new file mode 100644 index 000000000..82d14e766 --- /dev/null +++ b/certs/test/dh1024.pem @@ -0,0 +1,17 @@ + DH Parameters: (1024 bit) + prime: + 00:ee:73:a6:93:be:a9:b8:5f:52:b9:9c:d4:a8:0f: + 8d:f9:b0:53:29:a9:25:06:0e:95:dd:f5:89:c8:6b: + 09:ae:94:1c:62:35:05:39:ab:6d:46:c5:b2:a2:fd: + a0:e1:ba:01:a5:00:4f:7f:44:e5:74:81:8b:3a:2e: + fa:ea:fe:f6:c3:18:11:ca:fd:ee:8b:9c:9e:0d:1a: + 5a:57:77:74:63:91:e7:51:bb:6d:79:93:e2:b4:5c: + fa:21:21:ff:5d:b3:e7:5c:92:08:ca:cb:4e:e7:8c: + f3:1c:21:8c:44:8c:6d:31:60:7a:e6:37:15:79:1b: + 1d:5d:c3:56:c3:a0:4a:8d:03 + generator: 2 (0x2) +-----BEGIN DH PARAMETERS----- +MIGHAoGBAO5zppO+qbhfUrmc1KgPjfmwUympJQYOld31ichrCa6UHGI1BTmrbUbF +sqL9oOG6AaUAT39E5XSBizou+ur+9sMYEcr97oucng0aWld3dGOR51G7bXmT4rRc ++iEh/12z51ySCMrLTueM8xwhjESMbTFgeuY3FXkbHV3DVsOgSo0DAgEC +-----END DH PARAMETERS----- diff --git a/certs/test/dh512.der b/certs/test/dh512.der new file mode 100644 index 0000000000000000000000000000000000000000..f743db4219b6080049fd58d208f515c65f32584c GIT binary patch literal 72 zcmXqTV{&9@FH@fR@c!*A=RN~%|KwoS@^cMLeH&M}_#50f>3Z{Q>SJ%+ZLiB0tG)7N eZn=4VTh_L_fz#6tmOsmWD>>2isQP9mMkWBCtRchz literal 0 HcmV?d00001 diff --git a/certs/test/dh512.pem b/certs/test/dh512.pem new file mode 100644 index 000000000..d1fef9243 --- /dev/null +++ b/certs/test/dh512.pem @@ -0,0 +1,12 @@ + DH Parameters: (512 bit) + prime: + 00:87:76:23:99:e1:df:db:6a:43:8e:30:2b:4f:63: + 53:05:77:ce:80:02:8e:b1:a8:44:4f:30:d8:c9:45: + d9:cd:65:e3:4b:2d:b6:eb:77:a3:26:ea:4d:03:84: + d9:d7:b6:6a:b6:dd:51:97:66:c1:77:e6:6b:ed:19: + 91:45:c5:27:b3 + generator: 2 (0x2) +-----BEGIN DH PARAMETERS----- +MEYCQQCHdiOZ4d/bakOOMCtPY1MFd86AAo6xqERPMNjJRdnNZeNLLbbrd6Mm6k0D +hNnXtmq23VGXZsF35mvtGZFFxSezAgEC +-----END DH PARAMETERS----- diff --git a/examples/client/client.c b/examples/client/client.c index ee5dae9ca..0546bb0f2 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -130,6 +130,10 @@ static void Usage(void) printf("-c Certificate file, default %s\n", cliCert); printf("-k Key file, default %s\n", cliKey); printf("-A Certificate Authority file, default %s\n", caCert); +#ifndef NO_DH + printf("-Z Minimum DH key bits, default %d\n", + DEFAULT_MIN_DHKEY_BITS); +#endif printf("-b Benchmark connections and print stats\n"); printf("-s Use pre Shared keys\n"); printf("-t Track wolfSSL memory use\n"); @@ -224,6 +228,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) int atomicUser = 0; int pkCallbacks = 0; int overrideDateErrors = 0; + int minDhKeyBits = DEFAULT_MIN_DHKEY_BITS; char* cipherList = NULL; const char* verifyCert = caCert; const char* ourCert = cliCert; @@ -269,11 +274,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) (void)useClientCert; (void)overrideDateErrors; (void)disableCRL; + (void)minDhKeyBits; StackTrap(); while ((ch = mygetopt(argc, argv, - "?gdDusmNrwRitfxXUPCh:p:v:l:A:c:k:b:zS:L:ToO:a")) + "?gdDusmNrwRitfxXUPCh:p:v:l:A:c:k:Z:b:zS:L:ToO:a")) != -1) { switch (ch) { case '?' : @@ -375,6 +381,16 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) ourKey = myoptarg; break; + case 'Z' : + #ifndef NO_DH + minDhKeyBits = atoi(myoptarg); + if (minDhKeyBits <= 0 || minDhKeyBits > 16000) { + Usage(); + exit(MY_EX_USAGE); + } + #endif + break; + case 'b' : benchmark = atoi(myoptarg); if (benchmark < 0 || benchmark > 1000000) { @@ -570,6 +586,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) if (fewerPackets) wolfSSL_CTX_set_group_messages(ctx); +#ifndef NO_DH + wolfSSL_CTX_SetMinDhKey_Sz(ctx, (word16)minDhKeyBits); +#endif + if (usePsk) { #ifndef NO_PSK wolfSSL_CTX_set_psk_client_callback(ctx, my_psk_client_cb); diff --git a/examples/server/server.c b/examples/server/server.c index 5ebfb7d38..a8d597a7e 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -131,6 +131,11 @@ static void Usage(void) printf("-c Certificate file, default %s\n", svrCert); printf("-k Key file, default %s\n", svrKey); printf("-A Certificate Authority file, default %s\n", cliCert); +#ifndef NO_DH + printf("-D Diffie-Hellman Params file, default %s\n", dhParam); + printf("-Z Minimum DH key bits, default %d\n", + DEFAULT_MIN_DHKEY_BITS); +#endif printf("-d Disable client cert check\n"); printf("-b Bind to any interface instead of localhost only\n"); printf("-s Use pre Shared keys\n"); @@ -184,11 +189,13 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) int serverReadyFile = 0; int wc_shutdown = 0; int resume = 0; /* do resume, and resume count */ + int minDhKeyBits = DEFAULT_MIN_DHKEY_BITS; int ret; char* cipherList = NULL; const char* verifyCert = cliCert; const char* ourCert = svrCert; const char* ourKey = svrKey; + const char* ourDhParam = dhParam; int argc = ((func_args*)args)->argc; char** argv = ((func_args*)args)->argv; @@ -213,15 +220,17 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) (void)needDH; (void)ourKey; (void)ourCert; + (void)ourDhParam; (void)verifyCert; (void)useNtruKey; (void)doCliCertCheck; + (void)minDhKeyBits; #ifdef CYASSL_TIRTOS fdOpenSession(Task_self()); #endif - while ((ch = mygetopt(argc, argv, "?dbstnNufrRawPp:v:l:A:c:k:S:oO:")) + while ((ch = mygetopt(argc, argv, "?dbstnNufrRawPp:v:l:A:c:k:Z:S:oO:D:")) != -1) { switch (ch) { case '?' : @@ -310,6 +319,22 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) ourKey = myoptarg; break; + case 'D' : + #ifndef NO_DH + ourDhParam = myoptarg; + #endif + break; + + case 'Z' : + #ifndef NO_DH + minDhKeyBits = atoi(myoptarg); + if (minDhKeyBits <= 0 || minDhKeyBits > 16000) { + Usage(); + exit(MY_EX_USAGE); + } + #endif + break; + case 'N': nonBlocking = 1; break; @@ -451,6 +476,10 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) } #endif +#ifndef NO_DH + wolfSSL_CTX_SetMinDhKey_Sz(ctx, (word16)minDhKeyBits); +#endif + #ifdef HAVE_NTRU if (useNtruKey) { if (CyaSSL_CTX_use_NTRUPrivateKey_file(ctx, ourKey) @@ -579,7 +608,7 @@ while (1) { /* allow resume option */ SSL_set_fd(ssl, clientfd); if (usePsk == 0 || useAnon == 1 || cipherList != NULL || needDH == 1) { #if !defined(NO_FILESYSTEM) && !defined(NO_DH) && !defined(NO_ASN) - CyaSSL_SetTmpDH_file(ssl, dhParam, SSL_FILETYPE_PEM); + CyaSSL_SetTmpDH_file(ssl, ourDhParam, SSL_FILETYPE_PEM); #elif !defined(NO_DH) SetDH(ssl); /* repick suites with DHE, higher priority than PSK */ #endif diff --git a/src/internal.c b/src/internal.c index aa69f8310..217dec9b5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -372,6 +372,10 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method) return BAD_MUTEX_E; } +#ifndef NO_DH + ctx->minDhKeySz = MIN_DHKEY_SZ; +#endif + #ifdef HAVE_ECC ctx->eccTempKeySz = ECDHE_SIZE; #endif @@ -1537,6 +1541,10 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx) ssl->options.handShakeState = NULL_STATE; ssl->options.processReply = doProcessInit; +#ifndef NO_DH + ssl->options.minDhKeySz = ctx->minDhKeySz; +#endif + #ifdef WOLFSSL_DTLS ssl->dtls_timeout_init = DTLS_TIMEOUT_INIT; ssl->dtls_timeout_max = DTLS_TIMEOUT_MAX; @@ -8024,6 +8032,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case BAD_TICKET_ENCRYPT: return "Bad user ticket callback encrypt Error"; + case DH_KEY_SIZE_E: + return "DH key too small Error"; + default : return "unknown error number"; } @@ -9755,6 +9766,12 @@ static void PickHashSigAlgo(WOLFSSL* ssl, if ((*inOutIdx - begin) + length > size) return BUFFER_ERROR; + if (length < ssl->options.minDhKeySz) { + WOLFSSL_MSG("Server using a DH key that is too small"); + SendAlert(ssl, alert_fatal, handshake_failure); + return DH_KEY_SIZE_E; + } + ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap, DYNAMIC_TYPE_DH); @@ -9766,6 +9783,8 @@ static void PickHashSigAlgo(WOLFSSL* ssl, XMEMCPY(ssl->buffers.serverDH_P.buffer, input + *inOutIdx, length); *inOutIdx += length; + ssl->options.dhKeySz = length; + /* g */ if ((*inOutIdx - begin) + OPAQUE16_LEN > size) return BUFFER_ERROR; @@ -9885,6 +9904,12 @@ static void PickHashSigAlgo(WOLFSSL* ssl, if ((*inOutIdx - begin) + length > size) return BUFFER_ERROR; + if (length < ssl->options.minDhKeySz) { + WOLFSSL_MSG("Server using a DH key that is too small"); + SendAlert(ssl, alert_fatal, handshake_failure); + return DH_KEY_SIZE_E; + } + ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap, DYNAMIC_TYPE_DH); @@ -9896,6 +9921,8 @@ static void PickHashSigAlgo(WOLFSSL* ssl, XMEMCPY(ssl->buffers.serverDH_P.buffer, input + *inOutIdx, length); *inOutIdx += length; + ssl->options.dhKeySz = length; + /* g */ if ((*inOutIdx - begin) + OPAQUE16_LEN > size) return BUFFER_ERROR; diff --git a/src/ssl.c b/src/ssl.c index 258b91db6..7342e81a4 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -438,6 +438,9 @@ int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz, WOLFSSL_ENTER("wolfSSL_SetTmpDH"); if (ssl == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG; + if (pSz < ssl->options.minDhKeySz) + return DH_KEY_SIZE_E; + if (ssl->options.side != WOLFSSL_SERVER_END) return SIDE_ERROR; @@ -487,6 +490,9 @@ int wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX* ctx, const unsigned char* p, int pSz, WOLFSSL_ENTER("wolfSSL_CTX_SetTmpDH"); if (ctx == NULL || p == NULL || g == NULL) return BAD_FUNC_ARG; + if (pSz < ctx->minDhKeySz) + return DH_KEY_SIZE_E; + XFREE(ctx->serverDH_P.buffer, ctx->heap, DYNAMIC_TYPE_DH); XFREE(ctx->serverDH_G.buffer, ctx->heap, DYNAMIC_TYPE_DH); @@ -3894,6 +3900,35 @@ int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX* ctx, const char* fname, int format) } +int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz) +{ + if (ctx == NULL || keySz > 16000 || keySz % 8 != 0) + return BAD_FUNC_ARG; + + ctx->minDhKeySz = keySz / 8; + return SSL_SUCCESS; +} + + +int wolfSSL_SetMinDhKey_Sz(WOLFSSL* ssl, word16 keySz) +{ + if (ssl == NULL || keySz > 16000 || keySz % 8 != 0) + return BAD_FUNC_ARG; + + ssl->options.minDhKeySz = keySz / 8; + return SSL_SUCCESS; +} + + +int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return (ssl->options.dhKeySz * 8); +} + + #endif /* NO_DH */ diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index d9dc80dc0..f151c3fb5 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -133,6 +133,8 @@ enum wolfSSL_ErrorCodes { BAD_TICKET_MSG_SZ = -399, /* Bad session ticket msg size */ BAD_TICKET_ENCRYPT = -400, /* Bad user ticket encrypt */ + DH_KEY_SIZE_E = -401, /* DH Key too small */ + /* add strings to SetErrorString !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index edba235dc..d8e4da871 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -895,6 +895,20 @@ enum Misc { COPY = 1 /* should we copy static buffer for write */ }; + +#ifndef WOLFSSL_MIN_DHKEY_BITS + #ifdef WOLFSSL_MAX_STRENGTH + #define WOLFSSL_MIN_DHKEY_BITS 2048 + #else + #define WOLFSSL_MIN_DHKEY_BITS 1024 + #endif +#endif +#if (WOLFSSL_MIN_DHKEY_BITS % 8) + #error DH minimum bit size must be multiple of 8 +#endif +#define MIN_DHKEY_SZ (WOLFSSL_MIN_DHKEY_BITS / 8) + + #ifdef SESSION_INDEX /* Shift values for making a session index */ #define SESSIDX_ROW_SHIFT 4 @@ -1508,6 +1522,9 @@ struct WOLFSSL_CTX { byte quietShutdown; /* don't send close notify */ byte groupMessages; /* group handshake messages before sending */ byte minDowngrade; /* minimum downgrade version */ +#ifndef NO_DH + word16 minDhKeySz; /* minimum DH key size */ +#endif CallbackIORecv CBIORecv; CallbackIOSend CBIOSend; #ifdef WOLFSSL_DTLS @@ -1916,6 +1933,10 @@ typedef struct Options { byte minDowngrade; /* minimum downgrade version */ byte connectState; /* nonblocking resume */ byte acceptState; /* nonblocking resume */ +#ifndef NO_DH + word16 minDhKeySz; /* minimum DH key size */ + word16 dhKeySz; /* actual DH key size */ +#endif } Options; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index aaa100db8..f50bf9eb4 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -901,6 +901,10 @@ WOLFSSL_API int wolfSSL_CTX_SetTmpDH_buffer(WOLFSSL_CTX*, const unsigned char* WOLFSSL_API int wolfSSL_CTX_SetTmpDH_file(WOLFSSL_CTX*, const char* f, int format); #endif + +WOLFSSL_API int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX*, unsigned short); +WOLFSSL_API int wolfSSL_SetMinDhKey_Sz(WOLFSSL*, unsigned short); +WOLFSSL_API int wolfSSL_GetDhKey_Sz(WOLFSSL*); #endif /* NO_DH */ WOLFSSL_API int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL*, unsigned short); diff --git a/wolfssl/test.h b/wolfssl/test.h index 31d90f12b..1b1e444ba 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -154,6 +154,11 @@ #define CLIENT_DEFAULT_VERSION 3 #define CLIENT_DTLS_DEFAULT_VERSION (-2) #define CLIENT_INVALID_VERSION (-99) +#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_MAX_STRENGTH) + #define DEFAULT_MIN_DHKEY_BITS 2048 +#else + #define DEFAULT_MIN_DHKEY_BITS 1024 +#endif /* all certs relative to wolfSSL home directory now */ #define caCert "./certs/ca-cert.pem"