summaryrefslogtreecommitdiff
path: root/src/libstrongswan/credentials/containers
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2013-08-25 15:37:27 +0200
committerYves-Alexis Perez <corsac@debian.org>2013-08-25 15:37:27 +0200
commitc7307e752d8f47c68f834e22ee2ce0a14a70e695 (patch)
treefbb442a20ab54aad511b46a070e65b8d09c22791 /src/libstrongswan/credentials/containers
parentf74c6d77c3efb529e7403eeef0613c061eb895b3 (diff)
parent6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349 (diff)
downloadvyos-strongswan-c7307e752d8f47c68f834e22ee2ce0a14a70e695.tar.gz
vyos-strongswan-c7307e752d8f47c68f834e22ee2ce0a14a70e695.zip
Merge tag 'upstream/5.1.0'
Upstream version 5.1.0
Diffstat (limited to 'src/libstrongswan/credentials/containers')
-rw-r--r--src/libstrongswan/credentials/containers/container.c4
-rw-r--r--src/libstrongswan/credentials/containers/container.h15
-rw-r--r--src/libstrongswan/credentials/containers/pkcs12.c173
-rw-r--r--src/libstrongswan/credentials/containers/pkcs12.h78
4 files changed, 265 insertions, 5 deletions
diff --git a/src/libstrongswan/credentials/containers/container.c b/src/libstrongswan/credentials/containers/container.c
index d1e67b21b..7456d43db 100644
--- a/src/libstrongswan/credentials/containers/container.c
+++ b/src/libstrongswan/credentials/containers/container.c
@@ -15,9 +15,11 @@
#include "container.h"
-ENUM(container_type_names, CONTAINER_PKCS7, CONTAINER_PKCS7_ENVELOPED_DATA,
+ENUM(container_type_names, CONTAINER_PKCS7, CONTAINER_PKCS12,
"PKCS7",
"PKCS7_DATA",
"PKCS7_SIGNED_DATA",
"PKCS7_ENVELOPED_DATA",
+ "PKCS7_ENCRYPTED_DATA",
+ "PKCS12",
);
diff --git a/src/libstrongswan/credentials/containers/container.h b/src/libstrongswan/credentials/containers/container.h
index fc5c09041..ee329881d 100644
--- a/src/libstrongswan/credentials/containers/container.h
+++ b/src/libstrongswan/credentials/containers/container.h
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2012 Martin Willi
* Copyright (C) 2012 revosec AG
*
@@ -31,14 +34,18 @@ typedef enum container_type_t container_type_t;
* Type of the container.
*/
enum container_type_t {
- /** Any kind of PKCS7/CMS container */
+ /** Any kind of PKCS#7/CMS container */
CONTAINER_PKCS7,
- /** PKCS7/CMS plain "data" */
+ /** PKCS#7/CMS plain "data" */
CONTAINER_PKCS7_DATA,
- /** PKCS7/CMS "signed-data" */
+ /** PKCS#7/CMS "signed-data" */
CONTAINER_PKCS7_SIGNED_DATA,
- /** PKCS7/CMS "enveloped-data" */
+ /** PKCS#7/CMS "enveloped-data" */
CONTAINER_PKCS7_ENVELOPED_DATA,
+ /** PKCS#7/CMS "encrypted-data" */
+ CONTAINER_PKCS7_ENCRYPTED_DATA,
+ /** A PKCS#12 container */
+ CONTAINER_PKCS12,
};
/**
diff --git a/src/libstrongswan/credentials/containers/pkcs12.c b/src/libstrongswan/credentials/containers/pkcs12.c
new file mode 100644
index 000000000..7b812d27d
--- /dev/null
+++ b/src/libstrongswan/credentials/containers/pkcs12.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 "pkcs12.h"
+
+#include <utils/debug.h>
+
+/**
+ * v * ceiling(len/v)
+ */
+#define PKCS12_LEN(len, v) (((len) + v-1) & ~(v-1))
+
+/**
+ * Copy src to dst as many times as possible
+ */
+static inline void copy_chunk(chunk_t dst, chunk_t src)
+{
+ size_t i;
+
+ for (i = 0; i < dst.len; i++)
+ {
+ dst.ptr[i] = src.ptr[i % src.len];
+ }
+}
+
+/**
+ * Treat two chunks as integers in network order and add them together.
+ * The result is stored in the first chunk, if the second chunk is longer or the
+ * result overflows this is ignored.
+ */
+static void add_chunks(chunk_t a, chunk_t b)
+{
+ u_int16_t sum;
+ u_int8_t rem = 0;
+ ssize_t i, j;
+
+ for (i = a.len - 1, j = b.len -1; i >= 0 && j >= 0; i--, j--)
+ {
+ sum = a.ptr[i] + b.ptr[j] + rem;
+ a.ptr[i] = (u_char)sum;
+ rem = sum >> 8;
+ }
+ for (; i >= 0 && rem; i--)
+ {
+ sum = a.ptr[i] + rem;
+ a.ptr[i] = (u_char)sum;
+ rem = sum >> 8;
+ }
+}
+
+/**
+ * Do the actual key derivation with the given hasher, password and id.
+ */
+static bool derive_key(hash_algorithm_t hash, chunk_t unicode, chunk_t salt,
+ u_int64_t iterations, char id, chunk_t result)
+{
+ chunk_t out = result, D, S, P = chunk_empty, I, Ai, B, Ij;
+ hasher_t *hasher;
+ size_t Slen, v, u;
+ u_int64_t i;
+ bool success = FALSE;
+
+ hasher = lib->crypto->create_hasher(lib->crypto, hash);
+ if (!hasher)
+ {
+ DBG1(DBG_ASN, " %N hash algorithm not available",
+ hash_algorithm_names, hash);
+ return FALSE;
+ }
+ switch (hash)
+ {
+ case HASH_MD2:
+ case HASH_MD5:
+ case HASH_SHA1:
+ case HASH_SHA224:
+ case HASH_SHA256:
+ v = 64;
+ break;
+ case HASH_SHA384:
+ case HASH_SHA512:
+ v = 128;
+ break;
+ default:
+ goto end;
+ }
+ u = hasher->get_hash_size(hasher);
+
+ D = chunk_alloca(v);
+ memset(D.ptr, id, D.len);
+
+ Slen = PKCS12_LEN(salt.len, v);
+ I = chunk_alloca(Slen + PKCS12_LEN(unicode.len, v));
+ S = chunk_create(I.ptr, Slen);
+ P = chunk_create(I.ptr + Slen, I.len - Slen);
+ copy_chunk(S, salt);
+ copy_chunk(P, unicode);
+
+ Ai = chunk_alloca(u);
+ B = chunk_alloca(v);
+
+ while (TRUE)
+ {
+ if (!hasher->get_hash(hasher, D, NULL) ||
+ !hasher->get_hash(hasher, I, Ai.ptr))
+ {
+ goto end;
+ }
+ for (i = 1; i < iterations; i++)
+ {
+ if (!hasher->get_hash(hasher, Ai, Ai.ptr))
+ {
+ goto end;
+ }
+ }
+ memcpy(out.ptr, Ai.ptr, min(out.len, Ai.len));
+ out = chunk_skip(out, Ai.len);
+ if (!out.len)
+ {
+ break;
+ }
+ copy_chunk(B, Ai);
+ /* B = B+1 */
+ add_chunks(B, chunk_from_chars(0x01));
+ Ij = chunk_create(I.ptr, v);
+ for (i = 0; i < I.len; i += v, Ij.ptr += v)
+ { /* Ij = Ij + B + 1 */
+ add_chunks(Ij, B);
+ }
+ }
+ success = TRUE;
+end:
+ hasher->destroy(hasher);
+ return success;
+}
+
+/*
+ * Described in header
+ */
+bool pkcs12_derive_key(hash_algorithm_t hash, chunk_t password, chunk_t salt,
+ u_int64_t iterations, pkcs12_key_type_t type, chunk_t key)
+{
+ chunk_t unicode = chunk_empty;
+ bool success;
+ int i;
+
+ if (password.len)
+ { /* convert the password to UTF-16BE (without BOM) with 0 terminator */
+ unicode = chunk_alloca(password.len * 2 + 2);
+ for (i = 0; i < password.len; i++)
+ {
+ unicode.ptr[i * 2] = 0;
+ unicode.ptr[i * 2 + 1] = password.ptr[i];
+ }
+ unicode.ptr[i * 2] = 0;
+ unicode.ptr[i * 2 + 1] = 0;
+ }
+
+ success = derive_key(hash, unicode, salt, iterations, type, key);
+ memwipe(unicode.ptr, unicode.len);
+ return success;
+}
diff --git a/src/libstrongswan/credentials/containers/pkcs12.h b/src/libstrongswan/credentials/containers/pkcs12.h
new file mode 100644
index 000000000..f22ef045a
--- /dev/null
+++ b/src/libstrongswan/credentials/containers/pkcs12.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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 pkcs12 pkcs12
+ * @{ @ingroup containers
+ */
+
+#ifndef PKCS12_H_
+#define PKCS12_H_
+
+#include <credentials/containers/container.h>
+#include <crypto/hashers/hasher.h>
+
+typedef enum pkcs12_key_type_t pkcs12_key_type_t;
+typedef struct pkcs12_t pkcs12_t;
+
+/**
+ * The types of password based keys used by PKCS#12.
+ */
+enum pkcs12_key_type_t {
+ PKCS12_KEY_ENCRYPTION = 1,
+ PKCS12_KEY_IV = 2,
+ PKCS12_KEY_MAC = 3,
+};
+
+/**
+ * PKCS#12/PFX container type.
+ */
+struct pkcs12_t {
+
+ /**
+ * Implements container_t.
+ */
+ container_t container;
+
+ /**
+ * Create an enumerator over extracted certificates.
+ *
+ * @return enumerator over certificate_t
+ */
+ enumerator_t* (*create_cert_enumerator)(pkcs12_t *this);
+
+ /**
+ * Create an enumerator over extracted private keys.
+ *
+ * @return enumerator over private_key_t
+ */
+ enumerator_t* (*create_key_enumerator)(pkcs12_t *this);
+};
+
+/**
+ * Derive the keys used in PKCS#12 for password integrity/privacy mode.
+ *
+ * @param hash hash algorithm to use for key derivation
+ * @param password password (ASCII)
+ * @param salt salt value
+ * @param iterations number of iterations
+ * @param type type of key to derive
+ * @param key the returned key, must be allocated of desired length
+ * @return TRUE on success
+ */
+bool pkcs12_derive_key(hash_algorithm_t hash, chunk_t password, chunk_t salt,
+ u_int64_t iterations, pkcs12_key_type_t type, chunk_t key);
+
+#endif /** PKCS12_H_ @}*/