diff options
author | Miloslav Trmač <mitr@redhat.com> | 2010-10-27 00:05:26 +0200 |
---|---|---|
committer | Miloslav Trmač <mitr@redhat.com> | 2010-10-27 00:05:26 +0200 |
commit | 06a02e2391625a09e194acf1c6d31aecf2266b8f (patch) | |
tree | c880a79fc8dbc3156a4efe9392a3de32eb32f6cb | |
parent | 46536dbd9e60c46efe4c22916a320838eaa38110 (diff) | |
download | ncrypto-06a02e2391625a09e194acf1c6d31aecf2266b8f.tar.gz ncrypto-06a02e2391625a09e194acf1c6d31aecf2266b8f.tar.xz ncrypto-06a02e2391625a09e194acf1c6d31aecf2266b8f.zip |
Add "symmetric signature" (really HMAC) support
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | include/ncrypto/ncrypto.h | 34 | ||||
-rw-r--r-- | lib/ncrypto_local.c | 253 |
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; +} |