summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2010-08-19 18:20:26 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2010-08-19 18:20:26 +0200
commit5507ea6f51bd227ce4af661d550ad4d4de80674b (patch)
tree324958e4792047c42f9cc41041c5e0c7c0843103
parenta7befd9b8fba6f6d777f7d8436154dc62f1fa652 (diff)
downloadcryptodev-linux-5507ea6f51bd227ce4af661d550ad4d4de80674b.tar.gz
cryptodev-linux-5507ea6f51bd227ce4af661d550ad4d4de80674b.tar.xz
cryptodev-linux-5507ea6f51bd227ce4af661d550ad4d4de80674b.zip
Added KEY_WRAPPING flag that allows a key to be used for wrapping other keys.
Only superuser can enable this flag. Prevent short keys to wrap longer ones. Added initial stuff for supporting wrapping of private and public keys.
-rw-r--r--examples/ncr.c107
-rw-r--r--examples/pk.c116
-rw-r--r--ncr-dh.c12
-rw-r--r--ncr-dh.h2
-rw-r--r--ncr-int.h1
-rw-r--r--ncr-key-wrap.c57
-rw-r--r--ncr-key.c120
-rw-r--r--ncr-pk.c24
-rw-r--r--ncr-pk.h4
-rw-r--r--ncr.h4
10 files changed, 428 insertions, 19 deletions
diff --git a/examples/ncr.c b/examples/ncr.c
index 9a75a99..5169a14 100644
--- a/examples/ncr.c
+++ b/examples/ncr.c
@@ -208,7 +208,7 @@ test_ncr_key(int cfd)
static int
test_ncr_wrap_key(int cfd)
{
- int i;
+ int i, ret;
ncr_key_t key, key2;
struct ncr_key_data_st keydata;
struct ncr_key_wrap_st kwrap;
@@ -234,7 +234,7 @@ test_ncr_wrap_key(int cfd)
keydata.key_id_size = 2;
keydata.type = NCR_KEY_TYPE_SECRET;
keydata.algorithm = NCR_ALG_AES_CBC;
- keydata.flags = NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPABLE;
+ keydata.flags = NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPING;
keydata.key = key;
keydata.idata = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
@@ -279,12 +279,20 @@ test_ncr_wrap_key(int cfd)
kwrap.io = data;
kwrap.io_size = sizeof(data);
- if (ioctl(cfd, NCRIO_KEY_WRAP, &kwrap)) {
+ ret = ioctl(cfd, NCRIO_KEY_WRAP, &kwrap);
+
+ if (geteuid() == 0 && ret) {
fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
perror("ioctl(NCRIO_KEY_WRAP)");
return 1;
}
+ if (geteuid() != 0) {
+ /* cannot test further */
+ fprintf(stdout, "\t(Wrapping test not completed. Run as root)\n");
+ return 0;
+ }
+
data_size = kwrap.io_size;
if (kwrap.io_size != 24 || memcmp(data,
@@ -298,9 +306,6 @@ test_ncr_wrap_key(int cfd)
return 1;
}
-
-
-
/* test unwrapping */
fprintf(stdout, "\tKey Unwrap test...\n");
@@ -360,7 +365,94 @@ test_ncr_wrap_key(int cfd)
#endif
return 0;
+}
+
+/* check whether wrapping of long keys is not allowed with
+ * shorted wrapping keys */
+static int
+test_ncr_wrap_key2(int cfd)
+{
+ int ret;
+ ncr_key_t key, key2;
+ struct ncr_key_data_st keydata;
+ struct ncr_key_wrap_st kwrap;
+ uint8_t data[WRAPPED_KEY_DATA_SIZE];
+
+ /* test 1: generate a key in userspace import it
+ * to kernel via data and export it.
+ */
+
+ fprintf(stdout, "\tKey Wrap test II...\n");
+
+ if (geteuid() != 0) {
+ /* cannot test further */
+ fprintf(stdout, "\t(Wrapping test not completed. Run as root)\n");
+ return 0;
+ }
+
+ /* convert it to key */
+ if (ioctl(cfd, NCRIO_KEY_INIT, &key)) {
+ perror("ioctl(NCRIO_KEY_INIT)");
+ return 1;
+ }
+
+ keydata.key_id[0] = 'a';
+ keydata.key_id[2] = 'b';
+ keydata.key_id_size = 2;
+ keydata.type = NCR_KEY_TYPE_SECRET;
+ keydata.algorithm = NCR_ALG_AES_CBC;
+ keydata.flags = NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPING;
+
+ keydata.key = key;
+ keydata.idata = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
+ keydata.idata_size = 16;
+
+ if (ioctl(cfd, NCRIO_KEY_IMPORT, &keydata)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_KEY_IMPORT)");
+ return 1;
+ }
+
+
+ /* convert it to key */
+ if (ioctl(cfd, NCRIO_KEY_INIT, &key2)) {
+ perror("ioctl(NCRIO_KEY_INIT)");
+ return 1;
+ }
+ keydata.key_id[0] = 'b';
+ keydata.key_id[2] = 'a';
+ keydata.key_id_size = 2;
+ keydata.type = NCR_KEY_TYPE_SECRET;
+ keydata.algorithm = NCR_ALG_AES_CBC;
+ keydata.flags = NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPABLE;
+
+ keydata.key = key2;
+ keydata.idata = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF";
+ keydata.idata_size = 32;
+
+ if (ioctl(cfd, NCRIO_KEY_IMPORT, &keydata)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_KEY_IMPORT)");
+ return 1;
+ }
+
+ /* now try wrapping key2 using key */
+ memset(&kwrap, 0, sizeof(kwrap));
+ kwrap.algorithm = NCR_WALG_AES_RFC3394;
+ kwrap.keytowrap = key2;
+ kwrap.key = key;
+ kwrap.io = data;
+ kwrap.io_size = sizeof(data);
+
+ ret = ioctl(cfd, NCRIO_KEY_WRAP, &kwrap);
+ if (!ret) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ /* wrapping shouldn't have been allowed */
+ return 1;
+ }
+
+ return 0;
}
static int
@@ -939,6 +1031,9 @@ main()
if (test_ncr_wrap_key(fd))
return 1;
+ if (test_ncr_wrap_key2(fd))
+ return 1;
+
if (test_ncr_store_wrap_key(fd))
return 1;
diff --git a/examples/pk.c b/examples/pk.c
index 3102a3b..5f7c72a 100644
--- a/examples/pk.c
+++ b/examples/pk.c
@@ -524,6 +524,119 @@ struct ncr_key_derivation_params_st kderive;
return 0;
}
+/* check whether wrapping of long keys is not allowed with
+ * shorted wrapping keys */
+static int
+test_ncr_wrap_key3(int cfd)
+{
+ int ret, i;
+ ncr_key_t key;
+ struct ncr_key_data_st keydata;
+ struct ncr_key_wrap_st kwrap;
+ struct ncr_key_generate_st kgen;
+ ncr_key_t pubkey, privkey;
+ uint8_t data[DATA_SIZE];
+ /* only the first two should be allowed to be wrapped */
+ const int sizes[] = {1024, 3248, 5200};
+
+ fprintf(stdout, "Tests on key wrapping: ");
+ fflush(stdout);
+
+ /* convert it to key */
+ if (ioctl(cfd, NCRIO_KEY_INIT, &privkey)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_KEY_INIT)");
+ return 1;
+ }
+
+ if (ioctl(cfd, NCRIO_KEY_INIT, &pubkey)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_KEY_INIT)");
+ return 1;
+ }
+
+ if (geteuid() != 0) {
+ /* cannot test further */
+ fprintf(stdout, "\t(Wrapping test not completed. Run as root)\n");
+ return 0;
+ }
+
+ /* make a wrapping key */
+ if (ioctl(cfd, NCRIO_KEY_INIT, &key)) {
+ perror("ioctl(NCRIO_KEY_INIT)");
+ return 1;
+ }
+
+ keydata.key_id[0] = 'a';
+ keydata.key_id[2] = 'b';
+ keydata.key_id_size = 2;
+ keydata.type = NCR_KEY_TYPE_SECRET;
+ keydata.algorithm = NCR_ALG_AES_CBC;
+ keydata.flags = NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPING;
+
+ keydata.key = key;
+ keydata.idata = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
+ keydata.idata_size = 16;
+
+ if (ioctl(cfd, NCRIO_KEY_IMPORT, &keydata)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_KEY_IMPORT)");
+ return 1;
+ }
+
+ for (i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
+ memset(&kgen, 0, sizeof(kgen));
+ kgen.desc = privkey;
+ kgen.desc2 = pubkey;
+ kgen.params.algorithm = NCR_ALG_RSA;
+ kgen.params.keyflags = NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPABLE;
+ kgen.params.params.rsa.bits = sizes[i];
+
+ if (ioctl(cfd, NCRIO_KEY_GENERATE_PAIR, &kgen)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_KEY_GENERATE_PAIR)");
+ return 1;
+ }
+
+ /* now try wrapping key2 using key */
+ memset(&kwrap, 0, sizeof(kwrap));
+ kwrap.algorithm = NCR_WALG_AES_RFC5649;
+ kwrap.keytowrap = pubkey;
+ kwrap.key = key;
+ kwrap.io = data;
+ kwrap.io_size = sizeof(data);
+
+ ret = ioctl(cfd, NCRIO_KEY_WRAP, &kwrap);
+ if (ret) {
+ fprintf(stderr, "Error[%d-%d]: %s:%d\n", i, sizes[i], __func__, __LINE__);
+ /* wrapping of public key should have been allowed! */
+ return 1;
+ }
+
+ /* now try wrapping private using key */
+ memset(&kwrap, 0, sizeof(kwrap));
+ kwrap.algorithm = NCR_WALG_AES_RFC5649;
+ kwrap.keytowrap = privkey;
+ kwrap.key = key;
+ kwrap.io = data;
+ kwrap.io_size = sizeof(data);
+
+ ret = ioctl(cfd, NCRIO_KEY_WRAP, &kwrap);
+ if (ret && i != 2) {
+ fprintf(stderr, "Error[%d-%d]: %s:%d\n", i, sizes[i], __func__, __LINE__);
+ /* wrapping should have been allowed */
+ return 1;
+ } else if (ret == 0 && i == 2) {
+ fprintf(stderr, "Error[%d-%d]: %s:%d\n", i, sizes[i], __func__, __LINE__);
+ /* wrapping shouldn't have been allowed */
+ return 1;
+ }
+ }
+
+ fprintf(stdout, " Success\n");
+ return 0;
+}
+
#define RSA_ENCRYPT_SIZE 32
static int rsa_key_encrypt(int cfd, ncr_key_t privkey, ncr_key_t pubkey, int oaep)
@@ -961,6 +1074,9 @@ main()
if (test_ncr_dsa(fd))
return 1;
+
+ if (test_ncr_wrap_key3(fd))
+ return 1;
/* Close the original descriptor */
if (close(fd)) {
diff --git a/ncr-dh.c b/ncr-dh.c
index 235d021..04df2b3 100644
--- a/ncr-dh.c
+++ b/ncr-dh.c
@@ -281,3 +281,15 @@ fail:
return ret;
}
+
+int ncr_pk_get_dh_size( dh_key* key)
+{
+int ret;
+ ret = mp_count_bits(&key->p);
+ if (ret <= 0) {
+ err();
+ return -EINVAL;
+ }
+
+ return ret;
+}
diff --git a/ncr-dh.h b/ncr-dh.h
index cc45d32..183f790 100644
--- a/ncr-dh.h
+++ b/ncr-dh.h
@@ -22,4 +22,6 @@ int dh_import(const uint8_t *in, size_t inlen, dh_key *key);
int dh_derive_gxy(struct key_item_st* newkey, dh_key * key,
void* pk, size_t pk_size);
+int ncr_pk_get_dh_size( dh_key* key);
+
#endif
diff --git a/ncr-int.h b/ncr-int.h
index 84bca9e..df53ce3 100644
--- a/ncr-int.h
+++ b/ncr-int.h
@@ -169,5 +169,6 @@ int key_to_storage_data( uint8_t** data, size_t * data_size, const struct key_it
const struct algo_properties_st *_ncr_algo_to_properties(ncr_algorithm_t algo);
const struct algo_properties_st *ncr_key_params_get_sign_hash(const struct algo_properties_st *algo, struct ncr_key_params_st * params);
+int _ncr_key_get_sec_level(struct key_item_st* item);
#endif
diff --git a/ncr-key-wrap.c b/ncr-key-wrap.c
index 0c56def..eb68d92 100644
--- a/ncr-key-wrap.c
+++ b/ncr-key-wrap.c
@@ -430,6 +430,37 @@ cleanup:
return ret;
}
+/* will check if the kek is of equal or higher security level than
+ * wkey. To prevent encrypting a 256 bit key with an 128 bit one.
+ */
+int check_key_level(struct key_item_st* kek, struct key_item_st* wkey)
+{
+int kek_level, wkey_level;
+
+ /* allow wrapping of public keys with any key */
+ if (wkey->type == NCR_KEY_TYPE_PUBLIC)
+ return 0;
+
+ kek_level = _ncr_key_get_sec_level(kek);
+ if (kek_level < 0) {
+ err();
+ return kek_level;
+ }
+
+ wkey_level = _ncr_key_get_sec_level(wkey);
+ if (wkey_level < 0) {
+ err();
+ return wkey_level;
+ }
+
+ if (wkey_level > kek_level) {
+ err();
+ return -EPERM;
+ }
+
+ return 0;
+}
+
int ncr_key_wrap(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_wrap_st wrap;
@@ -462,6 +493,18 @@ int ret;
goto fail;
}
+ if (!(key->flags & NCR_KEY_FLAG_WRAPPING)) {
+ err();
+ ret = -EPERM;
+ goto fail;
+ }
+
+ ret = check_key_level(key, wkey);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
data_size = wrap.io_size;
data = kmalloc(data_size, GFP_KERNEL);
if (data == NULL) {
@@ -539,6 +582,12 @@ int ret;
goto fail;
}
+ if (!(key->flags & NCR_KEY_FLAG_WRAPPING)) {
+ err();
+ ret = -EPERM;
+ goto fail;
+ }
+
data_size = wrap.io_size;
data = kmalloc(data_size, GFP_KERNEL);
if (data == NULL) {
@@ -601,12 +650,6 @@ int ret;
return ret;
}
- if (!(wkey->flags & NCR_KEY_FLAG_WRAPPABLE)) {
- err();
- ret = -EPERM;
- goto fail;
- }
-
data_size = wrap.io_size;
data = kmalloc(data_size, GFP_KERNEL);
if (data == NULL) {
@@ -698,8 +741,6 @@ int ret;
goto fail;
}
- wkey->flags = NCR_KEY_FLAG_WRAPPABLE;
-
ret = _unwrap_aes_rfc5649(sdata, &sdata_size, &master_key, data, data_size, NULL, 0);
if (ret < 0) {
err();
diff --git a/ncr-key.c b/ncr-key.c
index bf438fa..e34367e 100644
--- a/ncr-key.c
+++ b/ncr-key.c
@@ -311,6 +311,15 @@ fail:
}
+unsigned int assign_key_flags(unsigned int flags)
+{
+ if (current_euid()==0) {
+ return flags;
+ } else {
+ return flags & (~(NCR_KEY_FLAG_WRAPPING));
+ }
+}
+
/* "imports" a key from a data item. If the key is not exportable
* to userspace then the key item will also not be.
*/
@@ -356,7 +365,7 @@ size_t tmp_size;
ret = -EINVAL;
goto fail;
}
- item->flags = data.flags;
+ item->flags = assign_key_flags(data.flags);
if (data.key_id_size > MAX_KEY_ID_SIZE) {
err();
@@ -370,7 +379,6 @@ size_t tmp_size;
switch(item->type) {
case NCR_KEY_TYPE_SECRET:
-
if (tmp_size > NCR_CIPHER_MAX_KEY_LEN) {
err();
ret = -EINVAL;
@@ -445,7 +453,8 @@ size_t size;
ncr_key_clear(item);
/* we generate only secret keys */
- item->flags = gen.params.keyflags;
+ item->flags = assign_key_flags(gen.params.keyflags);
+
algo = _ncr_algo_to_properties(gen.params.algorithm);
if (algo == NULL) {
err();
@@ -486,6 +495,106 @@ fail:
return ret;
}
+/* Those values are derived from "ECRYPT II Yearly Report on Algorithms and
+ * Keysizes (2009-2010)". It maps the strength of public key algorithms to
+ * symmetric ones. Should be kept up to date.
+ */
+struct {
+ unsigned int bits; /* sec level */
+ unsigned int rsa_bits;
+ unsigned int dlog_bits;
+} ecrypt_vals[] = {
+ {64, 816, 816},
+ {80, 1248, 1248},
+ {112, 2432, 2432},
+ {128, 3248, 3248},
+ {160, 5312, 5312},
+ {192, 7936, 7936},
+ {256, 15424, 15424},
+ {0,0,0}
+};
+
+unsigned int rsa_to_bits(unsigned int rsa_bits)
+{
+int i = 1;
+
+ if (rsa_bits <= ecrypt_vals[0].rsa_bits)
+ return ecrypt_vals[0].rsa_bits;
+
+ do {
+ if (rsa_bits <= ecrypt_vals[i].rsa_bits &&
+ rsa_bits > ecrypt_vals[i-1].rsa_bits) {
+
+ return ecrypt_vals[i].bits;
+ }
+ } while(ecrypt_vals[++i].bits != 0);
+
+ /* return the highest found so far */
+ return ecrypt_vals[i-1].bits;
+}
+
+unsigned int dlog_to_bits(unsigned int dlog_bits)
+{
+int i = 1;
+
+ if (dlog_bits <= ecrypt_vals[0].dlog_bits)
+ return ecrypt_vals[0].dlog_bits;
+
+ do {
+ if (dlog_bits <= ecrypt_vals[i].dlog_bits &&
+ dlog_bits > ecrypt_vals[i-1].dlog_bits) {
+
+ return ecrypt_vals[i].bits;
+ }
+ } while(ecrypt_vals[++i].bits != 0);
+
+ /* return the highest found so far */
+ return ecrypt_vals[i-1].bits;
+}
+
+/* returns the security level of the key in bits. Private/Public keys
+ * are mapped to symmetric key bits using the ECRYPT II 2010 recommendation.
+ */
+int _ncr_key_get_sec_level(struct key_item_st* item)
+{
+int bits;
+
+ if (item->type == NCR_KEY_TYPE_SECRET) {
+ return item->key.secret.size*8;
+ } else if (item->type == NCR_KEY_TYPE_PRIVATE) {
+ switch(item->algorithm->algo) {
+ case NCR_ALG_RSA:
+ bits = ncr_pk_get_rsa_size(&item->key.pk.rsa);
+ if (bits < 0) {
+ err();
+ return bits;
+ }
+
+ return rsa_to_bits(bits);
+ case NCR_ALG_DSA:
+ bits = ncr_pk_get_dsa_size(&item->key.pk.dsa);
+ if (bits < 0) {
+ err();
+ return bits;
+ }
+
+ return dlog_to_bits(bits);
+ case NCR_ALG_DH:
+ bits = ncr_pk_get_dh_size(&item->key.pk.dh);
+ if (bits < 0) {
+ err();
+ return bits;
+ }
+
+ return dlog_to_bits(bits);
+ default:
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+}
+
int ncr_key_info(struct ncr_lists *lst, void __user* arg)
{
struct ncr_key_info_st info;
@@ -549,7 +658,8 @@ int ret;
ncr_key_clear(private);
/* we generate only secret keys */
- private->flags = public->flags = gen.params.keyflags;
+ private->flags = public->flags = assign_key_flags(gen.params.keyflags);
+
private->algorithm = public->algorithm = _ncr_algo_to_properties(gen.params.algorithm);
if (private->algorithm == NULL) {
err();
@@ -614,7 +724,7 @@ struct key_item_st* newkey = NULL;
ncr_key_clear(newkey);
- newkey->flags = data.keyflags;
+ newkey->flags = assign_key_flags(data.keyflags);
switch (key->type) {
case NCR_KEY_TYPE_PUBLIC:
diff --git a/ncr-pk.c b/ncr-pk.c
index 1e83163..76b78c0 100644
--- a/ncr-pk.c
+++ b/ncr-pk.c
@@ -714,3 +714,27 @@ fail:
kfree(tmp);
return ret;
}
+
+int ncr_pk_get_rsa_size( rsa_key* key)
+{
+int ret;
+ ret = mp_count_bits(&key->N);
+ if (ret <= 0) {
+ err();
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+int ncr_pk_get_dsa_size( dsa_key* key)
+{
+int ret;
+ ret = mp_count_bits(&key->p);
+ if (ret <= 0) {
+ err();
+ return -EINVAL;
+ }
+
+ return ret;
+}
diff --git a/ncr-pk.h b/ncr-pk.h
index 25a0571..1c8d720 100644
--- a/ncr-pk.h
+++ b/ncr-pk.h
@@ -52,4 +52,8 @@ int _ncr_tomerr(int err);
int ncr_pk_derive(struct key_item_st* newkey, struct key_item_st* oldkey,
struct ncr_key_derivation_params_st * params);
+int ncr_pk_get_rsa_size( rsa_key* key);
+int ncr_pk_get_dsa_size( dsa_key* key);
+
+
#endif
diff --git a/ncr.h b/ncr.h
index a377824..cddde07 100644
--- a/ncr.h
+++ b/ncr.h
@@ -70,6 +70,10 @@ typedef int ncr_key_t;
*/
#define NCR_KEY_FLAG_DECRYPT (1<<2)
#define NCR_KEY_FLAG_SIGN (1<<3)
+/* This flag can only be set by administrator, to prevent
+ * adversaries exporting wrappable keys with random ones.
+ */
+#define NCR_KEY_FLAG_WRAPPING (1<<4)
struct ncr_key_generate_params_st {
ncr_algorithm_t algorithm; /* just a cipher algorithm when