Hi Mat, David, During the development of this patch, I saw that the test framework seems to be broken: when I change the expected values by one bit, the test framework will still mark the received result as PASS even though the returned data does not match the expected data. ---8<---- Add the interface logic to support DH with KDF handling support. The dh_compute code now allows the following options: - no KDF support / output of raw DH shared secret: dh_compute <private> <prime> <base> - KDF support without "other information" string: dh_compute <private> <prime> <base> <output length> <KDF type> - KDF support with "other information string: dh_compute <private> <prime> <base> <output length> <KDF type> <OI string> The test to verify the code is based on a test vector used for the CAVS testing of SP800-56A. Signed-off-by: Stephan Mueller <smueller@xxxxxxxxxx> --- keyctl.c | 14 +++++- keyutils.c | 48 ++++++++++++++++++ keyutils.h | 13 +++++ tests/keyctl/dh_compute/valid/runtest.sh | 83 ++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 2 deletions(-) diff --git a/keyctl.c b/keyctl.c index edb03de..32478b3 100644 --- a/keyctl.c +++ b/keyctl.c @@ -1638,14 +1638,24 @@ static void act_keyctl_dh_compute(int argc, char *argv[]) char *p; int ret, sep, col; - if (argc != 4) + if (argc != 4 && argc != 6 && argc != 7) format(); private = get_key_id(argv[1]); prime = get_key_id(argv[2]); base = get_key_id(argv[3]); - ret = keyctl_dh_compute_alloc(private, prime, base, &buffer); + if (argc == 4) + ret = keyctl_dh_compute_alloc(private, prime, base, &buffer); + else if (argc == 6) + ret = keyctl_dh_compute_kdf(private, prime, base, argv[4], + argv[5], NULL, &buffer); + else if (argc == 7) + ret = keyctl_dh_compute_kdf(private, prime, base, argv[4], + argv[5], argv[6], &buffer); + else + error("dh_compute: unknown number of arguments"); + if (ret < 0) error("keyctl_dh_compute_alloc"); diff --git a/keyutils.c b/keyutils.c index 2a69304..ffdd622 100644 --- a/keyutils.c +++ b/keyutils.c @@ -386,6 +386,54 @@ int keyctl_dh_compute_alloc(key_serial_t private, key_serial_t prime, } /* + * fetch DH computation results processed by a KDF into an + * allocated buffer + * - resulting buffer has an extra NUL added to the end + * - returns count (not including extraneous NUL) + */ +int keyctl_dh_compute_kdf(key_serial_t private, key_serial_t prime, + key_serial_t base, char *len, char *kdfname, + char *otherinfo, void **_buffer) +{ + char *buf; + unsigned long buflen; + int ret; + struct keyctl_dh_params params = { .private = private, + .prime = prime, + .base = base }; + struct keyctl_kdf_params kdfparams; + + buflen = strtoul(len, NULL, 10); + if (buflen > KEYCTL_KDF_MAX_OUTPUTLEN) + return -1; + + buf = malloc(buflen + 1); + if (!buf) + return -1; + + if (otherinfo) { + kdfparams.kdfname = kdfname; + kdfparams.kdfnamelen = strlen(kdfname); + kdfparams.otherinfo = otherinfo; + kdfparams.otherinfolen = strlen(otherinfo); + } else { + kdfparams.kdfname = kdfname; + kdfparams.kdfnamelen = strlen(kdfname); + kdfparams.otherinfo = NULL; + kdfparams.otherinfolen = 0; + } + ret = keyctl(KEYCTL_DH_COMPUTE, ¶ms, buf, buflen, &kdfparams); + if (ret < 0) { + free(buf); + return -1; + } + + buf[ret] = 0; + *_buffer = buf; + return ret; +} + +/* * Depth-first recursively apply a function over a keyring tree */ static int recursive_key_scan_aux(key_serial_t parent, key_serial_t key, diff --git a/keyutils.h b/keyutils.h index b321aa8..5026270 100644 --- a/keyutils.h +++ b/keyutils.h @@ -108,6 +108,16 @@ struct keyctl_dh_params { key_serial_t base; }; +struct keyctl_kdf_params { +#define KEYCTL_KDF_MAX_OUTPUTLEN 1024 /* max length of KDF output */ +#define KEYCTL_KDF_MAX_STRING_LEN 64 /* maximum length of strings */ + char *kdfname; + uint32_t kdfnamelen; + char *otherinfo; + uint32_t otherinfolen; + uint32_t flags; +}; + /* * syscall wrappers */ @@ -172,6 +182,9 @@ extern int keyctl_read_alloc(key_serial_t id, void **_buffer); extern int keyctl_get_security_alloc(key_serial_t id, char **_buffer); extern int keyctl_dh_compute_alloc(key_serial_t private, key_serial_t prime, key_serial_t base, void **_buffer); +int keyctl_dh_compute_kdf(key_serial_t private, key_serial_t prime, + key_serial_t base, char *len, char *kdfname, + char *otherinfo, void **_buffer); typedef int (*recursive_key_scanner_t)(key_serial_t parent, key_serial_t key, char *desc, int desc_len, void *data); diff --git a/tests/keyctl/dh_compute/valid/runtest.sh b/tests/keyctl/dh_compute/valid/runtest.sh index 40ec387..1c77268 100644 --- a/tests/keyctl/dh_compute/valid/runtest.sh +++ b/tests/keyctl/dh_compute/valid/runtest.sh @@ -80,6 +80,89 @@ marker "COMPUTE DH PUBLIC KEY" dh_compute $privateid $primeid $generatorid expect_payload payload $public + +################################################################ +# Testing DH compute with KDF according to SP800-56A +# +# test vectors from http://csrc.nist.gov/groups/STM/cavp/documents/keymgmt/KASTestVectorsFFC2014.zip +################################################################ + +# SHA-256 + +# XephemCAVS +private="\x81\xb2\xc6\x5f\x5c\xba\xc0\x0b\x13\x53\xac\x38\xbd\x77\xa2\x5a" +private+="\x86\x50\xed\x48\x5e\x41\x3e\xac\x1d\x6c\x48\x85" + +# P +prime="\xa3\xcc\x62\x23\xe5\x0c\x6e\x3f\x7b\xb0\x58\x1d\xcb\x9e\x9f\xf0" +prime+="\x2c\x58\x07\x68\x32\x8a\x15\x20\x7b\x1c\x32\x31\x7f\xb7\x84\x96" +prime+="\x81\x5e\x3c\xf7\xf9\xd0\x9c\xcb\x9f\xa8\x40\xff\x47\x98\x51\x1a" +prime+="\x17\xb5\x59\x28\x72\x1e\x5d\xfb\xcc\xc5\x41\x47\xe0\xf0\x5f\x85" +prime+="\xb3\xac\x41\x0b\x6a\xe3\xf5\x9b\x79\x6f\x3f\xea\xc7\xfc\x52\x49" +prime+="\x21\x7e\xb2\xa0\x45\x88\x29\x3a\x5a\xde\x22\x78\x79\xf4\x6c\xeb" +prime+="\x56\x45\x7b\x5c\x43\x12\x93\xe5\xe1\x04\xd1\xb9\x64\xbd\x2c\xdf" +prime+="\xde\xff\xa0\x40\x49\xa9\x1e\x67\xee\x8c\x86\xe9\x44\xf0\x4f\x94" +prime+="\x4a\x30\xe3\x61\xf8\xd1\x5d\x17\xe5\x01\x0c\xab\xb4\xef\x40\xc0" +prime+="\xeb\xa5\xf4\xa2\x52\xd4\xfd\x6c\xf9\xda\xe6\x0e\x86\xe4\xb3\x00" +prime+="\x9b\x1d\xfc\x92\x66\x70\x35\x72\x61\x58\x7a\xd0\x5c\x00\xa6\xc6" +prime+="\xf0\x10\x6c\xec\x8f\xc5\x91\x31\x51\x50\x84\xa8\x70\x59\x41\x65" +prime+="\xb4\x93\x90\xdb\x2d\x00\xe7\x53\x8f\x23\x0d\x53\x2f\x4a\x4e\xca" +prime+="\x83\x09\xd7\x07\xc0\xb3\x83\x5c\xee\x04\xf3\xca\x55\x8a\x22\xc6" +prime+="\xb5\x20\xfe\x25\xde\x6f\xfa\x90\xef\xda\x49\x27\xd0\x18\x59\x4c" +prime+="\x0c\x0b\x77\x06\x73\x93\xb7\xf1\xe0\xfc\x7c\xf2\x16\xaf\xf3\x9f" + +# YephemIUT +xa="\x9a\x70\x82\x2d\x3f\x06\x12\x3d\x0e\x51\x8e\xe1\x16\x51\xe5\xf6" +xa+="\xb1\x19\xdc\x3b\x97\xd5\xb1\xc0\xa2\xa6\xf6\xde\x94\x25\x64\xba" +xa+="\x10\x06\x1e\xec\xde\xb7\x36\x9c\xa5\x37\x49\x9e\x04\xb0\x36\xe9" +xa+="\x7f\x44\x5a\x95\x6f\x63\x69\xae\x6e\x63\xfd\x27\xea\xe3\xe3\x47" +xa+="\x85\x54\x47\xd3\xba\xc1\xc6\x0c\x10\xe7\x35\x07\x72\xc6\xc0\xc6" +xa+="\xfb\xf9\xca\x3e\x38\xf0\xe8\x65\x88\x25\xd3\xb2\x0f\x1f\x02\x8f" +xa+="\x35\xe3\x4d\x12\x35\x10\x3d\xf2\x33\x9b\x5b\x09\x9d\x3f\xe3\xe5" +xa+="\x34\x6a\x69\x16\x42\xba\xc5\xb0\xbb\x03\xcd\x5d\x04\xd7\x56\x26" +xa+="\x21\x49\x3f\xf1\xc4\x27\x3b\x6a\x45\xc5\xec\xb0\xb5\xe9\x08\xa0" +xa+="\xf9\xf5\x62\x28\x2e\x85\x3e\xfc\x9a\x7e\xa1\x12\xe9\x47\x4f\xf6" +xa+="\x94\x18\xf7\xc4\x7a\xe9\x66\xd4\x52\x4c\xa1\x70\x1b\x60\xa4\xbe" +xa+="\x15\xc7\x5e\x27\xb4\x05\x80\x64\x68\x15\x6e\x02\xcb\xc5\x8f\xf4" +xa+="\x66\x3c\x96\xac\x0c\x87\x36\x81\x35\xfa\x9b\x0b\xb6\x33\x7a\xe2" +xa+="\x58\x52\x1d\x7d\x60\xc2\xa9\x1b\x4e\xd7\x72\xad\x65\x03\x40\x49" +xa+="\x97\xf6\x79\x9d\xf6\x63\xa8\x99\x9c\xfd\x74\x7f\xa0\x67\xb9\x05" +xa+="\x8a\xb3\x3b\xc1\x45\x94\x36\x6f\x28\xf5\xa2\xd9\x00\xb6\x46\x7a" + +# Z +shared="0fdbd9a2 ebf50cba 489b4e4d 7cd6924a 42ee6324 a26988b2 22bc38e6 9cc445f1\n" +shared+="eb47c1a4 62eca39f 39bcd7b8 19dede51 30bc38da ec99c16f 40a4e5c1 9c97b796\n" +shared+="8b41823d a0650e37 13c73e6f 5f2a9dff 2e67dbf5 40ee66f4 e694c28f ba1d604b\n" +shared+="71b57b8a eeb67a35 ba425a38 490b6fb9 f713db22 6f893b7a 8962f426 ba3046fb\n" +shared+="cff8538c 16f583e8 ae947672 0ba55ff9 75b440d0 c4565cc7 5837d23a fea61a39\n" +shared+="e0b7f6c4 e24c2154 7eb19fce f8dbed10 b06a9cce 971c0f0f ba7c1d5c b5035eaa\n" +shared+="4fddd3ba fe757339 e3321e3e 4ebfe9e7 9c6c0401 4df63cf9 28d0a2c0 5b2d5521\n" +shared+="030c35f1 c84c97fe 64cad509 8012a003 d52d24c4 1a1f9348 b7575251 3facb02f\n" + +# OI +otherinfo="\xa1\xb2\xc3\xd4\xe5\x43\x41\x56\x53\x69\x64\x0d\x64\xc1\xb2" +otherinfo+="\x33\x61\xb2\x61\xde\x78\x68\x8e\xa8\x65\xfc\xff\x11\x3c\x84" + +# DKM +derived="8284e313 02c8a26b 393ec52d 9f9e0882\n" + +pcreate_key "-e $prime" user dh:prime @s +expect_keyid primeid + +pcreate_key "-e $xa" user dh:xa @s +expect_keyid xaid + +pcreate_key "-e $private" user dh:private @s +expect_keyid privateid + +marker "COMPUTE DH SHARED SECRET" +dh_compute $privateid $primeid $xaid +expect_payload payload $shared + +marker "COMPUTE DERIVED KEY FROM DH SHARED SECRET (SHA-256)" +dh_compute $privateid $primeid $xaid 16 "kdf_ctr(sha256)" "$(echo -e -n $otherinfo)" +expect_payload payload $derived + echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE # --- then report the results in the database --- -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html