diff options
author | David Howells <dhowells@redhat.com> | 2018-11-02 14:51:28 +0000 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2018-11-02 15:09:11 +0000 |
commit | 722c93ed66a23dde775ec2bd7928987a00c4b0d4 (patch) | |
tree | 8c710d12477003631d112a58ef12f342a1c4e733 | |
parent | 7194eeed229280e97d2402a8c2e06c9552fa612f (diff) | |
download | keyutils-722c93ed66a23dde775ec2bd7928987a00c4b0d4.tar.gz |
Add public key operations for encrypt, decrypt, sign and verify
Add encryption, decryption, signature creation and signature verification
public key operations. Example usage:
j=`openssl pkcs8 -in ~/pkcs7/firmwarekey2.priv -topk8 -nocrypt -outform DER | \
keyctl padd asymmetric foo @s`
echo -n abcdefghijklmnopqrst >/tmp/data
keyctl pkey_encrypt $j 0 /tmp/data enc=pkcs1 >/tmp/enc
keyctl pkey_decrypt $j 0 /tmp/enc enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec
keyctl pkey_sign $j 0 /tmp/data enc=pkcs1 hash=sha1 >/tmp/sig
keyctl pkey_verify $j 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-and-tested-by: Denis Kenzior <denkenz@gmail.com>
-rw-r--r-- | keyctl.c | 259 | ||||
-rw-r--r-- | keyutils.c | 63 | ||||
-rw-r--r-- | keyutils.h | 50 | ||||
-rw-r--r-- | version.lds | 5 |
4 files changed, 377 insertions, 0 deletions
@@ -16,8 +16,10 @@ #include <stdarg.h> #include <string.h> #include <unistd.h> +#include <fcntl.h> #include <ctype.h> #include <errno.h> +#include <sys/stat.h> #include <asm/unistd.h> #include "keyutils.h" #include <limits.h> @@ -71,6 +73,11 @@ static nr void act_keyctl_dh_compute(int argc, char *argv[]); static nr void act_keyctl_dh_compute_kdf(int argc, char *argv[]); static nr void act_keyctl_dh_compute_kdf_oi(int argc, char *argv[]); static nr void act_keyctl_restrict_keyring(int argc, char *argv[]); +static nr void act_keyctl_pkey_query(int argc, char *argv[]); +static nr void act_keyctl_pkey_encrypt(int argc, char *argv[]); +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[]); const struct command commands[] = { { act_keyctl___version, "--version", "" }, @@ -93,6 +100,11 @@ const struct command commands[] = { { act_keyctl_padd, "padd", "<type> <desc> <keyring>" }, { act_keyctl_pinstantiate, "pinstantiate","<key> <keyring>" }, { act_keyctl_pipe, "pipe", "<key>" }, + { act_keyctl_pkey_query, "pkey_query", "<key> <pass> [k=v]*" }, + { act_keyctl_pkey_encrypt, "pkey_encrypt", "<key> <pass> <datafile> [k=v]*" }, + { act_keyctl_pkey_decrypt, "pkey_decrypt", "<key> <pass> <datafile> [k=v]*" }, + { act_keyctl_pkey_sign, "pkey_sign", "<key> <pass> <datafile> [k=v]*" }, + { act_keyctl_pkey_verify, "pkey_verify", "<key> <pass> <datafile> <sigfile> [k=v]*" }, { act_keyctl_prequest2, "prequest2", "<type> <desc> [<dest_keyring>]" }, { act_keyctl_print, "print", "<key>" }, { act_keyctl_pupdate, "pupdate", "<key>" }, @@ -125,6 +137,7 @@ static int dump_key_tree(key_serial_t keyring, const char *name, int hex_key_IDs static void format(void) __attribute__((noreturn)); static void error(const char *msg) __attribute__((noreturn)); static key_serial_t get_key_id(char *arg); +static void *read_file(const char *name, size_t *_size); static uid_t myuid; static gid_t mygid, *mygroups; @@ -1841,6 +1854,219 @@ static void act_keyctl_restrict_keyring(int argc, char *argv[]) exit(0); } +/* + * Parse public key operation info arguments. + */ +static void pkey_parse_info(char **argv, char info[4096]) +{ + int i_len = 0; + + /* A number of key=val pairs can be provided after the main arguments + * to inform the kernel of things like encoding type and hash function. + */ + for (; *argv; argv++) { + int n = strlen(argv[0]); + + if (!memchr(argv[0], '=', n)) { + fprintf(stderr, "Option not in key=val form\n"); + exit(2); + } + if (n + 1 > 4096 - 1 - i_len) { + fprintf(stderr, "Too many info options\n"); + exit(2); + } + + if (i_len > 0) + info[i_len++] = ' '; + memcpy(info + i_len, argv[0], n); + i_len += n; + } + + info[i_len] = 0; +} + +/* + * Query a public key. + */ +static void act_keyctl_pkey_query(int argc, char *argv[]) +{ + struct keyctl_pkey_query result; + key_serial_t key; + char info[4096]; + + if (argc < 3) + format(); + pkey_parse_info(argv + 2, info); + + key = get_key_id(argv[1]); + if (strcmp(argv[2], "0") != 0) { + fprintf(stderr, "Password passing is not yet supported\n"); + exit(2); + } + + if (keyctl_pkey_query(key, info, &result) < 0) + error("keyctl_pkey_query"); + + printf("key_size=%u\n", result.key_size); + printf("max_data_size=%u\n", result.max_data_size); + printf("max_sig_size=%u\n", result.max_sig_size); + printf("max_enc_size=%u\n", result.max_enc_size); + printf("max_dec_size=%u\n", result.max_dec_size); + printf("encrypt=%c\n", result.supported_ops & KEYCTL_SUPPORTS_ENCRYPT ? 'y' : 'n'); + printf("decrypt=%c\n", result.supported_ops & KEYCTL_SUPPORTS_DECRYPT ? 'y' : 'n'); + printf("sign=%c\n", result.supported_ops & KEYCTL_SUPPORTS_SIGN ? 'y' : 'n'); + printf("verify=%c\n", result.supported_ops & KEYCTL_SUPPORTS_VERIFY ? 'y' : 'n'); + exit(0); +} + +/* + * Encrypt a blob. + */ +static void act_keyctl_pkey_encrypt(int argc, char *argv[]) +{ + struct keyctl_pkey_query result; + key_serial_t key; + size_t in_len; + long out_len; + void *in, *out; + char info[4096]; + + if (argc < 5) + format(); + pkey_parse_info(argv + 4, info); + + key = get_key_id(argv[1]); + if (strcmp(argv[2], "0") != 0) { + fprintf(stderr, "Password passing is not yet supported\n"); + exit(2); + } + in = read_file(argv[3], &in_len); + + if (keyctl_pkey_query(key, info, &result) < 0) + error("keyctl_pkey_query"); + + out = malloc(result.max_dec_size); + if (!out) + error("malloc"); + + out_len = keyctl_pkey_encrypt(key, info, + in, in_len, out, result.max_dec_size); + if (out_len < 0) + error("keyctl_pkey_encrypt"); + + if (fwrite(out, out_len, 1, stdout) != 1) + error("stdout"); + exit(0); +} + +/* + * Decrypt a blob. + */ +static void act_keyctl_pkey_decrypt(int argc, char *argv[]) +{ + struct keyctl_pkey_query result; + key_serial_t key; + size_t in_len; + long out_len; + void *in, *out; + char info[4096]; + + if (argc < 5) + format(); + pkey_parse_info(argv + 4, info); + + key = get_key_id(argv[1]); + if (strcmp(argv[2], "0") != 0) { + fprintf(stderr, "Password passing is not yet supported\n"); + exit(2); + } + in = read_file(argv[3], &in_len); + + if (keyctl_pkey_query(key, info, &result) < 0) + error("keyctl_pkey_query"); + + out = malloc(result.max_enc_size); + if (!out) + error("malloc"); + + out_len = keyctl_pkey_decrypt(key, info, + in, in_len, out, result.max_enc_size); + if (out_len < 0) + error("keyctl_pkey_decrypt"); + + if (fwrite(out, out_len, 1, stdout) != 1) + error("stdout"); + exit(0); +} + +/* + * Create a signature + */ +static void act_keyctl_pkey_sign(int argc, char *argv[]) +{ + struct keyctl_pkey_query result; + key_serial_t key; + size_t in_len; + long out_len; + void *in, *out; + char info[4096]; + + if (argc < 5) + format(); + pkey_parse_info(argv + 4, info); + + key = get_key_id(argv[1]); + if (strcmp(argv[2], "0") != 0) { + fprintf(stderr, "Password passing is not yet supported\n"); + exit(2); + } + in = read_file(argv[3], &in_len); + + if (keyctl_pkey_query(key, info, &result) < 0) + error("keyctl_pkey_query"); + + out = malloc(result.max_sig_size); + if (!out) + error("malloc"); + + out_len = keyctl_pkey_sign(key, info, + in, in_len, out, result.max_sig_size); + if (out_len < 0) + error("keyctl_pkey_sign"); + + if (fwrite(out, out_len, 1, stdout) != 1) + error("stdout"); + exit(0); +} + +/* + * Verify a signature. + */ +static void act_keyctl_pkey_verify(int argc, char *argv[]) +{ + key_serial_t key; + size_t data_len, sig_len; + void *data, *sig; + char info[4096]; + + if (argc < 5) + format(); + pkey_parse_info(argv + 5, info); + + key = get_key_id(argv[1]); + if (strcmp(argv[2], "0") != 0) { + fprintf(stderr, "Password passing is not yet supported\n"); + exit(2); + } + data = read_file(argv[3], &data_len); + sig = read_file(argv[4], &sig_len); + + if (keyctl_pkey_verify(key, info, + data, data_len, sig, sig_len) < 0) + error("keyctl_pkey_verify"); + exit(0); +} + /*****************************************************************************/ /* * parse a key identifier @@ -1909,6 +2135,39 @@ incorrect_key_by_name_spec: } /* end get_key_id() */ +/* + * Read the contents of a file into a buffer and return it. + */ +static void *read_file(const char *name, size_t *_size) +{ + struct stat st; + ssize_t r; + void *p; + int fd; + + fd = open(name, O_RDONLY); + if (fd < 0) + error(name); + if (fstat(fd, &st) < 0) + error(name); + + p = malloc(st.st_size); + if (!p) + error("malloc"); + r = read(fd, p, st.st_size); + if (r == -1) + error(name); + if (r != st.st_size) { + fprintf(stderr, "%s: Short read\n", name); + exit(1); + } + if (close(fd) < 0) + error(name); + + *_size = st.st_size; + return p; +} + /*****************************************************************************/ /* * recursively display a key/keyring tree @@ -264,6 +264,69 @@ long keyctl_restrict_keyring(key_serial_t keyring, const char *type, return keyctl(KEYCTL_RESTRICT_KEYRING, keyring, type, restriction); } +long keyctl_pkey_query(key_serial_t key_id, + const char *info, + struct keyctl_pkey_query *result) +{ + return keyctl(KEYCTL_PKEY_QUERY, key_id, info, result); +} + +long keyctl_pkey_encrypt(key_serial_t key_id, + const char *info, + const void *data, size_t data_len, + void *enc, size_t enc_len) +{ + struct keyctl_pkey_params params = { + .key_id = key_id, + .in_len = data_len, + .out_len = enc_len, + }; + + return keyctl(KEYCTL_PKEY_ENCRYPT, ¶ms, info, data, enc); +} + +long keyctl_pkey_decrypt(key_serial_t key_id, + const char *info, + const void *enc, size_t enc_len, + void *data, size_t data_len) +{ + struct keyctl_pkey_params params = { + .key_id = key_id, + .in_len = enc_len, + .out_len = data_len, + }; + + return keyctl(KEYCTL_PKEY_DECRYPT, ¶ms, info, enc, data); +} + +long keyctl_pkey_sign(key_serial_t key_id, + const char *info, + const void *data, size_t data_len, + void *sig, size_t sig_len) +{ + struct keyctl_pkey_params params = { + .key_id = key_id, + .in_len = data_len, + .out_len = sig_len, + }; + + return keyctl(KEYCTL_PKEY_SIGN, ¶ms, info, data, sig); +} + +long keyctl_pkey_verify(key_serial_t key_id, + const char *info, + const void *data, size_t data_len, + const void *sig, size_t sig_len) +{ + struct keyctl_pkey_params params = { + .key_id = key_id, + .in_len = data_len, + .in2_len = sig_len, + }; + + return keyctl(KEYCTL_PKEY_VERIFY, ¶ms, info, data, sig); +} + /*****************************************************************************/ /* * fetch key description into an allocated buffer @@ -100,6 +100,11 @@ typedef uint32_t key_perm_t; #define KEYCTL_INVALIDATE 21 /* invalidate a key */ #define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ #define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */ +#define KEYCTL_PKEY_QUERY 24 /* Query public key parameters */ +#define KEYCTL_PKEY_ENCRYPT 25 /* Encrypt a blob using a public key */ +#define KEYCTL_PKEY_DECRYPT 26 /* Decrypt a blob using a public key */ +#define KEYCTL_PKEY_SIGN 27 /* Create a public key signature */ +#define KEYCTL_PKEY_VERIFY 28 /* Verify a public key signature */ #define KEYCTL_RESTRICT_KEYRING 29 /* Restrict keys allowed to link to a keyring */ /* keyctl structures */ @@ -116,6 +121,31 @@ struct keyctl_kdf_params { uint32_t __spare[8]; }; +#define KEYCTL_SUPPORTS_ENCRYPT 0x01 +#define KEYCTL_SUPPORTS_DECRYPT 0x02 +#define KEYCTL_SUPPORTS_SIGN 0x04 +#define KEYCTL_SUPPORTS_VERIFY 0x08 + +struct keyctl_pkey_query { + unsigned int supported_ops; /* Which ops are supported */ + unsigned int key_size; /* Size of the key in bits */ + unsigned short max_data_size; /* Maximum size of raw data to sign in bytes */ + unsigned short max_sig_size; /* Maximum size of signature in bytes */ + unsigned short max_enc_size; /* Maximum size of encrypted blob in bytes */ + unsigned short max_dec_size; /* Maximum size of decrypted blob in bytes */ + unsigned int __spare[10]; +}; + +struct keyctl_pkey_params { + key_serial_t key_id; /* Serial no. of public key to use */ + unsigned int in_len; /* Input data size */ + union { + unsigned int out_len; /* Output buffer size (encrypt/decrypt/sign) */ + unsigned int in2_len; /* Second input data size (verify) */ + }; + unsigned int __spare[7]; +}; + /* * syscall wrappers */ @@ -178,6 +208,26 @@ extern long keyctl_dh_compute_kdf(key_serial_t private, key_serial_t prime, extern long keyctl_restrict_keyring(key_serial_t keyring, const char *type, const char *restriction); +extern long keyctl_pkey_query(key_serial_t key_id, + const char *info, + struct keyctl_pkey_query *result); +extern long keyctl_pkey_encrypt(key_serial_t key_id, + const char *info, + const void *data, size_t data_len, + void *enc, size_t enc_len); +extern long keyctl_pkey_decrypt(key_serial_t key_id, + const char *info, + const void *enc, size_t enc_len, + void *data, size_t data_len); +extern long keyctl_pkey_sign(key_serial_t key_id, + const char *info, + const void *data, size_t data_len, + void *sig, size_t sig_len); +extern long keyctl_pkey_verify(key_serial_t key_id, + const char *info, + const void *data, size_t data_len, + const void *sig, size_t sig_len); + /* * utilities */ diff --git a/version.lds b/version.lds index 4c5babe..018d4f3 100644 --- a/version.lds +++ b/version.lds @@ -66,6 +66,11 @@ KEYUTILS_1.6 { /* management functions */ keyctl_dh_compute; keyctl_dh_compute_alloc; + keyctl_pkey_query; + keyctl_pkey_encrypt; + keyctl_pkey_decrypt; + keyctl_pkey_sign; + keyctl_pkey_verify; } KEYUTILS_1.5; |