|
29 | 29 | #endif |
30 | 30 |
|
31 | 31 | #include <wolfssl/wolfcrypt/hmac.h> |
| 32 | +#include <wolfssl/wolfcrypt/kdf.h> |
32 | 33 | #include <wolfssl/wolfcrypt/types.h> |
33 | 34 | #include <wolfssl/internal.h> |
34 | 35 | #ifdef WOLF_CRYPTO_CB |
@@ -1057,3 +1058,148 @@ int test_wc_HKDF_NullKeyEdgeCases(void) |
1057 | 1058 | #endif |
1058 | 1059 | return EXPECT_RESULT(); |
1059 | 1060 | } /* END test_wc_HKDF_NullKeyEdgeCases */ |
| 1061 | + |
| 1062 | +#if defined(HAVE_HKDF) && !defined(NO_HMAC) && !defined(NO_KDF) && \ |
| 1063 | + !defined(NO_SHA256) && !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) && \ |
| 1064 | + defined(WOLF_CRYPTO_CB) |
| 1065 | +#define TEST_KDF_CRYPTOCB_DEVID 0x4b444658 /* "KDFX" */ |
| 1066 | + |
| 1067 | +typedef struct { |
| 1068 | + int called; |
| 1069 | + int inKeyNull; |
| 1070 | + int inKeyZeroed; |
| 1071 | + word32 inKeySz; |
| 1072 | +} TestKdfExtractCbCtx; |
| 1073 | + |
| 1074 | +/* Records the IKM handed to a callback, then declines so the software path |
| 1075 | + * still derives the PRK. */ |
| 1076 | +static int test_kdf_cryptocb_extract_cb(int cbDevId, wc_CryptoInfo* info, |
| 1077 | + void* ctx) |
| 1078 | +{ |
| 1079 | + TestKdfExtractCbCtx* cbCtx = (TestKdfExtractCbCtx*)ctx; |
| 1080 | + word32 j; |
| 1081 | + |
| 1082 | + (void)cbDevId; |
| 1083 | + if (info->algo_type == WC_ALGO_TYPE_KDF && |
| 1084 | + info->kdf.type == WC_KDF_TYPE_HKDF_EXTRACT) { |
| 1085 | + cbCtx->called++; |
| 1086 | + cbCtx->inKeySz = info->kdf.hkdf_extract.inKeySz; |
| 1087 | + cbCtx->inKeyNull = (info->kdf.hkdf_extract.inKey == NULL); |
| 1088 | + cbCtx->inKeyZeroed = 1; |
| 1089 | + for (j = 0; !cbCtx->inKeyNull && j < info->kdf.hkdf_extract.inKeySz; |
| 1090 | + j++) { |
| 1091 | + if (info->kdf.hkdf_extract.inKey[j] != 0) { |
| 1092 | + cbCtx->inKeyZeroed = 0; |
| 1093 | + } |
| 1094 | + } |
| 1095 | + } |
| 1096 | + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); |
| 1097 | +} |
| 1098 | +#endif |
| 1099 | + |
| 1100 | +/* A zero length IKM must not write into the caller's ikm buffer, whose |
| 1101 | + * required size is not implied by the length the caller passes in. */ |
| 1102 | +int test_wc_Tls13_HKDF_Extract_ZeroLenIkm(void) |
| 1103 | +{ |
| 1104 | + EXPECT_DECLS; |
| 1105 | +/* kdf.c sits inside the FIPS module boundary, so FIPS and selftest builds use a |
| 1106 | + * frozen copy that still writes into the caller's ikm buffer. Skip until a |
| 1107 | + * module revision carrying this fix ships. */ |
| 1108 | +#if defined(HAVE_HKDF) && !defined(NO_HMAC) && !defined(NO_KDF) && \ |
| 1109 | + !defined(NO_SHA256) && !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) |
| 1110 | + static const int digests[] = { |
| 1111 | + WC_SHA256, |
| 1112 | + #ifdef WOLFSSL_SHA384 |
| 1113 | + WC_SHA384, |
| 1114 | + #endif |
| 1115 | + #ifdef WOLFSSL_TLS13_SHA512 |
| 1116 | + WC_SHA512, |
| 1117 | + #endif |
| 1118 | + #ifdef WOLFSSL_SM3 |
| 1119 | + WC_SM3, |
| 1120 | + #endif |
| 1121 | + }; |
| 1122 | + byte prkNull[WC_MAX_DIGEST_SIZE]; |
| 1123 | + byte prkOther[WC_MAX_DIGEST_SIZE]; |
| 1124 | + byte zeros[WC_MAX_DIGEST_SIZE]; |
| 1125 | + byte sentinel[WC_MAX_DIGEST_SIZE]; |
| 1126 | + byte filled[WC_MAX_DIGEST_SIZE]; |
| 1127 | + byte small[4]; |
| 1128 | + word32 i; |
| 1129 | + int len = 0; |
| 1130 | +#ifdef WOLF_CRYPTO_CB |
| 1131 | + TestKdfExtractCbCtx cbCtx; |
| 1132 | +#endif |
| 1133 | + |
| 1134 | + XMEMSET(zeros, 0, sizeof(zeros)); |
| 1135 | + XMEMSET(filled, 0xA5, sizeof(filled)); |
| 1136 | + |
| 1137 | + /* Every digest the switch accepts, up to the WC_MAX_DIGEST_SIZE the scratch |
| 1138 | + * buffer is sized against. */ |
| 1139 | + for (i = 0; i < sizeof(digests) / sizeof(digests[0]); i++) { |
| 1140 | + ExpectIntGT(len = wc_HmacSizeByType(digests[i]), 0); |
| 1141 | + |
| 1142 | + /* ikmLen 0 feeds a digest length zeroed IKM rather than an empty one, |
| 1143 | + * so a NULL ikm must derive the same PRK as passing those zeros. */ |
| 1144 | + ExpectIntEQ(wc_Tls13_HKDF_Extract(prkNull, NULL, 0, NULL, 0, |
| 1145 | + digests[i]), 0); |
| 1146 | + ExpectIntEQ(wc_Tls13_HKDF_Extract(prkOther, NULL, 0, zeros, |
| 1147 | + (word32)len, digests[i]), 0); |
| 1148 | + ExpectBufEQ(prkNull, prkOther, (word32)len); |
| 1149 | + |
| 1150 | + /* The caller's buffer must come back untouched, through the _ex entry |
| 1151 | + * point that TLS 1.3 itself calls. */ |
| 1152 | + XMEMSET(sentinel, 0xA5, sizeof(sentinel)); |
| 1153 | + ExpectIntEQ(wc_Tls13_HKDF_Extract_ex(prkOther, NULL, 0, sentinel, 0, |
| 1154 | + digests[i], NULL, INVALID_DEVID), 0); |
| 1155 | + ExpectBufEQ(sentinel, filled, (word32)len); |
| 1156 | + ExpectBufEQ(prkNull, prkOther, (word32)len); |
| 1157 | + |
| 1158 | + XMEMSET(sentinel, 0xA5, sizeof(sentinel)); |
| 1159 | + ExpectIntEQ(wc_Tls13_HKDF_Extract(prkOther, NULL, 0, sentinel, 0, |
| 1160 | + digests[i]), 0); |
| 1161 | + ExpectBufEQ(sentinel, filled, (word32)len); |
| 1162 | + ExpectBufEQ(prkNull, prkOther, (word32)len); |
| 1163 | + |
| 1164 | + /* A NULL salt stays valid whatever saltLen says. */ |
| 1165 | + ExpectIntEQ(wc_Tls13_HKDF_Extract(prkOther, NULL, 5, NULL, 0, |
| 1166 | + digests[i]), 0); |
| 1167 | + ExpectBufEQ(prkNull, prkOther, (word32)len); |
| 1168 | + } |
| 1169 | + |
| 1170 | + /* ASan tripwire: a revert overruns this and may abort the binary under a |
| 1171 | + * stack protector. The sentinel above is what fails cleanly. */ |
| 1172 | + XMEMSET(small, 0xA5, sizeof(small)); |
| 1173 | + ExpectIntEQ(wc_Tls13_HKDF_Extract(prkNull, NULL, 0, small, 0, WC_SHA256), 0); |
| 1174 | + ExpectIntEQ(small[0], 0xA5); |
| 1175 | + ExpectIntEQ(small[3], 0xA5); |
| 1176 | + |
| 1177 | + ExpectIntEQ(wc_Tls13_HKDF_Extract(NULL, NULL, 0, zeros, |
| 1178 | + WC_SHA256_DIGEST_SIZE, WC_SHA256), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); |
| 1179 | + ExpectIntEQ(wc_Tls13_HKDF_Extract(prkNull, NULL, 0, NULL, 5, WC_SHA256), |
| 1180 | + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); |
| 1181 | + ExpectIntEQ(wc_Tls13_HKDF_Extract_ex(NULL, NULL, 0, zeros, |
| 1182 | + WC_SHA256_DIGEST_SIZE, WC_SHA256, NULL, INVALID_DEVID), |
| 1183 | + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); |
| 1184 | + ExpectIntEQ(wc_Tls13_HKDF_Extract_ex(prkNull, NULL, 0, NULL, 5, WC_SHA256, |
| 1185 | + NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); |
| 1186 | + |
| 1187 | +#ifdef WOLF_CRYPTO_CB |
| 1188 | + /* A callback dispatches before the software path, so it must receive the |
| 1189 | + * substituted zeroed IKM rather than the caller's untouched buffer. */ |
| 1190 | + XMEMSET(&cbCtx, 0, sizeof(cbCtx)); |
| 1191 | + XMEMSET(sentinel, 0xA5, sizeof(sentinel)); |
| 1192 | + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_KDF_CRYPTOCB_DEVID, |
| 1193 | + test_kdf_cryptocb_extract_cb, &cbCtx), 0); |
| 1194 | + ExpectIntEQ(wc_Tls13_HKDF_Extract_ex(prkOther, NULL, 0, sentinel, 0, |
| 1195 | + WC_SHA256, NULL, TEST_KDF_CRYPTOCB_DEVID), 0); |
| 1196 | + ExpectIntEQ(cbCtx.called, 1); |
| 1197 | + ExpectIntEQ(cbCtx.inKeyNull, 0); |
| 1198 | + ExpectIntEQ(cbCtx.inKeyZeroed, 1); |
| 1199 | + ExpectIntEQ(cbCtx.inKeySz, WC_SHA256_DIGEST_SIZE); |
| 1200 | + ExpectBufEQ(sentinel, filled, WC_SHA256_DIGEST_SIZE); |
| 1201 | + wc_CryptoCb_UnRegisterDevice(TEST_KDF_CRYPTOCB_DEVID); |
| 1202 | +#endif |
| 1203 | +#endif |
| 1204 | + return EXPECT_RESULT(); |
| 1205 | +} /* END test_wc_Tls13_HKDF_Extract_ZeroLenIkm */ |
0 commit comments