summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiloslav Trmač <mitr@redhat.com>2010-08-27 09:02:55 +0200
committerMiloslav Trmač <mitr@redhat.com>2010-08-27 09:02:55 +0200
commitdd5317620d70e6b438e40370163257e47ca385a3 (patch)
treef195a8cb4aa2ff6fbb5a51e0e6c13df1968401b6
parentc9c3bf34c8f7c12c0d961bf7c0beb13ad5b24950 (diff)
parentbf6a75c801ece98f608df29df3846033d22f28d7 (diff)
downloadkernel-crypto-dd5317620d70e6b438e40370163257e47ca385a3.tar.gz
kernel-crypto-dd5317620d70e6b438e40370163257e47ca385a3.tar.xz
kernel-crypto-dd5317620d70e6b438e40370163257e47ca385a3.zip
Merge branch 'pk-transparent-hash'
Conflicts: ncr-int.h
-rw-r--r--examples/pk.c245
-rw-r--r--ncr-int.h4
-rw-r--r--ncr-pk.c4
-rw-r--r--ncr-sessions.c75
-rw-r--r--ncr.h4
5 files changed, 318 insertions, 14 deletions
diff --git a/examples/pk.c b/examples/pk.c
index 81c5b49263d..5ccb73e5205 100644
--- a/examples/pk.c
+++ b/examples/pk.c
@@ -29,6 +29,7 @@
#define ALIGN_NL __attribute__((aligned(NLA_ALIGNTO)))
#define SIGNATURE_HASH "sha1"
+#define SIGNATURE_HASH_SIZE 20
#define ALG_AES_CBC "cbc(aes)"
#define ALG_DH "dh"
@@ -1035,6 +1036,126 @@ static int rsa_key_sign_verify(int cfd, ncr_key_t privkey, ncr_key_t pubkey, int
}
+static int rsa_key_sign_verify_transparent(int cfd, ncr_key_t privkey,
+ ncr_key_t pubkey, int pss)
+{
+ struct __attribute__((packed)) {
+ struct ncr_session_once f;
+ struct nlattr algo_head ALIGN_NL;
+ char algo[sizeof(NCR_ALG_RSA_TRANSPARENT_HASH)] ALIGN_NL;
+ struct nlattr key_head ALIGN_NL;
+ uint32_t key ALIGN_NL;
+ struct nlattr rsa_head ALIGN_NL;
+ uint32_t rsa ALIGN_NL;
+ struct nlattr sign_hash_head ALIGN_NL;
+ char sign_hash[sizeof(SIGNATURE_HASH)] ALIGN_NL;
+ struct nlattr input_head ALIGN_NL;
+ struct ncr_session_input_data input ALIGN_NL;
+ struct nlattr signature_head ALIGN_NL;
+ struct ncr_session_output_buffer signature ALIGN_NL;
+ } ksign;
+ struct __attribute__((packed)) {
+ struct ncr_session_once f;
+ struct nlattr algo_head ALIGN_NL;
+ char algo[sizeof(NCR_ALG_RSA_TRANSPARENT_HASH)] ALIGN_NL;
+ struct nlattr key_head ALIGN_NL;
+ uint32_t key ALIGN_NL;
+ struct nlattr rsa_head ALIGN_NL;
+ uint32_t rsa ALIGN_NL;
+ struct nlattr sign_hash_head ALIGN_NL;
+ char sign_hash[sizeof(SIGNATURE_HASH)] ALIGN_NL;
+ struct nlattr input_head ALIGN_NL;
+ struct ncr_session_input_data input ALIGN_NL;
+ struct nlattr signature_head ALIGN_NL;
+ struct ncr_session_input_data signature ALIGN_NL;
+ } kverify;
+ uint8_t data[SIGNATURE_HASH_SIZE];
+ uint8_t sig[DATA_SIZE];
+ size_t sig_size;
+ int ret;
+
+ fprintf(stdout, "Tests on transparent RSA (%s) key signature:",
+ (pss != 0) ? "PSS" : "PKCS V1.5");
+ fflush(stdout);
+
+ memset(data, 0x3, sizeof(data));
+
+ /* sign data */
+ memset(&ksign.f, 0, sizeof(ksign.f));
+ ksign.f.input_size = sizeof(ksign);
+ ksign.f.op = NCR_OP_SIGN;
+ ksign.algo_head.nla_len = NLA_HDRLEN + sizeof(ksign.algo);
+ ksign.algo_head.nla_type = NCR_ATTR_ALGORITHM;
+ strcpy(ksign.algo, NCR_ALG_RSA_TRANSPARENT_HASH);
+ ksign.key_head.nla_len = NLA_HDRLEN + sizeof(ksign.key);
+ ksign.key_head.nla_type = NCR_ATTR_KEY;
+ ksign.key = privkey;
+ ksign.rsa_head.nla_len = NLA_HDRLEN + sizeof(ksign.rsa);
+ ksign.rsa_head.nla_type = NCR_ATTR_RSA_ENCODING_METHOD;
+ ksign.rsa = (pss != 0) ? RSA_PKCS1_PSS : RSA_PKCS1_V1_5;
+ ksign.sign_hash_head.nla_len = NLA_HDRLEN + sizeof(ksign.sign_hash);
+ ksign.sign_hash_head.nla_type = NCR_ATTR_SIGNATURE_HASH_ALGORITHM;
+ strcpy(ksign.sign_hash, SIGNATURE_HASH);
+ ksign.input_head.nla_len = NLA_HDRLEN + sizeof(ksign.input);
+ ksign.input_head.nla_type = NCR_ATTR_UPDATE_INPUT_DATA;
+ ksign.input.data = data;
+ ksign.input.data_size = SIGNATURE_HASH_SIZE;
+ ksign.signature_head.nla_len = NLA_HDRLEN + sizeof(ksign.signature);
+ ksign.signature_head.nla_type = NCR_ATTR_FINAL_OUTPUT_BUFFER;
+ ksign.signature.buffer = sig;
+ ksign.signature.buffer_size = sizeof(sig);
+ ksign.signature.result_size_ptr = &sig_size;
+
+ if (ioctl(cfd, NCRIO_SESSION_ONCE, &ksign)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_SESSION_ONCE)");
+ return 1;
+ }
+
+ /* verify signature */
+ memset(data, 0x3, sizeof(data));
+
+ memset(&kverify.f, 0, sizeof(kverify.f));
+ kverify.f.input_size = sizeof(kverify);
+ kverify.f.op = NCR_OP_VERIFY;
+ kverify.algo_head.nla_len = NLA_HDRLEN + sizeof(kverify.algo);
+ kverify.algo_head.nla_type = NCR_ATTR_ALGORITHM;
+ strcpy(kverify.algo, NCR_ALG_RSA_TRANSPARENT_HASH);
+ kverify.key_head.nla_len = NLA_HDRLEN + sizeof(kverify.key);
+ kverify.key_head.nla_type = NCR_ATTR_KEY;
+ kverify.key = pubkey;
+ kverify.rsa_head.nla_len = NLA_HDRLEN + sizeof(kverify.rsa);
+ kverify.rsa_head.nla_type = NCR_ATTR_RSA_ENCODING_METHOD;
+ kverify.rsa = (pss != 0) ? RSA_PKCS1_PSS : RSA_PKCS1_V1_5;
+ kverify.sign_hash_head.nla_len = NLA_HDRLEN + sizeof(kverify.sign_hash);
+ kverify.sign_hash_head.nla_type = NCR_ATTR_SIGNATURE_HASH_ALGORITHM;
+ strcpy(kverify.sign_hash, SIGNATURE_HASH);
+ kverify.input_head.nla_len = NLA_HDRLEN + sizeof(kverify.input);
+ kverify.input_head.nla_type = NCR_ATTR_UPDATE_INPUT_DATA;
+ kverify.input.data = data;
+ kverify.input.data_size = SIGNATURE_HASH_SIZE;
+ kverify.signature_head.nla_len = NLA_HDRLEN + sizeof(kverify.signature);
+ kverify.signature_head.nla_type = NCR_ATTR_FINAL_INPUT_DATA;
+ kverify.signature.data = sig;
+ kverify.signature.data_size = sig_size;
+
+ ret = ioctl(cfd, NCRIO_SESSION_ONCE, &kverify);
+ if (ret < 0) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_SESSION_ONCE)");
+ return 1;
+ }
+
+ if (ret)
+ fprintf(stdout, " Success\n");
+ else {
+ fprintf(stdout, " Verification Failed!\n");
+ return 1;
+ }
+
+ return 0;
+}
+
static int dsa_key_sign_verify(int cfd, ncr_key_t privkey, ncr_key_t pubkey)
{
struct __attribute__((packed)) {
@@ -1142,6 +1263,112 @@ static int dsa_key_sign_verify(int cfd, ncr_key_t privkey, ncr_key_t pubkey)
}
+static int dsa_key_sign_verify_transparent(int cfd, ncr_key_t privkey,
+ ncr_key_t pubkey)
+{
+ struct __attribute__((packed)) {
+ struct ncr_session_once f;
+ struct nlattr algo_head ALIGN_NL;
+ char algo[sizeof(NCR_ALG_DSA_TRANSPARENT_HASH)] ALIGN_NL;
+ struct nlattr key_head ALIGN_NL;
+ uint32_t key ALIGN_NL;
+ struct nlattr sign_hash_head ALIGN_NL;
+ char sign_hash[sizeof(SIGNATURE_HASH)] ALIGN_NL;
+ struct nlattr input_head ALIGN_NL;
+ struct ncr_session_input_data input ALIGN_NL;
+ struct nlattr signature_head ALIGN_NL;
+ struct ncr_session_output_buffer signature ALIGN_NL;
+ } ksign;
+ struct __attribute__((packed)) {
+ struct ncr_session_once f;
+ struct nlattr algo_head ALIGN_NL;
+ char algo[sizeof(NCR_ALG_DSA_TRANSPARENT_HASH)] ALIGN_NL;
+ struct nlattr key_head ALIGN_NL;
+ uint32_t key ALIGN_NL;
+ struct nlattr sign_hash_head ALIGN_NL;
+ char sign_hash[sizeof(SIGNATURE_HASH)] ALIGN_NL;
+ struct nlattr input_head ALIGN_NL;
+ struct ncr_session_input_data input ALIGN_NL;
+ struct nlattr signature_head ALIGN_NL;
+ struct ncr_session_input_data signature ALIGN_NL;
+ } kverify;
+ uint8_t data[SIGNATURE_HASH_SIZE];
+ uint8_t sig[DATA_SIZE];
+ size_t sig_size;
+ int ret;
+
+ fprintf(stdout, "Tests on transparent DSA key signature:");
+ fflush(stdout);
+
+ memset(data, 0x3, sizeof(data));
+
+ /* sign data */
+ memset(&ksign.f, 0, sizeof(ksign.f));
+ ksign.f.input_size = sizeof(ksign);
+ ksign.f.op = NCR_OP_SIGN;
+ ksign.algo_head.nla_len = NLA_HDRLEN + sizeof(ksign.algo);
+ ksign.algo_head.nla_type = NCR_ATTR_ALGORITHM;
+ strcpy(ksign.algo, NCR_ALG_DSA_TRANSPARENT_HASH);
+ ksign.key_head.nla_len = NLA_HDRLEN + sizeof(ksign.key);
+ ksign.key_head.nla_type = NCR_ATTR_KEY;
+ ksign.key = privkey;
+ ksign.sign_hash_head.nla_len = NLA_HDRLEN + sizeof(ksign.sign_hash);
+ ksign.sign_hash_head.nla_type = NCR_ATTR_SIGNATURE_HASH_ALGORITHM;
+ strcpy(ksign.sign_hash, SIGNATURE_HASH);
+ ksign.input_head.nla_len = NLA_HDRLEN + sizeof(ksign.input);
+ ksign.input_head.nla_type = NCR_ATTR_UPDATE_INPUT_DATA;
+ ksign.input.data = data;
+ ksign.input.data_size = SIGNATURE_HASH_SIZE;
+ ksign.signature_head.nla_len = NLA_HDRLEN + sizeof(ksign.signature);
+ ksign.signature_head.nla_type = NCR_ATTR_FINAL_OUTPUT_BUFFER;
+ ksign.signature.buffer = sig;
+ ksign.signature.buffer_size = sizeof(sig);
+ ksign.signature.result_size_ptr = &sig_size;
+
+ if (ioctl(cfd, NCRIO_SESSION_ONCE, &ksign)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_SESSION_ONCE)");
+ return 1;
+ }
+
+ /* verify signature */
+ memset(&kverify.f, 0, sizeof(kverify.f));
+ kverify.f.input_size = sizeof(kverify);
+ kverify.f.op = NCR_OP_VERIFY;
+ kverify.algo_head.nla_len = NLA_HDRLEN + sizeof(kverify.algo);
+ kverify.algo_head.nla_type = NCR_ATTR_ALGORITHM;
+ strcpy(kverify.algo, NCR_ALG_DSA_TRANSPARENT_HASH);
+ kverify.key_head.nla_len = NLA_HDRLEN + sizeof(kverify.key);
+ kverify.key_head.nla_type = NCR_ATTR_KEY;
+ kverify.key = pubkey;
+ kverify.sign_hash_head.nla_len = NLA_HDRLEN + sizeof(kverify.sign_hash);
+ kverify.sign_hash_head.nla_type = NCR_ATTR_SIGNATURE_HASH_ALGORITHM;
+ strcpy(kverify.sign_hash, SIGNATURE_HASH);
+ kverify.input_head.nla_len = NLA_HDRLEN + sizeof(kverify.input);
+ kverify.input_head.nla_type = NCR_ATTR_UPDATE_INPUT_DATA;
+ kverify.input.data = data;
+ kverify.input.data_size = SIGNATURE_HASH_SIZE;
+ kverify.signature_head.nla_len = NLA_HDRLEN + sizeof(kverify.signature);
+ kverify.signature_head.nla_type = NCR_ATTR_FINAL_INPUT_DATA;
+ kverify.signature.data = sig;
+ kverify.signature.data_size = sizeof(sig);
+
+ ret = ioctl(cfd, NCRIO_SESSION_ONCE, &kverify);
+ if (ret < 0) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_SESSION_ONCE)");
+ return 1;
+ }
+
+ if (ret)
+ fprintf(stdout, " Success\n");
+ else {
+ fprintf(stdout, " Verification Failed!\n");
+ return 1;
+ }
+
+ return 0;
+}
static int test_ncr_rsa(int cfd)
{
@@ -1253,6 +1480,18 @@ static int test_ncr_rsa(int cfd)
return 1;
}
+ ret = rsa_key_sign_verify_transparent(cfd, privkey, pubkey, 1);
+ if (ret != 0) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ return 1;
+ }
+
+ ret = rsa_key_sign_verify_transparent(cfd, privkey, pubkey, 0);
+ if (ret != 0) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ return 1;
+ }
+
ret = rsa_key_encrypt(cfd, privkey, pubkey, 0);
if (ret != 0) {
fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
@@ -1377,6 +1616,12 @@ static int test_ncr_dsa(int cfd)
return 1;
}
+ ret = dsa_key_sign_verify_transparent(cfd, privkey, pubkey);
+ if (ret != 0) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ return 1;
+ }
+
return 0;
}
diff --git a/ncr-int.h b/ncr-int.h
index a6b37397c5f..87964b08065 100644
--- a/ncr-int.h
+++ b/ncr-int.h
@@ -18,7 +18,8 @@
struct nlattr;
struct ncr_out;
-// Not all known algorithms - only for quick internal identification
+// Not all known algorithms - only for quick internal identification. Note
+// that more than one struct algo_properties_st may share the same enum value!
enum ncr_algorithm {
NCR_ALG_NONE__,
NCR_ALG_NULL,
@@ -49,6 +50,7 @@ struct algo_properties_st {
unsigned can_kx:1; /* key exchange */
unsigned is_symmetric:1;
unsigned is_pk:1;
+ unsigned has_transparent_hash:1;
int digest_size;
/* NCR_KEY_TYPE_SECRET if for a secret key algorithm or MAC,
* NCR_KEY_TYPE_PUBLIC for a public key algorithm.
diff --git a/ncr-pk.c b/ncr-pk.c
index c6055dba1d5..9b9078efe38 100644
--- a/ncr-pk.c
+++ b/ncr-pk.c
@@ -358,7 +358,9 @@ int ncr_pk_cipher_init(const struct algo_properties_st *algo,
memset(ctx, 0, sizeof(*ctx));
- if (key->algorithm != algo) {
+ /* Allow using the same key for transparent and non-transparent
+ hashing. */
+ if (key->algorithm->algo != algo->algo) {
err();
return -EINVAL;
}
diff --git a/ncr-sessions.c b/ncr-sessions.c
index 3691127a757..c65db2f751e 100644
--- a/ncr-sessions.c
+++ b/ncr-sessions.c
@@ -49,6 +49,11 @@ struct session_item_st {
struct cipher_data cipher;
struct ncr_pk_ctx pk;
struct hash_data hash;
+ /* This is a hack, ideally we'd have a hash algorithm that simply
+ outputs its input as a digest. We'd still need to distinguish
+ between the hash to identify in the signature and the hash to
+ actually use, though. */
+ void *transparent_hash;
struct scatterlist *sg;
struct page **pages;
@@ -165,6 +170,7 @@ static void _ncr_sessions_item_put(struct session_item_st *item)
cryptodev_cipher_deinit(&item->cipher);
ncr_pk_cipher_deinit(&item->pk);
cryptodev_hash_deinit(&item->hash);
+ kfree(item->transparent_hash);
if (item->key)
_ncr_key_item_put(item->key);
kfree(item->sg);
@@ -272,8 +278,14 @@ static const struct algo_properties_st algo_properties[] = {
(yet). */
{ .algo = NCR_ALG_RSA, KSTR("rsa"), .is_pk = 1,
.can_encrypt=1, .can_sign=1, .key_type = NCR_KEY_TYPE_PUBLIC },
+ { .algo = NCR_ALG_RSA, KSTR(NCR_ALG_RSA_TRANSPARENT_HASH), .is_pk = 1,
+ .can_encrypt=1, .can_sign=1, .has_transparent_hash = 1,
+ .key_type = NCR_KEY_TYPE_PUBLIC },
{ .algo = NCR_ALG_DSA, KSTR("dsa"), .is_pk = 1,
.can_sign=1, .key_type = NCR_KEY_TYPE_PUBLIC },
+ { .algo = NCR_ALG_DSA, KSTR(NCR_ALG_DSA_TRANSPARENT_HASH), .is_pk = 1,
+ .can_sign=1, .has_transparent_hash = 1,
+ .key_type = NCR_KEY_TYPE_PUBLIC },
{ .algo = NCR_ALG_DH, KSTR("dh"), .is_pk = 1,
.can_kx=1, .key_type = NCR_KEY_TYPE_PUBLIC },
#undef KSTR
@@ -578,6 +590,15 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists,
err();
goto fail;
}
+
+ if (ns->algorithm->has_transparent_hash) {
+ ns->transparent_hash = kzalloc(ns->hash.digestsize, GFP_KERNEL);
+ if (ns->transparent_hash == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+ }
} else {
err();
ret = -EINVAL;
@@ -910,10 +931,27 @@ static int _ncr_session_update(struct session_item_st *sess,
case NCR_OP_SIGN:
case NCR_OP_VERIFY:
- ret = cryptodev_hash_update(&sess->hash, isg, isg_size);
- if (ret < 0) {
- err();
- goto fail;
+ if (sess->algorithm->has_transparent_hash) {
+ if (isg_size != sess->hash.digestsize) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ ret = sg_copy_to_buffer(isg, isg_cnt,
+ sess->transparent_hash,
+ isg_size);
+ if (ret != isg_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+ } else {
+ ret = cryptodev_hash_update(&sess->hash, isg,
+ isg_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
}
break;
default:
@@ -997,10 +1035,14 @@ static int _ncr_session_final(struct ncr_lists *lists,
ret = -EINVAL;
goto fail;
}
- ret = cryptodev_hash_final(&sess->hash, digest);
- if (ret < 0) {
- err();
- goto fail;
+ if (sess->algorithm->has_transparent_hash)
+ memcpy(digest, sess->transparent_hash, digest_size);
+ else {
+ ret = cryptodev_hash_final(&sess->hash, digest);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
}
if (!sess->algorithm->is_pk)
@@ -1036,10 +1078,14 @@ static int _ncr_session_final(struct ncr_lists *lists,
goto fail;
}
- ret = cryptodev_hash_final(&sess->hash, digest);
- if (ret < 0) {
- err();
- goto fail;
+ if (sess->algorithm->has_transparent_hash)
+ memcpy(digest, sess->transparent_hash, digest_size);
+ else {
+ ret = cryptodev_hash_final(&sess->hash, digest);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
}
cryptodev_hash_deinit(&sess->hash);
@@ -1130,6 +1176,11 @@ static int _ncr_session_update_key(struct ncr_lists *lists,
goto fail;
case NCR_OP_SIGN:
case NCR_OP_VERIFY:
+ if (sess->algorithm->has_transparent_hash) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
ret = _cryptodev_hash_update(&sess->hash,
key->key.secret.data, key->key.secret.size);
if (ret < 0) {
diff --git a/ncr.h b/ncr.h
index c248c6c87f1..ce84f7a7f85 100644
--- a/ncr.h
+++ b/ncr.h
@@ -69,6 +69,10 @@ enum {
#define NCR_CIPHER_MAX_BLOCK_LEN 32
#define NCR_HASH_MAX_OUTPUT_SIZE 64
+/* Better names wanted */
+#define NCR_ALG_DSA_TRANSPARENT_HASH "__dsa_transparent_hash"
+#define NCR_ALG_RSA_TRANSPARENT_HASH "__rsa_transparent_hash"
+
#define NCR_WALG_AES_RFC3394 "walg-aes-rfc3394" /* for secret keys only */
#define NCR_WALG_AES_RFC5649 "walg-aes-rfc5649" /* can wrap arbitrary key */