diff options
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | examples/pk.c | 152 | ||||
-rw-r--r-- | ncr-dh.c | 207 | ||||
-rw-r--r-- | ncr-dh.h | 6 | ||||
-rw-r--r-- | ncr-int.h | 6 | ||||
-rw-r--r-- | ncr-key.c | 71 | ||||
-rw-r--r-- | ncr-pk.c | 72 | ||||
-rw-r--r-- | ncr-pk.h | 3 | ||||
-rw-r--r-- | ncr.c | 4 | ||||
-rw-r--r-- | ncr.h | 13 |
10 files changed, 479 insertions, 57 deletions
@@ -1,3 +1,3 @@ * ioctl_compat() mode for ncr.h API as it is in cryptodev.h * Put limits to sessions - +* Export private keys to PKCS #8 format (can it be implemented?) diff --git a/examples/pk.c b/examples/pk.c index 1385a0e..69450b1 100644 --- a/examples/pk.c +++ b/examples/pk.c @@ -307,10 +307,15 @@ const char dh_params_txt[] = "-----BEGIN DH PARAMETERS-----\n"\ static int test_ncr_dh(int cfd) { struct ncr_key_generate_st kgen; -ncr_key_t private1, public1; +ncr_key_t private1, public1, public2, private2; +ncr_key_t z1, z2; int ret; gnutls_datum g, p, params; gnutls_dh_params_t dhp; +unsigned char y1[1024], y2[1024]; +size_t y1_size, y2_size; +struct ncr_key_data_st keydata; +struct ncr_key_derivation_params_st kderive; fprintf(stdout, "Tests on DH key exchange:"); fflush(stdout); @@ -367,6 +372,151 @@ gnutls_dh_params_t dhp; perror("ioctl(NCRIO_KEY_GENERATE)"); return 1; } + + /* generate another DH key */ + if (ioctl(cfd, NCRIO_KEY_INIT, &private2)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + if (ioctl(cfd, NCRIO_KEY_INIT, &public2)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + memset(&kgen, 0, sizeof(kgen)); + kgen.desc = private2; + kgen.desc2 = public2; + kgen.params.algorithm = NCR_ALG_DH; + kgen.params.keyflags = NCR_KEY_FLAG_EXPORTABLE; + kgen.params.params.dh.p = p.data; + kgen.params.params.dh.p_size = p.size; + kgen.params.params.dh.g = g.data; + kgen.params.params.dh.g_size = g.size; + + if (ioctl(cfd, NCRIO_KEY_GENERATE_PAIR, &kgen)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_GENERATE)"); + return 1; + } + + /* export y1=g^x1 */ + memset(&keydata, 0, sizeof(keydata)); + keydata.key = public1; + keydata.idata = y1; + keydata.idata_size = sizeof(y1); + + if (ioctl(cfd, NCRIO_KEY_EXPORT, &keydata)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_EXPORT)"); + return 1; + } + + y1_size = keydata.idata_size; + + /* export y2=g^x2 */ + memset(&keydata, 0, sizeof(keydata)); + keydata.key = public2; + keydata.idata = y2; + keydata.idata_size = sizeof(y2); + + if (ioctl(cfd, NCRIO_KEY_EXPORT, &keydata)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_EXPORT)"); + return 1; + } + + y2_size = keydata.idata_size; + + /* z1=y1^x2 */ + if (ioctl(cfd, NCRIO_KEY_INIT, &z1)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + memset(&kderive, 0, sizeof(kderive)); + kderive.derive = NCR_DERIVE_DH; + kderive.newkey = z1; + kderive.keyflags = NCR_KEY_FLAG_EXPORTABLE; + kderive.key = private1; + kderive.params.params.dh.pub = y2; + kderive.params.params.dh.pub_size = y2_size; + + if (ioctl(cfd, NCRIO_KEY_DERIVE, &kderive)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + /* z2=y2^x1 */ + if (ioctl(cfd, NCRIO_KEY_INIT, &z2)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + memset(&kderive, 0, sizeof(kderive)); + kderive.derive = NCR_DERIVE_DH; + kderive.newkey = z2; + kderive.keyflags = NCR_KEY_FLAG_EXPORTABLE; + kderive.key = private2; + kderive.params.params.dh.pub = y1; + kderive.params.params.dh.pub_size = y1_size; + + if (ioctl(cfd, NCRIO_KEY_DERIVE, &kderive)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + /* z1==z2 */ + memset(&keydata, 0, sizeof(keydata)); + keydata.key = z1; + keydata.idata = y1; + keydata.idata_size = sizeof(y1); + + if (ioctl(cfd, NCRIO_KEY_EXPORT, &keydata)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_EXPORT)"); + return 1; + } + y1_size = keydata.idata_size; + + memset(&keydata, 0, sizeof(keydata)); + keydata.key = z2; + keydata.idata = y2; + keydata.idata_size = sizeof(y2); + + if (ioctl(cfd, NCRIO_KEY_EXPORT, &keydata)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_EXPORT)"); + return 1; + } + y2_size = keydata.idata_size; + + if (y1_size == 0 || y1_size != y2_size || memcmp(y1, y2, y1_size) != 0) { + int i; + + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + fprintf(stderr, "Output in DH does not match (%d, %d)!\n", + (int)y1_size, (int)y2_size); + + fprintf(stderr, "Key1[%d]: ", (int) y1_size); + for(i=0;i<y1_size;i++) + fprintf(stderr, "%.2x:", y1[i]); + fprintf(stderr, "\n"); + + fprintf(stderr, "Key2[%d]: ", (int) y2_size); + for(i=0;i<y2_size;i++) + fprintf(stderr, "%.2x:", y2[i]); + fprintf(stderr, "\n"); + + return 1; + } + fprintf(stdout, " Success\n"); @@ -38,108 +38,245 @@ void dh_free(dh_key * key) mp_clear_multi(&key->p, &key->g, &key->x, NULL); } -int dh_import_params(dh_key * key, uint8_t* p, size_t p_size, uint8_t* g, size_t g_size) +int dh_import_params(dh_key * key, uint8_t * p, size_t p_size, uint8_t * g, + size_t g_size) { -int ret; -int err; - - if ((err = mp_init_multi(&key->p, &key->g, &key->x, &key->y, NULL)) != CRYPT_OK) { + int ret; + int err; + + if ((err = + mp_init_multi(&key->p, &key->g, &key->x, &key->y, + NULL)) != CRYPT_OK) { err(); return -ENOMEM; } - - if ((err = mp_read_unsigned_bin(&key->p, (unsigned char *)p, p_size)) != CRYPT_OK) { + + if ((err = + mp_read_unsigned_bin(&key->p, (unsigned char *) p, + p_size)) != CRYPT_OK) { err(); ret = _ncr_tomerr(err); goto fail; } - if ((err = mp_read_unsigned_bin(&key->g, (unsigned char *)g, g_size)) != CRYPT_OK) { + if ((err = + mp_read_unsigned_bin(&key->g, (unsigned char *) g, + g_size)) != CRYPT_OK) { err(); ret = _ncr_tomerr(err); goto fail; } return 0; -fail: + fail: mp_clear_multi(&key->p, &key->g, &key->x, &key->y, NULL); - + return ret; } int dh_generate_key(dh_key * key) { -void* buf; -int size; -int err, ret; + void *buf; + int size; + int err, ret; size = mp_unsigned_bin_size(&key->p); if (size == 0) { - err(); - return -EINVAL; + err(); + return -EINVAL; } - + buf = kmalloc(size, GFP_KERNEL); if (buf == NULL) { err(); return -ENOMEM; } - - get_random_bytes( buf, size); + + get_random_bytes(buf, size); if ((err = mp_read_unsigned_bin(&key->x, buf, size)) != CRYPT_OK) { err(); ret = _ncr_tomerr(err); goto fail; } - - err = mp_mod( &key->g, &key->p, &key->x); + + err = mp_mod(&key->x, &key->p, &key->x); if (err != CRYPT_OK) { err(); ret = _ncr_tomerr(err); goto fail; } - + key->type = PK_PRIVATE; - + ret = 0; -fail: + fail: kfree(buf); - + return ret; } -int dh_generate_public(dh_key * public, dh_key* private) +int dh_generate_public(dh_key * public, dh_key * private) { -int err, ret; + int err, ret; - err = mp_copy(&private->g, &public->g); + err = + mp_exptmod(&private->g, &private->x, &private->p, &public->y); if (err != CRYPT_OK) { err(); ret = _ncr_tomerr(err); goto fail; } + + public->type = PK_PUBLIC; + + ret = 0; + fail: + + return ret; +} + +int dh_export(uint8_t * out, unsigned long * outlen, int type, dh_key * key) +{ + unsigned long zero = 0; + int err; + + if (out == NULL || outlen == NULL || key == NULL) { + err(); + return -EINVAL; + } + + /* can we store the static header? */ + if (type == PK_PRIVATE && key->type != PK_PRIVATE) { + return -EINVAL; + } + + if (type != PK_PUBLIC && type != PK_PRIVATE) { + return -EINVAL; + } + + /* This encoding is different from the one in original + * libtomcrypt. It uses a compatible encoding with gnutls + * and openssl + */ + if (type == PK_PRIVATE) { + err = der_encode_sequence_multi(out, outlen, + LTC_ASN1_SHORT_INTEGER, 1UL, &zero, + LTC_ASN1_INTEGER, 1UL, &key->p, + LTC_ASN1_INTEGER, 1UL, &key->g, + LTC_ASN1_INTEGER, 1UL, &key->x, + LTC_ASN1_EOL, 0UL, NULL); + } else { + err = mp_unsigned_bin_size(&key->y); + if (err > *outlen) { + err(); + return -EOVERFLOW; + } + + *outlen = err; + + err = mp_to_unsigned_bin(&key->y, out); + } - err = mp_copy(&private->p, &public->p); if (err != CRYPT_OK) { err(); - ret = _ncr_tomerr(err); - goto fail; + return _ncr_tomerr(err); + } + + return 0; +} + +int dh_import(const uint8_t * in, size_t inlen, dh_key * key) +{ + int err; + unsigned long zero = 0; + + if (in == NULL || key == NULL) { + err(); + return -EINVAL; + } + + /* init key */ + if (mp_init_multi + (&key->p, &key->g, &key->x, &key->y, NULL) != CRYPT_OK) { + return -ENOMEM; + } + + /* get key type */ + if ((err = der_decode_sequence_multi(in, inlen, + LTC_ASN1_SHORT_INTEGER, 1UL, &zero, + LTC_ASN1_INTEGER, 1UL, &key->p, + LTC_ASN1_INTEGER, 1UL, &key->g, + LTC_ASN1_INTEGER, 1UL, &key->x, + LTC_ASN1_EOL, 0UL, NULL)) == CRYPT_OK) { + key->type = PK_PRIVATE; + } else { /* public */ + err = mp_read_unsigned_bin(&key->y, in, inlen); + key->type = PK_PUBLIC; } - err = mp_exptmod(&private->g, &private->x, &private->p, &public->y); if (err != CRYPT_OK) { + goto LBL_ERR; + } + + return 0; + + LBL_ERR: + mp_clear_multi(&key->p, &key->g, &key->x, &key->y, NULL); + return _ncr_tomerr(err); +} + +int dh_derive_gxy(struct key_item_st* newkey, dh_key * key, + void* pk, size_t pk_size) +{ +int ret, err; +mp_int y, gxy; + /* newkey will be a secret key with value of g^{xy} + */ + + if (mp_init_multi(&y, &gxy, NULL) != CRYPT_OK) { + err(); + return -ENOMEM; + } + + if (key->type != PK_PRIVATE) { + err(); + return -EINVAL; + } + + if ((err=mp_read_unsigned_bin(&y, pk, pk_size)) != CRYPT_OK) { err(); ret = _ncr_tomerr(err); goto fail; } - public->type = PK_PUBLIC; + if ((err=mp_exptmod(&y, &key->x, &key->p, &gxy))!= CRYPT_OK) { + err(); + ret = _ncr_tomerr(err); + goto fail; + } + err = mp_unsigned_bin_size(&gxy); + if (err > NCR_CIPHER_MAX_KEY_LEN) { + err(); + ret = -EOVERFLOW; + goto fail; + } + newkey->key.secret.size = err; + + err = mp_to_unsigned_bin(&gxy, newkey->key.secret.data); + if (err != CRYPT_OK) { + err(); + ret = _ncr_tomerr(err); + goto fail; + } + + newkey->type = NCR_KEY_TYPE_SECRET; + ret = 0; fail: - + mp_clear_multi(&y, &gxy, NULL); + return ret; - -} +} @@ -16,6 +16,10 @@ int dh_import_params(dh_key * key, uint8_t* p, size_t p_size, uint8_t* g, size_t void dh_free(dh_key * key); int dh_generate_public(dh_key * public, dh_key* private); -int dh_export(uint8_t *out, size_t *outlen, int type, dh_key *key); +int dh_export(uint8_t *out, unsigned long *outlen, int type, dh_key *key); 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); + #endif @@ -110,7 +110,11 @@ void ncr_deinit_lists(struct ncr_lists *lst); int ncr_ioctl(struct ncr_lists*, struct file *filp, unsigned int cmd, unsigned long arg); - + +/* key derivation */ +int ncr_key_derive(struct list_sem_st* key_lst, void __user* arg); + +/* key handling */ int ncr_key_init(struct list_sem_st*, void __user* arg); int ncr_key_deinit(struct list_sem_st*, void __user* arg); int ncr_key_export(struct list_sem_st* key_lst,void __user* arg); @@ -276,6 +276,7 @@ int ret; goto fail; } } + data.idata_size = item->key.secret.size; break; case NCR_KEY_TYPE_PUBLIC: @@ -346,7 +347,9 @@ size_t tmp_size; err(); return ret; } - + + ncr_key_clear(item); + tmp = kmalloc(data.idata_size, GFP_KERNEL); if (tmp == NULL) { err(); @@ -426,6 +429,9 @@ static void ncr_key_clear(struct key_item_st* item) ncr_pk_clear(item); } memset(&item->key, 0, sizeof(item->key)); + memset(item->key_id, 0, sizeof(item->key_id)); + item->key_id_size = 0; + item->flags = 0; return; } @@ -593,13 +599,64 @@ fail: return ret; } -int ncr_key_derive(struct list_sem_st* lst, void __user* arg) +/* "exports" a key to a data item. If the key is not exportable + * to userspace then the data item will also not be. + */ +int ncr_key_derive(struct list_sem_st* key_lst, void __user* arg) { - return -EINVAL; -} +struct ncr_key_derivation_params_st data; +int ret; +struct key_item_st* key = NULL; +struct key_item_st* newkey = NULL; -int ncr_key_get_public(struct list_sem_st* lst, void __user* arg) -{ - return -EINVAL; + if (unlikely(copy_from_user(&data, arg, sizeof(data)))) { + err(); + return -EFAULT; + } + + ret = ncr_key_item_get_read( &key, key_lst, data.key); + if (ret < 0) { + err(); + return ret; + } + + ret = ncr_key_item_get_write( &newkey, key_lst, data.newkey); + if (ret < 0) { + err(); + goto fail; + } + + ncr_key_clear(newkey); + + newkey->flags = data.keyflags; + + switch (key->type) { + case NCR_KEY_TYPE_PUBLIC: + case NCR_KEY_TYPE_PRIVATE: + ret = ncr_pk_derive(newkey, key, &data); + if (ret < 0) { + err(); + goto fail; + } + break; + default: + err(); + ret = -EINVAL; + goto fail; + } + + if (unlikely(copy_to_user(arg, &data, sizeof(data)))) { + err(); + ret = -EFAULT; + } else + ret = 0; + +fail: + if (key) + _ncr_key_item_put(key); + if (newkey) + _ncr_key_item_put(newkey); + return ret; + } @@ -143,7 +143,7 @@ fail: int ncr_pk_pack( const struct key_item_st * key, uint8_t * packed, uint32_t * packed_size) { unsigned long max_size = *packed_size; - int cret; + int cret, ret; if (packed == NULL || packed_size == NULL) { err(); @@ -167,18 +167,26 @@ int ncr_pk_pack( const struct key_item_st * key, uint8_t * packed, uint32_t * pa return _ncr_tomerr(cret); } break; + case NCR_ALG_DH: + ret = dh_export(packed, &max_size, key->key.pk.dsa.type, (void*)&key->key.pk.dsa); + if (ret < 0) { + err(); + return ret; + } + break; default: err(); return -EINVAL; } - + *packed_size = max_size; + return 0; } int ncr_pk_unpack( struct key_item_st * key, const void * packed, size_t packed_size) { - int cret; + int cret, ret; if (key == NULL || packed == NULL) { err(); @@ -200,6 +208,13 @@ int ncr_pk_unpack( struct key_item_st * key, const void * packed, size_t packed_ return _ncr_tomerr(cret); } break; + case NCR_ALG_DH: + ret = dh_import(packed, packed_size, (void*)&key->key.pk.dh); + if (ret < 0) { + err(); + return ret; + } + break; default: err(); return -EINVAL; @@ -366,7 +381,9 @@ void ncr_pk_queue_deinit(void) destroy_workqueue(pk_wq); } -const struct algo_properties_st *ncr_key_params_get_sign_hash(const struct algo_properties_st *algo, struct ncr_key_params_st * params) +const struct algo_properties_st *ncr_key_params_get_sign_hash( + const struct algo_properties_st *algo, + struct ncr_key_params_st * params) { ncr_algorithm_t id; @@ -698,3 +715,50 @@ fail: kfree(sig); return ret; } + +int ncr_pk_derive(struct key_item_st* newkey, struct key_item_st* oldkey, + struct ncr_key_derivation_params_st * params) +{ +int ret; +void* tmp = NULL; +size_t size; + + switch(params->derive) { + case NCR_DERIVE_DH: + if (oldkey->type != NCR_KEY_TYPE_PRIVATE && + oldkey->algorithm->algo != NCR_ALG_DH) { + err(); + return -EINVAL; + } + + size = params->params.params.dh.pub_size; + tmp = kmalloc(size, GFP_KERNEL); + if (tmp == NULL) { + err(); + return -ENOMEM; + } + + if (unlikely(copy_from_user(tmp, params->params.params.dh.pub, + size))) { + err(); + ret = -EFAULT; + goto fail; + } + + ret = dh_derive_gxy(newkey, &oldkey->key.pk.dh, tmp, size); + if (ret < 0) { + err(); + goto fail; + } + + break; + default: + err(); + return -EINVAL; + } + + ret = 0; +fail: + kfree(tmp); + return ret; +} @@ -53,4 +53,7 @@ int ncr_pk_cipher_verify(const struct ncr_pk_ctx* ctx, 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); + #endif @@ -106,7 +106,7 @@ struct ncr_master_key_st st; dprintk(0, KERN_DEBUG, "Master key was previously initialized.\n"); } - dprintk(0, KERN_INFO, "Intializing master key.\n"); + dprintk(0, KERN_INFO, "Initializing master key.\n"); master_key.type = NCR_KEY_TYPE_SECRET; @@ -159,10 +159,8 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp, return ncr_master_key_set(arg); case NCRIO_KEY_GENERATE_PAIR: return ncr_key_generate_pair(&lst->key, arg); -#if 0 case NCRIO_KEY_DERIVE: return ncr_key_derive(&lst->key, arg); -#endif default: return -EINVAL; } @@ -7,9 +7,8 @@ #endif #define NCR_CIPHER_MAX_BLOCK_LEN 32 -#define NCR_CIPHER_MAX_KEY_LEN 64 +#define NCR_CIPHER_MAX_KEY_LEN 512 #define NCR_HASH_MAX_OUTPUT_SIZE 64 -#define NCR_PK_MAX_OBJECT 640 typedef enum { NCR_ALG_NONE, @@ -132,8 +131,8 @@ struct ncr_key_params_st { size_t iv_size; } cipher; struct { - uint8_t peer_public[NCR_PK_MAX_OBJECT]; - size_t peer_public_size; + uint8_t __user *pub; + size_t pub_size; } dh; struct { ncr_rsa_type_t type; @@ -147,7 +146,13 @@ struct ncr_key_params_st { } params; }; +typedef enum { + NCR_DERIVE_DH=1, +} ncr_derive_t; + struct ncr_key_derivation_params_st { + ncr_derive_t derive; /* the derivation algorithm */ + ncr_key_t newkey; unsigned int keyflags; /* for new key */ |