diff --git a/examples/server/server.c b/examples/server/server.c index ac39075f3..d15217166 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -278,6 +278,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) int throughput = 0; int minDhKeyBits = DEFAULT_MIN_DHKEY_BITS; int minRsaKeyBits = DEFAULT_MIN_RSAKEY_BITS; + short minEccKeyBits = DEFAULT_MIN_ECCKEY_BITS; int doListen = 1; int crlFlags = 0; int ret; @@ -329,6 +330,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) (void)doCliCertCheck; (void)minDhKeyBits; (void)minRsaKeyBits; + (void)minEccKeyBits; (void)alpnList; (void)alpn_opt; (void)crlFlags; @@ -649,6 +651,11 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) err_sys("Error setting minimum RSA key size"); } #endif +#ifdef HAVE_ECC + if (wolfSSL_CTX_SetMinEccKey_Sz(ctx, minEccKeyBits) != SSL_SUCCESS){ + err_sys("Error setting minimum ECC key size"); + } +#endif #ifdef HAVE_NTRU if (useNtruKey) { diff --git a/src/internal.c b/src/internal.c index 06fa29237..1e81e3b6e 100755 --- a/src/internal.c +++ b/src/internal.c @@ -554,8 +554,8 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method) #ifndef NO_RSA ctx->minRsaKeySz = MIN_RSAKEY_SZ; #endif - #ifdef HAVE_ECC + ctx->minEccKeySz = MIN_ECCKEY_SZ; ctx->eccTempKeySz = ECDHE_SIZE; #endif @@ -2240,6 +2240,9 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) #ifndef NO_RSA ssl->options.minRsaKeySz = ctx->minRsaKeySz; #endif +#ifdef HAVE_ECC + ssl->options.minEccKeySz = ctx->minEccKeySz; +#endif ssl->options.sessionCacheOff = ctx->sessionCacheOff; ssl->options.sessionCacheFlushOff = ctx->sessionCacheFlushOff; @@ -5148,6 +5151,15 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, } break; #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + if (ssl->options.minEccKeySz < 0 || + dCert->pubKeySize < (word16)ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key size in cert chain error"); + ret = ECC_KEY_SIZE_E; + } + break; + #endif /* HAVE_ECC */ default: WOLFSSL_MSG("Key size not checked"); @@ -5534,6 +5546,16 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, #endif /* HAVE_ECC */ #endif /*HAVE_PK_CALLBACKS */ } + + /* check size of peer ECC key */ + if (ret == 0 && ssl->peerEccDsaKeyPresent && + !ssl->options.verifyNone && + wc_ecc_size(ssl->peerEccDsaKey) + < ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Peer ECC key is too small"); + } + } break; #endif /* HAVE_ECC */ @@ -10168,6 +10190,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case RSA_KEY_SIZE_E: return "RSA key too small"; + case ECC_KEY_SIZE_E: + return "ECC key too small"; + default : return "unknown error number"; } @@ -13982,6 +14007,12 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) WOLFSSL_MSG("Using ECC client cert"); usingEcc = 1; sigOutSz = MAX_ENCODED_SIG_SZ; + + /* check minimum size of ECC key */ + if (wc_ecc_size(&eccKey) < ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key size too small"); + return ECC_KEY_SIZE_E; + } } else { WOLFSSL_MSG("Bad client cert type"); @@ -14937,6 +14968,14 @@ int DoSessionTicket(WOLFSSL* ssl, goto exit_sske; } sigSz = wc_ecc_sig_size((ecc_key*)ssl->sigKey); /* worst case estimate */ + + /* check the minimum ECC key size */ + if (wc_ecc_size((ecc_key*)ssl->sigKey) < + ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key size too small"); + ret = ECC_KEY_SIZE_E; + goto exit_sske; + } break; } default: @@ -17219,6 +17258,11 @@ int DoSessionTicket(WOLFSSL* ssl, ssl->buffers.key->length); if (ret == 0) { private_key = (ecc_key*)ssl->sigKey; + if (wc_ecc_size(private_key) < + ssl->options.minEccKeySz) { + WOLFSSL_MSG("ECC key too small"); + ERROR_OUT(ECC_KEY_SIZE_E, exit_dcke); + } } } else if (ssl->eccTempKeyPresent == 0) { diff --git a/src/ssl.c b/src/ssl.c index 1dab84730..1eaca0782 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -483,6 +483,31 @@ int wolfSSL_GetObjectSize(void) } #endif +#ifdef HAVE_ECC +int wolfSSL_CTX_SetMinEccKey_Sz(WOLFSSL_CTX* ctx, short keySz) +{ + if (ctx == NULL || keySz < 0 || keySz % 8 != 0) { + WOLFSSL_MSG("Key size must be divisable by 8 or ctx was null"); + return BAD_FUNC_ARG; + } + + ctx->minEccKeySz = keySz / 8; + ctx->cm->minEccKeySz = keySz / 8; + return SSL_SUCCESS; +} + + +int wolfSSL_SetMinEccKey_Sz(WOLFSSL* ssl, short keySz) +{ + if (ssl == NULL || keySz < 0 || keySz % 8 != 0) { + WOLFSSL_MSG("Key size must be divisable by 8 or ssl was null"); + return BAD_FUNC_ARG; + } + + ssl->options.minEccKeySz = keySz / 8; + return SSL_SUCCESS; +} +#endif /* !NO_RSA */ #ifndef NO_RSA int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX* ctx, word16 keySz) @@ -1762,6 +1787,9 @@ WOLFSSL_CERT_MANAGER* wolfSSL_CertManagerNew(void) #ifndef NO_RSA cm->minRsaKeySz = MIN_RSAKEY_SZ; #endif + #ifdef HAVE_ECC + cm->minEccKeySz = MIN_ECCKEY_SZ; + #endif } return cm; @@ -2603,6 +2631,15 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) } break; #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + if (cm->minEccKeySz < 0 || + cert->pubKeySize < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG(" CA ECC key size error"); + } + break; + #endif /* HAVE_ECC */ default: WOLFSSL_MSG(" No key size check done on CA"); @@ -3524,6 +3561,23 @@ static int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, wc_ecc_free(&key); return SSL_BAD_FILE; } + + /* check for minimum ECC key size and then free */ + if (ssl) { + if (wc_ecc_size(&key) < ssl->options.minEccKeySz) { + wc_ecc_free(&key); + WOLFSSL_MSG("ECC private key too small"); + return ECC_KEY_SIZE_E; + } + } + else if (ctx) { + if (wc_ecc_size(&key) < ctx->minEccKeySz) { + wc_ecc_free(&key); + WOLFSSL_MSG("ECC private key too small"); + return ECC_KEY_SIZE_E; + } + } + wc_ecc_free(&key); eccKey = 1; if (ctx) @@ -3614,6 +3668,24 @@ static int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, } break; #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + if (ssl && !ssl->options.verifyNone) { + if (ssl->options.minEccKeySz < 0 || + cert->pubKeySize < (word16)ssl->options.minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + else if (ctx && !ctx->verifyNone) { + if (ctx->minEccKeySz < 0 || + cert->pubKeySize < (word16)ctx->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("Certificate ECC key size error"); + } + } + break; + #endif /* HAVE_ECC */ default: WOLFSSL_MSG("No key size check done on certificate"); diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 19a430a61..11aedea53 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -145,6 +145,7 @@ enum wolfSSL_ErrorCodes { ASYNC_NOT_PENDING = -408, /* Async operation not pending */ RSA_KEY_SIZE_E = -409, /* RSA key too small */ + ECC_KEY_SIZE_E = -410, /* ECC 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 eea8b2908..e20d28433 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1063,6 +1063,24 @@ enum Misc { /* 150 suites for now! */ #endif +/* set minimum ECC key size allowed */ +#ifndef WOLFSSL_MIN_ECC_BITS + #ifdef WOLFSSL_MAX_STRENGTH + #define WOLFSSL_MIN_ECC_BITS 256 + #else + #define WOLFSSL_MIN_ECC_BITS 224 + #endif +#endif /* WOLFSSL_MIN_ECC_BITS */ +#if (WOLFSSL_MIN_ECC_BITS % 8) + /* Some ECC keys are not divisable by 8 such as prime239v1 or sect131r1. + In these cases round down to the nearest value divisable by 8. The + restriction of being divisable by 8 is in place to match wc_ecc_size + function from wolfSSL. + */ + #error ECC minimum bit size must be a multiple of 8 +#endif +#define MIN_ECCKEY_SZ (WOLFSSL_MIN_ECC_BITS / 8) + /* set minimum RSA key size allowed */ #ifndef WOLFSSL_MIN_RSA_BITS #ifdef WOLFSSL_MAX_STRENGTH @@ -1500,6 +1518,9 @@ struct WOLFSSL_CERT_MANAGER { #ifndef NO_RSA word16 minRsaKeySz; /* minimum allowed RSA key size */ #endif +#ifdef HAVE_ECC + short minEccKeySz; /* minimum allowed ECC key size */ +#endif }; WOLFSSL_LOCAL int CM_SaveCertCache(WOLFSSL_CERT_MANAGER*, const char*); @@ -1898,6 +1919,9 @@ struct WOLFSSL_CTX { #endif #ifndef NO_RSA word16 minRsaKeySz; /* minimum RSA key size */ +#endif +#ifdef HAVE_ECC + short minEccKeySz; /* minimum ECC key size */ #endif CallbackIORecv CBIORecv; CallbackIOSend CBIOSend; @@ -2366,6 +2390,9 @@ typedef struct Options { #ifndef NO_RSA word16 minRsaKeySz; /* minimum RSA key size */ #endif +#ifdef HAVE_ECC + short minEccKeySz; /* minimum ECC key size */ +#endif } Options; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 72434bd63..755cde40e 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -943,6 +943,11 @@ WOLFSSL_API int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX*, unsigned short); WOLFSSL_API int wolfSSL_SetMinRsaKey_Sz(WOLFSSL*, unsigned short); #endif /* NO_RSA */ +#ifdef HAVE_ECC +WOLFSSL_API int wolfSSL_CTX_SetMinEccKey_Sz(WOLFSSL_CTX*, short); +WOLFSSL_API int wolfSSL_SetMinEccKey_Sz(WOLFSSL*, 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 bace1f322..140ac64ea 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -236,6 +236,11 @@ #else #define DEFAULT_MIN_RSAKEY_BITS 1024 #endif +#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_MAX_STRENGTH) + #define DEFAULT_MIN_ECCKEY_BITS 256 +#else + #define DEFAULT_MIN_ECCKEY_BITS 224 +#endif /* all certs relative to wolfSSL home directory now */ #if defined(WOLFSSL_NO_CURRDIR) || defined(WOLFSSL_MDK_SHELL)