diff options
| author | Miloslav Trmač <mitr@redhat.com> | 2010-10-13 22:45:03 +0200 |
|---|---|---|
| committer | Miloslav Trmač <mitr@redhat.com> | 2010-10-13 22:47:33 +0200 |
| commit | 9149cba1bdcb33b28790277586838264a5997b11 (patch) | |
| tree | 09e0f654edfebba764b857c170e335cfb9d9cf1e | |
| parent | d56f2ee027be7f2255403558039c9402753e42b5 (diff) | |
| download | ncrypto-9149cba1bdcb33b28790277586838264a5997b11.tar.gz ncrypto-9149cba1bdcb33b28790277586838264a5997b11.tar.xz ncrypto-9149cba1bdcb33b28790277586838264a5997b11.zip | |
Add RSA key import and one-shot operations
| -rw-r--r-- | Makefile.am | 9 | ||||
| -rw-r--r-- | include/ncrypto/ncrypto.h | 64 | ||||
| -rw-r--r-- | lib/ncrypto_nss.c | 586 | ||||
| -rw-r--r-- | tests/rsa.c | 105 |
4 files changed, 760 insertions, 4 deletions
diff --git a/Makefile.am b/Makefile.am index 961d8b8..26a8d16 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,16 +35,19 @@ AM_CPPFLAGS = -I $(top_srcdir)/include $(GLIB_CFLAGS) $(NSS_CFLAGS) \ ## Targets lib_LTLIBRARIES = lib/libncrypto.la pkginclude_HEADERS = include/ncrypto/ncrypto.h -TESTS = tests/digests tests/symm_ciphers +TESTS = tests/digests tests/rsa tests/symm_ciphers ## Rules noinst_PROGRAMS = $(TESTS) -lib_libncrypto_la_SOURCES = lib/ncrypto.c lib/ncrypto_local.c -lib_libncrypto_la_LDFLAGS = -version-info 0:0:0 $(OPENSSL_LIBS) +lib_libncrypto_la_SOURCES = lib/ncrypto.c lib/ncrypto_local.c lib/ncrypto_nss.c +lib_libncrypto_la_LDFLAGS = -version-info 0:0:0 $(NSS_LIBS) $(OPENSSL_LIBS) tests_digests_LDADD = lib/libncrypto.la $(GLIB_LIBS) tests_digests_LDFLAGS = -no-install +tests_rsa_LDADD = lib/libncrypto.la $(GLIB_LIBS) +tests_rsa_LDFLAGS = -no-install + tests_symm_ciphers_LDADD = lib/libncrypto.la $(GLIB_LIBS) tests_symm_ciphers_LDFLAGS = -no-install diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h index 0b5087d..5d8aeb0 100644 --- a/include/ncrypto/ncrypto.h +++ b/include/ncrypto/ncrypto.h @@ -33,7 +33,15 @@ Red Hat author: Miloslav Trmač <mitr@redhat.com> */ #include <pkcs11.h> /* In general, semantics aspects that are not documented here are same as in - PCKS#11. */ + PCKS#11. + + Simultaneous references to the same object from multiple threads (except for + simultaneous read accesses to a key) cause undefined behavior. */ + + /* Global state */ + +CK_RV ncr_open (void); +CK_RV ncr_close (void); /* Symmetric keys */ @@ -43,6 +51,60 @@ CK_RV ncr_symm_key_create (struct ncr_symm_key **key, CK_KEY_TYPE type, const void *value, size_t value_size); CK_RV ncr_symm_key_destroy (struct ncr_symm_key *key); + /* Asymmetric keys */ + +struct ncr_public_key; +struct ncr_private_key; + +CK_RV ncr_public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type, + const void *der, size_t der_size); +CK_RV ncr_public_key_destroy (struct ncr_public_key *key); +CK_RV ncr_private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, + const void *der, size_t der_size, + const void *public_value, + size_t public_value_size); +CK_RV ncr_private_key_destroy (struct ncr_private_key *key); + +CK_RV ncr_public_key_create_rsa (struct ncr_public_key **key, + const void *modulus, size_t modulus_size, + const void *public_exponent, + size_t public_exponent_size); +CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key, + const void *modulus, size_t modulus_size, + const void *public_exponent, + size_t public_exponent_size, + const void *private_exponent, + size_t private_exponent_size, + const void *prime_1, size_t prime_1_size, + const void *prime_2, size_t prime_2_size, + const void *exponent_1, + size_t exponent_1_size, + const void *exponent_2, + size_t exponent_2_size, + const void *coefficient, + size_t coefficient_size); + + /* Asymmetric operations */ + +CK_RV ncr_public_key_encrypt (CK_MECHANISM_TYPE mech, + struct ncr_public_key *key, void *dest, + size_t *dest_size_ptr, const void *src, + size_t src_size); +CK_RV ncr_private_key_decrypt (CK_MECHANISM_TYPE mech, + struct ncr_private_key *key, void *dest, + size_t *dest_size_ptr, const void *src, + size_t src_size); + +/* FIXME: Add multipart etc... */ +CK_RV ncr_private_key_sign (CK_MECHANISM_TYPE mech, + struct ncr_private_key *key, void *dest, + size_t *dest_size_ptr, const void *src, + size_t src_size); +CK_RV ncr_public_key_verify (CK_MECHANISM_TYPE mech, + struct ncr_public_key *key, const void *signature, + size_t signature_size, const void *src, + size_t src_size); + /* Digests */ struct ncr_digest_session; diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c new file mode 100644 index 0000000..12aaab8 --- /dev/null +++ b/lib/ncrypto_nss.c @@ -0,0 +1,586 @@ +/* NSS libncrypto implementation. + +Copyright 2010 Red Hat, Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Red Hat author: Miloslav Trmač <mitr@redhat.com> */ +#include <config.h> + +#include <pthread.h> + +#include <glib.h> +#include <keyhi.h> +#include <nss.h> +#include <pk11pub.h> + +#include <ncrypto/ncrypto.h> + + /* Global state */ + +/* FIXME: Only init NSS/connect to the daemon when actually necessary. */ + +static pthread_mutex_t refcount_mutex = PTHREAD_MUTEX_INITIALIZER; +static size_t refcount; + +CK_RV +ncr_open (void) +{ + if (pthread_mutex_lock (&refcount_mutex) != 0) + return CKR_GENERAL_ERROR; + + if (refcount == 0) + { + if (NSS_NoDB_Init (NULL) != SECSuccess) + { + (void)pthread_mutex_unlock (&refcount_mutex); + return CKR_GENERAL_ERROR; + } + } + refcount++; + + if (pthread_mutex_unlock (&refcount_mutex) != 0) + return CKR_GENERAL_ERROR; + + return CKR_OK; +} + +CK_RV +ncr_close (void) +{ + if (pthread_mutex_lock (&refcount_mutex) != 0) + return CKR_GENERAL_ERROR; + + refcount--; + if (refcount == 0) + { + if (NSS_Shutdown () != SECSuccess) + { + (void)pthread_mutex_unlock (&refcount_mutex); + return CKR_GENERAL_ERROR; + } + } + + if (pthread_mutex_unlock (&refcount_mutex) != 0) + return CKR_GENERAL_ERROR; + + return CKR_OK; +} + + /* Asymmetric keys */ + +struct ncr_public_key +{ + SECKEYPublicKey *key; +}; + +struct ncr_private_key +{ + SECKEYPrivateKey *key; +}; + +static CK_RV +public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type, + const SECItem *der_key) +{ + struct ncr_public_key *k; + + k = malloc (sizeof (*k)); + if (k == NULL) + return CKR_HOST_MEMORY; + + k->key = SECKEY_ImportDERPublicKey((SECItem *)der_key, type); + if (k->key == NULL) + { + free (k); + return CKR_GENERAL_ERROR; + } + + *key = k; + return CKR_OK; +} + +CK_RV +ncr_public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type, + const void *der, size_t der_size) +{ + SECItem der_key; + + g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); + g_return_val_if_fail (der != NULL, CKR_ARGUMENTS_BAD); + + der_key.data = (void *)der; + der_key.len = der_size; + return public_key_create (key, type, &der_key); +} + +CK_RV +ncr_public_key_destroy (struct ncr_public_key *key) +{ + g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); + + /* Note: this leaks "key->key", which the function does not free (642767). */ + SECKEY_DestroyPublicKey (key->key); + free (key); + return CKR_OK; +} + +static CK_RV +private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, + const SECItem *der_key, const SECItem *public_value) +{ + struct priv_key_info + { + SECItem version; + SECAlgorithmID algorithm; + SECItem private_key; + }; + + static const SEC_ASN1Template asn1_template[] = + { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct priv_key_info) }, + { SEC_ASN1_INTEGER, offsetof (struct priv_key_info, version), NULL, 0, }, + { SEC_ASN1_INLINE, offsetof (struct priv_key_info, algorithm), + SECOID_AlgorithmIDTemplate, 0, }, + { + SEC_ASN1_OCTET_STRING, offsetof (struct priv_key_info, private_key), + NULL, 0, + }, + /* Attributes are optional and we never use them. */ + { 0, 0, NULL, 0 } + }; + static const uint8_t wrap_key[32]; /* = { 0, }; */ + static const uint8_t wrap_iv[16]; /* = { 0, }; */ + static const uint8_t zero; /* = 0; */ + + struct ncr_private_key *k; + struct priv_key_info der_input; + PK11SlotInfo *slot; + SECItem der_info, *der_res, key_item, iv_item, wrapped_item; + SECOidTag alg_tag; + SECStatus ss; + PK11SymKey *wrapping_key; + PK11Context *ctx; + int wrapped_len; + + switch (type) + { + case CKK_RSA: + alg_tag = SEC_OID_PKCS1_RSA_ENCRYPTION; + break; + + default: + g_return_val_if_reached (CKR_ARGUMENTS_BAD); + } + + k = malloc (sizeof (*k)); + if (k == NULL) + return CKR_HOST_MEMORY; + + der_input.version.type = siUnsignedInteger; + der_input.version.data = (void *)&zero; + der_input.version.len = sizeof (zero); + if (SECOID_SetAlgorithmID (NULL, &der_input.algorithm, alg_tag, NULL) + != SECSuccess) + { + free (k); + return CKR_GENERAL_ERROR; + } + der_input.private_key = *der_key; + + der_info.data = NULL; + der_info.len = 0; + der_res = SEC_ASN1EncodeItem (NULL, &der_info, &der_input, asn1_template); + + SECOID_DestroyAlgorithmID (&der_input.algorithm, PR_FALSE); + + if (der_res == NULL) + { + free (k); + return CKR_HOST_MEMORY; + } + + slot = PK11_GetBestSlot (CKM_AES_CBC_PAD, NULL); + if (slot == NULL) + goto err_der_info; + + key_item.data = (void *)wrap_key; + key_item.len = sizeof (wrap_key); + wrapping_key = PK11_ImportSymKeyWithFlags (slot, CKM_AES_CBC_PAD, + PK11_OriginUnwrap, CKA_FLAGS_ONLY, + &key_item, + CKF_ENCRYPT | CKF_UNWRAP, + PR_FALSE /* isPerm */, NULL); + if (wrapping_key == NULL) + goto err_slot; + iv_item.data = (void *)wrap_iv; + iv_item.len = sizeof (wrap_iv); + + ctx = PK11_CreateContextBySymKey (CKM_AES_CBC_PAD, CKA_ENCRYPT, wrapping_key, + &iv_item); + if (ctx == NULL) + goto err_wrapping_key; + if (SECITEM_AllocItem (NULL, &wrapped_item, der_info.len + 16) == NULL) + { + PK11_DestroyContext (ctx, PR_TRUE); + goto err_wrapping_key; + } + ss = PK11_CipherOp (ctx, wrapped_item.data, &wrapped_len, wrapped_item.len, + der_info.data, der_info.len); + if (ss != SECSuccess) + { + PK11_DestroyContext (ctx, PR_TRUE); + goto err_wrapped_item; + } + /* C_EncryptFinal is only available through this function. "Nice.". */ + ss = PK11_DigestFinal (ctx, wrapped_item.data + wrapped_len, + &wrapped_item.len, wrapped_len); + PK11_DestroyContext (ctx, PR_TRUE); + if (ss != SECSuccess) + goto err_wrapped_item; + wrapped_item.len += wrapped_len; + + k->key = PK11_UnwrapPrivKey (slot, wrapping_key, CKM_AES_CBC_PAD, &iv_item, + &wrapped_item, NULL, (SECItem *)public_value, + PR_FALSE /* token */, PR_FALSE /* sensitive */, + type, NULL, 0, NULL); + SECITEM_ZfreeItem (&wrapped_item, PR_FALSE); + PK11_FreeSymKey (wrapping_key); + PK11_FreeSlot (slot); + PORT_Free (der_info.data); + + if (k->key == NULL) + goto err_k; + + *key = k; + return CKR_OK; + + err_wrapped_item: + SECITEM_ZfreeItem (&wrapped_item, PR_FALSE); + err_wrapping_key: + PK11_FreeSymKey (wrapping_key); + err_slot: + PK11_FreeSlot (slot); + err_der_info: + PORT_Free (der_info.data); + err_k: + free (k); + return CKR_GENERAL_ERROR; +} + +/* FIXME: public_value should not be necessary, it is somewhere inside "der". */ +CK_RV +ncr_private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, + const void *der, size_t der_size, + const void *public_value, size_t public_value_size) +{ + SECItem der_key; + SECItem public; + + g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); + g_return_val_if_fail (der != NULL, CKR_ARGUMENTS_BAD); + + der_key.data = (void *)der; + der_key.len = der_size; + public.data = (void *)public_value; + public.len = public_value_size; + return private_key_create (key, type, &der_key, &public); +} + +CK_RV +ncr_private_key_destroy (struct ncr_private_key *key) +{ + g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); + + SECKEY_DestroyPrivateKey (key->key); + free (key); + return CKR_OK; +} + +CK_RV +ncr_public_key_create_rsa (struct ncr_public_key **key, const void *modulus, + size_t modulus_size, const void *public_exponent, + size_t public_exponent_size) +{ + struct rsa_pub_key + { + SECItem modulus, public_exponent; + }; + + static const SEC_ASN1Template asn1_template[] = + { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct rsa_pub_key) }, +#define INT(X) { SEC_ASN1_INTEGER, offsetof (struct rsa_pub_key, X), NULL, 0, } + INT (modulus), INT (public_exponent), +#undef INT + { 0, 0, NULL, 0 } + }; + + struct rsa_pub_key der_input; + SECItem der_key; + CK_RV res; + + g_return_val_if_fail (modulus != NULL, CKR_ARGUMENTS_BAD); + g_return_val_if_fail (public_exponent != NULL, CKR_ARGUMENTS_BAD); + +#define INT(X) \ + der_input.X.type = siUnsignedInteger; \ + der_input.X.data = (void *)X; \ + der_input.X.len = X##_size; + + INT (modulus); + INT (public_exponent); +#undef INT + + der_key.data = NULL; + der_key.len = 0; + if (SEC_ASN1EncodeItem(NULL, &der_key, &der_input, asn1_template) == NULL) + return CKR_HOST_MEMORY; + + res = public_key_create (key, CKK_RSA, &der_key); + PORT_Free (der_key.data); + + return res; +} + +CK_RV +ncr_private_key_create_rsa (struct ncr_private_key **key, const void *modulus, + size_t modulus_size, const void *public_exponent, + size_t public_exponent_size, + const void *private_exponent, + size_t private_exponent_size, const void *prime_1, + size_t prime_1_size, const void *prime_2, + size_t prime_2_size, const void *exponent_1, + size_t exponent_1_size, const void *exponent_2, + size_t exponent_2_size, const void *coefficient, + size_t coefficient_size) +{ + struct rsa_pub_key + { + SECItem version; + SECItem modulus, public_exponent, private_exponent, prime_1, prime_2; + SECItem exponent_1, exponent_2, coefficient; + }; + + static const SEC_ASN1Template asn1_template[] = + { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct rsa_pub_key) }, +#define INT(X) { SEC_ASN1_INTEGER, offsetof (struct rsa_pub_key, X), NULL, 0, } + INT (version), + INT (modulus), INT (public_exponent), INT (private_exponent), + INT (prime_1), INT (prime_2), INT (exponent_1), INT (exponent_2), + INT (coefficient), +#undef INT + { 0, 0, NULL, 0 } + }; + static const uint8_t zero; /* = 0; */ + + struct rsa_pub_key der_input; + SECItem der_key; + CK_RV res; + + g_return_val_if_fail (modulus != NULL, CKR_ARGUMENTS_BAD); + g_return_val_if_fail (public_exponent != NULL, CKR_ARGUMENTS_BAD); + + der_input.version.type = siUnsignedInteger; + der_input.version.data = (void *)&zero; + der_input.version.len = sizeof (zero); +#define INT(X) \ + der_input.X.type = siUnsignedInteger; \ + der_input.X.data = (void *)X; \ + der_input.X.len = X##_size; + + INT (modulus); + INT (public_exponent); + INT (private_exponent); + INT (prime_1); + INT (prime_2); + INT (exponent_1); + INT (exponent_2); + INT (coefficient); +#undef INT + + der_key.data = NULL; + der_key.len = 0; + if (SEC_ASN1EncodeItem (NULL, &der_key, &der_input, asn1_template) == NULL) + return CKR_HOST_MEMORY; + + res = private_key_create (key, CKK_RSA, &der_key, &der_input.modulus); + PORT_Free (der_key.data); + + return res; +} + + /* Asymmetric operations */ + +CK_RV +ncr_public_key_encrypt (CK_MECHANISM_TYPE mech, struct ncr_public_key *key, + void *dest, size_t *dest_size_ptr, const void *src, + size_t src_size) +{ + size_t dest_size; + SECStatus ss; + + g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); + g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD); + + /* This is correct for RSA, at least. */ + dest_size = SECKEY_SignatureLen (key->key); + if (dest_size == 0) + return CKR_GENERAL_ERROR; + if (dest == NULL) + { + *dest_size_ptr = dest_size; + return CKR_OK; + } + if (*dest_size_ptr < dest_size) + { + *dest_size_ptr = dest_size; + return CKR_BUFFER_TOO_SMALL; + } + *dest_size_ptr = dest_size; + + g_return_val_if_fail (dest != NULL, CKR_ARGUMENTS_BAD); + g_return_val_if_fail (src != NULL || src_size == 0, CKR_ARGUMENTS_BAD); + + switch (mech) + { + case CKM_RSA_PKCS: + ss = PK11_PubEncryptPKCS1 (key->key, dest, (void *)src, src_size, NULL); + break; + + case CKM_RSA_X_509: + ss = PK11_PubEncryptRaw (key->key, dest, (void *)src, src_size, NULL); + break; + + default: + g_return_val_if_reached (CKR_MECHANISM_INVALID); + } + if (ss != SECSuccess) + return CKR_GENERAL_ERROR; + + return CKR_OK; +} + +CK_RV +ncr_private_key_decrypt (CK_MECHANISM_TYPE mech, struct ncr_private_key *key, + void *dest, size_t *dest_size_ptr, const void *src, + size_t src_size) +{ + unsigned out_len; + SECStatus ss; + + g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); + g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD); + + g_return_val_if_fail (src != NULL || src_size == 0, CKR_ARGUMENTS_BAD); + + /* Don't change the value if the PrivDecrypt function doesn't touch it. */ + out_len = *dest_size_ptr; + switch (mech) + { + case CKM_RSA_PKCS: + ss = PK11_PrivDecryptPKCS1 (key->key, dest, &out_len, *dest_size_ptr, + (void *)src, src_size); + break; + + case CKM_RSA_X_509: + ss = PK11_PrivDecryptRaw (key->key, dest, &out_len, *dest_size_ptr, + (void *)src, src_size); + break; + + default: + g_return_val_if_reached (CKR_MECHANISM_INVALID); + } + *dest_size_ptr = out_len; + if (ss != SECSuccess) + return CKR_GENERAL_ERROR; + + return CKR_OK; +} + +CK_RV +ncr_private_key_sign (CK_MECHANISM_TYPE mech, struct ncr_private_key *key, + void *dest, size_t *dest_size_ptr, const void *src, + size_t src_size) +{ + size_t dest_size; + SECItem src_item, dest_item; + + g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); + g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD); + + g_return_val_if_fail (mech == PK11_MapSignKeyType (key->key->keyType), + CKR_MECHANISM_INVALID); + + dest_size = PK11_SignatureLen (key->key); + if (dest_size == 0) + return CKR_GENERAL_ERROR; + if (dest == NULL) + { + *dest_size_ptr = dest_size; + return CKR_OK; + } + if (*dest_size_ptr < dest_size) + { + *dest_size_ptr = dest_size; + return CKR_BUFFER_TOO_SMALL; + } + + g_return_val_if_fail (dest != NULL, CKR_ARGUMENTS_BAD); + g_return_val_if_fail (src != NULL || src_size == 0, CKR_ARGUMENTS_BAD); + + src_item.data = (void *)src; + src_item.len = src_size; + dest_item.data = dest; + dest_item.len = *dest_size_ptr; + + if (PK11_Sign (key->key, &dest_item, &src_item) != SECSuccess) + return CKR_GENERAL_ERROR; + + *dest_size_ptr = dest_item.len; + return CKR_OK; +} + +CK_RV +ncr_public_key_verify (CK_MECHANISM_TYPE mech, struct ncr_public_key *key, + const void *signature, size_t signature_size, + const void *src, size_t src_size) +{ + SECItem sig_item, src_item; + + g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); + g_return_val_if_fail (signature != NULL || signature_size == 0, + CKR_ARGUMENTS_BAD); + g_return_val_if_fail (src != NULL || src_size == 0, CKR_ARGUMENTS_BAD); + + g_return_val_if_fail (mech == PK11_MapSignKeyType (key->key->keyType), + CKR_MECHANISM_INVALID); + + sig_item.data = (void *)signature; + sig_item.len = signature_size; + src_item.data = (void *)src; + src_item.len = src_size; + + return PK11_Verify (key->key, &sig_item, &src_item, NULL) == SECSuccess + ? CKR_OK : CKR_GENERAL_ERROR; +} diff --git a/tests/rsa.c b/tests/rsa.c new file mode 100644 index 0000000..d836690 --- /dev/null +++ b/tests/rsa.c @@ -0,0 +1,105 @@ +/* RSA tests. + +Copyright 2010 Red Hat, Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Red Hat author: Miloslav Trmač <mitr@redhat.com> */ + +#include <assert.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> +#include <ncrypto/ncrypto.h> + +static const uint8_t modulus[64] = "\xB8\xC7\x54\x15\x90\xCF\x91\x7A\xF3\x4C\x45\x53\xC2\x0A\xDA\x84\x4C\x09\x48\x10\x06\x41\xC5\x97\x57\x02\xDA\x0E\x7E\x64\x46\xBD\xC6\x75\x42\xCD\x32\x23\x0C\xEC\x2B\x1C\x60\x03\x68\x1E\x4F\x28\x78\xD8\xB0\xC1\xAC\xA7\x21\xE4\x15\x74\x65\x16\x1C\x59\xC8\x85"; +static const uint8_t public_exponent[3] = "\x01\x00\x01"; +static const uint8_t private_exponent[64] = "\x7B\xD6\xC3\xC8\xEC\x53\xE1\x09\xC9\x13\xDE\x06\xE3\xAE\xC8\x83\x10\x3E\xCC\x38\x49\x29\x3D\x97\x4F\x6E\x8E\xDC\x55\xE3\x38\xF1\x03\xEB\xC1\x09\x80\x16\xB8\x9F\xE1\xC0\x21\x77\xD4\xEE\xF7\x30\xD1\x85\x2B\x1F\x4F\xFE\xD1\x01\xCD\x35\x78\x4A\x97\x6F\x38\x65"; +static const uint8_t prime_1[32] = "\xF5\x7E\xFA\xED\xE0\xEC\x9C\x4E\x6F\xDF\xED\x64\x58\xEC\x18\xA9\x8E\x60\x2E\x49\x7E\xDF\x8E\xCF\x9F\xA5\x4A\x32\xA3\x27\x7E\x1B"; +static const uint8_t prime_2[32] = "\xC0\xAF\x49\x15\x49\x8D\x88\xFB\x28\x7D\x33\x25\x07\x37\xE0\x99\x2C\xA8\x6D\x46\x4F\x7D\x7D\x6E\x01\x95\x6B\x2B\x18\x1B\xBD\xDF"; +static const uint8_t exponent_1[32] = "\xC3\x34\x0F\xB4\xBC\x87\x87\x95\xFA\xF1\x14\x63\x19\x2D\xCA\x42\x70\x5A\x5C\x13\xC6\x95\x5E\x8A\x0B\x08\x34\x22\x65\x87\x0E\x87"; +static const uint8_t exponent_2[32] = "\x27\x3B\x89\x85\xEC\x14\x05\x70\x1E\x2E\x5F\xDB\x8A\x3C\xB6\x5E\x79\xD9\x51\x66\x9F\x88\xCD\xA1\x38\x71\x54\x00\xD2\x47\xD3\xC1"; +static const uint8_t coefficient[32] = "\x39\x09\x3A\x43\xCF\xE3\x65\x63\x2F\x5F\x11\xED\x2C\x42\x88\xEF\xCA\x26\x1E\x08\x96\xCF\x0A\x8F\xCB\x88\x45\x50\xEF\x6A\x38\x07"; + +static const uint8_t input[] = "\x00\x01\x02\x03\x04\x05"; + +int +main (void) +{ + struct ncr_public_key *public; + struct ncr_private_key *private; + uint8_t dest[4096]; + size_t src_size, dest_size; + CK_RV res; + + res = ncr_open (); + assert (res == CKR_OK); + + /* Test the generic version as well? */ + res = ncr_public_key_create_rsa (&public, modulus, sizeof (modulus), + public_exponent, sizeof (public_exponent)); + assert (res == CKR_OK); + res = ncr_private_key_create_rsa (&private, modulus, sizeof (modulus), + public_exponent, sizeof (public_exponent), + private_exponent, sizeof (private_exponent), + prime_1, sizeof (prime_1), prime_2, + sizeof (prime_2), exponent_1, + sizeof (exponent_1), exponent_2, + sizeof (exponent_2), coefficient, + sizeof (coefficient)); + assert (res == CKR_OK); + + + dest_size = sizeof (dest); + res = ncr_public_key_encrypt (CKM_RSA_PKCS, public, dest, &dest_size, input, + sizeof (input)); + assert (res == CKR_OK); + src_size = dest_size; + dest_size = sizeof (dest); + /* PKCS#11 allows in-place operation */ + res = ncr_private_key_decrypt (CKM_RSA_PKCS, private, dest, &dest_size, dest, + src_size); + assert (res == CKR_OK); + assert (dest_size == sizeof (input)); + assert (memcmp (dest, input, dest_size) == 0); + + dest_size = sizeof (dest); + res = ncr_private_key_sign (CKM_RSA_PKCS, private, dest, &dest_size, input, + sizeof (input)); + assert (res == CKR_OK); + res = ncr_public_key_verify (CKM_RSA_PKCS, public, dest, dest_size, input, + sizeof (input)); + assert (res == CKR_OK); + + res = ncr_private_key_destroy (private); + assert (res == CKR_OK); + + res = ncr_public_key_destroy (public); + assert (res == CKR_OK); + + res = ncr_close (); + assert (res == CKR_OK); + + return EXIT_SUCCESS; +} |
