aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2010-11-08 10:59:54 +0100
committerMartin Willi <martin@revosec.ch>2010-12-20 09:52:02 +0100
commit1b5de7ce3bddedab12703c578b7c8fe90bea116e (patch)
treea96ebfe4a051c8cc5936fbbdce79285b7e376f5e
parenta5c973b9559f03ab036caa076fa119260f1d0ceb (diff)
downloadstrongswan-1b5de7ce3bddedab12703c578b7c8fe90bea116e.tar.bz2
strongswan-1b5de7ce3bddedab12703c578b7c8fe90bea116e.tar.xz
Use a generic AF_ALG wrapper for common operations
-rw-r--r--src/libstrongswan/plugins/af_alg/Makefile.am1
-rw-r--r--src/libstrongswan/plugins/af_alg/af_alg_ops.c221
-rw-r--r--src/libstrongswan/plugins/af_alg/af_alg_ops.h90
3 files changed, 312 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/af_alg/Makefile.am b/src/libstrongswan/plugins/af_alg/Makefile.am
index 53e62bc29..f258d2422 100644
--- a/src/libstrongswan/plugins/af_alg/Makefile.am
+++ b/src/libstrongswan/plugins/af_alg/Makefile.am
@@ -11,6 +11,7 @@ endif
libstrongswan_af_alg_la_SOURCES = \
af_alg_plugin.h af_alg_plugin.c \
+ af_alg_ops.h af_alg_ops.c \
af_alg_hasher.h af_alg_hasher.c \
af_alg_signer.h af_alg_signer.c \
af_alg_crypter.h af_alg_crypter.c
diff --git a/src/libstrongswan/plugins/af_alg/af_alg_ops.c b/src/libstrongswan/plugins/af_alg/af_alg_ops.c
new file mode 100644
index 000000000..37eeab54e
--- /dev/null
+++ b/src/libstrongswan/plugins/af_alg/af_alg_ops.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "af_alg_ops.h"
+
+#include <unistd.h>
+#include <errno.h>
+#include <linux/socket.h>
+
+#include <debug.h>
+
+typedef struct private_af_alg_ops_t private_af_alg_ops_t;
+
+/**
+ * Private data of an af_alg_ops_t object.
+ */
+struct private_af_alg_ops_t {
+
+ /**
+ * Public af_alg_ops_t interface.
+ */
+ af_alg_ops_t public;
+
+ /**
+ * Transform FD
+ */
+ int tfm;
+
+ /**
+ * Operation FD
+ */
+ int op;
+};
+
+METHOD(af_alg_ops_t, reset, void,
+ private_af_alg_ops_t *this)
+{
+ if (this->op != -1)
+ {
+ close(this->op);
+ this->op = -1;
+ }
+}
+
+METHOD(af_alg_ops_t, hash, void,
+ private_af_alg_ops_t *this, chunk_t data, char *out, size_t outlen)
+{
+ ssize_t len;
+
+ while (this->op == -1)
+ {
+ this->op = accept(this->tfm, NULL, 0);
+ if (this->op == -1)
+ {
+ DBG1(DBG_LIB, "opening AF_ALG hasher failed: %s", strerror(errno));
+ sleep(1);
+ }
+ }
+ do
+ {
+ len = send(this->op, data.ptr, data.len, out ? 0 : MSG_MORE);
+ if (len == -1)
+ {
+ DBG1(DBG_LIB, "writing to AF_ALG hasher failed: %s", strerror(errno));
+ sleep(1);
+ }
+ else
+ {
+ data = chunk_skip(data, len);
+ }
+ }
+ while (data.len);
+
+ if (out)
+ {
+ while (read(this->op, out, outlen) != outlen)
+ {
+ DBG1(DBG_LIB, "reading AF_ALG hasher failed: %s", strerror(errno));
+ sleep(1);
+ }
+ reset(this);
+ }
+}
+
+METHOD(af_alg_ops_t, crypt, void,
+ private_af_alg_ops_t *this, u_int32_t type, chunk_t iv, chunk_t data,
+ char *out)
+{
+ struct msghdr msg = {};
+ struct cmsghdr *cmsg;
+ struct af_alg_iv *ivm;
+ struct iovec iov;
+ char buf[CMSG_SPACE(sizeof(type)) +
+ CMSG_SPACE(offsetof(struct af_alg_iv, iv) + iv.len)];
+ ssize_t len;
+ int op;
+
+ while ((op = accept(this->tfm, NULL, 0)) == -1)
+ {
+ DBG1(DBG_LIB, "accepting AF_ALG crypter failed: %s", strerror(errno));
+ sleep(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_OP;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(type));
+ *(u_int32_t*)CMSG_DATA(cmsg) = type;
+
+ cmsg = CMSG_NXTHDR(&msg, cmsg);
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_IV;
+ cmsg->cmsg_len = CMSG_LEN(offsetof(struct af_alg_iv, iv) + iv.len);
+ ivm = (void*)CMSG_DATA(cmsg);
+ ivm->ivlen = iv.len;
+ memcpy(ivm->iv, iv.ptr, iv.len);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ while (data.len)
+ {
+ iov.iov_base = data.ptr;
+ iov.iov_len = data.len;
+
+ len = sendmsg(op, &msg, 0);
+ if (len == -1)
+ {
+ DBG1(DBG_LIB, "writing to AF_ALG crypter failed: %s",
+ strerror(errno));
+ sleep(1);
+ continue;
+ }
+ if (read(op, out, len) != len)
+ {
+ DBG1(DBG_LIB, "reading from AF_ALG crypter failed: %s",
+ strerror(errno));
+ }
+ data = chunk_skip(data, len);
+ /* no IV for subsequent data chunks */
+ msg.msg_controllen = 0;
+ }
+ close(op);
+}
+
+METHOD(af_alg_ops_t, set_key, void,
+ private_af_alg_ops_t *this, chunk_t key)
+{
+ if (setsockopt(this->tfm, SOL_ALG, ALG_SET_KEY, key.ptr, key.len) == -1)
+ {
+ DBG1(DBG_LIB, "setting AF_ALG key failed: %s", strerror(errno));
+ }
+}
+
+METHOD(af_alg_ops_t, destroy, void,
+ private_af_alg_ops_t *this)
+{
+ close(this->tfm);
+ if (this->op != -1)
+ {
+ close(this->op);
+ }
+ free(this);
+}
+
+/**
+ * See header
+ */
+af_alg_ops_t *af_alg_ops_create(char *type, char *alg)
+{
+ private_af_alg_ops_t *this;
+ struct sockaddr_alg sa = {
+ .salg_family = AF_ALG,
+ };
+
+ strncpy(sa.salg_type, type, sizeof(sa.salg_type));
+ strncpy(sa.salg_name, alg, sizeof(sa.salg_name));
+
+ INIT(this,
+ .public = {
+ .hash = _hash,
+ .reset = _reset,
+ .crypt = _crypt,
+ .set_key = _set_key,
+ .destroy = _destroy,
+ },
+ .tfm = socket(AF_ALG, SOCK_SEQPACKET, 0),
+ .op = -1,
+ );
+ if (this->tfm == -1)
+ {
+ DBG1(DBG_LIB, "opening AF_ALG socket failed: %s", strerror(errno));
+ free(this);
+ return NULL;
+ }
+ if (bind(this->tfm, (struct sockaddr*)&sa, sizeof(sa)) == -1)
+ {
+ DBG1(DBG_LIB, "binding AF_ALG socket for '%s' failed: %s",
+ sa.salg_name, strerror(errno));
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+}
diff --git a/src/libstrongswan/plugins/af_alg/af_alg_ops.h b/src/libstrongswan/plugins/af_alg/af_alg_ops.h
new file mode 100644
index 000000000..ad164029f
--- /dev/null
+++ b/src/libstrongswan/plugins/af_alg/af_alg_ops.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+* @defgroup af_alg_ops af_alg_ops
+ * @{ @ingroup af_alg
+ */
+
+#ifndef AF_ALG_OPS_H_
+#define AF_ALG_OPS_H_
+
+#include <library.h>
+
+#include <linux/if_alg.h>
+
+#ifndef AF_ALG
+#define AF_ALG 38
+#endif /* AF_ALG */
+
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif /* SOL_ALG */
+
+typedef struct af_alg_ops_t af_alg_ops_t;
+
+/**
+ * Helper to run AF_ALG operations.
+ */
+struct af_alg_ops_t {
+
+ /**
+ * Hash a chunk of data.
+ *
+ * @param data data to hash
+ * @param out buffer to write hash to, NULL for append mode
+ * @param outlen number of bytes to read into out
+ */
+ void (*hash)(af_alg_ops_t *this, chunk_t data, char *out, size_t outlen);
+
+ /**
+ * Reset hasher state.
+ */
+ void (*reset)(af_alg_ops_t *this);
+
+ /**
+ * En-/Decrypt a chunk of data.
+ *
+ * @param type crypto operation (ALG_OP_DECRYPT/ALG_OP_ENCRYPT)
+ * @param iv iv to use
+ * @param data data to encrypt/decrypt
+ * @param out buffer write processed data to
+ */
+ void (*crypt)(af_alg_ops_t *this, u_int32_t type, chunk_t iv, chunk_t data,
+ char *out);
+
+ /**
+ * Set the key for en-/decryption or HMAC/XCBC operations.
+ *
+ * @param key key to set for transform
+ */
+ void (*set_key)(af_alg_ops_t *this, chunk_t key);
+
+ /**
+ * Destroy a af_alg_ops_t.
+ */
+ void (*destroy)(af_alg_ops_t *this);
+};
+
+/**
+ * Create a af_alg_ops instance.
+ *
+ * @param type algorithm type (hash, skcipher)
+ * @param alg algorithm name
+ * @return TRUE if AF_ALG socket bound successfully
+ */
+af_alg_ops_t *af_alg_ops_create(char *type, char *alg);
+
+#endif /** AF_ALG_OPS_H_ @}*/