summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiloslav Trmač <mitr@redhat.com>2010-10-27 00:05:26 +0200
committerMiloslav Trmač <mitr@redhat.com>2010-10-27 00:05:26 +0200
commit06a02e2391625a09e194acf1c6d31aecf2266b8f (patch)
treec880a79fc8dbc3156a4efe9392a3de32eb32f6cb
parent46536dbd9e60c46efe4c22916a320838eaa38110 (diff)
downloadncrypto-06a02e2391625a09e194acf1c6d31aecf2266b8f.tar.gz
ncrypto-06a02e2391625a09e194acf1c6d31aecf2266b8f.tar.xz
ncrypto-06a02e2391625a09e194acf1c6d31aecf2266b8f.zip
Add "symmetric signature" (really HMAC) support
-rw-r--r--Makefile.am5
-rw-r--r--include/ncrypto/ncrypto.h34
-rw-r--r--lib/ncrypto_local.c253
3 files changed, 291 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 26a8d16..92bdeef 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,7 +35,7 @@ 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/rsa tests/symm_ciphers
+TESTS = tests/digests tests/rsa tests/symm_ciphers tests/symm_signatures
## Rules
noinst_PROGRAMS = $(TESTS)
@@ -51,3 +51,6 @@ tests_rsa_LDFLAGS = -no-install
tests_symm_ciphers_LDADD = lib/libncrypto.la $(GLIB_LIBS)
tests_symm_ciphers_LDFLAGS = -no-install
+
+tests_symm_signatures_LDADD = lib/libncrypto.la $(GLIB_LIBS)
+tests_symm_signatures_LDFLAGS = -no-install
diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h
index aef6bb4..24d8e8e 100644
--- a/include/ncrypto/ncrypto.h
+++ b/include/ncrypto/ncrypto.h
@@ -183,4 +183,38 @@ CK_RV ncr_symm_cipher_decrypt (struct ncr_symm_cipher_session *sess, void *dest,
size_t *dest_size_ptr, const void *src,
size_t src_size);
+ /* Symmetric signatures */
+
+struct ncr_symm_signature_session;
+
+/* Session lifetime management. */
+CK_RV ncr_symm_signature_alloc (struct ncr_symm_signature_session **sess,
+ CK_MECHANISM_TYPE mech);
+CK_RV ncr_symm_signature_free (struct ncr_symm_signature_session *sess);
+/* Use either ncr_symm_signature_sign_{init,update,final} (), or
+ ncr_symm_signature_{sign_init,sign} (). After finishing such a call
+ sequence, a new sequence can be started within the same session. Same for
+ verification sequences.
+
+ Symmetric signature mechanisms tend to use keys of type
+ CKK_GENERIC_SECRET. */
+CK_RV ncr_symm_signature_sign_init (struct ncr_symm_signature_session *sess,
+ struct ncr_symm_key *key);
+CK_RV ncr_symm_signature_sign_update (struct ncr_symm_signature_session *sess,
+ const void *data, size_t size);
+CK_RV ncr_symm_signature_sign_final (struct ncr_symm_signature_session *sess,
+ void *dest, size_t *size_ptr);
+CK_RV ncr_symm_signature_sign (struct ncr_symm_signature_session *sess,
+ void *dest, size_t *dest_size_ptr,
+ const void *data, size_t data_size);
+CK_RV ncr_symm_signature_verify_init (struct ncr_symm_signature_session *sess,
+ struct ncr_symm_key *key);
+CK_RV ncr_symm_signature_verify_update (struct ncr_symm_signature_session *sess,
+ const void *data, size_t size);
+CK_RV ncr_symm_signature_verify_final (struct ncr_symm_signature_session *sess,
+ const void *signature, size_t size);
+CK_RV ncr_symm_signature_verify (struct ncr_symm_signature_session *sess,
+ const void *signature, size_t signature_size,
+ const void *data, size_t data_size);
+
#endif
diff --git a/lib/ncrypto_local.c b/lib/ncrypto_local.c
index 8f6473c..8cf4667 100644
--- a/lib/ncrypto_local.c
+++ b/lib/ncrypto_local.c
@@ -32,6 +32,7 @@ Red Hat author: Miloslav Trmač <mitr@redhat.com> */
#include <glib.h>
#include <openssl/evp.h>
+#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <ncrypto/ncrypto.h>
@@ -695,3 +696,255 @@ ncr_symm_cipher_decrypt (struct ncr_symm_cipher_session *sess, void *dest,
{
return symm_cipher (sess, false, dest, dest_size_ptr, src, src_size);
}
+
+ /* Symmetric signature handling */
+
+static const EVP_MD *
+symm_signature_evp_from_hmac_mech (CK_MECHANISM_TYPE mech)
+{
+ switch (mech)
+ {
+#define E(M, E) \
+ case CKM_##M##_HMAC: \
+ return EVP_##E ();
+ E (MD5, md5);
+ E (SHA_1, sha1);
+ E (SHA224, sha224);
+ E (SHA256, sha256);
+ E (SHA384, sha384);
+ E (SHA512, sha512);
+#undef E
+ default:
+ g_return_val_if_reached (NULL);
+ }
+}
+
+struct ncr_symm_signature_session
+{
+ HMAC_CTX ctx;
+ const EVP_MD *md;
+ size_t md_size;
+ bool signing;
+ /* Debugging only */
+ enum { NSSS_NEW, NSSS_INITIALIZED, NSSS_UPDATED, NSSS_FINISHED } state;
+};
+
+CK_RV
+ncr_symm_signature_alloc (struct ncr_symm_signature_session **sess,
+ CK_MECHANISM_TYPE mech)
+{
+ struct ncr_symm_signature_session *s;
+ const EVP_MD *md;
+
+ g_return_val_if_fail (sess != NULL, CKR_ARGUMENTS_BAD);
+
+ md = symm_signature_evp_from_hmac_mech (mech);
+ if (md == NULL)
+ return CKR_MECHANISM_INVALID;
+
+ s = malloc (sizeof (*s));
+ if (s == NULL)
+ return CKR_HOST_MEMORY;
+
+ HMAC_CTX_init (&s->ctx);
+ s->state = NSSS_NEW;
+ s->md = md;
+ s->md_size = EVP_MD_size (md);
+ g_assert (s->md_size <= EVP_MAX_MD_SIZE);
+ *sess = s;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_symm_signature_free (struct ncr_symm_signature_session *sess)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+
+ HMAC_CTX_cleanup (&sess->ctx);
+ free (sess);
+ return CKR_OK;
+}
+
+static CK_RV
+symm_signature_init (struct ncr_symm_signature_session *sess, bool sign,
+ struct ncr_symm_key *key)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSSS_NEW || sess->state == NSSS_FINISHED,
+ CKR_OPERATION_ACTIVE);
+ g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID);
+
+ /* This is not assured, but holds for supported mechanisms. */
+ g_return_val_if_fail (key->type == CKK_GENERIC_SECRET,
+ CKR_KEY_TYPE_INCONSISTENT);
+
+ if (HMAC_Init_ex (&sess->ctx, key->value, key->size, sess->md, NULL) == 0)
+ return ckr_openssl ();
+
+ sess->signing = sign;
+ sess->state = NSSS_INITIALIZED;
+ return CKR_OK;
+}
+
+static CK_RV
+symm_signature_update (struct ncr_symm_signature_session *sess, bool sign,
+ const void *data, size_t size)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (data != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess->state == NSSS_INITIALIZED
+ || sess->state == NSSS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+ g_return_val_if_fail (sess->signing == sign, CKR_OPERATION_NOT_INITIALIZED);
+
+ if (HMAC_Update (&sess->ctx, data, size) == 0)
+ return ckr_openssl ();
+
+ sess->state = NSSS_UPDATED;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_symm_signature_sign_init (struct ncr_symm_signature_session *sess,
+ struct ncr_symm_key *key)
+{
+ return symm_signature_init (sess, true, key);
+}
+
+CK_RV
+ncr_symm_signature_sign_update (struct ncr_symm_signature_session *sess,
+ const void *data, size_t size)
+{
+ return symm_signature_update (sess, true, data, size);
+}
+
+CK_RV
+ncr_symm_signature_sign_final (struct ncr_symm_signature_session *sess,
+ void *dest, size_t *size_ptr)
+{
+ int res;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSSS_INITIALIZED
+ || sess->state == NSSS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+ g_return_val_if_fail (size_ptr != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess->signing == true, CKR_OPERATION_NOT_INITIALIZED);
+
+ if (dest == NULL)
+ {
+ *size_ptr = sess->md_size;
+ return CKR_OK;
+ }
+ if (*size_ptr < sess->md_size)
+ {
+ *size_ptr = sess->md_size;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+ *size_ptr = sess->md_size;
+
+ g_return_val_if_fail (dest != NULL, CKR_ARGUMENTS_BAD);
+
+ res = HMAC_Final (&sess->ctx, dest, NULL);
+ sess->state = NSSS_FINISHED;
+ return res ? CKR_OK : ckr_openssl ();
+}
+
+CK_RV
+ncr_symm_signature_sign (struct ncr_symm_signature_session *sess, void *dest,
+ size_t *dest_size_ptr, const void *data,
+ size_t data_size)
+{
+ int res;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSSS_INITIALIZED,
+ CKR_OPERATION_NOT_INITIALIZED);
+ g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess->signing == true, CKR_OPERATION_NOT_INITIALIZED);
+
+ if (dest == NULL)
+ {
+ *dest_size_ptr = sess->md_size;
+ return CKR_OK;
+ }
+ if (*dest_size_ptr < sess->md_size)
+ {
+ *dest_size_ptr = sess->md_size;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+ *dest_size_ptr = sess->md_size;
+
+ g_return_val_if_fail (data != NULL, CKR_ARGUMENTS_BAD);
+
+ res = (HMAC_Update (&sess->ctx, data, data_size) != 0
+ && HMAC_Final (&sess->ctx, dest, NULL) != 0);
+ sess->state = NSSS_FINISHED;
+ return res ? CKR_OK : ckr_openssl ();
+}
+
+CK_RV
+ncr_symm_signature_verify_init (struct ncr_symm_signature_session *sess,
+ struct ncr_symm_key *key)
+{
+ return symm_signature_init (sess, false, key);
+}
+
+CK_RV
+ncr_symm_signature_verify_update (struct ncr_symm_signature_session *sess,
+ const void *data, size_t size)
+{
+ return symm_signature_update (sess, false, data, size);
+}
+
+CK_RV
+ncr_symm_signature_verify_final (struct ncr_symm_signature_session *sess,
+ const void *signature, size_t size)
+{
+ uint8_t buf[EVP_MAX_MD_SIZE];
+ int res;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSSS_INITIALIZED
+ || sess->state == NSSS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+ g_return_val_if_fail (signature != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess->signing == false, CKR_OPERATION_NOT_INITIALIZED);
+
+ res = HMAC_Final (&sess->ctx, buf, NULL);
+ sess->state = NSSS_FINISHED;
+ if (res == 0)
+ return ckr_openssl ();
+ if (size != sess->md_size)
+ return CKR_SIGNATURE_LEN_RANGE;
+ if (memcmp (signature, buf, size) != 0)
+ return CKR_SIGNATURE_INVALID;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_symm_signature_verify (struct ncr_symm_signature_session *sess,
+ const void *signature, size_t signature_size,
+ const void *data, size_t data_size)
+{
+ uint8_t buf[EVP_MAX_MD_SIZE];
+ int res;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSSS_INITIALIZED,
+ CKR_OPERATION_NOT_INITIALIZED);
+ g_return_val_if_fail (data != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (signature != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess->signing == false, CKR_OPERATION_NOT_INITIALIZED);
+
+ res = (HMAC_Update (&sess->ctx, data, data_size) != 0
+ && HMAC_Final (&sess->ctx, buf, NULL) != 0);
+ sess->state = NSSS_FINISHED;
+ if (res == 0)
+ return ckr_openssl ();
+ if (signature_size != sess->md_size)
+ return CKR_SIGNATURE_LEN_RANGE;
+ if (memcmp (signature, buf, signature_size) != 0)
+ return CKR_SIGNATURE_INVALID;
+ return CKR_OK;
+}