diff options
author | David Howells <dhowells@redhat.com> | 2019-05-30 15:23:02 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-06-19 13:42:09 +0100 |
commit | f9761a6a9abec83c7fd7a9cbc96237f7cd344808 (patch) | |
tree | d861c399235c4ebb6934c82aac884b84bbccf4b5 | |
parent | 0f70f77491bb6976a2bf761224fec1a9cc6cfb87 (diff) | |
download | keyutils-f9761a6a9abec83c7fd7a9cbc96237f7cd344808.tar.gz |
Provide the ability to query subsystem capabilities
Provide the ability to query the capabilities of the keyrings subsystem.
Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r-- | keyctl.c | 48 | ||||
-rw-r--r-- | keyutils.c | 50 | ||||
-rw-r--r-- | keyutils.h | 15 | ||||
-rw-r--r-- | man/keyctl.1 | 56 | ||||
-rw-r--r-- | man/keyctl.3 | 2 | ||||
-rw-r--r-- | man/keyctl_capabilities.3 | 109 | ||||
-rw-r--r-- | tests/keyctl/supports/bad-args/runtest.sh | 23 | ||||
-rw-r--r-- | tests/keyctl/supports/valid/runtest.sh | 23 | ||||
-rw-r--r-- | tests/toolbox.inc.sh | 28 | ||||
-rw-r--r-- | version.lds | 1 |
10 files changed, 355 insertions, 0 deletions
@@ -79,6 +79,7 @@ static nr void act_keyctl_pkey_decrypt(int argc, char *argv[]); static nr void act_keyctl_pkey_sign(int argc, char *argv[]); static nr void act_keyctl_pkey_verify(int argc, char *argv[]); static nr void act_keyctl_move(int argc, char *argv[]); +static nr void act_keyctl_supports(int argc, char *argv[]); const struct command commands[] = { { act_keyctl___version, "--version", "" }, @@ -129,6 +130,7 @@ const struct command commands[] = { { NULL, "session", "<name> [<prog> <arg1> <arg2> ...]" }, { act_keyctl_setperm, "setperm", "<key> <mask>" }, { act_keyctl_show, "show", "[-x] [<keyring>]" }, + { act_keyctl_supports, "supports", "[<cap>]" }, { act_keyctl_timeout, "timeout", "<key> <timeout>" }, { act_keyctl_unlink, "unlink", "<key> [<keyring>]" }, { act_keyctl_update, "update", "<key> <data>" }, @@ -2098,6 +2100,52 @@ static void act_keyctl_move(int argc, char *argv[]) exit(0); } +struct capability_def { + const char *name; /* Textual name of capability */ + unsigned int index; /* Index in capabilities array */ + unsigned char mask; /* Mask on capabilities array element */ +}; + +static const struct capability_def capabilities[] = { + { "capabilities", 0, KEYCTL_CAPS0_CAPABILITIES }, + { "persistent_keyrings", 0, KEYCTL_CAPS0_PERSISTENT_KEYRINGS }, + { "dh_compute", 0, KEYCTL_CAPS0_DIFFIE_HELLMAN }, + { "public_key", 0, KEYCTL_CAPS0_PUBLIC_KEY }, + { "big_key_type", 0, KEYCTL_CAPS0_BIG_KEY }, + { "key_invalidate", 0, KEYCTL_CAPS0_INVALIDATE }, + { "restrict_keyring", 0, KEYCTL_CAPS0_RESTRICT_KEYRING }, + { "move_key", 0, KEYCTL_CAPS0_MOVE }, + {} +}; + +/* + * Detect/list capabilities. + */ +static void act_keyctl_supports(int argc, char *argv[]) +{ + const struct capability_def *p; + unsigned char caps[256]; + + if (argc < 1 || argc > 2) + format(); + + if (keyctl_capabilities(caps, sizeof(caps)) < 0) + error("keyctl_capabilities"); + + if (argc == 1) { + for (p = capabilities; p->name; p++) + printf("have_%s=%c\n", + p->name, + (caps[p->index] & p->mask) ? '1' : '0'); + exit(0); + } else { + for (p = capabilities; p->name; p++) + if (strcmp(argv[1], p->name) == 0) + exit((caps[p->index] & p->mask) ? 0 : 1); + exit(3); + } +} + /*****************************************************************************/ /* * parse a key identifier @@ -335,6 +335,56 @@ long keyctl_move(key_serial_t id, return keyctl(KEYCTL_MOVE, id, from_ringid, to_ringid, flags); } +long keyctl_capabilities(unsigned char *buffer, size_t buflen) +{ + long n; + + n = keyctl(KEYCTL_CAPABILITIES, buffer, buflen); + if (n != -1 || errno != EOPNOTSUPP) + return n; + + /* Emulate the operation */ + if (buflen > 0) { + memset(buffer, 0, buflen); + + errno = 0; + keyctl_get_persistent(-1, 0); + if (errno != EOPNOTSUPP) + buffer[0] |= KEYCTL_CAPS0_PERSISTENT_KEYRINGS; + + errno = 0; + keyctl_dh_compute(0, 0, 0, NULL, 0); + if (errno != EOPNOTSUPP) + buffer[0] |= KEYCTL_CAPS0_DIFFIE_HELLMAN; + + errno = 0; + keyctl_pkey_query(0, NULL, NULL); + if (errno != EOPNOTSUPP) + buffer[0] |= KEYCTL_CAPS0_PUBLIC_KEY; + + /* Can't emulate KEYCTL_CAPS0_BIG_KEY without a valid + * destination keyring. + */ + + errno = 0; + keyctl_invalidate(0); + if (errno != EOPNOTSUPP) + buffer[0] |= KEYCTL_CAPS0_INVALIDATE; + + errno = 0; + keyctl_restrict_keyring(0, NULL, NULL); + if (errno != EOPNOTSUPP) + buffer[0] |= KEYCTL_CAPS0_RESTRICT_KEYRING; + + errno = 0; + keyctl_move(0, 0, 0, 0); + if (errno != EOPNOTSUPP) + buffer[0] |= KEYCTL_CAPS0_MOVE; + } + + return sizeof(unsigned char); +} + /*****************************************************************************/ /* * fetch key description into an allocated buffer @@ -107,6 +107,7 @@ typedef uint32_t key_perm_t; #define KEYCTL_PKEY_VERIFY 28 /* Verify a public key signature */ #define KEYCTL_RESTRICT_KEYRING 29 /* Restrict keys allowed to link to a keyring */ #define KEYCTL_MOVE 30 /* Move keys between keyrings */ +#define KEYCTL_CAPABILITIES 31 /* Find capabilities of keyrings subsystem */ /* keyctl structures */ struct keyctl_dh_params { @@ -150,6 +151,19 @@ struct keyctl_pkey_params { #define KEYCTL_MOVE_EXCL 0x00000001 /* Do not displace from the to-keyring */ /* + * Capabilities flags. The capabilities list is an array of 8-bit integers; + * each integer can carry up to 8 flags. + */ +#define KEYCTL_CAPS0_CAPABILITIES 0x01 /* KEYCTL_CAPABILITIES supported */ +#define KEYCTL_CAPS0_PERSISTENT_KEYRINGS 0x02 /* Persistent keyrings enabled */ +#define KEYCTL_CAPS0_DIFFIE_HELLMAN 0x04 /* Diffie-Hellman ops enabled */ +#define KEYCTL_CAPS0_PUBLIC_KEY 0x08 /* Public key ops enabled */ +#define KEYCTL_CAPS0_BIG_KEY 0x10 /* big_key-type enabled */ +#define KEYCTL_CAPS0_INVALIDATE 0x20 /* KEYCTL_INVALIDATE supported */ +#define KEYCTL_CAPS0_RESTRICT_KEYRING 0x40 /* KEYCTL_RESTRICT_KEYRING supported */ +#define KEYCTL_CAPS0_MOVE 0x80 /* KEYCTL_MOVE supported */ + +/* * syscall wrappers */ extern key_serial_t add_key(const char *type, @@ -234,6 +248,7 @@ extern long keyctl_move(key_serial_t id, key_serial_t from_ringid, key_serial_t to_ringid, unsigned int flags); +extern long keyctl_capabilities(unsigned char *buffer, size_t buflen); /* * utilities diff --git a/man/keyctl.1 b/man/keyctl.1 index bf841aa..1c8f569 100644 --- a/man/keyctl.1 +++ b/man/keyctl.1 @@ -13,6 +13,8 @@ keyctl \- key management facility control .SH SYNOPSIS \fBkeyctl\fR \-\-version .br +\fBkeyctl\fR supports [<cap>] +.br \fBkeyctl\fR show [\-x] [<keyring>] .br \fBkeyctl\fR add <type> <desc> <data> <keyring> @@ -177,6 +179,60 @@ $ keyctl \-\-version keyctl from keyutils\-1.5.3 (Built 2011\-08\-24) .fi .RE +.SS Query subsystem capabilities +\fBkeyctl\fR supports [<cap>] + +This command can list the available capabilities: + +.RS +.nf +$ keyctl supports +have_capabilities=0 +have_persistent_keyrings=1 +have_dh_compute=1 +have_public_key=1 +... +.fi +.RE +.P +And it can query a capability: + +.RS +.nf +$ keyctl supports pkey +echo $? +0 +.fi +.RE + +which returns 0 if the capability is supported, 1 if it isn't and 3 if the +name is not recognised. The capabilities supported are: +.TP +.B capabilities +The kernel supports capability querying. If not, the other capabilities will +be queried as best libkeyutils can manage. +.TP +.B persistent_keyrings +The kernel supports persistent keyrings. +.TP +.B dh_compute +The kernel supports Diffie-Hellman computation operations. +.TP +.B public_key +The kernel supports public key operations. +.TP +.B big_key_type +The kernel supports the big_key key type. +.TP +.B key_invalidate +The kernel supports the invalidate key operaiton. +.TP +.B restrict_keyring +The kernel supports the restrict_keyring operation. +.TP +.B move_key +The kernel supports the move key operation. + .SS Show process keyrings \fBkeyctl show [\-x] [<keyring>]\fR diff --git a/man/keyctl.3 b/man/keyctl.3 index dcef9c6..b0f5fdc 100644 --- a/man/keyctl.3 +++ b/man/keyctl.3 @@ -37,6 +37,8 @@ and then telling the linker it should link in the library: .br .BR keyctl_chown (3) .br +.BR keyctl_capabilities (3) +.br .BR keyctl_clear (3) .br .BR keyctl_describe (3) diff --git a/man/keyctl_capabilities.3 b/man/keyctl_capabilities.3 new file mode 100644 index 0000000..cc4d86c --- /dev/null +++ b/man/keyctl_capabilities.3 @@ -0,0 +1,109 @@ +.\" +.\" Copyright (C) 2019 Red Hat, Inc. All Rights Reserved. +.\" Written by David Howells (dhowells@redhat.com) +.\" +.\" 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_CAPABILITIES 3 "30 May 2019" Linux "Linux Key Management Calls" +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH NAME +keyctl_capabilities \- Query subsystem capabilities +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH SYNOPSIS +.nf +.B #include <keyutils.h> +.sp +.BI "long keyctl_capabilities(unsigned char *" buffer ", size_t " buflen ");" +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH DESCRIPTION +.BR keyctl_capabilities () +queries the keyrings subsystem in the kernel to ask about its capabilities and +fills in the array in the buffer with bits that indicate the presence or +absence of specific features in the keyrings subsystem. +.P +The function returns the amount of data the kernel has available, irrespective +of the amount of buffer space available. If the buffer is shorter than the +data, a short copy will be made; if the buffer is larger than the data, the +excess space will be cleared. +.P +If this operation is not available in the kernel, the keyutils library will be +emulate it as best it can and the capability bit that indicates if the kernel +operation is available will be cleared. +.P +In +.IR buffer[0] , +the following capabilities exist: +.TP +.B KEYCTL_CAPS0_CAPABILITIES +This is set if the kernel supports this operation and cleared otherwise. If +it is cleared, the rest of the flags are emulated. +.TP +.B KEYCTL_CAPS0_PERSISTENT_KEYRINGS +This is set if the kernel supports persistent keyrings and cleared otherwise. +See +.BR keyctl_get_persistent ( 3 ). +.TP +.B KEYCTL_CAPS0_DIFFIE_HELLMAN +This is set if the kernel supports Diffie-Hellman calculation and cleared +otherwise. See +.BR keyctl_dh_compute ( 3 ). +.TP +.B KEYCTL_CAPS0_PUBLIC_KEY +This is set if the kernel supports public-key operations and cleared +otherwise. See +.BR keyctl_pkey_query ( 3 ). +.TP +.B KEYCTL_CAPS0_BIG_KEY +This is set if the kernel supports the big_key key type and cleared otherwise. +.TP +.B KEYCTL_CAPS0_INVALIDATE +This is set if the kernel supports key invalidation and cleared otherwise. +See +.BR keyctl_invalidate ( 3 ). +.TP +.B KEYCTL_CAPS0_RESTRICT_KEYRING +This is set if the kernel supports restrictions on keyrings and cleared +otherwise. See +.BR keyctl_restrict_keyring ( 3 ). +.TP +.B KEYCTL_CAPS0_MOVE +This is set if the kernel supports the move key operation and cleared +otherwise. See +.BR keyctl_move ( 3 ). +.P +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH RETURN VALUE +On success +.BR keyctl_capabilities () +returns the size of the data it has available, irrespective of the size of the +buffer. On error, the value +.B -1 +will be returned and +.I errno +will have been set to an appropriate error. +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.SH ERRORS +.TP +.B EFAULT +The buffer cannot be written to. +.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.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 +.ad l +.nh +.BR keyctl (1), +.BR add_key (2), +.BR keyctl (2), +.BR request_key (2), +.BR keyctl (3), +.BR keyrings (7), +.BR keyutils (7) diff --git a/tests/keyctl/supports/bad-args/runtest.sh b/tests/keyctl/supports/bad-args/runtest.sh new file mode 100644 index 0000000..05581a4 --- /dev/null +++ b/tests/keyctl/supports/bad-args/runtest.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +. ../../../prepare.inc.sh +. ../../../toolbox.inc.sh + + +# ---- do the actual testing ---- + +result=PASS +echo "++++ BEGINNING TEST" >$OUTPUTFILE + +# check that two arguments fails correctly +marker "TWO ARGS" +expect_args_error keyctl support 0 0 + +# check that three arguments fails correctly +marker "THREE ARGS" +expect_args_error keyctl support 0 0 0 + +echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE + +# --- then report the results in the database --- +toolbox_report_result $TEST $result diff --git a/tests/keyctl/supports/valid/runtest.sh b/tests/keyctl/supports/valid/runtest.sh new file mode 100644 index 0000000..2c62ef2 --- /dev/null +++ b/tests/keyctl/supports/valid/runtest.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +. ../../../prepare.inc.sh +. ../../../toolbox.inc.sh + + +# ---- do the actual testing ---- + +result=PASS +echo "++++ BEGINNING TEST" >$OUTPUTFILE + +# Check that listing caps works +marker "LIST CAPS" +supports + +# check that querying a cap works +marker "QUERY CAP" +supports --unrecognised xxx + +echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE + +# --- then report the results in the database --- +toolbox_report_result $TEST $result diff --git a/tests/toolbox.inc.sh b/tests/toolbox.inc.sh index a0bdd51..e7b9635 100644 --- a/tests/toolbox.inc.sh +++ b/tests/toolbox.inc.sh @@ -1203,6 +1203,34 @@ function move_key () ############################################################################### # +# Query supported features +# +############################################################################### +function supports () +{ + my_exitval=0 + if [ "x$1" = "x--fail" ] + then + my_exitval=1 + shift + elif [ "x$1" = "x--unrecognised" ] + then + my_exitval=3 + shift + fi + + echo keyctl supports $* >>$OUTPUTFILE + keyctl supports $* >>$OUTPUTFILE 2>&1 + err=$? + if [ $err != $my_exitval ] + then + echo exitcode=$err >>$OUTPUTFILE + failed + fi +} + +############################################################################### +# # Make sure we sleep at least N seconds # ############################################################################### diff --git a/version.lds b/version.lds index 9e78ea2..d2e4d26 100644 --- a/version.lds +++ b/version.lds @@ -95,5 +95,6 @@ KEYUTILS_1.8 { KEYUTILS_1.9 { /* Management functions */ keyctl_move; + keyctl_capabilities; } KEYUTILS_1.8; |