diff --git a/examples/server/server.c b/examples/server/server.c index 65845dd0a..64a0a263d 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -276,7 +276,8 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) int loopIndefinitely = 0; int echoData = 0; int throughput = 0; - int minDhKeyBits = DEFAULT_MIN_DHKEY_BITS; + int minDhKeyBits = DEFAULT_MIN_DHKEY_BITS; + int minRsaKeyBits = DEFAULT_MIN_RSAKEY_BITS; int doListen = 1; int crlFlags = 0; int ret; @@ -327,6 +328,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) (void)useNtruKey; (void)doCliCertCheck; (void)minDhKeyBits; + (void)minRsaKeyBits; (void)alpnList; (void)alpn_opt; (void)crlFlags; @@ -642,7 +644,14 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #endif #ifndef NO_DH - wolfSSL_CTX_SetMinDhKey_Sz(ctx, (word16)minDhKeyBits); + if (wolfSSL_CTX_SetMinDhKey_Sz(ctx, (word16)minDhKeyBits) != SSL_SUCCESS) { + err_sys("Error setting minimum DH key size"); + } +#endif +#ifndef NO_RSA + if (wolfSSL_CTX_SetMinRsaKey_Sz(ctx, (word16)minRsaKeyBits) != SSL_SUCCESS){ + err_sys("Error setting minimum RSA key size"); + } #endif #ifdef HAVE_NTRU diff --git a/src/internal.c b/src/internal.c index 9407321da..f6aa4382c 100755 --- a/src/internal.c +++ b/src/internal.c @@ -549,7 +549,10 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method) } #ifndef NO_DH - ctx->minDhKeySz = MIN_DHKEY_SZ; + ctx->minDhKeySz = MIN_DHKEY_SZ; +#endif +#ifndef NO_RSA + ctx->minRsaKeySz = MIN_RSAKEY_SZ; #endif #ifdef HAVE_ECC @@ -2234,6 +2237,9 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) #ifndef NO_DH ssl->options.minDhKeySz = ctx->minDhKeySz; #endif +#ifndef NO_RSA + ssl->options.minRsaKeySz = ctx->minRsaKeySz; +#endif ssl->options.sessionCacheOff = ctx->sessionCacheOff; ssl->options.sessionCacheFlushOff = ctx->sessionCacheFlushOff; @@ -5130,6 +5136,23 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, subjectHash = dCert->subjectHash; #endif + /* Check key sizes for certs. Is redundent check since ProcessBuffer + also performs this check. */ + switch (dCert->keyOID) { + #ifndef NO_RSA + case RSAk: + if (dCert->pubKeySize < ssl->options.minRsaKeySz) { + WOLFSSL_MSG("RSA key in cert chain was too small"); + ret = RSA_KEY_SIZE_E; + } + break; + #endif /* !NO_RSA */ + + default: + WOLFSSL_MSG("Key size not checked"); + break; /* key is not being checked for size if not in switch */ + } + if (ret == 0 && dCert->isCA == 0) { WOLFSSL_MSG("Chain cert is not a CA, not adding as one"); } @@ -5441,6 +5464,15 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, #endif /* NO_RSA */ #endif /*HAVE_PK_CALLBACKS */ } + + /* check size of peer RSA key */ + if (ret == 0 && ssl->peerRsaKeyPresent && + wc_RsaEncryptSize(ssl->peerRsaKey) + < ssl->options.minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Peer RSA key is too small"); + } + } break; #endif /* NO_RSA */ @@ -10130,6 +10162,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case ASYNC_NOT_PENDING: return "Async operation not pending"; + case RSA_KEY_SIZE_E: + return "RSA key too small"; + default : return "unknown error number"; } @@ -13919,8 +13954,13 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) if (ret == 0) ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &idx, &key, ssl->buffers.key->length); - if (ret == 0) + if (ret == 0) { sigOutSz = wc_RsaEncryptSize(&key); + if (sigOutSz < ssl->options.minRsaKeySz) { + WOLFSSL_MSG("RSA key size too small"); + return RSA_KEY_SIZE_E; + } + } else #endif { @@ -14868,6 +14908,11 @@ int DoSessionTicket(WOLFSSL* ssl, goto exit_sske; } sigSz = wc_RsaEncryptSize((RsaKey*)ssl->sigKey); + + if (sigSz < ssl->options.minRsaKeySz) { + WOLFSSL_MSG("RSA signature key size too small"); + goto exit_sske; + } break; } #endif /* !NO_RSA */ @@ -15151,6 +15196,11 @@ int DoSessionTicket(WOLFSSL* ssl, sigSz = wc_RsaEncryptSize((RsaKey*)ssl->sigKey); length += sigSz; + if (sigSz < ssl->options.minRsaKeySz) { + WOLFSSL_MSG("RSA key size too small"); + goto exit_sske; + } + if (IsAtLeastTLSv1_2(ssl)) { length += HASH_SIG_SIZE; } @@ -16971,6 +17021,10 @@ int DoSessionTicket(WOLFSSL* ssl, goto exit_dcke; } length = wc_RsaEncryptSize((RsaKey*)ssl->sigKey); + if (length < ssl->options.minRsaKeySz) { + WOLFSSL_MSG("Peer RSA key is too small"); + goto exit_dcke; + } ssl->arrays->preMasterSz = SECRET_LEN; if (ssl->options.tls) { diff --git a/src/ssl.c b/src/ssl.c index f916c185c..14e993c41 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -480,6 +480,32 @@ int wolfSSL_GetObjectSize(void) #endif +#ifndef NO_RSA +int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX* ctx, word16 keySz) +{ + if (ctx == NULL || keySz % 8 != 0) { + WOLFSSL_MSG("Key size must be divisable by 8 or ctx was null"); + return BAD_FUNC_ARG; + } + + ctx->minRsaKeySz = keySz / 8; + ctx->cm->minRsaKeySz = keySz / 8; + return SSL_SUCCESS; +} + + +int wolfSSL_SetMinRsaKey_Sz(WOLFSSL* ssl, word16 keySz) +{ + if (ssl == NULL || keySz % 8 != 0) { + WOLFSSL_MSG("Key size must be divisable by 8 or ssl was null"); + return BAD_FUNC_ARG; + } + + ssl->options.minRsaKeySz = keySz / 8; + return SSL_SUCCESS; +} +#endif /* !NO_RSA */ + #ifndef NO_DH /* server Diffie-Hellman parameters, SSL_SUCCESS on ok */ int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz, @@ -1727,6 +1753,11 @@ WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew(void) return NULL; } #endif + + /* set default minimum key size allowed */ + #ifndef NO_RSA + cm->minRsaKeySz = MIN_RSAKEY_SZ; + #endif } return cm; @@ -2555,6 +2586,22 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) subjectHash = cert->subjectHash; #endif + /* check CA key size */ + switch (cert->keyOID) { + #ifndef NO_RSA + case RSAk: + if (cert->pubKeySize < cm->minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG(" CA RSA key is too small"); + } + break; + #endif /* !NO_RSA */ + + default: + WOLFSSL_MSG(" No key size check done on CA"); + break; /* no size check if key type is not in switch */ + } + if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA) { WOLFSSL_MSG(" Can't add as CA if not actually one"); ret = NOT_CA_ERROR; @@ -3428,6 +3475,20 @@ static int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, if (!eccKey) ret = SSL_BAD_FILE; } else { + /* check that the size of the RSA key is enough */ + int RsaSz = wc_RsaEncryptSize((RsaKey*)key); + if (ssl) { + if (RsaSz < ssl->options.minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Private Key size too small"); + } + } + else if(ctx) { + if (RsaSz < ctx->minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Private Key size too small"); + } + } rsaKey = 1; (void)rsaKey; /* for no ecc builds */ } @@ -3527,10 +3588,38 @@ static int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, } #endif + /* check key size of cert */ + switch (cert->keyOID) { + #ifndef NO_RSA + case RSAk: + if (ssl) { + if (cert->pubKeySize < ssl->options.minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Certificate RSA key size too small"); + } + } + else if (ctx) { + if (cert->pubKeySize < ctx->minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG("Certificate RSA key size too small"); + } + } + break; + #endif /* !NO_RSA */ + + default: + WOLFSSL_MSG("No key size check done on certificate"); + break; /* do no check if not a case for the key */ + } + FreeDecodedCert(cert); #ifdef WOLFSSL_SMALL_STACK XFREE(cert, heap, DYNAMIC_TYPE_TMP_BUFFER); #endif + + if (ret != 0) { + return ret; + } } return SSL_SUCCESS; diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 96a89cf81..19a430a61 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -144,6 +144,7 @@ enum wolfSSL_ErrorCodes { OCSP_INVALID_STATUS = -407, /* Invalid OCSP Status */ ASYNC_NOT_PENDING = -408, /* Async operation not pending */ + RSA_KEY_SIZE_E = -409, /* RSA key too small */ /* 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 8c88e471e..3fdbe6c3b 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1063,7 +1063,22 @@ enum Misc { /* 150 suites for now! */ #endif +/* set minimum RSA key size allowed */ +#ifndef WOLFSSL_MIN_RSA_BITS + #ifdef WOLFSSL_MAX_STRENGTH + #define WOLFSSL_MIN_RSA_BITS 2048 + #else + #define WOLFSSL_MIN_RSA_BITS 1024 + #endif +#endif /* WOLFSSL_MIN_RSA_BITS */ +#if (WOLFSSL_MIN_RSA_BITS % 8) + /* This is to account for the example case of a min size of 2050 bits but + still allows 2049 bit key. So we need the measurment to be in bytes. */ + #error RSA minimum bit size must be a multiple of 8 +#endif +#define MIN_RSAKEY_SZ (WOLFSSL_MIN_RSA_BITS / 8) +/* set minimum DH key size allowed */ #ifndef WOLFSSL_MIN_DHKEY_BITS #ifdef WOLFSSL_MAX_STRENGTH #define WOLFSSL_MIN_DHKEY_BITS 2048 @@ -1481,6 +1496,10 @@ struct WOLFSSL_CERT_MANAGER { byte ocspSendNonce; /* send the OCSP nonce ? */ byte ocspUseOverrideURL; /* ignore cert's responder, override */ byte ocspStaplingEnabled; /* is OCSP Stapling on ? */ + +#ifndef NO_RSA + word16 minRsaKeySz; /* minimum allowed RSA key size */ +#endif }; WOLFSSL_LOCAL int CM_SaveCertCache(WOLFSSL_CERT_MANAGER*, const char*); @@ -1876,6 +1895,9 @@ struct WOLFSSL_CTX { byte minDowngrade; /* minimum downgrade version */ #ifndef NO_DH word16 minDhKeySz; /* minimum DH key size */ +#endif +#ifndef NO_RSA + word16 minRsaKeySz; /* minimum RSA key size */ #endif CallbackIORecv CBIORecv; CallbackIOSend CBIOSend; @@ -2341,6 +2363,9 @@ typedef struct Options { word16 minDhKeySz; /* minimum DH key size */ word16 dhKeySz; /* actual DH key size */ #endif +#ifndef NO_RSA + word16 minRsaKeySz; /* minimum RSA key size */ +#endif } Options; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index f7b1373a7..72434bd63 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -938,6 +938,11 @@ WOLFSSL_API int wolfSSL_SetMinDhKey_Sz(WOLFSSL*, unsigned short); WOLFSSL_API int wolfSSL_GetDhKey_Sz(WOLFSSL*); #endif /* NO_DH */ +#ifndef NO_RSA +WOLFSSL_API int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX*, unsigned short); +WOLFSSL_API int wolfSSL_SetMinRsaKey_Sz(WOLFSSL*, unsigned short); +#endif /* NO_RSA */ + WOLFSSL_API int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL*, unsigned short); WOLFSSL_API int wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX*, unsigned short); diff --git a/wolfssl/test.h b/wolfssl/test.h index 293ef0309..7d8ecbf16 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -231,6 +231,11 @@ #else #define DEFAULT_MIN_DHKEY_BITS 1024 #endif +#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_MAX_STRENGTH) + #define DEFAULT_MIN_RSAKEY_BITS 2048 +#else + #define DEFAULT_MIN_RSAKEY_BITS 1024 +#endif /* all certs relative to wolfSSL home directory now */ #if defined(WOLFSSL_NO_CURRDIR) || defined(WOLFSSL_MDK_SHELL)