summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile.am4
-rw-r--r--lib/ncrypto_alg.c1272
-rw-r--r--lib/ncrypto_local.c809
4 files changed, 1276 insertions, 811 deletions
diff --git a/.gitignore b/.gitignore
index 346049f..1229db3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,4 +12,6 @@
/build
/config.h.in
/configure
+# For builds with other kernels
+/include/linux
/m4 \ No newline at end of file
diff --git a/Makefile.am b/Makefile.am
index 7019a5f..fd2eaf2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,8 +41,8 @@ TESTS = tests/digests tests/private_keys tests/rsa \
## Rules
noinst_PROGRAMS = $(TESTS)
-lib_libncrypto_la_SOURCES = lib/internal.h lib/ncrypto.c lib/ncrypto_local.c \
- lib/ncrypto_nss.c
+lib_libncrypto_la_SOURCES = lib/internal.h lib/ncrypto.c lib/ncrypto_alg.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)
diff --git a/lib/ncrypto_alg.c b/lib/ncrypto_alg.c
new file mode 100644
index 0000000..bc72383
--- /dev/null
+++ b/lib/ncrypto_alg.c
@@ -0,0 +1,1272 @@
+/* AF_ALG crypto 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 <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <linux/if_alg.h>
+
+#include <ncrypto/ncrypto.h>
+
+#include "internal.h"
+
+/* This is in <linux/socket.h>, but not exposed by it to user-space. */
+#define AF_ALG 38 /* Algorithm sockets */
+#define SOL_ALG 279
+
+ /* Helpers */
+
+static CK_RV
+ckr_errno (void)
+{
+ /* FIXME: Something better */
+ return CKR_GENERAL_ERROR;
+}
+
+ /* Digest handling */
+
+/* Semantically, md_size_ptr should be "size_t *", but values will fit into
+ "int *" just as fine. */
+static CK_RV
+digest_params_from_mech (CK_MECHANISM_TYPE mech,
+ const struct sockaddr_alg **sa_ptr, int *md_size_ptr)
+{
+ const struct sockaddr_alg *sa;
+ int md_size;
+
+ switch (mech)
+ {
+#define E(MECH, NAME, SIZE) \
+ case CKM_##MECH: \
+ { \
+ static const struct sockaddr_alg addr = \
+ { .salg_family = AF_ALG, .salg_type = "hash", .salg_name = (NAME) }; \
+ \
+ sa = &addr; \
+ md_size = (SIZE); \
+ break; \
+ } \
+
+ E (MD5, "md5", 16);
+ E (SHA_1, "sha1", 20);
+ E (SHA224, "sha224", 28);
+ E (SHA256, "sha256", 32);
+ E (SHA384, "sha384", 48);
+ E (SHA512, "sha512", 64);
+#undef E
+ default:
+ g_return_val_if_reached (CKR_MECHANISM_INVALID);
+ }
+ *sa_ptr = sa;
+ *md_size_ptr = md_size;
+ return CKR_OK;
+}
+
+struct ncr_digest_session
+{
+ int fd;
+ int md_size; /* size_t semantically */
+ /* Debugging only */
+ enum { NDS_NEW, NDS_INITIALIZED, NDS_UPDATED, NDS_FINISHED } state;
+};
+
+CK_RV
+ncr_digest_alloc (struct ncr_digest_session **sess, CK_MECHANISM_TYPE mech)
+{
+ struct ncr_digest_session *s;
+ const struct sockaddr_alg *sa;
+ int top_fd;
+ CK_RV res;
+
+ g_return_val_if_fail (sess != NULL, CKR_ARGUMENTS_BAD);
+
+ s = malloc (sizeof (*s));
+ if (s == NULL)
+ return CKR_HOST_MEMORY;
+
+ res = digest_params_from_mech (mech, &sa, &s->md_size);
+ if (res != CKR_OK)
+ goto err_s;
+
+ top_fd = socket (AF_ALG, SOCK_SEQPACKET, 0);
+ if (top_fd == -1)
+ {
+ res = ckr_errno ();
+ goto err_s;
+ }
+ if (bind (top_fd, (struct sockaddr *)sa, sizeof (*sa)) != 0)
+ {
+ res = ckr_errno ();
+ goto err_top_fd;
+ }
+
+ s->fd = accept (top_fd, NULL, 0);
+ if (s->fd == -1)
+ {
+ res = ckr_errno ();
+ goto err_top_fd;
+ }
+ (void)close (top_fd);
+
+ s->state = NDS_NEW;
+ *sess = s;
+ return CKR_OK;
+
+ err_top_fd:
+ (void)close (top_fd);
+ err_s:
+ free (s);
+ return res;
+}
+
+CK_RV
+ncr_digest_free (struct ncr_digest_session *sess)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+
+ (void)close (sess->fd);
+ free (sess);
+ return CKR_OK;
+}
+
+CK_RV
+ncr_digest_clone (struct ncr_digest_session **clone,
+ struct ncr_digest_session *sess)
+{
+ struct ncr_digest_session *c;
+
+ g_return_val_if_fail (clone != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NDS_INITIALIZED
+ || sess->state == NDS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+
+ c = malloc (sizeof (*c));
+ if (c == NULL)
+ return CKR_HOST_MEMORY;
+
+ c->fd = accept (sess->fd, NULL, 0);
+ if (c->fd == -1)
+ {
+ free (c);
+ return ckr_errno ();
+ }
+ c->state = sess->state;
+ c->md_size = sess->md_size;
+ *clone = c;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_digest_init (struct ncr_digest_session *sess)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NDS_NEW || sess->state == NDS_FINISHED,
+ CKR_OPERATION_ACTIVE);
+ /* Nothing to do. */
+ sess->state = NDS_INITIALIZED;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_digest_update (struct ncr_digest_session *sess, const void *data,
+ size_t size)
+{
+ ssize_t res;
+
+ 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 (size <= SSIZE_MAX, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess->state == NDS_INITIALIZED
+ || sess->state == NDS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+
+ res = sendto (sess->fd, data, size, MSG_MORE, NULL, 0);
+ if (res == -1)
+ return ckr_errno ();
+ if (res != (ssize_t)size) /* "size" overflow verified above */
+ return CKR_GENERAL_ERROR; /* What? */
+
+ sess->state = NDS_UPDATED;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_digest_final (struct ncr_digest_session *sess, void *dest,
+ size_t *size_ptr)
+{
+ ssize_t res;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NDS_INITIALIZED
+ || sess->state == NDS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+ g_return_val_if_fail (size_ptr != NULL, CKR_ARGUMENTS_BAD);
+
+ if (dest == NULL)
+ {
+ *size_ptr = sess->md_size;
+ return CKR_OK;
+ }
+ if (*size_ptr < (size_t)sess->md_size)
+ {
+ *size_ptr = sess->md_size;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+ *size_ptr = sess->md_size;
+
+ res = write (sess->fd, "", 0);
+ if (res != -1)
+ res = read (sess->fd, dest, sess->md_size);
+ sess->state = NDS_FINISHED;
+ if (res == sess->md_size)
+ return CKR_OK;
+ if (res == -1)
+ return ckr_errno ();
+ return CKR_GENERAL_ERROR; /* What? */
+}
+
+CK_RV
+ncr_digest (struct ncr_digest_session *sess, void *dest, size_t *dest_size_ptr,
+ const void *data, size_t data_size)
+{
+ ssize_t res;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NDS_INITIALIZED,
+ CKR_OPERATION_NOT_INITIALIZED);
+ g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
+
+ if (dest == NULL)
+ {
+ *dest_size_ptr = sess->md_size;
+ return CKR_OK;
+ }
+ if (*dest_size_ptr < (size_t)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);
+ g_return_val_if_fail (data_size <= SSIZE_MAX, CKR_ARGUMENTS_BAD);
+
+ sess->state = NDS_FINISHED;
+
+ res = write (sess->fd, data, data_size);
+ if (res == (ssize_t)data_size) /* "data_size" overflow verified above */
+ {
+ res = read (sess->fd, dest, sess->md_size);
+ if (res == sess->md_size)
+ return CKR_OK;
+ }
+ if (res == -1)
+ return ckr_errno ();
+ return CKR_GENERAL_ERROR; /* What? */
+}
+
+CK_RV
+ncr_digest_standalone (CK_MECHANISM_TYPE mech, void *dest,
+ size_t *dest_size_ptr, const void *data,
+ size_t data_size)
+{
+ const struct sockaddr_alg *sa;
+ int top_fd, fd, md_size;
+ ssize_t res;
+ CK_RV ret;
+
+ g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
+
+ ret = digest_params_from_mech (mech, &sa, &md_size);
+ if (ret != CKR_OK)
+ return ret;
+
+ if (dest == NULL)
+ {
+ *dest_size_ptr = md_size;
+ return CKR_OK;
+ }
+ if (*dest_size_ptr < (size_t)md_size)
+ {
+ *dest_size_ptr = md_size;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+ *dest_size_ptr = md_size;
+
+ g_return_val_if_fail (data != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (data_size <= SSIZE_MAX, CKR_ARGUMENTS_BAD);
+
+ top_fd = socket (AF_ALG, SOCK_SEQPACKET, 0);
+ if (top_fd == -1)
+ return ckr_errno ();
+ if (bind (top_fd, (struct sockaddr *)sa, sizeof (*sa)) != 0)
+ goto err_top_fd;
+ fd = accept (top_fd, NULL, 0);
+ if (fd == -1)
+ goto err_top_fd;
+ (void)close (top_fd);
+
+ res = write (fd, data, data_size);
+ if (res == (ssize_t)data_size) /* "data_size" overflow verified above */
+ {
+ res = read (fd, dest, md_size);
+ if (res == md_size)
+ {
+ ret = CKR_OK;
+ goto end;
+ }
+ }
+ if (res == -1)
+ ret = ckr_errno ();
+ else
+ ret = CKR_GENERAL_ERROR; /* What? */
+
+ end:
+ close (fd);
+ return ret;
+
+ err_top_fd:
+ ret = ckr_errno ();
+ (void)close (top_fd);
+ return ret;
+}
+
+ /* Symmetric signature handling */
+
+#define MAX_HMAC_SIZE 64
+
+/* In the kernel, digests and HMAC are both .salg_type = "hash", but we need
+ to treat them differently: For digest sessions, we only need to keep the
+ slave file descriptor, but for HMAC we need the parent to be able to change
+ the key. */
+
+struct ncr_symm_signature_session
+{
+ int parent_fd, child_fd;
+ const struct sockaddr_alg *sa;
+ int md_size; /* size_t semantically */
+ bool signing;
+ /* Debugging only */
+ enum { NSSS_NEW, NSSS_INITIALIZED, NSSS_UPDATED, NSSS_FINISHED } state;
+};
+
+static CK_RV
+symm_signature_params_from_mech (struct ncr_symm_signature_session *sess,
+ CK_MECHANISM_TYPE mech)
+{
+ const struct sockaddr_alg *sa;
+ int md_size;
+
+ switch (mech)
+ {
+#define E(MECH, NAME, SIZE) \
+ case CKM_##MECH: \
+ { \
+ static const struct sockaddr_alg addr = \
+ { .salg_family = AF_ALG, .salg_type = "hash", .salg_name = (NAME) }; \
+ G_STATIC_ASSERT ((SIZE) <= MAX_HMAC_SIZE); \
+ \
+ sa = &addr; \
+ md_size = (SIZE); \
+ break; \
+ }
+ E (MD5_HMAC, "hmac(md5)", 16);
+ E (SHA_1_HMAC, "hmac(sha1)", 20);
+ E (SHA224_HMAC, "hmac(sha224)", 28);
+ E (SHA256_HMAC, "hmac(sha256)", 32);
+ E (SHA384_HMAC, "hmac(sha384)", 48);
+ E (SHA512_HMAC, "hmac(sha512)", 64);
+#undef E
+ default:
+ g_return_val_if_reached (CKR_MECHANISM_INVALID);
+ }
+ sess->sa = sa;
+ sess->md_size = md_size;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_symm_signature_alloc (struct ncr_symm_signature_session **sess,
+ CK_MECHANISM_TYPE mech)
+{
+ struct ncr_symm_signature_session *s;
+ CK_RV res;
+
+ g_return_val_if_fail (sess != NULL, CKR_ARGUMENTS_BAD);
+
+ s = malloc (sizeof (*s));
+ if (s == NULL)
+ return CKR_HOST_MEMORY;
+
+ res = symm_signature_params_from_mech (s, mech);
+ if (res != CKR_OK)
+ goto err_s;
+
+ s->parent_fd = socket (AF_ALG, SOCK_SEQPACKET, 0);
+ if (s->parent_fd == -1)
+ {
+ res = ckr_errno ();
+ goto err_s;
+ }
+ if (bind (s->parent_fd, (struct sockaddr *)s->sa, sizeof (*s->sa)) != 0)
+ {
+ res = ckr_errno ();
+ goto err_parent_fd;
+ }
+
+ s->child_fd = -1;
+ s->state = NSSS_NEW;
+ *sess = s;
+ return CKR_OK;
+
+ err_parent_fd:
+ (void)close (s->parent_fd);
+ err_s:
+ free (s);
+ return res;
+}
+
+CK_RV
+ncr_symm_signature_free (struct ncr_symm_signature_session *sess)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+
+ if (sess->child_fd != -1)
+ (void)close (sess->child_fd);
+ (void)close (sess->parent_fd);
+ free (sess);
+ return CKR_OK;
+}
+
+CK_RV
+ncr_symm_signature_clone (struct ncr_symm_signature_session **clone,
+ struct ncr_symm_signature_session *sess)
+{
+ struct ncr_symm_signature_session *c;
+ int new_sess_parent_fd;
+ CK_RV res;
+
+ g_return_val_if_fail (clone != NULL, CKR_ARGUMENTS_BAD);
+ 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);
+
+ c = malloc (sizeof (*c));
+ if (c == NULL)
+ return CKR_HOST_MEMORY;
+
+ /* This is a little complicated: parent_fd holds the "transform", which is
+ parametrized by the key. A mere accept () on child_fd would create two
+ sockets sharing a parent_fd, and reinitializing a session on one with a
+ different key would change the underlying key of the other.
+
+ Therefore, create an entirely new parent_fd for _both_ clones. The
+ "old" parent_fd will be implicitly referred to by child_fd of both clones,
+ but any session reinitialization will use the new parent_fd values. */
+ new_sess_parent_fd = socket (AF_ALG, SOCK_SEQPACKET, 0);
+ if (new_sess_parent_fd == -1)
+ {
+ res = ckr_errno ();
+ goto err_c;
+ }
+ if (bind (new_sess_parent_fd, (struct sockaddr *)sess->sa,
+ sizeof (*sess->sa)) != 0)
+ {
+ res = ckr_errno ();
+ goto err_new_sess_parent_fd;
+ }
+
+ c->parent_fd = socket (AF_ALG, SOCK_SEQPACKET, 0);
+ if (c->parent_fd == -1)
+ {
+ res = ckr_errno ();
+ goto err_new_sess_parent_fd;
+ }
+ if (bind (c->parent_fd, (struct sockaddr *)sess->sa, sizeof (*sess->sa)) != 0)
+ {
+ res = ckr_errno ();
+ goto err_c_parent_fd;
+ }
+
+ c->child_fd = accept (sess->child_fd, NULL, 0);
+ if (c->child_fd == -1)
+ {
+ res = ckr_errno ();
+ goto err_c_parent_fd;
+ }
+
+ (void)close (sess->parent_fd);
+ sess->parent_fd = new_sess_parent_fd;
+ c->state = sess->state;
+ c->sa = sess->sa;
+ c->md_size = sess->md_size;
+ c->signing = sess->signing;
+ *clone = c;
+ return CKR_OK;
+
+ err_c_parent_fd:
+ (void)close (c->parent_fd);
+ err_new_sess_parent_fd:
+ (void)close (new_sess_parent_fd);
+ err_c:
+ free (c);
+ return res;
+}
+
+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);
+ /* We need key->size to fit into socklen_t. There is no SOCKLEN_MAX, but
+ it is at least INT32_MAX, which is plenty. */
+ g_return_val_if_fail (key->size <= INT32_MAX, CKR_KEY_SIZE_RANGE);
+
+ /* This is not assured, but holds for supported mechanisms. */
+ g_return_val_if_fail (key->type == CKK_GENERIC_SECRET,
+ CKR_KEY_TYPE_INCONSISTENT);
+
+ if (setsockopt (sess->parent_fd, SOL_ALG, ALG_SET_KEY, key->value,
+ key->size) != 0)
+ return ckr_errno ();
+
+ sess->child_fd = accept (sess->parent_fd, NULL, 0);
+ if (sess->child_fd == -1)
+ return ckr_errno ();
+
+ 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)
+{
+ ssize_t res;
+
+ 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 (size <= SSIZE_MAX, 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);
+
+ res = sendto (sess->child_fd, data, size, MSG_MORE, NULL, 0);
+ if (res == -1)
+ return ckr_errno ();
+ if (res != (ssize_t)size) /* "size" overflow verified above */
+ return CKR_GENERAL_ERROR; /* What? */
+
+ 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;
+ CK_RV ret;
+
+ 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 < (size_t)sess->md_size)
+ {
+ *size_ptr = sess->md_size;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+ *size_ptr = sess->md_size;
+
+ res = write (sess->child_fd, "", 0);
+ if (res != -1)
+ res = read (sess->child_fd, dest, sess->md_size);
+ if (res == sess->md_size)
+ ret = CKR_OK;
+ else if (res == -1)
+ ret = ckr_errno ();
+ else
+ ret = CKR_GENERAL_ERROR; /* What? */
+
+ (void)close (sess->child_fd);
+ sess->child_fd = -1;
+ sess->state = NSSS_FINISHED;
+ return ret;
+}
+
+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;
+ CK_RV ret;
+
+ 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 < (size_t)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);
+ g_return_val_if_fail (data_size <= SSIZE_MAX, CKR_ARGUMENTS_BAD);
+
+ res = write (sess->child_fd, data, data_size);
+ if (res == (ssize_t)data_size) /* "data_size" overflow verified above */
+ {
+ res = read (sess->child_fd, dest, sess->md_size);
+ if (res == sess->md_size)
+ {
+ ret = CKR_OK;
+ goto end;
+ }
+ }
+ if (res == -1)
+ ret = ckr_errno ();
+ else
+ ret = CKR_GENERAL_ERROR; /* What? */
+
+ end:
+ (void)close (sess->child_fd);
+ sess->child_fd = -1;
+ sess->state = NSSS_FINISHED;
+ return ret;
+}
+
+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[MAX_HMAC_SIZE];
+ int res;
+ CK_RV ret;
+
+ 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 = write (sess->child_fd, "", 0);
+ if (res != -1)
+ res = read (sess->child_fd, buf, sess->md_size);
+ if (res == sess->md_size)
+ {
+ if (size != (size_t)sess->md_size)
+ ret = CKR_SIGNATURE_LEN_RANGE;
+ else if (memcmp (signature, buf, size) != 0)
+ ret = CKR_SIGNATURE_INVALID;
+ else
+ ret = CKR_OK;
+ }
+ else if (res == -1)
+ ret = ckr_errno ();
+ else
+ ret = CKR_GENERAL_ERROR; /* What? */
+
+ (void)close (sess->child_fd);
+ sess->child_fd = -1;
+ sess->state = NSSS_FINISHED;
+ return ret;
+}
+
+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[MAX_HMAC_SIZE];
+ int res;
+ CK_RV ret;
+
+ 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 (data_size <= SSIZE_MAX, 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 = write (sess->child_fd, data, data_size);
+ if (res == (ssize_t)data_size) /* "data_size" overflow verified above */
+ {
+ res = read (sess->child_fd, buf, sess->md_size);
+ if (res == sess->md_size)
+ {
+ if (signature_size != (size_t)sess->md_size)
+ ret = CKR_SIGNATURE_LEN_RANGE;
+ else if (memcmp (signature, buf, signature_size) != 0)
+ ret = CKR_SIGNATURE_INVALID;
+ else
+ ret = CKR_OK;
+ goto end;
+ }
+ }
+ if (res == -1)
+ ret = ckr_errno ();
+ else
+ ret = CKR_GENERAL_ERROR; /* What? */
+ end:
+ (void)close (sess->child_fd);
+ sess->child_fd = -1;
+ sess->state = NSSS_FINISHED;
+ return ret;
+}
+
+ /* Symmetric encryption */
+
+static CK_RV
+cipher_params_from_mech (CK_MECHANISM_TYPE mech,
+ const struct sockaddr_alg **sa_ptr)
+{
+ const struct sockaddr_alg *sa;
+
+ switch (mech)
+ {
+#define E(MECH, NAME) \
+ case CKM_##MECH: \
+ { \
+ static const struct sockaddr_alg addr = \
+ { \
+ .salg_family = AF_ALG, .salg_type = "skcipher", \
+ .salg_name = (NAME) \
+ }; \
+ \
+ sa = &addr; \
+ break; \
+ } \
+
+ E(AES_ECB, "ecb(aes)");
+ E(AES_CBC, "cbc(aes)");
+ E(DES3_ECB, "ecb(des3_ede)");
+ E(DES3_CBC, "cbc(des3_ede)");
+
+ default:
+ g_return_val_if_reached (CKR_MECHANISM_INVALID);
+ }
+ *sa_ptr = sa;
+ return CKR_OK;
+}
+
+struct ncr_symm_cipher_session
+{
+ int parent_fd, child_fd;
+ CK_MECHANISM_TYPE mech;
+ bool encrypting;
+ /* Debugging only */
+ enum { NSCS_NEW, NSCS_INITIALIZED, NSCS_UPDATED, NSCS_FINISHED } state;
+};
+
+CK_RV
+ncr_symm_cipher_alloc (struct ncr_symm_cipher_session **sess,
+ CK_MECHANISM_TYPE mech)
+{
+ struct ncr_symm_cipher_session *s;
+ const struct sockaddr_alg *sa;
+ CK_RV res;
+
+ g_return_val_if_fail (sess != NULL, CKR_ARGUMENTS_BAD);
+
+ res = cipher_params_from_mech (mech, &sa);
+ if (res != CKR_OK)
+ return res;
+
+ s = malloc (sizeof (*s));
+ if (s == NULL)
+ return CKR_HOST_MEMORY;
+
+ s->parent_fd = socket (AF_ALG, SOCK_SEQPACKET, 0);
+ if (s->parent_fd == -1)
+ {
+ res = ckr_errno ();
+ goto err_s;
+ }
+ if (bind (s->parent_fd, (struct sockaddr *)sa, sizeof (*sa)) != 0)
+ {
+ res = ckr_errno ();
+ goto err_parent_fd;
+ }
+
+ s->child_fd = -1;
+ s->mech = mech;
+ s->state = NSCS_NEW;
+ *sess = s;
+ return CKR_OK;
+
+ err_parent_fd:
+ (void)close (s->parent_fd);
+ err_s:
+ free (s);
+ return res;
+}
+
+CK_RV
+ncr_symm_cipher_free (struct ncr_symm_cipher_session *sess)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+
+ if (sess->child_fd != -1)
+ (void)close (sess->child_fd);
+ (void)close (sess->parent_fd);
+ free (sess);
+ return CKR_OK;
+}
+
+CK_RV
+ncr_symm_cipher_change_iv (struct ncr_symm_cipher_session *sess, const void *iv,
+ size_t iv_size)
+{
+ uint8_t cmsg_buf[4096]; /* The size is arbitrary. */
+ size_t cmsg_space;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct af_alg_iv iv_header;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSCS_INITIALIZED
+ || sess->state == NSCS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+ g_return_val_if_fail (iv != NULL || iv_size == 0, CKR_ARGUMENTS_BAD);
+ /* Implicitly restricts iv_size so that it fits into iv_header.ivlen */
+ cmsg_space = CMSG_SPACE (sizeof (iv_header) + iv_size);
+ g_return_val_if_fail (cmsg_space > iv_size && cmsg_space <= sizeof (cmsg_buf),
+ CKR_MECHANISM_PARAM_INVALID);
+
+ /* The IV might be left pending until the first actual data arrives, saving
+ one system call, but we prefer reporting invalid IV immediately. */
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = NULL;
+ msg.msg_iovlen = 0;
+ msg.msg_control = cmsg_buf;
+ msg.msg_controllen = cmsg_space;
+
+ iv_header.ivlen = iv_size;
+ cmsg = CMSG_FIRSTHDR (&msg);
+ g_return_val_if_fail (cmsg != NULL, CKR_GENERAL_ERROR); /* What? */
+ cmsg->cmsg_len = CMSG_LEN (sizeof (iv_header) + iv_size);
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_IV;
+ memcpy (CMSG_DATA (cmsg), &iv_header, sizeof (iv_header));
+ memcpy (CMSG_DATA (cmsg) + sizeof (iv_header), iv, iv_size);
+
+ if (sendmsg (sess->child_fd, &msg, MSG_MORE) != 0)
+ return ckr_errno ();
+
+ return CKR_OK;
+}
+
+static CK_RV
+symm_cipher_init (struct ncr_symm_cipher_session *sess, bool encrypt,
+ struct ncr_symm_key *key, const void *param,
+ size_t param_size)
+{
+ uint8_t cmsg_buf[4096]; /* The size is arbitrary. */
+ size_t cmsg_space;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct af_alg_iv iv;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSCS_NEW || sess->state == NSCS_FINISHED,
+ CKR_OPERATION_ACTIVE);
+ g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID);
+ /* We need key->size to fit into socklen_t. There is no SOCKLEN_MAX, but
+ it is at least INT32_MAX, which is plenty. */
+ g_return_val_if_fail (key->size <= INT32_MAX, CKR_KEY_SIZE_RANGE);
+ g_return_val_if_fail (param != NULL || param_size == 0, CKR_ARGUMENTS_BAD);
+ /* Implicitly restricts param_size so that it fits into iv.ivlen */
+ cmsg_space = CMSG_SPACE (sizeof (iv) + param_size);
+ g_return_val_if_fail (cmsg_space > param_size
+ && cmsg_space <= sizeof (cmsg_buf),
+ CKR_MECHANISM_PARAM_INVALID);
+
+ switch (sess->mech)
+ {
+ case CKM_AES_ECB:
+ case CKM_AES_CBC:
+ g_return_val_if_fail (key->type == CKK_AES, CKR_KEY_TYPE_INCONSISTENT);
+ break;
+
+ case CKM_DES3_ECB:
+ case CKM_DES3_CBC:
+ g_return_val_if_fail (key->type == CKK_DES3, CKR_KEY_TYPE_INCONSISTENT);
+ break;
+
+ default:
+ g_return_val_if_reached (CKR_MECHANISM_INVALID);
+ }
+
+ if (setsockopt (sess->parent_fd, SOL_ALG, ALG_SET_KEY, key->value,
+ key->size) != 0)
+ return ckr_errno ();
+
+ sess->child_fd = accept (sess->parent_fd, NULL, 0);
+ if (sess->child_fd == -1)
+ return ckr_errno ();
+
+ /* The IV might be left pending until the first actual data arrives, saving
+ one system call, but we prefer reporting invalid IV immediately. */
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = NULL;
+ msg.msg_iovlen = 0;
+ msg.msg_control = cmsg_buf;
+ msg.msg_controllen = cmsg_space;
+
+ iv.ivlen = param_size;
+ cmsg = CMSG_FIRSTHDR (&msg);
+ g_return_val_if_fail (cmsg != NULL, CKR_GENERAL_ERROR); /* What? */
+ cmsg->cmsg_len = CMSG_LEN (sizeof (iv) + param_size);
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_IV;
+ memcpy (CMSG_DATA (cmsg), &iv, sizeof (iv));
+ memcpy (CMSG_DATA (cmsg) + sizeof (iv), param, param_size);
+
+ if (sendmsg (sess->child_fd, &msg, MSG_MORE) != 0)
+ {
+ CK_RV res;
+
+ res = ckr_errno ();
+ (void)close (sess->child_fd);
+ sess->child_fd = -1;
+ return res;
+ }
+
+ sess->encrypting = encrypt;
+ sess->state = NSCS_INITIALIZED;
+ return CKR_OK;
+}
+
+static CK_RV
+symm_cipher_update (struct ncr_symm_cipher_session *sess, bool encrypt,
+ void *dest, size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ size_t done;
+ uint32_t alg_op;
+ uint8_t cmsg_buf[CMSG_SPACE (sizeof (alg_op))];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (src_size <= SSIZE_MAX, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess->state == NSCS_INITIALIZED
+ || sess->state == NSCS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+ g_return_val_if_fail (sess->encrypting == encrypt,
+ CKR_OPERATION_NOT_INITIALIZED);
+
+ if (dest == NULL)
+ {
+ *dest_size_ptr = src_size;
+ return CKR_OK;
+ }
+ if (*dest_size_ptr < src_size)
+ {
+ *dest_size_ptr = src_size;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ g_return_val_if_fail (src != NULL || src_size == 0, CKR_ARGUMENTS_BAD);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsg_buf;
+ msg.msg_controllen = sizeof (cmsg_buf);
+
+ alg_op = sess->encrypting ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
+ cmsg = CMSG_FIRSTHDR (&msg);
+ cmsg->cmsg_len = CMSG_LEN (sizeof (alg_op));
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_OP;
+ memcpy (CMSG_DATA (cmsg), &alg_op, sizeof (alg_op));
+
+ done = 0;
+ while (done < src_size)
+ {
+ ssize_t run, ret;
+
+ iov.iov_base = (uint8_t *)src + done;
+ iov.iov_len = src_size - done;
+ run = sendmsg (sess->child_fd, &msg, MSG_DONTWAIT | MSG_MORE);
+ if (run < 0)
+ /* The IV may have already been changed if some partial data was
+ previously accepted, too bad. */
+ return ckr_errno ();
+ g_return_val_if_fail (run != 0, CKR_GENERAL_ERROR); /* What? */
+ ret = recvfrom (sess->child_fd, (uint8_t *)dest + done, run, MSG_DONTWAIT,
+ NULL, 0);
+ if (ret < 0)
+ return ckr_errno ();
+ g_return_val_if_fail (ret == run, CKR_GENERAL_ERROR);
+ done += run;
+ }
+
+ *dest_size_ptr = src_size;
+ sess->state = NSCS_UPDATED;
+ return CKR_OK;
+}
+
+/* EVP_CipherUpdate + EVP_CipherFinal_ex */
+static CK_RV
+do_symm_cipher_update_final (struct ncr_symm_cipher_session *sess,
+ bool encrypt, void *dest, size_t *dest_size_ptr,
+ const void *src, size_t src_size)
+{
+ size_t done;
+ uint32_t alg_op;
+ uint8_t cmsg_buf[CMSG_SPACE (sizeof (alg_op))];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ CK_RV res;
+
+ /* The caller has verified session and its state. */
+ g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (src_size <= SSIZE_MAX, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess->encrypting == encrypt,
+ CKR_OPERATION_NOT_INITIALIZED);
+
+ if (dest == NULL)
+ {
+ *dest_size_ptr = src_size;
+ return CKR_OK;
+ }
+ if (*dest_size_ptr < src_size)
+ {
+ *dest_size_ptr = src_size;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ g_return_val_if_fail (src != NULL || src_size == 0, CKR_ARGUMENTS_BAD);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsg_buf;
+ msg.msg_controllen = sizeof (cmsg_buf);
+
+ alg_op = sess->encrypting ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
+ cmsg = CMSG_FIRSTHDR (&msg);
+ cmsg->cmsg_len = CMSG_LEN (sizeof (alg_op));
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_OP;
+ memcpy (CMSG_DATA (cmsg), &alg_op, sizeof (alg_op));
+
+ done = 0;
+ while (done < src_size)
+ {
+ ssize_t run, ret;
+
+ iov.iov_base = (uint8_t *)src + done;
+ iov.iov_len = src_size - done;
+ run = sendmsg (sess->child_fd, &msg, MSG_DONTWAIT /* no MSG_MORE */);
+ if (run < 0)
+ {
+ /* The IV may have already been changed if some partial data was
+ previously accepted, too bad. */
+ res = ckr_errno ();
+ goto err;
+ }
+ g_return_val_if_fail (run != 0, CKR_GENERAL_ERROR); /* What? */
+ ret = recvfrom (sess->child_fd, (uint8_t *)dest + done, run, MSG_DONTWAIT,
+ NULL, 0);
+ if (ret < 0)
+ {
+ res = ckr_errno ();
+ goto err;
+ }
+ g_return_val_if_fail (ret == run, CKR_GENERAL_ERROR);
+ done += run;
+ }
+
+ *dest_size_ptr = src_size;
+ res = CKR_OK;
+ err:
+ (void)close (sess->child_fd);
+ sess->child_fd = -1;
+ sess->state = NSCS_FINISHED;
+ return res;
+}
+
+static CK_RV
+symm_cipher_final (struct ncr_symm_cipher_session *sess, bool encrypt,
+ void *dest, size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSCS_INITIALIZED
+ || sess->state == NSCS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+
+ return do_symm_cipher_update_final (sess, encrypt, dest, dest_size_ptr, src,
+ src_size);
+}
+
+static CK_RV
+symm_cipher (struct ncr_symm_cipher_session *sess, bool encrypt, void *dest,
+ size_t *dest_size_ptr, const void *src, size_t src_size)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSCS_INITIALIZED,
+ CKR_OPERATION_NOT_INITIALIZED);
+
+ return do_symm_cipher_update_final (sess, encrypt, dest, dest_size_ptr, src,
+ src_size);
+}
+
+CK_RV
+ncr_symm_cipher_encrypt_init (struct ncr_symm_cipher_session *sess,
+ struct ncr_symm_key *key, const void *param,
+ size_t param_size)
+{
+ return symm_cipher_init (sess, true, key, param, param_size);
+}
+
+CK_RV
+ncr_symm_cipher_encrypt_update (struct ncr_symm_cipher_session *sess,
+ void *dest, size_t *dest_size_ptr,
+ const void *src, size_t src_size)
+{
+ return symm_cipher_update (sess, true, dest, dest_size_ptr, src, src_size);
+}
+
+CK_RV
+ncr_symm_cipher_encrypt_final (struct ncr_symm_cipher_session *sess, void *dest,
+ size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ return symm_cipher_final (sess, true, dest, dest_size_ptr, src, src_size);
+}
+
+CK_RV
+ncr_symm_cipher_encrypt (struct ncr_symm_cipher_session *sess, void *dest,
+ size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ return symm_cipher (sess, true, dest, dest_size_ptr, src, src_size);
+}
+
+CK_RV
+ncr_symm_cipher_decrypt_init (struct ncr_symm_cipher_session *sess,
+ struct ncr_symm_key *key, const void *param,
+ size_t param_size)
+{
+ return symm_cipher_init (sess, false, key, param, param_size);
+}
+
+CK_RV
+ncr_symm_cipher_decrypt_update (struct ncr_symm_cipher_session *sess,
+ void *dest, size_t *dest_size_ptr,
+ const void *src, size_t src_size)
+{
+ return symm_cipher_update (sess, false, dest, dest_size_ptr, src, src_size);
+}
+
+CK_RV
+ncr_symm_cipher_decrypt_final (struct ncr_symm_cipher_session *sess, void *dest,
+ size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ return symm_cipher_final (sess, false, dest, dest_size_ptr, src, src_size);
+}
+
+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)
+{
+ return symm_cipher (sess, false, dest, dest_size_ptr, src, src_size);
+}
diff --git a/lib/ncrypto_local.c b/lib/ncrypto_local.c
index c4af43a..5a138fc 100644
--- a/lib/ncrypto_local.c
+++ b/lib/ncrypto_local.c
@@ -31,8 +31,6 @@ Red Hat author: Miloslav Trmač <mitr@redhat.com> */
#include <string.h>
#include <glib.h>
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <ncrypto/ncrypto.h>
@@ -237,810 +235,3 @@ ncr_symm_key_destroy (struct ncr_symm_key *key)
free (key);
return CKR_OK;
}
-
- /* Digest handling */
-
-static const EVP_MD *
-digest_evp_from_mech (CK_MECHANISM_TYPE mech)
-{
- switch (mech)
- {
-#define E(M, E) \
- case CKM_##M: \
- 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_digest_session
-{
- EVP_MD_CTX ctx;
- const EVP_MD *md;
- size_t md_size;
- /* Debugging only */
- enum { NDS_NEW, NDS_INITIALIZED, NDS_UPDATED, NDS_FINISHED } state;
-};
-
-CK_RV
-ncr_digest_alloc (struct ncr_digest_session **sess, CK_MECHANISM_TYPE mech)
-{
- struct ncr_digest_session *s;
- const EVP_MD *md;
-
- g_return_val_if_fail (sess != NULL, CKR_ARGUMENTS_BAD);
-
- md = digest_evp_from_mech (mech);
- if (md == NULL)
- return CKR_MECHANISM_INVALID;
-
- s = malloc (sizeof (*s));
- if (s == NULL)
- return CKR_HOST_MEMORY;
-
- EVP_MD_CTX_init (&s->ctx);
- s->state = NDS_NEW;
- s->md = md;
- s->md_size = EVP_MD_size (md);
- *sess = s;
- return CKR_OK;
-}
-
-CK_RV
-ncr_digest_free (struct ncr_digest_session *sess)
-{
- g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
-
- EVP_MD_CTX_cleanup (&sess->ctx);
- free (sess);
- return CKR_OK;
-}
-
-CK_RV
-ncr_digest_clone (struct ncr_digest_session **clone,
- struct ncr_digest_session *sess)
-{
- struct ncr_digest_session *c;
-
- g_return_val_if_fail (clone != NULL, CKR_ARGUMENTS_BAD);
- g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
- g_return_val_if_fail (sess->state == NDS_INITIALIZED
- || sess->state == NDS_UPDATED,
- CKR_OPERATION_NOT_INITIALIZED);
-
- c = malloc (sizeof (*c));
- if (c == NULL)
- return CKR_HOST_MEMORY;
-
- EVP_MD_CTX_init (&c->ctx);
- if (EVP_MD_CTX_copy_ex (&c->ctx, &sess->ctx) == 0)
- {
- free (c);
- return ckr_openssl ();
- }
- c->state = sess->state;
- c->md = sess->md;
- c->md_size = sess->md_size;
- *clone = c;
- return CKR_OK;
-}
-
-CK_RV
-ncr_digest_init (struct ncr_digest_session *sess)
-{
- g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
- g_return_val_if_fail (sess->state == NDS_NEW || sess->state == NDS_FINISHED,
- CKR_OPERATION_ACTIVE);
-
- if (EVP_DigestInit_ex (&sess->ctx, sess->md, NULL) == 0)
- return ckr_openssl ();
-
- sess->state = NDS_INITIALIZED;
- return CKR_OK;
-}
-
-CK_RV
-ncr_digest_update (struct ncr_digest_session *sess, 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 == NDS_INITIALIZED
- || sess->state == NDS_UPDATED,
- CKR_OPERATION_NOT_INITIALIZED);
-
- if (EVP_DigestUpdate (&sess->ctx, data, size) == 0)
- return ckr_openssl ();
-
- sess->state = NDS_UPDATED;
- return CKR_OK;
-}
-
-CK_RV
-ncr_digest_final (struct ncr_digest_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 == NDS_INITIALIZED
- || sess->state == NDS_UPDATED,
- CKR_OPERATION_NOT_INITIALIZED);
- g_return_val_if_fail (size_ptr != NULL, CKR_ARGUMENTS_BAD);
-
- 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;
-
- res = EVP_DigestFinal_ex (&sess->ctx, dest, NULL);
- sess->state = NDS_FINISHED;
- return res ? CKR_OK : ckr_openssl ();
-}
-
-CK_RV
-ncr_digest (struct ncr_digest_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 == NDS_INITIALIZED,
- CKR_OPERATION_NOT_INITIALIZED);
- g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
-
- 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 = (EVP_DigestUpdate (&sess->ctx, data, data_size) != 0
- && EVP_DigestFinal_ex (&sess->ctx, dest, NULL) != 0);
- sess->state = NDS_FINISHED;
- return res ? CKR_OK : ckr_openssl ();
-}
-
-CK_RV
-ncr_digest_standalone (CK_MECHANISM_TYPE mech, void *dest,
- size_t *dest_size_ptr, const void *data,
- size_t data_size)
-{
- const EVP_MD *md;
- size_t md_size;
-
- g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
-
- md = digest_evp_from_mech (mech);
- if (md == NULL)
- return CKR_MECHANISM_INVALID;
-
- md_size = EVP_MD_size (md);
- if (dest == NULL)
- {
- *dest_size_ptr = md_size;
- return CKR_OK;
- }
- if (*dest_size_ptr < md_size)
- {
- *dest_size_ptr = md_size;
- return CKR_BUFFER_TOO_SMALL;
- }
- *dest_size_ptr = md_size;
-
- g_return_val_if_fail (data != NULL, CKR_ARGUMENTS_BAD);
-
- return EVP_Digest (data, data_size, dest, NULL, md, NULL) != 0
- ? CKR_OK : ckr_openssl ();
-}
-
- /* Symmetric encryption */
-
-struct ncr_symm_cipher_session
-{
- EVP_CIPHER_CTX ctx;
- CK_MECHANISM_TYPE mech;
- bool encrypting;
- /* Debugging only */
- enum { NSCS_NEW, NSCS_INITIALIZED, NSCS_UPDATED, NSCS_FINISHED } state;
-};
-
-CK_RV
-ncr_symm_cipher_alloc (struct ncr_symm_cipher_session **sess,
- CK_MECHANISM_TYPE mech)
-{
- struct ncr_symm_cipher_session *s;
-
- g_return_val_if_fail (sess != NULL, CKR_ARGUMENTS_BAD);
- /* FIXME? Validate "mech" */
-
- s = malloc (sizeof (*s));
- if (s == NULL)
- return CKR_HOST_MEMORY;
-
- EVP_CIPHER_CTX_init (&s->ctx);
- s->mech = mech;
- s->state = NSCS_NEW;
- *sess = s;
- return CKR_OK;
-}
-
-CK_RV
-ncr_symm_cipher_free (struct ncr_symm_cipher_session *sess)
-{
- g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
-
- EVP_CIPHER_CTX_cleanup (&sess->ctx);
- free (sess);
- return CKR_OK;
-}
-
-CK_RV
-ncr_symm_cipher_change_iv (struct ncr_symm_cipher_session *sess, const void *iv,
- size_t iv_size)
-{
- g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
- g_return_val_if_fail (sess->state == NSCS_INITIALIZED
- || sess->state == NSCS_UPDATED,
- CKR_OPERATION_NOT_INITIALIZED);
- g_return_val_if_fail (iv != NULL || iv_size == 0, CKR_ARGUMENTS_BAD);
-
- g_return_val_if_fail (iv_size
- == (unsigned)EVP_CIPHER_CTX_iv_length (&sess->ctx),
- CKR_MECHANISM_PARAM_INVALID);
- g_assert (iv_size <= sizeof (sess->ctx.oiv)
- && iv_size <= sizeof (sess->ctx.iv));
-
- memcpy (sess->ctx.oiv, iv, iv_size);
- memcpy (sess->ctx.iv, iv, iv_size);
- return CKR_OK;
-}
-
-static CK_RV
-symm_cipher_init (struct ncr_symm_cipher_session *sess, bool encrypt,
- struct ncr_symm_key *key, const void *param,
- size_t param_size)
-{
- const EVP_CIPHER *type;
-
- g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
- g_return_val_if_fail (sess->state == NSCS_NEW || sess->state == NSCS_FINISHED,
- CKR_OPERATION_ACTIVE);
- g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID);
- g_return_val_if_fail (param != NULL || param_size == 0, CKR_ARGUMENTS_BAD);
-
- switch (sess->mech)
- {
-#define AES_SWITCH(MODE) \
- switch (key->size) \
- { \
- AES_ENTRY (MODE, 128); \
- AES_ENTRY (MODE, 192); \
- AES_ENTRY (MODE, 256); \
- default: \
- g_return_val_if_reached (CKR_KEY_SIZE_RANGE); \
- }
-#define AES_ENTRY(MODE, SIZE) \
- case (SIZE) / 8: \
- type = EVP_aes_##SIZE##_##MODE (); \
- break;
-
- case CKM_AES_ECB:
- g_return_val_if_fail (key->type == CKK_AES, CKR_KEY_TYPE_INCONSISTENT);
- g_return_val_if_fail (param_size == 0, CKR_MECHANISM_PARAM_INVALID);
- AES_SWITCH (ecb);
- break;
-
- case CKM_AES_CBC:
- g_return_val_if_fail (key->type == CKK_AES, CKR_KEY_TYPE_INCONSISTENT);
- g_return_val_if_fail (param_size == 16, CKR_MECHANISM_PARAM_INVALID);
- AES_SWITCH (cbc);
- break;
-#undef AES_ENTRY
-
- case CKM_DES3_ECB:
- g_return_val_if_fail (key->type == CKK_DES3, CKR_KEY_TYPE_INCONSISTENT);
- g_return_val_if_fail (key->size == 24, CKR_KEY_SIZE_RANGE);
- g_return_val_if_fail (param_size == 0, CKR_MECHANISM_PARAM_INVALID);
- type = EVP_des_ede3 ();
- break;
-
- case CKM_DES3_CBC:
- g_return_val_if_fail (key->type == CKK_DES3, CKR_KEY_TYPE_INCONSISTENT);
- g_return_val_if_fail (key->size == 24, CKR_KEY_SIZE_RANGE);
- g_return_val_if_fail (param_size == 8, CKR_MECHANISM_PARAM_INVALID);
- type = EVP_des_ede3_cbc ();
- break;
-
- default:
- g_return_val_if_reached (CKR_MECHANISM_INVALID);
- }
-
- if (EVP_CipherInit_ex (&sess->ctx, type, NULL, key->value,
- param_size != 0 ? param : NULL, encrypt ? 1 : 0) == 0)
- return ckr_openssl ();
- if (EVP_CIPHER_CTX_set_padding (&sess->ctx, 0) == 0)
- return ckr_openssl ();
-
- sess->encrypting = encrypt;
- sess->state = NSCS_INITIALIZED;
- return CKR_OK;
-}
-
-static CK_RV
-symm_cipher_update (struct ncr_symm_cipher_session *sess, bool encrypt,
- void *dest, size_t *dest_size_ptr, const void *src,
- size_t src_size)
-{
- int outl;
-
- g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
- g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
- g_return_val_if_fail (sess->state == NSCS_INITIALIZED
- || sess->state == NSCS_UPDATED,
- CKR_OPERATION_NOT_INITIALIZED);
- g_return_val_if_fail (sess->encrypting == encrypt,
- CKR_OPERATION_NOT_INITIALIZED);
-
- if (dest == NULL)
- {
- *dest_size_ptr = src_size;
- return CKR_OK;
- }
- if (*dest_size_ptr < src_size) /* FIXME? this does not handle partial data */
- {
- *dest_size_ptr = src_size;
- return CKR_BUFFER_TOO_SMALL;
- }
-
- g_return_val_if_fail (src != NULL || src_size == 0, CKR_ARGUMENTS_BAD);
-
- if (EVP_CipherUpdate (&sess->ctx, dest, &outl, src, src_size) == 0)
- return ckr_openssl ();
-
- *dest_size_ptr = outl;
- sess->state = NSCS_UPDATED;
- return CKR_OK;
-}
-
-/* EVP_CipherUpdate + EVP_CipherFinal_ex */
-static CK_RV
-do_symm_cipher_update_final (struct ncr_symm_cipher_session *sess,
- bool encrypt, void *dest, size_t *dest_size_ptr,
- const void *src, size_t src_size)
-{
- int outl;
- size_t dest_size;
-
- /* The caller has verified session and its state. */
- g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
- g_return_val_if_fail (sess->encrypting == encrypt,
- CKR_OPERATION_NOT_INITIALIZED);
-
- if (dest == NULL)
- {
- *dest_size_ptr = src_size;
- return CKR_OK;
- }
- if (*dest_size_ptr < src_size)
- {
- *dest_size_ptr = src_size;
- return CKR_BUFFER_TOO_SMALL;
- }
-
- g_return_val_if_fail (src != NULL || src_size == 0, CKR_ARGUMENTS_BAD);
-
- if (EVP_CipherUpdate (&sess->ctx, dest, &outl, src, src_size) == 0)
- {
- sess->state = NSCS_FINISHED;
- return ckr_openssl ();
- }
-
- dest_size = outl;
-
- if (EVP_CipherFinal_ex (&sess->ctx, (uint8_t *)dest + outl, &outl) == 0)
- {
- sess->state = NSCS_FINISHED;
- return ckr_openssl ();
- }
-
- *dest_size_ptr = dest_size + outl;
-
- sess->state = NSCS_FINISHED;
- return CKR_OK;
-}
-
-static CK_RV
-symm_cipher_final (struct ncr_symm_cipher_session *sess, bool encrypt,
- void *dest, size_t *dest_size_ptr, const void *src,
- size_t src_size)
-{
- g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
- g_return_val_if_fail (sess->state == NSCS_INITIALIZED
- || sess->state == NSCS_UPDATED,
- CKR_OPERATION_NOT_INITIALIZED);
-
- return do_symm_cipher_update_final (sess, encrypt, dest, dest_size_ptr, src,
- src_size);
-}
-
-static CK_RV
-symm_cipher (struct ncr_symm_cipher_session *sess, bool encrypt, void *dest,
- size_t *dest_size_ptr, const void *src, size_t src_size)
-{
- g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
- g_return_val_if_fail (sess->state == NSCS_INITIALIZED,
- CKR_OPERATION_NOT_INITIALIZED);
-
- return do_symm_cipher_update_final (sess, encrypt, dest, dest_size_ptr, src,
- src_size);
-}
-
-CK_RV
-ncr_symm_cipher_encrypt_init (struct ncr_symm_cipher_session *sess,
- struct ncr_symm_key *key, const void *param,
- size_t param_size)
-{
- return symm_cipher_init (sess, true, key, param, param_size);
-}
-
-CK_RV
-ncr_symm_cipher_encrypt_update (struct ncr_symm_cipher_session *sess,
- void *dest, size_t *dest_size_ptr,
- const void *src, size_t src_size)
-{
- return symm_cipher_update (sess, true, dest, dest_size_ptr, src, src_size);
-}
-
-CK_RV
-ncr_symm_cipher_encrypt_final (struct ncr_symm_cipher_session *sess, void *dest,
- size_t *dest_size_ptr, const void *src,
- size_t src_size)
-{
- return symm_cipher_final (sess, true, dest, dest_size_ptr, src, src_size);
-}
-
-CK_RV
-ncr_symm_cipher_encrypt (struct ncr_symm_cipher_session *sess, void *dest,
- size_t *dest_size_ptr, const void *src,
- size_t src_size)
-{
- return symm_cipher (sess, true, dest, dest_size_ptr, src, src_size);
-}
-
-CK_RV
-ncr_symm_cipher_decrypt_init (struct ncr_symm_cipher_session *sess,
- struct ncr_symm_key *key, const void *param,
- size_t param_size)
-{
- return symm_cipher_init (sess, false, key, param, param_size);
-}
-
-CK_RV
-ncr_symm_cipher_decrypt_update (struct ncr_symm_cipher_session *sess,
- void *dest, size_t *dest_size_ptr,
- const void *src, size_t src_size)
-{
- return symm_cipher_update (sess, false, dest, dest_size_ptr, src, src_size);
-}
-
-CK_RV
-ncr_symm_cipher_decrypt_final (struct ncr_symm_cipher_session *sess, void *dest,
- size_t *dest_size_ptr, const void *src,
- size_t src_size)
-{
- return symm_cipher_final (sess, false, dest, dest_size_ptr, src, src_size);
-}
-
-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)
-{
- 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;
-}
-
-CK_RV
-ncr_symm_signature_clone (struct ncr_symm_signature_session **clone,
- struct ncr_symm_signature_session *sess)
-{
- struct ncr_symm_signature_session *c;
-
- g_return_val_if_fail (clone != NULL, CKR_ARGUMENTS_BAD);
- 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);
-
- c = malloc (sizeof (*c));
- if (c == NULL)
- return CKR_HOST_MEMORY;
-
- /* HMAC_CTX_copy is undocumented, and seems not to need MD_CTX_init, but
- openssl internally calls HMAC_CTX_init before HMAC_CTX_copy, so we do as
- well. */
- HMAC_CTX_init (&c->ctx);
- if (HMAC_CTX_copy (&c->ctx, &sess->ctx) == 0)
- {
- free (c);
- return ckr_openssl ();
- }
- c->state = sess->state;
- c->md = sess->md;
- c->md_size = sess->md_size;
- c->signing = sess->signing;
- *clone = c;
- 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;
-
- 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;
-}