diff --git a/configure.ac b/configure.ac index b9b5adf96..26ee1472e 100644 --- a/configure.ac +++ b/configure.ac @@ -6006,6 +6006,8 @@ if test "x$ENABLED_OPENSSLCOEXIST" = "xyes"; then fi fi +AS_IF([test "x$ENABLED_WOLFSSH" = "xyes"],[AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSL_WOLFSSH"]) + if test "x$ENABLED_CERTS" = "xno" || test "x$ENABLED_LEANPSK" = "xyes" || test "x$ENABLED_ASN" = "xno"; then AM_CFLAGS="$AM_CFLAGS -DNO_ASN -DNO_CERTS" fi diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index 0af2c2d17..16b44ea3b 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -1590,5 +1590,249 @@ int wc_PRF_TLS(byte* digest, word32 digLen, const byte* secret, word32 secLen, #endif /* HAVE_HKDF */ + +#ifdef WOLFSSL_WOLFSSH + +static +int _HashInit(byte hashId, wc_Hmac_Hash* hash) +{ + int ret = BAD_FUNC_ARG; + + switch (hashId) { + #ifndef NO_SHA + case WC_SHA: + ret = wc_InitSha(&hash->sha); + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + ret = wc_InitSha256(&hash->sha256); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + ret = wc_InitSha384(&hash->sha384); + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + ret = wc_InitSha512(&hash->sha512); + break; + #endif /* WOLFSSL_SHA512 */ + } + + return ret; +} + +static +int _HashUpdate(byte hashId, wc_Hmac_Hash* hash, + const byte* data, word32 dataSz) +{ + int ret = BAD_FUNC_ARG; + + switch (hashId) { + #ifndef NO_SHA + case WC_SHA: + ret = wc_ShaUpdate(&hash->sha, data, dataSz); + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + ret = wc_Sha256Update(&hash->sha256, data, dataSz); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + ret = wc_Sha384Update(&hash->sha384, data, dataSz); + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + ret = wc_Sha512Update(&hash->sha512, data, dataSz); + break; + #endif /* WOLFSSL_SHA512 */ + } + + return ret; +} + +static +int _HashFinal(byte hashId, wc_Hmac_Hash* hash, byte* digest) +{ + int ret = BAD_FUNC_ARG; + + switch (hashId) { + #ifndef NO_SHA + case WC_SHA: + ret = wc_ShaFinal(&hash->sha, digest); + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + ret = wc_Sha256Final(&hash->sha256, digest); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + ret = wc_Sha384Final(&hash->sha384, digest); + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + ret = wc_Sha512Final(&hash->sha512, digest); + break; + #endif /* WOLFSSL_SHA512 */ + } + + return ret; +} + +static +void _HashFree(byte hashId, wc_Hmac_Hash* hash) +{ + switch (hashId) { + #ifndef NO_SHA + case WC_SHA: + wc_ShaFree(&hash->sha); + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + wc_Sha256Free(&hash->sha256); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + wc_Sha384Free(&hash->sha384); + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + wc_Sha512Free(&hash->sha512); + break; + #endif /* WOLFSSL_SHA512 */ + } +} + + +#define LENGTH_SZ 4 + +int wc_SSH_KDF(byte hashId, byte keyId, byte* key, word32 keySz, + const byte* k, word32 kSz, const byte* h, word32 hSz, + const byte* sessionId, word32 sessionIdSz) +{ + word32 blocks, remainder; + wc_Hmac_Hash hash; + enum wc_HashType enmhashId = (enum wc_HashType)hashId; + byte kPad = 0; + byte pad = 0; + byte kSzFlat[LENGTH_SZ]; + int digestSz; + int ret; + + if (key == NULL || keySz == 0 || + k == NULL || kSz == 0 || + h == NULL || hSz == 0 || + sessionId == NULL || sessionIdSz == 0) { + + return BAD_FUNC_ARG; + } + + digestSz = wc_HmacSizeByType(enmhashId); + if (digestSz < 0) { + return BAD_FUNC_ARG; + } + + if (k[0] & 0x80) kPad = 1; + c32toa(kSz + kPad, kSzFlat); + + blocks = keySz / digestSz; + remainder = keySz % digestSz; + + ret = _HashInit(enmhashId, &hash); + if (ret == 0) + ret = _HashUpdate(enmhashId, &hash, kSzFlat, LENGTH_SZ); + if (ret == 0 && kPad) + ret = _HashUpdate(enmhashId, &hash, &pad, 1); + if (ret == 0) + ret = _HashUpdate(enmhashId, &hash, k, kSz); + if (ret == 0) + ret = _HashUpdate(enmhashId, &hash, h, hSz); + if (ret == 0) + ret = _HashUpdate(enmhashId, &hash, &keyId, sizeof(keyId)); + if (ret == 0) + ret = _HashUpdate(enmhashId, &hash, sessionId, sessionIdSz); + + if (ret == 0) { + if (blocks == 0) { + if (remainder > 0) { + byte lastBlock[WC_MAX_DIGEST_SIZE]; + ret = _HashFinal(enmhashId, &hash, lastBlock); + if (ret == 0) + XMEMCPY(key, lastBlock, remainder); + } + } + else { + word32 runningKeySz, curBlock; + + runningKeySz = digestSz; + ret = _HashFinal(enmhashId, &hash, key); + + for (curBlock = 1; curBlock < blocks; curBlock++) { + ret = _HashInit(enmhashId, &hash); + if (ret != 0) break; + ret = _HashUpdate(enmhashId, &hash, kSzFlat, LENGTH_SZ); + if (ret != 0) break; + if (kPad) + ret = _HashUpdate(enmhashId, &hash, &pad, 1); + if (ret != 0) break; + ret = _HashUpdate(enmhashId, &hash, k, kSz); + if (ret != 0) break; + ret = _HashUpdate(enmhashId, &hash, h, hSz); + if (ret != 0) break; + ret = _HashUpdate(enmhashId, &hash, key, runningKeySz); + if (ret != 0) break; + ret = _HashFinal(enmhashId, &hash, key + runningKeySz); + if (ret != 0) break; + runningKeySz += digestSz; + } + + if (remainder > 0) { + byte lastBlock[WC_MAX_DIGEST_SIZE]; + if (ret == 0) + ret = _HashInit(enmhashId, &hash); + if (ret == 0) + ret = _HashUpdate(enmhashId, &hash, kSzFlat, LENGTH_SZ); + if (ret == 0 && kPad) + ret = _HashUpdate(enmhashId, &hash, &pad, 1); + if (ret == 0) + ret = _HashUpdate(enmhashId, &hash, k, kSz); + if (ret == 0) + ret = _HashUpdate(enmhashId, &hash, h, hSz); + if (ret == 0) + ret = _HashUpdate(enmhashId, &hash, key, runningKeySz); + if (ret == 0) + ret = _HashFinal(enmhashId, &hash, lastBlock); + if (ret == 0) + XMEMCPY(key + runningKeySz, lastBlock, remainder); + } + } + } + + _HashFree(enmhashId, &hash); + + return ret; +} + +#endif /* WOLFSSL_SSH */ + #endif /* HAVE_FIPS */ #endif /* NO_HMAC */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 41cf264de..3221cbf65 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -934,6 +934,13 @@ initDefaultName(); #endif #endif /* !NO_HMAC */ +#ifdef WOLFSSL_WOLFSSH + if ( (ret = sshkdf_test()) != 0) + return err_sys("SSH-KDF test failed!\n", ret); + else + test_pass("SSH-KDF test passed!\n"); +#endif /* WOLFSSL_WOLFSSH */ + #if defined(HAVE_X963_KDF) && defined(HAVE_ECC) if ( (ret = x963kdf_test()) != 0) return err_sys("X963-KDF test failed!\n", ret); @@ -19905,6 +19912,167 @@ WOLFSSL_TEST_SUBROUTINE int pwdbased_test(void) #endif /* HAVE_HKDF */ +#ifdef WOLFSSL_WOLFSSH + +typedef struct { + byte hashId; + byte keyId; + const byte* k; + word32 kSz; + const byte* h; + word32 hSz; + const byte* sessionId; + word32 sessionIdSz; + const byte* expectedKey; + word32 expectedKeySz; +} SshKdfTestVector; + + +/** Test Vector Set #3: SHA-256 **/ +const byte sshKdfTvSet3k[] = { + 0x6A, 0xC3, 0x82, 0xEA, 0xAC, 0xA0, 0x93, 0xE1, + 0x25, 0xE2, 0x5C, 0x24, 0xBE, 0xBC, 0x84, 0x64, + 0x0C, 0x11, 0x98, 0x75, 0x07, 0x34, 0x4B, 0x5C, + 0x73, 0x9C, 0xEB, 0x84, 0xA9, 0xE0, 0xB2, 0x22, + 0xB9, 0xA8, 0xB5, 0x1C, 0x83, 0x9E, 0x5E, 0xBE, + 0x49, 0xCF, 0xAD, 0xBF, 0xB3, 0x95, 0x99, 0x76, + 0x4E, 0xD5, 0x22, 0x09, 0x9D, 0xC9, 0x12, 0x75, + 0x19, 0x50, 0xDC, 0x7D, 0xC9, 0x7F, 0xBD, 0xC0, + 0x63, 0x28, 0xB6, 0x8F, 0x22, 0x78, 0x1F, 0xD3, + 0x15, 0xAF, 0x56, 0x80, 0x09, 0xA5, 0x50, 0x9E, + 0x5B, 0x87, 0xA1, 0x1B, 0xF5, 0x27, 0xC0, 0x56, + 0xDA, 0xFF, 0xD8, 0x2A, 0xB6, 0xCB, 0xC2, 0x5C, + 0xCA, 0x37, 0x14, 0x34, 0x59, 0xE7, 0xBC, 0x63, + 0xBC, 0xDE, 0x52, 0x75, 0x7A, 0xDE, 0xB7, 0xDF, + 0x01, 0xCF, 0x12, 0x17, 0x3F, 0x1F, 0xEF, 0x81, + 0x02, 0xEC, 0x5A, 0xB1, 0x42, 0xC2, 0x13, 0xDD, + 0x9D, 0x30, 0x69, 0x62, 0x78, 0xA8, 0xD8, 0xBC, + 0x32, 0xDD, 0xE9, 0x59, 0x2D, 0x28, 0xC0, 0x78, + 0xC6, 0xD9, 0x2B, 0x94, 0x7D, 0x82, 0x5A, 0xCA, + 0xAB, 0x64, 0x94, 0x84, 0x6A, 0x49, 0xDE, 0x24, + 0xB9, 0x62, 0x3F, 0x48, 0x89, 0xE8, 0xAD, 0xC3, + 0x8E, 0x8C, 0x66, 0x9E, 0xFF, 0xEF, 0x17, 0x60, + 0x40, 0xAD, 0x94, 0x5E, 0x90, 0xA7, 0xD3, 0xEE, + 0xC1, 0x5E, 0xFE, 0xEE, 0x78, 0xAE, 0x71, 0x04, + 0x3C, 0x96, 0x51, 0x11, 0x03, 0xA1, 0x6B, 0xA7, + 0xCA, 0xF0, 0xAC, 0xD0, 0x64, 0x2E, 0xFD, 0xBE, + 0x80, 0x99, 0x34, 0xFA, 0xA1, 0xA5, 0xF1, 0xBD, + 0x11, 0x04, 0x36, 0x49, 0xB2, 0x5C, 0xCD, 0x1F, + 0xEE, 0x2E, 0x38, 0x81, 0x5D, 0x4D, 0x5F, 0x5F, + 0xC6, 0xB4, 0x10, 0x29, 0x69, 0xF2, 0x1C, 0x22, + 0xAE, 0x1B, 0x0E, 0x7D, 0x36, 0x03, 0xA5, 0x56, + 0xA1, 0x32, 0x62, 0xFF, 0x62, 0x8D, 0xE2, 0x22 +}; +const byte sshKdfTvSet3h[] = { + 0x7B, 0x70, 0x01, 0x18, 0x5E, 0x25, 0x6D, 0x44, + 0x93, 0x44, 0x5F, 0x39, 0xA5, 0x5F, 0xB9, 0x05, + 0xE6, 0x32, 0x1F, 0x4B, 0x5D, 0xD8, 0xBB, 0xF3, + 0x10, 0x0D, 0x51, 0xBA, 0x0B, 0xDA, 0x3D, 0x2D +}; +const byte sshKdfTvSet3sid[] = { + 0x7B, 0x70, 0x01, 0x18, 0x5E, 0x25, 0x6D, 0x44, + 0x93, 0x44, 0x5F, 0x39, 0xA5, 0x5F, 0xB9, 0x05, + 0xE6, 0x32, 0x1F, 0x4B, 0x5D, 0xD8, 0xBB, 0xF3, + 0x10, 0x0D, 0x51, 0xBA, 0x0B, 0xDA, 0x3D, 0x2D +}; +const byte sshKdfTvSet3a[] = { + 0x81, 0xF0, 0x33, 0x0E, 0xF6, 0xF0, 0x53, 0x61, + 0xB3, 0x82, 0x3B, 0xFD, 0xED, 0x6E, 0x1D, 0xE9 +}; +const byte sshKdfTvSet3b[] = { + 0x3F, 0x6F, 0xD2, 0x06, 0x5E, 0xEB, 0x2B, 0x0B, + 0x1D, 0x93, 0x19, 0x5A, 0x1F, 0xED, 0x48, 0xA5 +}; +const byte sshKdfTvSet3c[] = { + 0xC3, 0x54, 0x71, 0x03, 0x4E, 0x6F, 0xD6, 0x54, + 0x76, 0x13, 0x17, 0x8E, 0x23, 0x43, 0x5F, 0x21 +}; +const byte sshKdfTvSet3d[] = { + 0x7E, 0x9D, 0x79, 0x03, 0x20, 0x90, 0xD9, 0x9F, + 0x98, 0xB0, 0x15, 0x63, 0x4D, 0xD9, 0xF4, 0x62 +}; +const byte sshKdfTvSet3e[] = { + 0x24, 0xEE, 0x55, 0x9A, 0xD7, 0xCE, 0x71, 0x2B, + 0x68, 0x5D, 0x0B, 0x22, 0x71, 0xE4, 0x43, 0xC1, + 0x7A, 0xB1, 0xD1, 0xDC, 0xEB, 0x5A, 0x36, 0x05, + 0x69, 0xD2, 0x5D, 0x5D, 0xC2, 0x43, 0x00, 0x2F +}; +const byte sshKdfTvSet3f[] = { + 0xC3, 0x41, 0x9C, 0x2B, 0x96, 0x62, 0x35, 0x86, + 0x9D, 0x71, 0x4B, 0xA5, 0xAC, 0x48, 0xDD, 0xB7, + 0xD9, 0xE3, 0x5C, 0x8C, 0x19, 0xAA, 0xC7, 0x34, + 0x22, 0x33, 0x7A, 0x37, 0x34, 0x53, 0x60, 0x7E +}; + +static const SshKdfTestVector sshKdfTestVectors[] = { + {WC_HASH_TYPE_SHA256, 'A', + sshKdfTvSet3k, sizeof(sshKdfTvSet3k), + sshKdfTvSet3h, sizeof(sshKdfTvSet3h), + sshKdfTvSet3sid, sizeof(sshKdfTvSet3sid), + sshKdfTvSet3a, sizeof(sshKdfTvSet3a)}, + {WC_HASH_TYPE_SHA256, 'B', + sshKdfTvSet3k, sizeof(sshKdfTvSet3k), + sshKdfTvSet3h, sizeof(sshKdfTvSet3h), + sshKdfTvSet3sid, sizeof(sshKdfTvSet3sid), + sshKdfTvSet3b, sizeof(sshKdfTvSet3b)}, + {WC_HASH_TYPE_SHA256, 'C', + sshKdfTvSet3k, sizeof(sshKdfTvSet3k), + sshKdfTvSet3h, sizeof(sshKdfTvSet3h), + sshKdfTvSet3sid, sizeof(sshKdfTvSet3sid), + sshKdfTvSet3c, sizeof(sshKdfTvSet3c)}, + {WC_HASH_TYPE_SHA256, 'D', + sshKdfTvSet3k, sizeof(sshKdfTvSet3k), + sshKdfTvSet3h, sizeof(sshKdfTvSet3h), + sshKdfTvSet3sid, sizeof(sshKdfTvSet3sid), + sshKdfTvSet3d, sizeof(sshKdfTvSet3d)}, + {WC_HASH_TYPE_SHA256, 'E', + sshKdfTvSet3k, sizeof(sshKdfTvSet3k), + sshKdfTvSet3h, sizeof(sshKdfTvSet3h), + sshKdfTvSet3sid, sizeof(sshKdfTvSet3sid), + sshKdfTvSet3e, sizeof(sshKdfTvSet3e)}, + {WC_HASH_TYPE_SHA256, 'F', + sshKdfTvSet3k, sizeof(sshKdfTvSet3k), + sshKdfTvSet3h, sizeof(sshKdfTvSet3h), + sshKdfTvSet3sid, sizeof(sshKdfTvSet3sid), + sshKdfTvSet3f, sizeof(sshKdfTvSet3f)}, +}; + + +int sshkdf_test(void) +{ + int result = 0; + word32 i; + word32 tc = sizeof(sshKdfTestVectors)/sizeof(SshKdfTestVector); + const SshKdfTestVector* tv = NULL; + byte cKey[32]; /* Greater of SHA256_DIGEST_SIZE and AES_BLOCK_SIZE */ + /* sId - Session ID, eKey - Expected Key, cKey - Calculated Key */ + + for (i = 0, tv = sshKdfTestVectors; i < tc; i++, tv++) { + result = wc_SSH_KDF(tv->hashId, tv->keyId, + cKey, tv->expectedKeySz, + tv->k, tv->kSz, tv->h, tv->hSz, + tv->sessionId, tv->sessionIdSz); + + if (result != 0) { + printf("KDF: Could not derive key.\n"); + result = -101; + } + else { + if (memcmp(cKey, tv->expectedKey, tv->expectedKeySz) != 0) { + printf("KDF: Calculated Key does not match Expected Key.\n"); + result = -102; + } + } + + if (result != 0) break; + } + + return result; +} + +#endif /* WOLFSSL_WOLFSSH */ + + #if defined(HAVE_ECC) && defined(HAVE_X963_KDF) WOLFSSL_TEST_SUBROUTINE int x963kdf_test(void) diff --git a/wolfssl/wolfcrypt/hmac.h b/wolfssl/wolfcrypt/hmac.h index 9ca61d3c4..08f5959ae 100644 --- a/wolfssl/wolfcrypt/hmac.h +++ b/wolfssl/wolfcrypt/hmac.h @@ -236,6 +236,16 @@ WOLFSSL_API int wc_HKDF(int type, const byte* inKey, word32 inKeySz, #endif /* HAVE_HKDF */ +#ifdef WOLFSSL_WOLFSSH + +WOLFSSL_API int wc_SSH_KDF(byte hashId, byte keyId, + byte* key, word32 keySz, + const byte* k, word32 kSz, + const byte* h, word32 hSz, + const byte* sessionId, word32 sessionIdSz); + +#endif /* WOLFSSL_SSH */ + #ifdef __cplusplus } /* extern "C" */ #endif