diff options
-rw-r--r-- | examples/ncr.c | 107 | ||||
-rw-r--r-- | examples/pk.c | 116 | ||||
-rw-r--r-- | ncr-dh.c | 12 | ||||
-rw-r--r-- | ncr-dh.h | 2 | ||||
-rw-r--r-- | ncr-int.h | 1 | ||||
-rw-r--r-- | ncr-key-wrap.c | 57 | ||||
-rw-r--r-- | ncr-key.c | 120 | ||||
-rw-r--r-- | ncr-pk.c | 24 | ||||
-rw-r--r-- | ncr-pk.h | 4 | ||||
-rw-r--r-- | ncr.h | 4 |
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)) { @@ -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; +} @@ -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 @@ -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(); @@ -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: @@ -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; +} @@ -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 @@ -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 |