Stephan, On Thu, 4 Aug 2016, Stephan Mueller wrote:
Hi Mat, David, this patch covers all comments you raised. I also added a man page for the new API calls. ---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_kdf <private> <prime> <base> <output length> <KDF type> - KDF support with "other information string: dh_compute_kdf_oi <private> <prime> <base> <output length> <KDF type> where the OI string is provided on STDIN. 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> --- Makefile | 1 + keyctl.c | 125 +++++++++++++++++++++++ keyutils.c | 44 ++++++++ keyutils.h | 15 +++ man/keyctl_dh_compute_kdf.3 | 143 ++++++++++++++++++++++++++ tests/keyctl/dh_compute/valid/runtest.sh | 168 +++++++++++++++++++++++++++++++ tests/toolbox.inc.sh | 44 ++++++++ version.lds | 2 + 8 files changed, 542 insertions(+) create mode 100644 man/keyctl_dh_compute_kdf.3
diff --git a/keyutils.c b/keyutils.c index 2a69304..0da640c 100644 --- a/keyutils.c +++ b/keyutils.c @@ -244,6 +244,20 @@ long keyctl_dh_compute(key_serial_t private, key_serial_t prime, return keyctl(KEYCTL_DH_COMPUTE, ¶ms, buffer, buflen, 0); } +long keyctl_dh_compute_kdf(key_serial_t private, key_serial_t prime, + key_serial_t base, char *kdfname, char *otherinfo, + size_t otherinfolen, char *buffer, size_t buflen) +{ + struct keyctl_dh_params params = { .private = private, + .prime = prime, + .base = base }; + struct keyctl_kdf_params kdfparams = { .kdfname = kdfname, + .otherinfo = otherinfo, + .otherinfolen = otherinfolen }; + + return keyctl(KEYCTL_DH_COMPUTE, ¶ms, buffer, buflen, &kdfparams); +} + /*****************************************************************************/ /* * fetch key description into an allocated buffer @@ -386,6 +400,36 @@ 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) + */
I don't think this function should be added. Since genlen is known, the caller can handle all of the memory management and call keyctl_dh_compute_kdf itself. Other _alloc functions do something extra, like ask the kernel how big of a buffer is needed.
+int keyctl_dh_compute_kdf_alloc(key_serial_t private, key_serial_t prime, + key_serial_t base, size_t genlen, char *kdfname, + char *otherinfo, size_t otherinfolen, + void **_buffer) +{ + char *buf; + int ret; + + buf = malloc(genlen + 1); + if (!buf) + return -1; + + ret = keyctl_dh_compute_kdf(private, prime, base, kdfname, otherinfo, + otherinfolen, buf, genlen); + 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..d5abd92 100644 --- a/keyutils.h +++ b/keyutils.h @@ -108,6 +108,13 @@ struct keyctl_dh_params { key_serial_t base; }; +struct keyctl_kdf_params { + char *kdfname; + char *otherinfo; + uint32_t otherinfolen; + uint32_t __spare[8]; +}; + /* * syscall wrappers */ @@ -163,6 +170,10 @@ extern long keyctl_invalidate(key_serial_t id); extern long keyctl_get_persistent(uid_t uid, key_serial_t id); extern long keyctl_dh_compute(key_serial_t private, key_serial_t prime, key_serial_t base, char *buffer, size_t buflen); +extern long keyctl_dh_compute_kdf(key_serial_t private, key_serial_t prime, + key_serial_t base, char *kdfname, + char *otherinfo, size_t otherinfolen, + char *buffer, size_t buflen); /* * utilities @@ -172,6 +183,10 @@ 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); +extern int keyctl_dh_compute_kdf_alloc(key_serial_t private, key_serial_t prime, + key_serial_t base, size_t genlen, + char *kdfname, char *otherinfo, + size_t otherinfolen, 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/man/keyctl_dh_compute_kdf.3 b/man/keyctl_dh_compute_kdf.3 new file mode 100644 index 0000000..06e2b29 --- /dev/null +++ b/man/keyctl_dh_compute_kdf.3
My vote is to include this content in keyctl_dh_compute.3 instead of adding a separate man page.
@@ -0,0 +1,143 @@ +.\" +.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. +.\" Copyright (C) 2016 Intel Corporation. All rights reserved. +.\" +.\" This program is free software; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License +.\" as published by the Free Software Foundation; either version +.\" 2 of the License, or (at your option) any later version. +.\" +.TH KEYCTL_DH_COMPUTE 3 "26 Jul 2016" Linux "Linux Key Management Calls" +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH NAME +keyctl_dh_compute_kdf \- Derive key from a Diffie-Hellman shared secret +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH SYNOPSIS +.nf +.B #include <keyutils.h> +.sp +.BI "long keyctl_dh_compute_kdf(key_serial_t " private ", key_serial_t " prime , +.BI "key_serial_t " base ", char *" kdfname ", char *" otherinfo ", +.BI "size_t " otherinfolen ", char *" buffer ", size_t " buflen ");" +.sp +.BI "long keyctl_dh_compute_kdf_alloc(key_serial_t " private, +.BI "key_serial_t " prime ", key_serial_t " base ", size_t " genlen ", +.BI "char *" kdfname ", "char *" otherinfo ", size_t " otherinfolen ", +.BI "void **" _buffer ");" +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH DESCRIPTION +.BR keyctl_dh_compute_kdf () +derives a key from a Diffie-Hellman shared secret according to the protocol +specified in SP800-56A. +.P +For the Diffie-Hellman computation, the following algorithm is used:: +.IP +.I base +^ +.I private +( mod +.I prime +) +.P +To implement the protocol of SP800-56A +.I base +is a key containing the remote public key to compute the Diffie-Hellman +shared secret. That shared secret is post-processed with a key derivation +function. +.P +.IR base ", " private ", and " prime +must all refer to +.BR user -type +keys containing the parameters for the computation. Each of these keys must +grant the caller +.B read +permission in order for them to be used. +.P +The +.I kdfname +specifies the Linux kernel crypto API name for a key derivation function +using a non-keyed hash, such as kdf_ctr(sha256). Using the counter KDF function +specified with kdf_ctr() makes the key derivation compliant to SP800-56A. +The +.I kdfname +must be a NULL terminated string. +.P +Following the specification of SP800-56A section 5.8.1.2 the +.I otherinfo +parameter may be provided. The format of the OtherInfo field is defined +by the caller. The caller may also specify NULL as a valid argument when +no OtherInfo data shall be processed. The length of the +.I otherinfo +parameter is specified with +.I otherinfolen +and is restricted to a maximum length by the kernel. +.P +The KDF returns the requested number of bytes specified with the +.I genlen +or the +.I buflen +parameter depending on the invoked function. +.P +.I buffer +and +.I buflen +specify the buffer into which the computed result will be placed. +.P +.BR keyctl_dh_compute_kdf_alloc () +is similar to +.BR keyctl_dh_compute_kdf () +except that it allocates a buffer with the size of +.I genlen +to hold the payload data and places the data in it. If successful, a pointer +to the buffer is placed in +.IR *_buffer . +The caller must free the buffer. +.P +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH RETURN VALUE +On success +.BR keyctl_dh_compute_kdf () +returns the amount of data placed into the buffer when +.I buflen +is non-zero. +.P +On success +.BR keyctl_dh_compute_kdf_alloc () +returns the amount of data in the buffer. +.P +On error, both functions set errno to an appropriate code and return the value +.BR -1 . +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH ERRORS +.TP +.B ENOKEY +One of the keys specified is invalid or not readable. +.TP +.B EINVAL +The buffer pointer is invalid or buflen is too small. +.TP +.B EOPNOTSUPP +One of the keys was not a valid user key. +.TP +.B EMSGSIZE +The size of either +.I otherinfolen +or +.I buflen +is too big. +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH LINKING +This is a library function that can be found in +.IR libkeyutils . +When linking, +.B -lkeyutils +should be specified to the linker. +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH SEE ALSO +.BR keyctl (1), +.br +.BR keyctl (2), +.br +.BR keyctl (3), +.br +.BR keyutils (7)
-- Mat Martineau Intel OTC -- 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