From df3abee72c5ee23224bb5687982ba5799aea8577 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 10 May 2017 12:59:22 +1000 Subject: [PATCH 1/2] TLS v1.3 Interop changes Added Curve25519 for TLS v1.3 only. Curve25519 won't work with older protocol versions. Always send signature algorithm extension in TLS v1.3 for server certificates. If only doing PSK doesn't need to be sent though. --- src/tls.c | 329 ++++++++++++++++++++++++++++++++++++++++++--- wolfssl/internal.h | 1 + 2 files changed, 313 insertions(+), 17 deletions(-) diff --git a/src/tls.c b/src/tls.c index 24943275f..fb60eadae 100755 --- a/src/tls.c +++ b/src/tls.c @@ -40,6 +40,10 @@ #include #endif +#ifdef HAVE_CURVE25519 + #include +#endif + #ifdef HAVE_NTRU #include "libntruencrypt/ntru_crypto.h" #include @@ -4304,9 +4308,9 @@ static word16 TLSX_SupportedVersions_Write(byte* data, byte* output) /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ if (pv.minor - i == TLSv1_3_MINOR) { /* The TLS draft major number. */ - *(output++) = 0x7f; + *(output++) = TLS_DRAFT_MAJOR; /* Version of draft supported. */ - *(output++) = 18; + *(output++) = TLS_DRAFT_MINOR; continue; } @@ -4347,7 +4351,8 @@ static int TLSX_SupportedVersions_Parse(WOLFSSL *ssl, byte* input, /* Find first match. */ for (i = 0; i < len; i += OPAQUE16_LEN) { /* TODO: [TLS13] Remove code when TLS v1.3 becomes an RFC. */ - if (input[i] == 0x7f && input[i + OPAQUE8_LEN] == 18) { + if (input[i] == TLS_DRAFT_MAJOR && + input[i + OPAQUE8_LEN] == TLS_DRAFT_MINOR) { ssl->version.minor = TLSv1_3_MINOR; ssl->options.tls1_3 = 1; TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, input, @@ -4411,6 +4416,174 @@ static int TLSX_SetSupportedVersions(TLSX** extensions, const void* data, #endif /* WOLFSSL_TLS13 */ +/******************************************************************************/ +/* Sugnature Algorithms */ +/******************************************************************************/ + +#ifdef WOLFSSL_TLS13 +/* Return the size of the SignatureAlgorithms extension's data. + * + * data Unused + * returns the length of data that will be in the extension. + */ +static word16 TLSX_SignatureAlgorithms_GetSize(byte* data) +{ + int cnt = 0; + + (void)data; + +#ifndef NO_RSA + #ifndef NO_SHA1 + cnt++; + #endif + #ifndef NO_SHA256 + cnt++; + #endif + #ifdef HAVE_SHA384 + cnt++; + #endif + #ifdef HAVE_SHA512 + cnt++; + #endif +#endif + +#ifdef HAVE_ECC + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + cnt++; + #endif + #endif + #if !defined(NO_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + cnt++; + #endif + #endif + #if !defined(NO_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + cnt++; + #endif + #endif +#endif + + return OPAQUE16_LEN + cnt * OPAQUE16_LEN; +} + +/* Writes the SignatureAlgorithms extension into the buffer. + * + * data Unused + * output The buffer to write the extension into. + * returns the length of data that was written. + */ +static word16 TLSX_SignatureAlgorithms_Write(byte* data, byte* output) +{ + int idx = OPAQUE16_LEN; + + (void)data; + +#ifndef NO_RSA + #ifndef NO_SHA1 + output[idx++] = 0x02; + output[idx++] = 0x01; + #endif + #ifndef NO_SHA256 + output[idx++] = 0x04; + output[idx++] = 0x01; + #endif + #ifdef HAVE_SHA384 + output[idx++] = 0x05; + output[idx++] = 0x01; + #endif + #ifdef HAVE_SHA512 + output[idx++] = 0x06; + output[idx++] = 0x01; + #endif +#endif + +#ifdef HAVE_ECC + #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + output[idx++] = 0x04; + output[idx++] = 0x03; + #endif + #endif + #if !defined(NO_ECC384) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + output[idx++] = 0x05; + output[idx++] = 0x03; + #endif + #endif + #if !defined(NO_ECC521) || defined(HAVE_ALL_CURVES) + #ifndef NO_ECC_SECP + output[idx++] = 0x06; + output[idx++] = 0x03; + #endif + #endif +#endif + + output[0] = (idx - OPAQUE16_LEN) >> 8; + output[1] = idx - OPAQUE16_LEN; + + return idx; +} + +/* Parse the SignatureAlgorithms extension. + * + * ssl The SSL/TLS object. + * input The buffer with the extension data. + * length The length of the extension data. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SignatureAlgorithms_Parse(WOLFSSL *ssl, byte* input, + word16 length) +{ + int ret = 0; + word16 len; + + (void)ssl; + + /* Must contain a length and at least algorithm. */ + if (length < OPAQUE16_LEN + OPAQUE16_LEN || (length & 1) != 0) + return BUFFER_ERROR; + + ato16(input, &len); + + /* Algorithm array must fill rest of data. */ + if (length != OPAQUE16_LEN + len) + return BUFFER_ERROR; + + /* Ignore for now. */ + + return ret; +} + +/* Sets a new SupportedVersions extension into the extension list. + * + * extensions The list of extensions. + * data The extensions specific data. + * heap The heap used for allocation. + * returns 0 on success, otherwise failure. + */ +static int TLSX_SetSignatureAlgorithms(TLSX** extensions, const void* data, + void* heap) +{ + if (extensions == NULL) + return BAD_FUNC_ARG; + + return TLSX_Push(extensions, TLSX_SIGNATURE_ALGORITHMS, (void *)data, heap); +} + +#define SA_GET_SIZE TLSX_SignatureAlgorithms_GetSize +#define SA_WRITE TLSX_SignatureAlgorithms_Write +#define SA_PARSE TLSX_SignatureAlgorithms_Parse + +#else + +#define SA_GET_SIZE(a) 0 +#define SA_WRITE(a, b) 0 +#define SA_PARSE(a, b, c) 0 + +#endif + /******************************************************************************/ /* Key Share */ /******************************************************************************/ @@ -4588,9 +4761,52 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) #endif #ifdef HAVE_CURVE25519 case WOLFSSL_ECC_X25519: - curveId = ECC_X25519; - dataSize = keySize = 32; - break; + { + curve25519_key* key; + /* Allocate an ECC key to hold private key. */ + key = (curve25519_key*)XMALLOC(sizeof(curve25519_key), + ssl->heap, DYNAMIC_TYPE_TLSX); + if (key == NULL) { + WOLFSSL_MSG("EccTempKey Memory error"); + return MEMORY_E; + } + + dataSize = keySize = 32; + + /* Make an ECC key. */ + ret = wc_curve25519_init(key); + if (ret != 0) + goto end; + ret = wc_curve25519_make_key(ssl->rng, keySize, key); + if (ret != 0) + goto end; + + /* Allocate space for the public key. */ + keyData = XMALLOC(dataSize, ssl->heap, DYNAMIC_TYPE_TLSX); + if (keyData == NULL) { + WOLFSSL_MSG("Key data Memory error"); + ret = MEMORY_E; + goto end; + } + + /* Export public key. */ + if (wc_curve25519_export_public_ex(key, keyData, &dataSize, + EC25519_LITTLE_ENDIAN) != 0) { + ret = ECC_EXPORT_ERROR; + goto end; + } + + kse->ke = keyData; + kse->keLen = dataSize; + kse->key = key; + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Public ECC Key"); + WOLFSSL_BUFFER(keyData, dataSize); +#endif + + goto end; + } #endif #ifdef HAVE_X448 case WOLFSSL_ECC_X448: @@ -4922,8 +5138,42 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) #endif #ifdef HAVE_CURVE25519 case WOLFSSL_ECC_X25519: - curveId = ECC_X25519; - break; + { + curve25519_key* key = (curve25519_key*)keyShareEntry->key; + curve25519_key* peerEccKey; + + if (ssl->peerEccKey != NULL) + wc_ecc_free(ssl->peerEccKey); + + peerEccKey = (curve25519_key*)XMALLOC(sizeof(curve25519_key), + ssl->heap, DYNAMIC_TYPE_TLSX); + if (peerEccKey == NULL) { + WOLFSSL_MSG("PeerEccKey Memory error"); + return MEMORY_ERROR; + } + ret = wc_curve25519_init(peerEccKey); + if (ret != 0) + return ret; +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Peer ECC Key"); + WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); +#endif + + /* Point is validated by import function. */ + if (wc_curve25519_import_public_ex(keyShareEntry->ke, + keyShareEntry->keLen, peerEccKey, + EC25519_LITTLE_ENDIAN) != 0) { + return ECC_PEERKEY_ERROR; + } + + ssl->arrays->preMasterSz = ENCRYPT_LEN; + ret = wc_curve25519_shared_secret_ex(key, peerEccKey, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, + EC25519_LITTLE_ENDIAN); + wc_curve25519_free(peerEccKey); + XFREE(peerEccKey, ssl->heap, DYNAMIC_TYPE_TLSX); + return ret; + } #endif #ifdef HAVE_X448 case WOLFSSL_ECC_X448: @@ -6136,6 +6386,9 @@ void TLSX_FreeAll(TLSX* list, void* heap) ALPN_FREE_ALL((ALPN*)extension->data, heap); break; + case TLSX_SIGNATURE_ALGORITHMS: + break; + #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: break; @@ -6237,6 +6490,12 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType) length += ALPN_GET_SIZE((ALPN*)extension->data); break; + case TLSX_SIGNATURE_ALGORITHMS: +#ifdef WOLFSSL_TLS13 + length += SA_GET_SIZE(extension->data); +#endif + break; + #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: length += SV_GET_SIZE(extension->data); @@ -6355,6 +6614,13 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, offset += ALPN_WRITE((ALPN*)extension->data, output + offset); break; + case TLSX_SIGNATURE_ALGORITHMS: +#ifdef WOLFSSL_TLS13 + WOLFSSL_MSG("Signature Algorithms extension to write"); + offset += SA_WRITE(extension->data, output + offset); +#endif + break; + #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: WOLFSSL_MSG("Supported Versions extension to write"); @@ -6760,6 +7026,15 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) if (ret != SSL_SUCCESS) return ret; #endif #endif + #ifdef WOLFSSL_TLS13 + #if defined(HAVE_CURVE25519) + #ifndef NO_ECC_SECP + ret = TLSX_UseSupportedCurve(&ssl->extensions, + WOLFSSL_ECC_X25519, ssl->heap); + if (ret != SSL_SUCCESS) return ret; + #endif + #endif + #endif } #endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */ } /* is not server */ @@ -6771,6 +7046,11 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) if ((ret = TLSX_SetSupportedVersions(&ssl->extensions, ssl, ssl->heap)) != 0) return ret; + /* Add TLS v1.3 extension: signature algorithms */ + WOLFSSL_MSG("Adding signature algorithms extension"); + if ((ret = TLSX_SetSignatureAlgorithms(&ssl->extensions, NULL, + ssl->heap)) != 0) + return ret; /* Add FFDHE supported groups. */ #ifdef HAVE_FFDHE_2048 @@ -6898,6 +7178,7 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl) #if defined(WOLFSSL_TLS13) if (!IsAtLeastTLSv1_3(ssl->version)) { TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #ifndef NO_PSK TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); @@ -6914,9 +7195,11 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl) client_hello); } +#ifndef WOLFSSL_TLS13 if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) - length += HELLO_EXT_SZ + HELLO_EXT_SIGALGO_SZ + length += HELLO_EXT_SZ + OPAQUE16_LEN + + ssl->suites->hashSigAlgoSz; +#endif #ifdef HAVE_EXTENDED_MASTER if (ssl->options.haveEMS) @@ -6946,6 +7229,7 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) #if defined(WOLFSSL_TLS13) if (!IsAtLeastTLSv1_3(ssl->version)) { TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS)); + TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS)); TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #ifndef NO_PSK TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES)); @@ -6964,10 +7248,11 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) offset += TLSX_Write(ssl->ctx->extensions, output + offset, semaphore, client_hello); +#ifndef WOLFSSL_TLS13 if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) { int i; /* extension type */ - c16toa(HELLO_EXT_SIG_ALGO, output + offset); + c16toa(TLSX_SIGNATURE_ALGORITHMS, output + offset); offset += HELLO_EXT_TYPE_SZ; /* extension data length */ @@ -6983,6 +7268,7 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, offset++) output[offset] = ssl->suites->hashSigAlgo[i]; } +#endif #ifdef HAVE_EXTENDED_MASTER if (ssl->options.haveEMS) { @@ -7285,16 +7571,11 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, ret = ALPN_PARSE(ssl, input + offset, size, isRequest); break; - case HELLO_EXT_SIG_ALGO: +#ifndef WOLFSSL_TLS13 + case TLSX_SIGNATURE_ALGORITHMS: WOLFSSL_MSG("Extended signature algorithm extension received"); if (isRequest) { -#ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version) && - msgType != client_hello) { - return EXT_NOT_ALLOWED; - } -#endif /* do not mess with offset inside the switch! */ if (IsAtLeastTLSv1_2(ssl)) { ato16(input + offset, &suites->hashSigAlgoSz); @@ -7312,6 +7593,7 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, } break; +#endif #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: @@ -7327,6 +7609,19 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, ret = SV_PARSE(ssl, input + offset, size); break; + case TLSX_SIGNATURE_ALGORITHMS: + WOLFSSL_MSG("Signature Algorithms extension received"); + + if (!IsAtLeastTLSv1_3(ssl->version)) + break; + + if (IsAtLeastTLSv1_3(ssl->version) && + msgType != client_hello) { + return EXT_NOT_ALLOWED; + } + ret = SA_PARSE(ssl, input + offset, size); + break; + case TLSX_KEY_SHARE: WOLFSSL_MSG("Key Share extension received"); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index ae9c00b97..9b490bddd 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1747,6 +1747,7 @@ typedef enum { TLSX_TRUNCATED_HMAC = 0x0004, TLSX_STATUS_REQUEST = 0x0005, /* a.k.a. OCSP stapling */ TLSX_SUPPORTED_GROUPS = 0x000a, /* a.k.a. Supported Curves */ + TLSX_SIGNATURE_ALGORITHMS = 0x000d, TLSX_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */ TLSX_STATUS_REQUEST_V2 = 0x0011, /* a.k.a. OCSP stapling v2 */ TLSX_QUANTUM_SAFE_HYBRID = 0x0018, /* a.k.a. QSH */ From ec6d8f48b8f18efd978abe144f459f21fd3f28ac Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 10 May 2017 16:59:11 +1000 Subject: [PATCH 2/2] Add PSS for TLS v1.3 --- configure.ac | 1 + src/internal.c | 41 ++++++++++++- src/tls.c | 25 ++++++++ src/tls13.c | 69 ++++++++++++++------- wolfcrypt/src/rsa.c | 133 ++++++++++++++++++++++++++++++++++++++-- wolfssl/internal.h | 12 ++-- wolfssl/wolfcrypt/rsa.h | 4 ++ 7 files changed, 251 insertions(+), 34 deletions(-) diff --git a/configure.ac b/configure.ac index 87eb28026..d20614d8f 100644 --- a/configure.ac +++ b/configure.ac @@ -243,6 +243,7 @@ AC_ARG_ENABLE([tls13], if test "$ENABLED_TLS13" = "yes" then AM_CFLAGS="-DWOLFSSL_TLS13 -DHAVE_TLS_EXTENSIONS -DHAVE_FFDHE_2048 $AM_CFLAGS" + AM_CFLAGS="-DWC_RSA_PSS $AM_CFLAGS" fi # check if TLS v1.3 was enabled for conditionally running tls13.test script diff --git a/src/internal.c b/src/internal.c index 25fa2ac48..a6db2d19d 100755 --- a/src/internal.c +++ b/src/internal.c @@ -2773,8 +2773,9 @@ int RsaSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, return ret; } -int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, - byte** out, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx) +int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, byte** out, int sigAlgo, + int hashAlgo, RsaKey* key, const byte* keyBuf, word32 keySz, + void* ctx) { int ret; @@ -2782,6 +2783,8 @@ int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, (void)keyBuf; (void)keySz; (void)ctx; + (void)sigAlgo; + (void)hashAlgo; WOLFSSL_ENTER("RsaVerify"); @@ -2792,7 +2795,37 @@ int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, else #endif /*HAVE_PK_CALLBACKS */ { - ret = wc_RsaSSL_VerifyInline(in, inSz, out, key); +#ifdef WOLFSSL_TLS13 + #ifdef WC_RSA_PSS + if (sigAlgo == rsa_pss_sa_algo) { + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + int mgf = 0; + switch (hashAlgo) { + case sha512_mac: + #ifdef WOLFSSL_SHA512 + hashType = WC_HASH_TYPE_SHA512; + mgf = WC_MGF1SHA512; + #endif + break; + case sha384_mac: + #ifdef WOLFSSL_SHA384 + hashType = WC_HASH_TYPE_SHA384; + mgf = WC_MGF1SHA384; + #endif + break; + case sha256_mac: + #ifndef NO_SHA256 + hashType = WC_HASH_TYPE_SHA256; + mgf = WC_MGF1SHA256; + #endif + break; + } + ret = wc_RsaPSS_VerifyInline(in, inSz, out, hashType, mgf, key); + } + else + #endif +#endif + ret = wc_RsaSSL_VerifyInline(in, inSz, out, key); } /* Handle async pending response */ @@ -16323,6 +16356,7 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, ret = RsaVerify(ssl, args->verifySig, args->verifySigSz, &args->output, + rsa_sa_algo, no_mac, ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.peerRsaKey.buffer, @@ -21091,6 +21125,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, input + args->idx, args->sz, &args->output, + rsa_sa_algo, no_mac, ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.peerRsaKey.buffer, diff --git a/src/tls.c b/src/tls.c index fb60eadae..796fc89fa 100755 --- a/src/tls.c +++ b/src/tls.c @@ -4445,6 +4445,17 @@ static word16 TLSX_SignatureAlgorithms_GetSize(byte* data) #ifdef HAVE_SHA512 cnt++; #endif + #ifdef WC_RSA_PSS + #ifndef NO_SHA256 + cnt++; + #endif + #ifdef HAVE_SHA384 + cnt++; + #endif + #ifdef HAVE_SHA512 + cnt++; + #endif + #endif #endif #ifdef HAVE_ECC @@ -4497,6 +4508,20 @@ static word16 TLSX_SignatureAlgorithms_Write(byte* data, byte* output) output[idx++] = 0x06; output[idx++] = 0x01; #endif + #ifdef WC_RSA_PSS + #ifndef NO_SHA256 + output[idx++] = 0x08; + output[idx++] = 0x04; + #endif + #ifdef HAVE_SHA384 + output[idx++] = 0x08; + output[idx++] = 0x05; + #endif + #ifdef HAVE_SHA512 + output[idx++] = 0x08; + output[idx++] = 0x06; + #endif + #endif #endif #ifdef HAVE_ECC diff --git a/src/tls13.c b/src/tls13.c index aa8d727c8..badf1d098 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -2851,12 +2851,18 @@ static INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) static INLINE void DecodeSigAlg(byte* input, byte* hashAlgo, byte* hsType) { switch (input[0]) { - /* PSS signatures: 0x080[4-6] */ + case 0x08: + /* PSS signatures: 0x080[4-6] */ + if (input[1] <= 0x06) { + *hsType = input[0]; + *hashAlgo = input[1]; + } + break; /* ED25519: 0x0807 */ /* ED448: 0x0808 */ default: *hashAlgo = input[0]; - *hsType = input[1]; + *hsType = input[1]; break; } } @@ -3048,13 +3054,14 @@ static int CreateECCEncodedSig(byte* sigData, int sigDataSz, int hashAlgo) * based on the digest of the signature data. * * ssl The SSL/TLS object. + * hashAlgo The signature algorithm used to generate signature. * hashAlgo The hash algorithm used to generate signature. * decSig The decrypted signature. * decSigSz The size of the decrypted signature. * returns 0 on success, otherwise failure. */ -static int CheckRSASignature(WOLFSSL* ssl, int hashAlgo, byte* decSig, - word32 decSigSz) +static int CheckRSASignature(WOLFSSL* ssl, int sigAlgo, int hashAlgo, + byte* decSig, word32 decSigSz) { int ret = 0; byte sigData[MAX_SIG_DATA_SZ]; @@ -3066,21 +3073,38 @@ static int CheckRSASignature(WOLFSSL* ssl, int hashAlgo, byte* decSig, #endif word32 sigSz; + if (sigAlgo == rsa_sa_algo) { #ifdef WOLFSSL_SMALL_STACK - encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (encodedSig == NULL) { - ret = MEMORY_E; - goto end; - } + encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (encodedSig == NULL) { + ret = MEMORY_E; + goto end; + } #endif - CreateSigData(ssl, sigData, &sigDataSz, 1); - sigSz = CreateRSAEncodedSig(encodedSig, sigData, sigDataSz, hashAlgo); - /* Check the encoded and decrypted signature data match. */ - if (decSigSz != sigSz || decSig == NULL || - XMEMCMP(decSig, encodedSig, sigSz) != 0) { - ret = VERIFY_CERT_ERROR; + CreateSigData(ssl, sigData, &sigDataSz, 1); + sigSz = CreateRSAEncodedSig(encodedSig, sigData, sigDataSz, hashAlgo); + /* Check the encoded and decrypted signature data match. */ + if (decSigSz != sigSz || decSig == NULL || + XMEMCMP(decSig, encodedSig, sigSz) != 0) { + ret = VERIFY_CERT_ERROR; + } + } + else { + CreateSigData(ssl, sigData, &sigDataSz, 1); + sigSz = CreateECCEncodedSig(sigData, sigDataSz, hashAlgo); + if (decSigSz != sigSz || decSig == NULL) + ret = VERIFY_CERT_ERROR; + else { + decSig -= 2 * decSigSz; + XMEMCPY(decSig, sigData, decSigSz); + decSig -= 8; + XMEMSET(decSig, 0, 8); + CreateECCEncodedSig(decSig, 8 + decSigSz * 2, hashAlgo); + if (XMEMCMP(decSig, decSig + 8 + decSigSz * 2, decSigSz) != 0) + ret = VERIFY_CERT_ERROR; + } } #ifdef WOLFSSL_SMALL_STACK @@ -3783,8 +3807,9 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, !ssl->peerEccDsaKeyPresent) { WOLFSSL_MSG("Oops, peer sent ECC key but not in verify"); } - if (args->sigAlgo == rsa_sa_algo && - (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)) { + if ((args->sigAlgo == rsa_sa_algo || + args->sigAlgo == rsa_pss_sa_algo) && + (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent)) { WOLFSSL_MSG("Oops, peer sent RSA key but not in verify"); } @@ -3818,11 +3843,12 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, case TLS_ASYNC_DO: { #ifndef NO_RSA - if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent) { + if (args->sigAlgo == rsa_sa_algo || + args->sigAlgo == rsa_pss_sa_algo) { WOLFSSL_MSG("Doing RSA peer cert verify"); ret = RsaVerify(ssl, sig->buffer, sig->length, &args->output, - ssl->peerRsaKey, + args->sigAlgo, args->hashAlgo, ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS ssl->buffers.peerRsaKey.buffer, ssl->buffers.peerRsaKey.length, @@ -3868,7 +3894,8 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, { #ifndef NO_RSA if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { - ret = CheckRSASignature(ssl, args->hashAlgo, args->output, args->sendSz); + ret = CheckRSASignature(ssl, args->sigAlgo, args->hashAlgo, + args->output, args->sendSz); if (ret != 0) goto exit_dcv; } diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index afeec506d..e419d6bb6 100755 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -261,7 +261,7 @@ int wc_FreeRsaKey(RsaKey* key) } -#ifndef WC_NO_RSA_OAEP +#if !defined(WC_NO_RSA_OAEP) || defined(WC_RSA_PSS) /* Uses MGF1 standard as a mask generation function hType: hash type used seed: seed to use for generating mask @@ -572,6 +572,50 @@ static int RsaPad_OAEP(const byte* input, word32 inputLen, byte* pkcsBlock, } #endif /* !WC_NO_RSA_OAEP */ +#ifdef WC_RSA_PSS +static int RsaPad_PSS(const byte* input, word32 inputLen, byte* pkcsBlock, + word32 pkcsBlockLen, WC_RNG* rng, enum wc_HashType hType, int mgf, + void* heap) +{ + int ret; + int hLen, i; + byte* s; + byte* m; + byte* h; + byte salt[WC_MAX_DIGEST_SIZE]; + + hLen = wc_HashGetDigestSize(hType); + if (hLen < 0) + return hLen; + + s = m = pkcsBlock; + XMEMSET(m, 0, 8); + m += 8; + XMEMCPY(m, input, inputLen); + m += inputLen; + if ((ret = wc_RNG_GenerateBlock(rng, salt, hLen)) != 0) + return ret; + XMEMCPY(m, salt, hLen); + m += hLen; + + h = pkcsBlock + pkcsBlockLen - 1 - hLen; + if ((ret = wc_Hash(hType, s, (word32)(m - s), h, hLen)) != 0) + return ret; + pkcsBlock[pkcsBlockLen - 1] = 0xbc; + + ret = RsaMGF(mgf, h, hLen, pkcsBlock, pkcsBlockLen - hLen - 1, heap); + if (ret != 0) + return ret; + pkcsBlock[0] &= 0x7f; + + m = pkcsBlock + pkcsBlockLen - 1 - hLen - hLen - 1; + *(m++) ^= 0x01; + for (i = 0; i < hLen; i++) + m[i] ^= salt[i]; + + return 0; +} +#endif static int RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock, word32 pkcsBlockLen, byte padValue, WC_RNG* rng) @@ -635,16 +679,25 @@ static int wc_RsaPad_ex(const byte* input, word32 inputLen, byte* pkcsBlock, case WC_RSA_PKCSV15_PAD: /*WOLFSSL_MSG("wolfSSL Using RSA PKCSV15 padding");*/ ret = RsaPad(input, inputLen, pkcsBlock, pkcsBlockLen, - padValue, rng); + padValue, rng); break; #ifndef WC_NO_RSA_OAEP case WC_RSA_OAEP_PAD: WOLFSSL_MSG("wolfSSL Using RSA OAEP padding"); ret = RsaPad_OAEP(input, inputLen, pkcsBlock, pkcsBlockLen, - padValue, rng, hType, mgf, optLabel, labelLen, heap); + padValue, rng, hType, mgf, optLabel, labelLen, heap); break; #endif + + #ifdef WC_RSA_PSS + case WC_RSA_PSS_PAD: + WOLFSSL_MSG("wolfSSL Using RSA PSS padding"); + ret = RsaPad_PSS(input, inputLen, pkcsBlock, pkcsBlockLen, + rng, hType, mgf, heap); + break; + #endif + default: WOLFSSL_MSG("Unknown RSA Pad Type"); ret = RSA_PAD_E; @@ -748,6 +801,53 @@ static int RsaUnPad_OAEP(byte *pkcsBlock, unsigned int pkcsBlockLen, } #endif /* WC_NO_RSA_OAEP */ +#ifdef WC_RSA_PSS +static int RsaUnPad_PSS(byte *pkcsBlock, unsigned int pkcsBlockLen, + byte **output, enum wc_HashType hType, int mgf, + void* heap) +{ + int ret; + byte* tmp; + int hLen, i; + + hLen = wc_HashGetDigestSize(hType); + if (hLen < 0) + return hLen; + + if (pkcsBlock[pkcsBlockLen - 1] != 0xbc) + return BAD_PADDING_E; + + tmp = (byte*)XMALLOC(pkcsBlockLen, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL) { + return MEMORY_E; + } + + if ((ret = RsaMGF(mgf, pkcsBlock + pkcsBlockLen - 1 - hLen, hLen, + tmp, pkcsBlockLen - 1 - hLen, heap)) != 0) { + XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + tmp[0] &= 0x7f; + for (i = 0; i < (int)(pkcsBlockLen - 1 - hLen - hLen - 1); i++) { + if (tmp[i] != pkcsBlock[i]) { + XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER); + return BAD_PADDING_E; + } + } + if (tmp[i] != (pkcsBlock[i] ^ 0x01)) { + XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER); + return BAD_PADDING_E; + } + for (i++; i < (int)(pkcsBlockLen - 1 - hLen); i++) + pkcsBlock[i] ^= tmp[i]; + + XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER); + + *output = pkcsBlock + i; + return hLen; +} +#endif /* UnPad plaintext, set start to *output, return length of plaintext, * < 0 on error */ @@ -817,6 +917,14 @@ static int wc_RsaUnPad_ex(byte* pkcsBlock, word32 pkcsBlockLen, byte** out, break; #endif + #ifdef WC_RSA_PSS + case WC_RSA_PSS_PAD: + WOLFSSL_MSG("wolfSSL Using RSA PSS un-padding"); + ret = RsaUnPad_PSS((byte*)pkcsBlock, pkcsBlockLen, out, hType, mgf, + heap); + break; + #endif + default: WOLFSSL_MSG("Unknown RSA UnPad Type"); ret = RSA_PAD_E; @@ -1105,7 +1213,8 @@ int wc_RsaFunction(const byte* in, word32 inLen, byte* out, rsa_type : type of RSA: RSA_PUBLIC_ENCRYPT, RSA_PUBLIC_DECRYPT, RSA_PRIVATE_ENCRYPT or RSA_PRIVATE_DECRYPT pad_value: RSA_BLOCK_TYPE_1 or RSA_BLOCK_TYPE_2 - pad_type : type of padding: WC_RSA_PKCSV15_PAD or WC_RSA_OAEP_PAD + pad_type : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD or + WC_RSA_PSS_PAD hash : type of hash algorithm to use found in wolfssl/wolfcrypt/hash.h mgf : type of mask generation function to use label : optional label @@ -1212,7 +1321,8 @@ static int RsaPublicEncryptEx(const byte* in, word32 inLen, byte* out, rsa_type : type of RSA: RSA_PUBLIC_ENCRYPT, RSA_PUBLIC_DECRYPT, RSA_PRIVATE_ENCRYPT or RSA_PRIVATE_DECRYPT pad_value: RSA_BLOCK_TYPE_1 or RSA_BLOCK_TYPE_2 - pad_type : type of padding: WC_RSA_PKCSV15_PAD or WC_RSA_OAEP_PAD + pad_type : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD + WC_RSA_PSS_PAD hash : type of hash algorithm to use found in wolfssl/wolfcrypt/hash.h mgf : type of mask generation function to use label : optional label @@ -1446,6 +1556,19 @@ int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen, WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, rng); } +#ifdef WC_RSA_PSS +int wc_RsaPSS_VerifyInline(byte* in, word32 inLen, byte** out, + enum wc_HashType hash, int mgf, RsaKey* key) +{ + WC_RNG* rng = NULL; +#ifdef WC_RSA_BLINDING + rng = key->rng; +#endif + return RsaPrivateDecryptEx(in, inLen, in, inLen, out, key, + RSA_PUBLIC_DECRYPT, RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD, + hash, mgf, NULL, 0, rng); +} +#endif int wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen, RsaKey* key, WC_RNG* rng) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 9b490bddd..0c6c3ed57 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2345,10 +2345,11 @@ enum KeyExchangeAlgorithm { /* Supported Authentication Schemes */ enum SignatureAlgorithm { - anonymous_sa_algo, - rsa_sa_algo, - dsa_sa_algo, - ecc_dsa_sa_algo + anonymous_sa_algo = 0, + rsa_sa_algo = 1, + dsa_sa_algo = 2, + ecc_dsa_sa_algo = 4, + rsa_pss_sa_algo = 8 }; @@ -3407,7 +3408,8 @@ WOLFSSL_LOCAL int VerifyClientSuite(WOLFSSL* ssl); WOLFSSL_LOCAL int RsaSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, word32* outSz, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx); WOLFSSL_LOCAL int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, - byte** out, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx); + byte** out, int sigAlgo, int hashAlgo, RsaKey* key, + const byte* keyBuf, word32 keySz, void* ctx); WOLFSSL_LOCAL int RsaDec(WOLFSSL* ssl, byte* in, word32 inSz, byte** out, word32* outSz, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx); WOLFSSL_LOCAL int RsaEnc(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, diff --git a/wolfssl/wolfcrypt/rsa.h b/wolfssl/wolfcrypt/rsa.h index a64eb8708..6905d1dd2 100644 --- a/wolfssl/wolfcrypt/rsa.h +++ b/wolfssl/wolfcrypt/rsa.h @@ -126,6 +126,9 @@ WOLFSSL_API int wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key); WOLFSSL_API int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen, RsaKey* key); +WOLFSSL_API int wc_RsaPSS_VerifyInline(byte* in, word32 inLen, byte** out, + enum wc_HashType hash, int mgf, + RsaKey* key); WOLFSSL_API int wc_RsaEncryptSize(RsaKey* key); #ifndef HAVE_FIPS /* to avoid asn duplicate symbols @wc_fips */ @@ -156,6 +159,7 @@ WOLFSSL_API int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng); /* Padding types */ #define WC_RSA_PKCSV15_PAD 0 #define WC_RSA_OAEP_PAD 1 +#define WC_RSA_PSS_PAD 2 WOLFSSL_API int wc_RsaPublicEncrypt_ex(const byte* in, word32 inLen, byte* out, word32 outLen, RsaKey* key, WC_RNG* rng, int type,