1*d6004f2dSGernotS /* 2*d6004f2dSGernotS * This file and its contents are supplied under the terms of the 3*d6004f2dSGernotS * Common Development and Distribution License ("CDDL"), version 1.0. 4*d6004f2dSGernotS * You may only use this file in accordance with the terms of version 5*d6004f2dSGernotS * 1.0 of the CDDL. 6*d6004f2dSGernotS * 7*d6004f2dSGernotS * A full copy of the text of the CDDL should have accompanied this 8*d6004f2dSGernotS * source. A copy of the CDDL is also available via the Internet at 9*d6004f2dSGernotS * http://www.illumos.org/license/CDDL. 10*d6004f2dSGernotS */ 11*d6004f2dSGernotS 12*d6004f2dSGernotS /* 13*d6004f2dSGernotS * Copyright 2026 Gernot Strasser 14*d6004f2dSGernotS */ 15*d6004f2dSGernotS 16*d6004f2dSGernotS /* 17*d6004f2dSGernotS * ktest(8) coverage for the kernel SHA-256 block transform, in particular the 18*d6004f2dSGernotS * amd64 runtime dispatch between the generic transform and the Intel SHA 19*d6004f2dSGernotS * Extensions ("SHA-NI") path in sha2.c. 20*d6004f2dSGernotS * 21*d6004f2dSGernotS * Tests: 22*d6004f2dSGernotS * kat - known-answer test against precomputed digests for inputs 23*d6004f2dSGernotS * of many lengths, including ones that cross the dispatch's 24*d6004f2dSGernotS * 32 KiB (512-block) kernel-FPU window and odd tail blocks. 25*d6004f2dSGernotS * incremental - the same inputs fed via varied SHA2Update() increments, 26*d6004f2dSGernotS * exercising the partial-block buffering and the single 27*d6004f2dSGernotS * block tail path in SHA2Final(). 28*d6004f2dSGernotS * fallback_equiv - hashes each input twice, once with SHA-NI forced off 29*d6004f2dSGernotS * (sha256_ni_disable=1, generic path) and once on, and 30*d6004f2dSGernotS * asserts both match each other and the known answer. This 31*d6004f2dSGernotS * is the differential that catches dispatch / chunking / 32*d6004f2dSGernotS * kernel-FPU bugs without needing an external reference. 33*d6004f2dSGernotS * It is skipped on non-amd64 platforms and on CPUs without 34*d6004f2dSGernotS * the SHA extensions, where both paths would be identical. 35*d6004f2dSGernotS * 36*d6004f2dSGernotS * The test input of length L is the deterministic byte pattern b[i] = i & 0xff, 37*d6004f2dSGernotS * so the expected digests below are reproducible with any sha256 tool. 38*d6004f2dSGernotS */ 39*d6004f2dSGernotS 40*d6004f2dSGernotS #include <sys/types.h> 41*d6004f2dSGernotS #include <sys/ddi.h> 42*d6004f2dSGernotS #include <sys/sunddi.h> 43*d6004f2dSGernotS #include <sys/modctl.h> 44*d6004f2dSGernotS #include <sys/kmem.h> 45*d6004f2dSGernotS #include <sys/systm.h> 46*d6004f2dSGernotS #include <sys/sysmacros.h> 47*d6004f2dSGernotS #include <sys/stdbool.h> 48*d6004f2dSGernotS #include <sys/debug.h> 49*d6004f2dSGernotS #include <sys/sha2.h> 50*d6004f2dSGernotS #include <sys/ktest.h> 51*d6004f2dSGernotS #ifdef __amd64 52*d6004f2dSGernotS #include <sys/x86_archext.h> 53*d6004f2dSGernotS #endif 54*d6004f2dSGernotS 55*d6004f2dSGernotS /* 56*d6004f2dSGernotS * The largest test vector, 128 KiB + 1 byte. The amd64 dispatch in sha2.c 57*d6004f2dSGernotS * hands the SHA-NI transform at most 512 64-byte blocks (32 KiB) per 58*d6004f2dSGernotS * kernel-FPU window, so this length spans four full windows plus a trailing 59*d6004f2dSGernotS * partial block; the 32704..32833 vectors below straddle the first window 60*d6004f2dSGernotS * boundary (32 KiB - 64, exactly 32 KiB, +1, +64, and +65 bytes). 61*d6004f2dSGernotS */ 62*d6004f2dSGernotS #define SHA256_KT_MAXLEN 131073 63*d6004f2dSGernotS 64*d6004f2dSGernotS /* Expected SHA-256 of b[i] = (i & 0xff) for i in [0, len). */ 65*d6004f2dSGernotS static const struct { 66*d6004f2dSGernotS size_t len; 67*d6004f2dSGernotS uint8_t dig[SHA256_DIGEST_LENGTH]; 68*d6004f2dSGernotS } sha256_kat_vec[] = { 69*d6004f2dSGernotS { 0, { 70*d6004f2dSGernotS 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 71*d6004f2dSGernotS 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 72*d6004f2dSGernotS 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 73*d6004f2dSGernotS 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 } }, 74*d6004f2dSGernotS { 1, { 75*d6004f2dSGernotS 0x6e, 0x34, 0x0b, 0x9c, 0xff, 0xb3, 0x7a, 0x98, 76*d6004f2dSGernotS 0x9c, 0xa5, 0x44, 0xe6, 0xbb, 0x78, 0x0a, 0x2c, 77*d6004f2dSGernotS 0x78, 0x90, 0x1d, 0x3f, 0xb3, 0x37, 0x38, 0x76, 78*d6004f2dSGernotS 0x85, 0x11, 0xa3, 0x06, 0x17, 0xaf, 0xa0, 0x1d } }, 79*d6004f2dSGernotS { 3, { 80*d6004f2dSGernotS 0xae, 0x4b, 0x32, 0x80, 0xe5, 0x6e, 0x2f, 0xaf, 81*d6004f2dSGernotS 0x83, 0xf4, 0x14, 0xa6, 0xe3, 0xda, 0xbe, 0x9d, 82*d6004f2dSGernotS 0x5f, 0xbe, 0x18, 0x97, 0x65, 0x44, 0xc0, 0x5f, 83*d6004f2dSGernotS 0xed, 0x12, 0x1a, 0xcc, 0xb8, 0x5b, 0x53, 0xfc } }, 84*d6004f2dSGernotS { 55, { 85*d6004f2dSGernotS 0x46, 0x3e, 0xb2, 0x8e, 0x72, 0xf8, 0x2e, 0x0a, 86*d6004f2dSGernotS 0x96, 0xc0, 0xa4, 0xcc, 0x53, 0x69, 0x0c, 0x57, 87*d6004f2dSGernotS 0x12, 0x81, 0x13, 0x1f, 0x67, 0x2a, 0xa2, 0x29, 88*d6004f2dSGernotS 0xe0, 0xd4, 0x5a, 0xe5, 0x9b, 0x59, 0x8b, 0x59 } }, 89*d6004f2dSGernotS { 56, { 90*d6004f2dSGernotS 0xda, 0x2a, 0xe4, 0xd6, 0xb3, 0x67, 0x48, 0xf2, 91*d6004f2dSGernotS 0xa3, 0x18, 0xf2, 0x3e, 0x7a, 0xb1, 0xdf, 0xdf, 92*d6004f2dSGernotS 0x45, 0xac, 0xdc, 0x9d, 0x04, 0x9b, 0xd8, 0x0e, 93*d6004f2dSGernotS 0x59, 0xde, 0x82, 0xa6, 0x08, 0x95, 0xf5, 0x62 } }, 94*d6004f2dSGernotS { 57, { 95*d6004f2dSGernotS 0x2f, 0xe7, 0x41, 0xaf, 0x80, 0x1c, 0xc2, 0x38, 96*d6004f2dSGernotS 0x60, 0x2a, 0xc0, 0xec, 0x6a, 0x7b, 0x0c, 0x3a, 97*d6004f2dSGernotS 0x8a, 0x87, 0xc7, 0xfc, 0x7d, 0x7f, 0x02, 0xa3, 98*d6004f2dSGernotS 0xfe, 0x03, 0xd1, 0xc1, 0x2e, 0xac, 0x4d, 0x8f } }, 99*d6004f2dSGernotS { 63, { 100*d6004f2dSGernotS 0x29, 0xaf, 0x26, 0x86, 0xfd, 0x53, 0x37, 0x4a, 101*d6004f2dSGernotS 0x36, 0xb0, 0x84, 0x66, 0x94, 0xcc, 0x34, 0x21, 102*d6004f2dSGernotS 0x77, 0xe4, 0x28, 0xd1, 0x64, 0x75, 0x15, 0xf0, 103*d6004f2dSGernotS 0x78, 0x78, 0x4d, 0x69, 0xcd, 0xb9, 0xe4, 0x88 } }, 104*d6004f2dSGernotS { 64, { 105*d6004f2dSGernotS 0xfd, 0xea, 0xb9, 0xac, 0xf3, 0x71, 0x03, 0x62, 106*d6004f2dSGernotS 0xbd, 0x26, 0x58, 0xcd, 0xc9, 0xa2, 0x9e, 0x8f, 107*d6004f2dSGernotS 0x9c, 0x75, 0x7f, 0xcf, 0x98, 0x11, 0x60, 0x3a, 108*d6004f2dSGernotS 0x8c, 0x44, 0x7c, 0xd1, 0xd9, 0x15, 0x11, 0x08 } }, 109*d6004f2dSGernotS { 65, { 110*d6004f2dSGernotS 0x4b, 0xfd, 0x2c, 0x8b, 0x6f, 0x1e, 0xec, 0x7a, 111*d6004f2dSGernotS 0x2a, 0xfe, 0xb4, 0x8b, 0x93, 0x4e, 0xe4, 0xb2, 112*d6004f2dSGernotS 0x69, 0x41, 0x82, 0x02, 0x7e, 0x6d, 0x0f, 0xc0, 113*d6004f2dSGernotS 0x75, 0x07, 0x4f, 0x2f, 0xab, 0xb3, 0x17, 0x81 } }, 114*d6004f2dSGernotS { 127, { 115*d6004f2dSGernotS 0x92, 0xca, 0x0f, 0xa6, 0x65, 0x1e, 0xe2, 0xf9, 116*d6004f2dSGernotS 0x7b, 0x88, 0x4b, 0x72, 0x46, 0xa5, 0x62, 0xfa, 117*d6004f2dSGernotS 0x71, 0x25, 0x0f, 0xed, 0xef, 0xe5, 0xeb, 0xf2, 118*d6004f2dSGernotS 0x70, 0xd3, 0x1c, 0x54, 0x6b, 0xfe, 0xa9, 0x76 } }, 119*d6004f2dSGernotS { 128, { 120*d6004f2dSGernotS 0x47, 0x1f, 0xb9, 0x43, 0xaa, 0x23, 0xc5, 0x11, 121*d6004f2dSGernotS 0xf6, 0xf7, 0x2f, 0x8d, 0x16, 0x52, 0xd9, 0xc8, 122*d6004f2dSGernotS 0x80, 0xcf, 0xa3, 0x92, 0xad, 0x80, 0x50, 0x31, 123*d6004f2dSGernotS 0x20, 0x54, 0x77, 0x03, 0xe5, 0x6a, 0x2b, 0xe5 } }, 124*d6004f2dSGernotS { 129, { 125*d6004f2dSGernotS 0x50, 0x99, 0xc6, 0xa5, 0x62, 0x03, 0xf9, 0x68, 126*d6004f2dSGernotS 0x7f, 0x7d, 0x33, 0xf4, 0xbf, 0xdf, 0x57, 0x6d, 127*d6004f2dSGernotS 0x31, 0xdc, 0x91, 0xf6, 0xb6, 0x95, 0xec, 0xea, 128*d6004f2dSGernotS 0x38, 0xb2, 0x77, 0x0c, 0x87, 0x63, 0x11, 0x35 } }, 129*d6004f2dSGernotS { 8192, { 130*d6004f2dSGernotS 0xdc, 0x40, 0x4a, 0x61, 0x3f, 0xed, 0xae, 0xb5, 131*d6004f2dSGernotS 0x40, 0x34, 0x51, 0x4b, 0xc6, 0x50, 0x5f, 0x56, 132*d6004f2dSGernotS 0xb9, 0x33, 0xca, 0xa5, 0x25, 0x02, 0x99, 0xba, 133*d6004f2dSGernotS 0x7d, 0x09, 0x43, 0x77, 0xa5, 0x1c, 0xaa, 0x46 } }, 134*d6004f2dSGernotS { 32704, { 135*d6004f2dSGernotS 0x6a, 0x1c, 0xd5, 0xbb, 0x6e, 0x41, 0xf2, 0x83, 136*d6004f2dSGernotS 0x45, 0x2a, 0x9b, 0xa5, 0x15, 0x24, 0xdd, 0x9e, 137*d6004f2dSGernotS 0xbb, 0x8b, 0x43, 0x3c, 0x1d, 0x23, 0x05, 0x14, 138*d6004f2dSGernotS 0x1c, 0xa9, 0x02, 0x09, 0xbd, 0x63, 0x53, 0xb5 } }, 139*d6004f2dSGernotS { 32768, { 140*d6004f2dSGernotS 0xe1, 0x13, 0x60, 0x25, 0x1d, 0x11, 0x73, 0x65, 141*d6004f2dSGernotS 0x0c, 0xdc, 0xd2, 0x0f, 0x11, 0x1d, 0x8f, 0x1c, 142*d6004f2dSGernotS 0xa2, 0xe4, 0x12, 0xf5, 0x72, 0xe8, 0xb3, 0x6a, 143*d6004f2dSGernotS 0x4d, 0xc0, 0x67, 0x12, 0x1c, 0x17, 0x99, 0xb8 } }, 144*d6004f2dSGernotS { 32769, { 145*d6004f2dSGernotS 0xb9, 0x3c, 0x16, 0xc9, 0x98, 0x95, 0xf1, 0x59, 146*d6004f2dSGernotS 0x33, 0x47, 0xab, 0x57, 0xaf, 0x0c, 0x0a, 0x82, 147*d6004f2dSGernotS 0xf9, 0x67, 0x2e, 0xcb, 0x3d, 0xeb, 0xb5, 0x9d, 148*d6004f2dSGernotS 0x12, 0x4e, 0x1b, 0x38, 0xf3, 0x87, 0x1f, 0x01 } }, 149*d6004f2dSGernotS { 32832, { 150*d6004f2dSGernotS 0x20, 0x6a, 0xa6, 0xcc, 0x56, 0xb0, 0x0c, 0x13, 151*d6004f2dSGernotS 0xa5, 0xce, 0x97, 0xf3, 0xf8, 0x02, 0x99, 0xda, 152*d6004f2dSGernotS 0x72, 0x3c, 0xa1, 0xeb, 0xea, 0xc3, 0x5f, 0xba, 153*d6004f2dSGernotS 0x5f, 0xba, 0x1b, 0xf9, 0xd3, 0x96, 0x45, 0xcc } }, 154*d6004f2dSGernotS { 32833, { 155*d6004f2dSGernotS 0xa7, 0x9b, 0xe6, 0x6d, 0x16, 0xb1, 0x3e, 0x05, 156*d6004f2dSGernotS 0xd7, 0x4b, 0xa2, 0xd8, 0x89, 0x64, 0x8f, 0x02, 157*d6004f2dSGernotS 0x5e, 0x5e, 0xb0, 0x52, 0xf1, 0x83, 0x0b, 0x29, 158*d6004f2dSGernotS 0xe8, 0xa9, 0x27, 0x64, 0x85, 0x78, 0x40, 0x2d } }, 159*d6004f2dSGernotS { 65536, { 160*d6004f2dSGernotS 0x7d, 0xac, 0xa2, 0x09, 0x5d, 0x04, 0x38, 0x26, 161*d6004f2dSGernotS 0x0f, 0xa8, 0x49, 0x18, 0x3d, 0xfc, 0x67, 0xfa, 162*d6004f2dSGernotS 0xa4, 0x59, 0xfd, 0xf4, 0x93, 0x6e, 0x1b, 0xc9, 163*d6004f2dSGernotS 0x1e, 0xec, 0x6b, 0x28, 0x1b, 0x27, 0xe4, 0xc2 } }, 164*d6004f2dSGernotS { 131073, { 165*d6004f2dSGernotS 0x59, 0x14, 0x3c, 0x73, 0xfb, 0xc6, 0x69, 0xc1, 166*d6004f2dSGernotS 0x8b, 0xde, 0xb3, 0x6c, 0x7c, 0xfa, 0x13, 0x88, 167*d6004f2dSGernotS 0x8c, 0x03, 0xa2, 0xd9, 0x35, 0xb1, 0x8d, 0x93, 168*d6004f2dSGernotS 0x9c, 0x62, 0x86, 0x92, 0x36, 0x0c, 0x16, 0xff } }, 169*d6004f2dSGernotS }; 170*d6004f2dSGernotS 171*d6004f2dSGernotS /* SHA-256("abc"), the canonical FIPS 180-2 anchor. */ 172*d6004f2dSGernotS static const uint8_t sha256_abc_dig[SHA256_DIGEST_LENGTH] = { 173*d6004f2dSGernotS 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 174*d6004f2dSGernotS 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 175*d6004f2dSGernotS 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 176*d6004f2dSGernotS 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad 177*d6004f2dSGernotS }; 178*d6004f2dSGernotS 179*d6004f2dSGernotS /* 180*d6004f2dSGernotS * Allocate a SHA256_KT_MAXLEN buffer and fill it with the deterministic 181*d6004f2dSGernotS * b[i] = i & 0xff pattern. Each test allocates its own buffer rather than 182*d6004f2dSGernotS * sharing one, so the tests carry no mutable global state and make no 183*d6004f2dSGernotS * assumption about whether ktest runs them serially. Freed with 184*d6004f2dSGernotS * sha256_kt_free(). 185*d6004f2dSGernotS */ 186*d6004f2dSGernotS static uint8_t * 187*d6004f2dSGernotS sha256_kt_alloc(void) 188*d6004f2dSGernotS { 189*d6004f2dSGernotS uint8_t *buf = kmem_alloc(SHA256_KT_MAXLEN, KM_SLEEP); 190*d6004f2dSGernotS 191*d6004f2dSGernotS for (size_t i = 0; i < SHA256_KT_MAXLEN; i++) 192*d6004f2dSGernotS buf[i] = (uint8_t)(i & 0xff); 193*d6004f2dSGernotS 194*d6004f2dSGernotS return (buf); 195*d6004f2dSGernotS } 196*d6004f2dSGernotS 197*d6004f2dSGernotS static void 198*d6004f2dSGernotS sha256_kt_free(uint8_t *buf) 199*d6004f2dSGernotS { 200*d6004f2dSGernotS kmem_free(buf, SHA256_KT_MAXLEN); 201*d6004f2dSGernotS } 202*d6004f2dSGernotS 203*d6004f2dSGernotS static void 204*d6004f2dSGernotS sha256_kt_oneshot(const uint8_t *in, size_t len, uint8_t *out) 205*d6004f2dSGernotS { 206*d6004f2dSGernotS SHA256_CTX ctx; 207*d6004f2dSGernotS 208*d6004f2dSGernotS SHA2Init(SHA256, &ctx); 209*d6004f2dSGernotS SHA2Update(&ctx, in, len); 210*d6004f2dSGernotS SHA2Final(out, &ctx); 211*d6004f2dSGernotS } 212*d6004f2dSGernotS 213*d6004f2dSGernotS /* 214*d6004f2dSGernotS * kat: one-shot hash of each vector, compared against the precomputed digest. 215*d6004f2dSGernotS */ 216*d6004f2dSGernotS void 217*d6004f2dSGernotS sha256_kat_test(ktest_ctx_hdl_t *ctx) 218*d6004f2dSGernotS { 219*d6004f2dSGernotS uint8_t out[SHA256_DIGEST_LENGTH]; 220*d6004f2dSGernotS uint8_t *buf = sha256_kt_alloc(); 221*d6004f2dSGernotS bool fail = false; 222*d6004f2dSGernotS size_t faillen = 0; 223*d6004f2dSGernotS uint_t nfail = 0; 224*d6004f2dSGernotS 225*d6004f2dSGernotS /* canonical "abc" anchor */ 226*d6004f2dSGernotS sha256_kt_oneshot((const uint8_t *)"abc", 3, out); 227*d6004f2dSGernotS if (bcmp(out, sha256_abc_dig, SHA256_DIGEST_LENGTH) != 0) { 228*d6004f2dSGernotS KT_FAIL(ctx, "SHA-256(\"abc\") mismatch"); 229*d6004f2dSGernotS sha256_kt_free(buf); 230*d6004f2dSGernotS return; 231*d6004f2dSGernotS } 232*d6004f2dSGernotS 233*d6004f2dSGernotS for (size_t v = 0; v < ARRAY_SIZE(sha256_kat_vec); v++) { 234*d6004f2dSGernotS const size_t len = sha256_kat_vec[v].len; 235*d6004f2dSGernotS 236*d6004f2dSGernotS sha256_kt_oneshot(buf, len, out); 237*d6004f2dSGernotS if (bcmp(out, sha256_kat_vec[v].dig, 238*d6004f2dSGernotS SHA256_DIGEST_LENGTH) != 0) { 239*d6004f2dSGernotS if (!fail) 240*d6004f2dSGernotS faillen = len; 241*d6004f2dSGernotS fail = true; 242*d6004f2dSGernotS nfail++; 243*d6004f2dSGernotS } 244*d6004f2dSGernotS } 245*d6004f2dSGernotS 246*d6004f2dSGernotS sha256_kt_free(buf); 247*d6004f2dSGernotS 248*d6004f2dSGernotS if (fail) { 249*d6004f2dSGernotS KT_FAIL(ctx, "%u vector(s) mismatched, first at len %zu", 250*d6004f2dSGernotS nfail, faillen); 251*d6004f2dSGernotS } else { 252*d6004f2dSGernotS KT_PASS(ctx); 253*d6004f2dSGernotS } 254*d6004f2dSGernotS } 255*d6004f2dSGernotS 256*d6004f2dSGernotS /* 257*d6004f2dSGernotS * incremental: feed each vector through SHA2Update() in a range of step 258*d6004f2dSGernotS * sizes to exercise the partial-block buffering and the Final() tail path. 259*d6004f2dSGernotS */ 260*d6004f2dSGernotS void 261*d6004f2dSGernotS sha256_incremental_test(ktest_ctx_hdl_t *ctx) 262*d6004f2dSGernotS { 263*d6004f2dSGernotS static const size_t steps[] = { 1, 7, 31, 64, 1000 }; 264*d6004f2dSGernotS uint8_t out[SHA256_DIGEST_LENGTH]; 265*d6004f2dSGernotS uint8_t *buf = sha256_kt_alloc(); 266*d6004f2dSGernotS bool fail = false; 267*d6004f2dSGernotS size_t faillen = 0, failstep = 0; 268*d6004f2dSGernotS uint_t nfail = 0; 269*d6004f2dSGernotS 270*d6004f2dSGernotS for (size_t v = 0; v < ARRAY_SIZE(sha256_kat_vec); v++) { 271*d6004f2dSGernotS const size_t len = sha256_kat_vec[v].len; 272*d6004f2dSGernotS 273*d6004f2dSGernotS for (size_t s = 0; s < ARRAY_SIZE(steps); s++) { 274*d6004f2dSGernotS const size_t step = steps[s]; 275*d6004f2dSGernotS SHA256_CTX c; 276*d6004f2dSGernotS 277*d6004f2dSGernotS SHA2Init(SHA256, &c); 278*d6004f2dSGernotS for (size_t off = 0; off < len; off += step) { 279*d6004f2dSGernotS SHA2Update(&c, buf + off, 280*d6004f2dSGernotS MIN(step, len - off)); 281*d6004f2dSGernotS } 282*d6004f2dSGernotS SHA2Final(out, &c); 283*d6004f2dSGernotS 284*d6004f2dSGernotS if (bcmp(out, sha256_kat_vec[v].dig, 285*d6004f2dSGernotS SHA256_DIGEST_LENGTH) != 0) { 286*d6004f2dSGernotS if (!fail) { 287*d6004f2dSGernotS faillen = len; 288*d6004f2dSGernotS failstep = step; 289*d6004f2dSGernotS } 290*d6004f2dSGernotS fail = true; 291*d6004f2dSGernotS nfail++; 292*d6004f2dSGernotS } 293*d6004f2dSGernotS } 294*d6004f2dSGernotS } 295*d6004f2dSGernotS 296*d6004f2dSGernotS sha256_kt_free(buf); 297*d6004f2dSGernotS 298*d6004f2dSGernotS if (fail) { 299*d6004f2dSGernotS KT_FAIL(ctx, "%u case(s) mismatched, first at len %zu " 300*d6004f2dSGernotS "step %zu", nfail, faillen, failstep); 301*d6004f2dSGernotS } else { 302*d6004f2dSGernotS KT_PASS(ctx); 303*d6004f2dSGernotS } 304*d6004f2dSGernotS } 305*d6004f2dSGernotS 306*d6004f2dSGernotS /* 307*d6004f2dSGernotS * fallback_equiv: hash each vector with SHA-NI forced off and on, and assert 308*d6004f2dSGernotS * both equal the known answer. This exercises the amd64 dispatch and its 309*d6004f2dSGernotS * sha256_ni_disable tunable in sha2.c, so it is skipped elsewhere, and it is 310*d6004f2dSGernotS * skipped unless the CPU has every feature the dispatch requires before it 311*d6004f2dSGernotS * will use the SHA-NI path -- otherwise both the "on" and "off" runs take 312*d6004f2dSGernotS * the generic path (which the kat test already covers) and the differential 313*d6004f2dSGernotS * proves nothing. The set checked here mirrors sha256_ni_usable() in sha2.c 314*d6004f2dSGernotS * exactly: the SHA extensions plus the SSE2, SSSE3 and SSE4.1 instructions 315*d6004f2dSGernotS * that amd64/sha256-ni.S uses around them. 316*d6004f2dSGernotS */ 317*d6004f2dSGernotS #ifdef __amd64 318*d6004f2dSGernotS extern int sha256_ni_disable; 319*d6004f2dSGernotS 320*d6004f2dSGernotS void 321*d6004f2dSGernotS sha256_fallback_equiv_test(ktest_ctx_hdl_t *ctx) 322*d6004f2dSGernotS { 323*d6004f2dSGernotS uint8_t gen_dig[SHA256_DIGEST_LENGTH]; 324*d6004f2dSGernotS uint8_t ni_dig[SHA256_DIGEST_LENGTH]; 325*d6004f2dSGernotS uint8_t *buf; 326*d6004f2dSGernotS int saved; 327*d6004f2dSGernotS bool fail = false; 328*d6004f2dSGernotS size_t faillen = 0; 329*d6004f2dSGernotS uint_t nfail = 0; 330*d6004f2dSGernotS 331*d6004f2dSGernotS if (!is_x86_feature(x86_featureset, X86FSET_SSE2) || 332*d6004f2dSGernotS !is_x86_feature(x86_featureset, X86FSET_SSSE3) || 333*d6004f2dSGernotS !is_x86_feature(x86_featureset, X86FSET_SSE4_1) || 334*d6004f2dSGernotS !is_x86_feature(x86_featureset, X86FSET_SHA)) { 335*d6004f2dSGernotS KT_SKIP(ctx, "CPU lacks a feature the SHA-NI path requires"); 336*d6004f2dSGernotS return; 337*d6004f2dSGernotS } 338*d6004f2dSGernotS 339*d6004f2dSGernotS buf = sha256_kt_alloc(); 340*d6004f2dSGernotS saved = sha256_ni_disable; 341*d6004f2dSGernotS 342*d6004f2dSGernotS for (size_t v = 0; v < ARRAY_SIZE(sha256_kat_vec); v++) { 343*d6004f2dSGernotS const size_t len = sha256_kat_vec[v].len; 344*d6004f2dSGernotS 345*d6004f2dSGernotS sha256_ni_disable = 1; /* generic */ 346*d6004f2dSGernotS sha256_kt_oneshot(buf, len, gen_dig); 347*d6004f2dSGernotS sha256_ni_disable = 0; /* SHA-NI */ 348*d6004f2dSGernotS sha256_kt_oneshot(buf, len, ni_dig); 349*d6004f2dSGernotS 350*d6004f2dSGernotS if (bcmp(gen_dig, ni_dig, SHA256_DIGEST_LENGTH) != 0 || 351*d6004f2dSGernotS bcmp(ni_dig, sha256_kat_vec[v].dig, 352*d6004f2dSGernotS SHA256_DIGEST_LENGTH) != 0) { 353*d6004f2dSGernotS if (!fail) 354*d6004f2dSGernotS faillen = len; 355*d6004f2dSGernotS fail = true; 356*d6004f2dSGernotS nfail++; 357*d6004f2dSGernotS } 358*d6004f2dSGernotS } 359*d6004f2dSGernotS 360*d6004f2dSGernotS sha256_ni_disable = saved; 361*d6004f2dSGernotS sha256_kt_free(buf); 362*d6004f2dSGernotS 363*d6004f2dSGernotS if (fail) { 364*d6004f2dSGernotS KT_FAIL(ctx, "%u vector(s) mismatched, first at len %zu", 365*d6004f2dSGernotS nfail, faillen); 366*d6004f2dSGernotS } else { 367*d6004f2dSGernotS KT_PASS(ctx); 368*d6004f2dSGernotS } 369*d6004f2dSGernotS } 370*d6004f2dSGernotS #else /* !__amd64 */ 371*d6004f2dSGernotS void 372*d6004f2dSGernotS sha256_fallback_equiv_test(ktest_ctx_hdl_t *ctx) 373*d6004f2dSGernotS { 374*d6004f2dSGernotS KT_SKIP(ctx, "SHA-NI dispatch is amd64-only"); 375*d6004f2dSGernotS } 376*d6004f2dSGernotS #endif /* __amd64 */ 377*d6004f2dSGernotS 378*d6004f2dSGernotS static struct modlmisc sha256_ktest_modlmisc = { 379*d6004f2dSGernotS .misc_modops = &mod_miscops, 380*d6004f2dSGernotS .misc_linkinfo = "SHA-256 ktest module" 381*d6004f2dSGernotS }; 382*d6004f2dSGernotS 383*d6004f2dSGernotS static struct modlinkage sha256_ktest_modlinkage = { 384*d6004f2dSGernotS .ml_rev = MODREV_1, 385*d6004f2dSGernotS .ml_linkage = { &sha256_ktest_modlmisc, NULL } 386*d6004f2dSGernotS }; 387*d6004f2dSGernotS 388*d6004f2dSGernotS int 389*d6004f2dSGernotS _init(void) 390*d6004f2dSGernotS { 391*d6004f2dSGernotS int ret; 392*d6004f2dSGernotS ktest_module_hdl_t *km = NULL; 393*d6004f2dSGernotS ktest_suite_hdl_t *ks = NULL; 394*d6004f2dSGernotS 395*d6004f2dSGernotS VERIFY0(ktest_create_module("sha2", &km)); 396*d6004f2dSGernotS VERIFY0(ktest_add_suite(km, "sha256", &ks)); 397*d6004f2dSGernotS VERIFY0(ktest_add_test(ks, "kat", sha256_kat_test, 398*d6004f2dSGernotS KTEST_FLAG_NONE)); 399*d6004f2dSGernotS VERIFY0(ktest_add_test(ks, "incremental", sha256_incremental_test, 400*d6004f2dSGernotS KTEST_FLAG_NONE)); 401*d6004f2dSGernotS VERIFY0(ktest_add_test(ks, "fallback_equiv", 402*d6004f2dSGernotS sha256_fallback_equiv_test, KTEST_FLAG_NONE)); 403*d6004f2dSGernotS 404*d6004f2dSGernotS if ((ret = ktest_register_module(km)) != 0) { 405*d6004f2dSGernotS ktest_free_module(km); 406*d6004f2dSGernotS return (ret); 407*d6004f2dSGernotS } 408*d6004f2dSGernotS 409*d6004f2dSGernotS if ((ret = mod_install(&sha256_ktest_modlinkage)) != 0) { 410*d6004f2dSGernotS ktest_unregister_module("sha2"); 411*d6004f2dSGernotS return (ret); 412*d6004f2dSGernotS } 413*d6004f2dSGernotS 414*d6004f2dSGernotS return (0); 415*d6004f2dSGernotS } 416*d6004f2dSGernotS 417*d6004f2dSGernotS int 418*d6004f2dSGernotS _fini(void) 419*d6004f2dSGernotS { 420*d6004f2dSGernotS int ret; 421*d6004f2dSGernotS 422*d6004f2dSGernotS if ((ret = mod_remove(&sha256_ktest_modlinkage)) != 0) 423*d6004f2dSGernotS return (ret); 424*d6004f2dSGernotS 425*d6004f2dSGernotS ktest_unregister_module("sha2"); 426*d6004f2dSGernotS return (0); 427*d6004f2dSGernotS } 428*d6004f2dSGernotS 429*d6004f2dSGernotS int 430*d6004f2dSGernotS _info(struct modinfo *modinfop) 431*d6004f2dSGernotS { 432*d6004f2dSGernotS return (mod_info(&sha256_ktest_modlinkage, modinfop)); 433*d6004f2dSGernotS } 434