summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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