ARG_ENABL_SET([af-alg], [enable AF_ALG crypto interface to Linux Crypto API.])
ARG_ENABL_SET([bliss], [enable BLISS software implementation plugin.])
ARG_ENABL_SET([blowfish], [enable Blowfish software implementation plugin.])
+ARG_ENABL_SET([botan], [enables the Botan crypto plugin.])
ARG_ENABL_SET([ccm], [enables the CCM AEAD wrapper crypto plugin.])
ARG_ENABL_SET([chapoly], [enables the ChaCha20/Poly1305 AEAD plugin.])
ARG_DISBL_SET([cmac], [disable CMAC crypto implementation plugin.])
)
fi
+if test x$botan = xtrue; then
+ PKG_CHECK_MODULES(botan, [botan-2])
+ AC_SUBST(botan_CFLAGS)
+ AC_SUBST(botan_LIBS)
+fi
+
if test x$uci = xtrue; then
AC_CHECK_LIB([uci],[uci_alloc_context],[LIBS="$LIBS"],[AC_MSG_ERROR([UCI library libuci not found])],[])
AC_CHECK_HEADER([uci.h],,[AC_MSG_ERROR([UCI header uci.h not found!])])
ADD_PLUGIN([padlock], [s charon])
ADD_PLUGIN([openssl], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
ADD_PLUGIN([gcrypt], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
+ADD_PLUGIN([botan], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
ADD_PLUGIN([af-alg], [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
ADD_PLUGIN([fips-prf], [s charon nm cmd])
ADD_PLUGIN([gmp], [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen fuzz])
AM_CONDITIONAL(USE_PADLOCK, test x$padlock = xtrue)
AM_CONDITIONAL(USE_OPENSSL, test x$openssl = xtrue)
AM_CONDITIONAL(USE_GCRYPT, test x$gcrypt = xtrue)
+AM_CONDITIONAL(USE_BOTAN, test x$botan = xtrue)
AM_CONDITIONAL(USE_AGENT, test x$agent = xtrue)
AM_CONDITIONAL(USE_KEYCHAIN, test x$keychain = xtrue)
AM_CONDITIONAL(USE_PKCS11, test x$pkcs11 = xtrue)
src/libstrongswan/plugins/padlock/Makefile
src/libstrongswan/plugins/openssl/Makefile
src/libstrongswan/plugins/gcrypt/Makefile
+ src/libstrongswan/plugins/botan/Makefile
src/libstrongswan/plugins/agent/Makefile
src/libstrongswan/plugins/keychain/Makefile
src/libstrongswan/plugins/pkcs11/Makefile
endif
endif
+if USE_BOTAN
+ SUBDIRS += plugins/botan
+if MONOLITHIC
+ libstrongswan_la_LIBADD += plugins/botan/libstrongswan-botan.la
+endif
+endif
+
if USE_FIPS_PRF
SUBDIRS += plugins/fips_prf
if MONOLITHIC
--- /dev/null
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan
+
+AM_CFLAGS = \
+ $(PLUGIN_CFLAGS) \
+ $(botan_CFLAGS)
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-botan.la
+else
+plugin_LTLIBRARIES = libstrongswan-botan.la
+endif
+
+libstrongswan_botan_la_SOURCES = \
+ botan_plugin.h botan_plugin.c \
+ botan_rng.h botan_rng.c \
+ botan_hasher.h botan_hasher.c \
+ botan_hmac.h botan_hmac.c \
+ botan_crypter.h botan_crypter.c \
+ botan_rsa_public_key.h botan_rsa_public_key.c \
+ botan_rsa_private_key.h botan_rsa_private_key.c \
+ botan_diffie_hellman.h botan_diffie_hellman.c \
+ botan_ec_diffie_hellman.h botan_ec_diffie_hellman.c \
+ botan_ec_public_key.h botan_ec_public_key.c \
+ botan_ec_private_key.h botan_ec_private_key.c \
+ botan_util.c \
+ botan_gcm.h botan_gcm.c
+
+libstrongswan_botan_la_LDFLAGS = -module -avoid-version
+libstrongswan_botan_la_LIBADD = $(botan_LIBS)
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Copyright (C) 2018 Konstantinos Kolelis
+ * Copyright (C) 2018 Tobias Hommel
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_crypter.h"
+
+#include <botan/ffi.h>
+
+typedef struct private_botan_crypter_t private_botan_crypter_t;
+
+/**
+ * Private data of botan_crypter_t
+ */
+struct private_botan_crypter_t {
+
+ /**
+ * Public part of this class
+ */
+ botan_crypter_t public;
+
+ /**
+ * The key
+ */
+ chunk_t key;
+
+ /**
+ * The cipher name
+ */
+ const char* cipher_name;
+};
+
+/**
+ * Do the actual en/decryption
+ */
+static bool crypt(private_botan_crypter_t *this, chunk_t data, chunk_t iv,
+ chunk_t *dst, uint32_t init_flag)
+{
+ botan_cipher_t cipher;
+ size_t output_written = 0;
+ size_t input_consumed = 0;
+ uint8_t *in, *out;
+ bool success = FALSE;
+
+ in = data.ptr;
+ if (dst)
+ {
+ *dst= chunk_alloc(data.len);
+ out = dst->ptr;
+ }
+ else
+ {
+ out = data.ptr;
+ }
+
+ if (botan_cipher_init(&cipher, this->cipher_name, init_flag))
+ {
+ return FALSE;
+ }
+
+ if (!botan_cipher_set_key(cipher, this->key.ptr, this->key.len)
+ && !botan_cipher_start(cipher, iv.ptr, iv.len)
+ && !botan_cipher_update(cipher, BOTAN_CIPHER_UPDATE_FLAG_FINAL, out,
+ data.len, &output_written, in, data.len,
+ &input_consumed)
+ && (output_written == input_consumed))
+ {
+ success = TRUE;
+ }
+
+ botan_cipher_destroy(cipher);
+ return success;
+}
+
+METHOD(crypter_t, decrypt, bool,
+ private_botan_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
+{
+ return crypt(this, data, iv, dst, BOTAN_CIPHER_INIT_FLAG_DECRYPT);
+}
+
+
+METHOD(crypter_t, encrypt, bool,
+ private_botan_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
+{
+ return crypt(this, data, iv, dst, BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
+}
+
+METHOD(crypter_t, get_block_size, size_t,
+ private_botan_crypter_t *this)
+{
+ return AES_BLOCK_SIZE;
+}
+
+METHOD(crypter_t, get_iv_size, size_t,
+ private_botan_crypter_t *this)
+{
+ return AES_BLOCK_SIZE;
+}
+
+METHOD(crypter_t, get_key_size, size_t,
+ private_botan_crypter_t *this)
+{
+ return this->key.len;
+}
+
+METHOD(crypter_t, set_key, bool,
+ private_botan_crypter_t *this, chunk_t key)
+{
+ memcpy(this->key.ptr, key.ptr, min(key.len, this->key.len));
+ return TRUE;
+}
+
+METHOD(crypter_t, destroy, void,
+ private_botan_crypter_t *this)
+{
+ chunk_clear(&this->key);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+botan_crypter_t *botan_crypter_create(encryption_algorithm_t algo,
+ size_t key_size)
+{
+ private_botan_crypter_t *this;
+
+ INIT(this,
+ .public = {
+ .crypter = {
+ .encrypt = _encrypt,
+ .decrypt = _decrypt,
+ .get_block_size = _get_block_size,
+ .get_iv_size = _get_iv_size,
+ .get_key_size = _get_key_size,
+ .set_key = _set_key,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+
+ switch (algo)
+ {
+ case ENCR_AES_CBC:
+ switch (key_size)
+ {
+ case 16:
+ /* AES 128 */
+ this->cipher_name = "AES-128/CBC/NoPadding";
+ break;
+ case 24:
+ /* AES-192 */
+ this->cipher_name = "AES-192/CBC/NoPadding";
+ break;
+ case 32:
+ /* AES-256 */
+ this->cipher_name = "AES-256/CBC/NoPadding";
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+ break;
+ default:
+ {
+ free(this);
+ return NULL;
+
+ }
+ }
+
+ this->key = chunk_alloc(key_size);
+ return &this->public;
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Copyright (C) 2018 Konstantinos Kolelis
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_crypter botan_crypter
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_CRYPTER_H_
+#define BOTAN_CRYPTER_H_
+
+typedef struct botan_crypter_t botan_crypter_t;
+
+#include <crypto/crypters/crypter.h>
+
+/**
+ * Implementation of crypters using Botan.
+ */
+struct botan_crypter_t {
+
+ /**
+ * Implements crypter_t interface.
+ */
+ crypter_t crypter;
+};
+
+/**
+ * Constructor to create botan_crypter_t.
+ *
+ * @param algo algorithm to implement
+ * @param key_size key size in bytes
+ * @return botan_crypter_t, NULL if not supported
+ */
+botan_crypter_t *botan_crypter_create(encryption_algorithm_t algo,
+ size_t key_size);
+
+#endif /** BOTAN_CRYPTER_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Copyright (C) 2018 Konstantinos Kolelis
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_diffie_hellman.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_DIFFIE_HELLMAN
+
+#include "botan_util.h"
+
+#include <botan/ffi.h>
+
+#include <utils/debug.h>
+
+typedef struct private_botan_diffie_hellman_t private_botan_diffie_hellman_t;
+
+/**
+ * Private data of an botan_diffie_hellman_t object.
+ */
+struct private_botan_diffie_hellman_t {
+
+ /**
+ * Public botan_diffie_hellman_t interface
+ */
+ botan_diffie_hellman_t public;
+
+ /**
+ * Diffie Hellman group number
+ */
+ diffie_hellman_group_t group;
+
+ /**
+ * Private key
+ */
+ botan_privkey_t dh_key;
+
+ /**
+ * Diffie hellman shared secret
+ */
+ chunk_t shared_secret;
+
+ /**
+ * Generator value
+ */
+ botan_mp_t g;
+
+ /**
+ * Modulus
+ */
+ botan_mp_t p;
+
+};
+
+bool load_private_key(private_botan_diffie_hellman_t *this, chunk_t value)
+{
+ botan_mp_t xa;
+ if (chunk_to_botan_mp(value, &xa))
+ {
+ return FALSE;
+ }
+
+ if (botan_privkey_destroy(this->dh_key) ||
+ botan_privkey_load_dh (&this->dh_key, this->p, this->g, xa))
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(diffie_hellman_t, set_other_public_value, bool,
+ private_botan_diffie_hellman_t *this, chunk_t value)
+{
+ botan_pk_op_ka_t op;
+
+ if (!diffie_hellman_verify_value(this->group, value))
+ {
+ return FALSE;
+ }
+
+ chunk_clear(&this->shared_secret);
+ botan_pk_op_key_agreement_create(&op, this->dh_key, "Raw", 0);
+
+ /* get shared secret key size */
+ if (botan_pk_op_key_agreement(op, NULL, &this->shared_secret.len, value.ptr,
+ value.len, NULL, 0)
+ != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ return FALSE;
+ }
+
+ this->shared_secret = chunk_alloc(this->shared_secret.len);
+ if (botan_pk_op_key_agreement(op, this->shared_secret.ptr,
+ &this->shared_secret.len, value.ptr,
+ value.len, NULL, 0))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_my_public_value, bool,
+ private_botan_diffie_hellman_t *this, chunk_t *value)
+{
+ *value = chunk_empty;
+
+ /* get key size of public key first */
+ if (botan_pk_op_key_agreement_export_public(this->dh_key, NULL, &value->len)
+ != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ return FALSE;
+ }
+
+ *value = chunk_alloc(value->len);
+ if (botan_pk_op_key_agreement_export_public(this->dh_key, value->ptr,
+ &value->len))
+ {
+ chunk_clear(value);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+METHOD(diffie_hellman_t, set_private_value, bool,
+ private_botan_diffie_hellman_t *this, chunk_t value)
+{
+ return load_private_key(this, value);
+}
+
+METHOD(diffie_hellman_t, get_shared_secret, bool,
+ private_botan_diffie_hellman_t *this, chunk_t *secret)
+{
+ if (this->shared_secret.len == 0)
+ {
+ return FALSE;
+ }
+
+ *secret = chunk_clone(this->shared_secret);
+ return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
+ private_botan_diffie_hellman_t *this)
+{
+ return this->group;
+}
+
+METHOD(diffie_hellman_t, destroy, void,
+ private_botan_diffie_hellman_t *this)
+{
+ botan_mp_destroy(this->p);
+ botan_mp_destroy(this->g);
+ botan_privkey_destroy(this->dh_key);
+ chunk_clear(&this->shared_secret);
+ free(this);
+}
+
+/*
+ * Generic internal constructor
+ */
+botan_diffie_hellman_t *create_generic(diffie_hellman_group_t group,
+ chunk_t g, chunk_t p)
+{
+ private_botan_diffie_hellman_t *this;
+
+ INIT(this,
+ .public = {
+ .dh = {
+ .get_shared_secret = _get_shared_secret,
+ .set_other_public_value = _set_other_public_value,
+ .get_my_public_value = _get_my_public_value,
+ .set_private_value = _set_private_value,
+ .get_dh_group = _get_dh_group,
+ .destroy = _destroy,
+ },
+ },
+ .group = group,
+ );
+
+ if (chunk_to_botan_mp(p, &this->p))
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ if (chunk_to_botan_mp(g, &this->g))
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ chunk_t random;
+ rng_t *rng;
+ rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+ if (rng && rng->allocate_bytes(rng, p.len, &random))
+ {
+ rng->destroy(rng);
+ if (!load_private_key(this, random))
+ {
+ destroy(this);
+ chunk_clear(&random);
+ return NULL;
+ }
+ }
+
+ return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+botan_diffie_hellman_t *
+botan_diffie_hellman_create(diffie_hellman_group_t group)
+{
+ diffie_hellman_params_t *params;
+ params = diffie_hellman_get_params(group);
+ if (!params)
+ {
+ return NULL;
+ }
+ return create_generic(group, params->generator, params->prime);
+}
+
+/*
+ * Described in header.
+ */
+botan_diffie_hellman_t *
+botan_diffie_hellman_create_custom(diffie_hellman_group_t group, chunk_t g,
+ chunk_t p)
+{
+ if (group == MODP_CUSTOM)
+ {
+ return create_generic(group, g, p);
+ }
+ return NULL;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Copyright (C) 2018 Konstantinos Kolelis
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_diffie_hellman botan_diffie_hellman
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_DIFFIE_HELLMAN_H_
+#define BOTAN_DIFFIE_HELLMAN_H_
+
+typedef struct botan_diffie_hellman_t botan_diffie_hellman_t;
+
+#include <crypto/diffie_hellman.h>
+
+/**
+ * Implementation of the Diffie-Hellman algorithm using Botan.
+ */
+struct botan_diffie_hellman_t {
+
+ /**
+ * Implements diffie_hellman_t interface.
+ */
+ diffie_hellman_t dh;
+};
+
+/**
+ * Creates a new botan_diffie_hellman_t object.
+ *
+ * @param group Diffie Hellman group number to use
+ * @return botan_diffie_hellman_t object,
+ * NULL if not supported
+ */
+botan_diffie_hellman_t *
+botan_diffie_hellman_create(diffie_hellman_group_t group);
+
+/**
+ * Creates a new botan_diffie_hellman_t object for MODP_CUSTOM.
+ *
+ * @param group MODP_CUSTOM
+ * @param g generator
+ * @param p prime
+ * @return botan_diffie_hellman_t object,
+ * NULL if not supported
+ */
+botan_diffie_hellman_t *
+botan_diffie_hellman_create_custom(diffie_hellman_group_t group, chunk_t g,
+ chunk_t p);
+
+#endif /** BOTAN_DIFFIE_HELLMAN_H_ @}*/
+
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_ec_diffie_hellman.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_ECDH
+
+#include <utils/debug.h>
+
+#include <botan/ffi.h>
+
+typedef struct private_botan_ec_diffie_hellman_t
+ private_botan_ec_diffie_hellman_t;
+
+/**
+ * Private data of a botan_ec_diffie_hellman_t object.
+ */
+struct private_botan_ec_diffie_hellman_t {
+ /**
+ * Public botan_ec_diffie_hellman_t interface
+ */
+ botan_ec_diffie_hellman_t public;
+
+ /**
+ * Diffie Hellman group
+ */
+ diffie_hellman_group_t group;
+
+ /**
+ * EC curve name
+ */
+ const char* curve_name;
+
+ /**
+ * EC private key
+ */
+ botan_privkey_t key;
+
+ /**
+ * Shared secret
+ */
+ chunk_t shared_secret;
+
+ /**
+ * True if shared secret is computed
+ */
+ bool computed;
+};
+
+METHOD(diffie_hellman_t, set_other_public_value, bool,
+ private_botan_ec_diffie_hellman_t *this, chunk_t value)
+{
+ if (!diffie_hellman_verify_value(this->group, value))
+ {
+ return FALSE;
+ }
+
+ botan_pk_op_ka_t ka;
+ if (botan_pk_op_key_agreement_create(&ka, this->key, "Raw", 0))
+ {
+ return FALSE;
+ }
+
+ /* prepend 0x04 to indicate uncompressed point format */
+ uint8_t indic = 0x04;
+ value = chunk_cata("cc", chunk_from_thing(indic), value);
+ size_t out_len = 0;
+ if (botan_pk_op_key_agreement(ka, NULL, &out_len, value.ptr, value.len,
+ NULL, 0)
+ != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ botan_pk_op_key_agreement_destroy(ka);
+ return FALSE;
+ }
+
+ if (out_len == 0)
+ {
+ botan_pk_op_key_agreement_destroy(ka);
+ return FALSE;
+ }
+
+ chunk_clear(&this->shared_secret);
+ this->shared_secret = chunk_alloc(out_len);
+ if (botan_pk_op_key_agreement(ka, this->shared_secret.ptr,
+ &this->shared_secret.len, value.ptr,
+ value.len, NULL, 0))
+ {
+ chunk_clear(&this->shared_secret);
+ botan_pk_op_key_agreement_destroy(ka);
+ return FALSE;
+ }
+
+ botan_pk_op_key_agreement_destroy(ka);
+ this->computed = TRUE;
+ return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_my_public_value, bool,
+ private_botan_ec_diffie_hellman_t *this, chunk_t *value)
+{
+ chunk_t pkey = chunk_empty;
+ if (botan_pk_op_key_agreement_export_public(this->key, NULL, &pkey.len)
+ != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ return FALSE;
+ }
+
+ pkey = chunk_alloca(pkey.len);
+ if (botan_pk_op_key_agreement_export_public(this->key, pkey.ptr, &pkey.len))
+ {
+ return FALSE;
+ }
+
+ /* skip 0x04 byte prepended by botan */
+ *value = chunk_clone(chunk_skip(pkey, 1));
+ return TRUE;
+}
+
+METHOD(diffie_hellman_t, set_private_value, bool,
+ private_botan_ec_diffie_hellman_t *this, chunk_t value)
+{
+ botan_mp_t scalar;
+ if (botan_mp_init(&scalar))
+ {
+ return FALSE;
+ }
+
+ if (botan_mp_from_bin(scalar, value.ptr, value.len))
+ {
+ botan_mp_destroy(scalar);
+ return FALSE;
+ }
+
+ if (botan_privkey_destroy(this->key))
+ {
+ botan_mp_destroy(scalar);
+ return FALSE;
+ }
+
+ if (botan_privkey_load_ecdh(&this->key, scalar, this->curve_name))
+ {
+ botan_mp_destroy(scalar);
+ return FALSE;
+ }
+
+ botan_mp_destroy(scalar);
+ this->computed = FALSE;
+ return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_shared_secret, bool,
+ private_botan_ec_diffie_hellman_t *this, chunk_t *secret)
+{
+ if (!this->computed)
+ {
+ return FALSE;
+ }
+ *secret = chunk_clone(this->shared_secret);
+ return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
+ private_botan_ec_diffie_hellman_t *this)
+{
+ return this->group;
+}
+
+METHOD(diffie_hellman_t, destroy, void,
+ private_botan_ec_diffie_hellman_t *this)
+{
+ botan_privkey_destroy(this->key);
+ chunk_clear(&this->shared_secret);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+botan_ec_diffie_hellman_t *
+botan_ec_diffie_hellman_create(diffie_hellman_group_t group)
+{
+ private_botan_ec_diffie_hellman_t *this;
+
+ INIT(this,
+ .public = {
+ .dh = {
+ .get_shared_secret = _get_shared_secret,
+ .set_other_public_value = _set_other_public_value,
+ .get_my_public_value = _get_my_public_value,
+ .set_private_value = _set_private_value,
+ .get_dh_group = _get_dh_group,
+ .destroy = _destroy,
+ },
+ },
+ .group = group,
+ );
+
+ switch (group)
+ {
+ case ECP_256_BIT:
+ this->curve_name = "secp256r1";
+ break;
+ case ECP_384_BIT:
+ this->curve_name = "secp384r1";
+ break;
+ case ECP_521_BIT:
+ this->curve_name = "secp521r1";
+ break;
+ case ECP_256_BP:
+ this->curve_name = "brainpool256r1";
+ break;
+ case ECP_384_BP:
+ this->curve_name = "brainpool384r1";
+ break;
+ case ECP_512_BP:
+ this->curve_name = "brainpool512r1";
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+
+ return &this->public;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_ec_diffie_hellman botan_ec_diffie_hellman
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_EC_DIFFIE_HELLMAN_H_
+#define BOTAN_EC_DIFFIE_HELLMAN_H_
+
+typedef struct botan_ec_diffie_hellman_t botan_ec_diffie_hellman_t;
+
+#include <library.h>
+
+/**
+ * Implementation of the EC Diffie-Hellman algorithm using Botan.
+ */
+struct botan_ec_diffie_hellman_t {
+
+ /**
+ * Implements diffie_hellman_t interface.
+ */
+ diffie_hellman_t dh;
+};
+
+/**
+ * Creates a new botan_ec_diffie_hellman_t object.
+ *
+ * @param group EC Diffie Hellman group number to use
+ * @return botan_ec_diffie_hellman_t object, NULL if not supported
+ */
+botan_ec_diffie_hellman_t *
+botan_ec_diffie_hellman_create(diffie_hellman_group_t group);
+
+#endif /** BOTAN_EC_DIFFIE_HELLMAN_H_ @}*/
+
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Copyright (C) 2018 Konstantinos Kolelis
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include "botan_ec_private_key.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_ECDSA
+
+#include <asn1/asn1.h>
+#include <asn1/oid.h>
+#include <asn1/asn1_parser.h>
+
+#include <utils/debug.h>
+
+#include <botan/ffi.h>
+
+typedef struct private_botan_ec_private_key_t private_botan_ec_private_key_t;
+
+/**
+ * Private data of a botan_ec_private_key_t object.
+ */
+struct private_botan_ec_private_key_t {
+ /**
+ * Public interface for this signer.
+ */
+ botan_ec_private_key_t public;
+
+ /**
+ * Botan ec private key
+ */
+ botan_privkey_t key;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
+};
+
+#define SIG_FORMAT_IEEE_1363 0
+#define SIG_FORMAT_DER_SEQUENCE 1
+
+/* implemented in ec public key */
+bool botan_ec_fingerprint(botan_pubkey_t *ec, cred_encoding_type_t type,
+ chunk_t *fp);
+
+/**
+ * Build a DER encoded signature as in RFC 3279 or as in RFC 4754
+ */
+static bool build_signature(botan_privkey_t key, const char *hash_and_padding,
+ int signature_format, chunk_t data,
+ chunk_t *signature)
+{
+ if (!hash_and_padding || !signature)
+ {
+ return FALSE;
+ }
+
+ botan_pk_op_sign_t sign_op;
+
+ if (botan_pk_op_sign_create(&sign_op, key, hash_and_padding, 0))
+ {
+ return FALSE;
+ }
+
+ botan_rng_t rng;
+ if (botan_rng_init(&rng, "user"))
+ {
+ return FALSE;
+ }
+
+ /* get size of signature first */
+ if (botan_pk_op_sign_update(sign_op, data.ptr, data.len))
+ {
+ botan_rng_destroy(rng);
+ botan_pk_op_sign_destroy(sign_op);
+ return FALSE;
+ }
+
+ signature->len = 0;
+ if (botan_pk_op_sign_finish(sign_op, rng, NULL, &signature->len)
+ != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ botan_rng_destroy(rng);
+ botan_pk_op_sign_destroy(sign_op);
+ return FALSE;
+ }
+
+ /* now get the signature */
+ *signature = chunk_alloc(signature->len);
+ if (botan_pk_op_sign_update(sign_op, data.ptr, data.len))
+ {
+ botan_rng_destroy(rng);
+ botan_pk_op_sign_destroy(sign_op);
+ return FALSE;
+ }
+
+ if (botan_pk_op_sign_finish(sign_op, rng, signature->ptr, &signature->len))
+ {
+ botan_rng_destroy(rng);
+ botan_pk_op_sign_destroy(sign_op);
+ return FALSE;
+ }
+
+ botan_rng_destroy(rng);
+ botan_pk_op_sign_destroy(sign_op);
+
+ if (signature_format == SIG_FORMAT_DER_SEQUENCE)
+ {
+ /* format as ASN.1 sequence of two integers r,s */
+ chunk_t r, s = chunk_empty;
+ chunk_split(*signature, "aa", signature->len / 2, &r,
+ signature->len / 2, &s);
+
+ chunk_free(signature);
+ *signature = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_integer("c", r),
+ asn1_integer("c", s));
+ }
+
+ return TRUE;
+}
+
+METHOD(private_key_t, sign, bool,
+ private_botan_ec_private_key_t *this, signature_scheme_t scheme,
+ void *params, chunk_t data, chunk_t *signature)
+{
+ switch (scheme)
+ {
+ case SIGN_ECDSA_WITH_NULL:
+ /* r||s -> Botan::IEEE_1363, data is the hash already */
+ return build_signature(this->key, "Raw",
+ SIG_FORMAT_IEEE_1363, data, signature);
+ case SIGN_ECDSA_WITH_SHA1_DER:
+ /* DER SEQUENCE of two INTEGERS r,s -> Botan::DER_SEQUENCE */
+ return build_signature(this->key, "EMSA1(SHA-1)",
+ SIG_FORMAT_DER_SEQUENCE, data, signature);
+ case SIGN_ECDSA_WITH_SHA256_DER:
+ return build_signature(this->key, "EMSA1(SHA-256)",
+ SIG_FORMAT_DER_SEQUENCE, data, signature);
+ case SIGN_ECDSA_WITH_SHA384_DER:
+ return build_signature(this->key, "EMSA1(SHA-384)",
+ SIG_FORMAT_DER_SEQUENCE, data, signature);
+ case SIGN_ECDSA_WITH_SHA512_DER:
+ return build_signature(this->key, "EMSA1(SHA-512)",
+ SIG_FORMAT_DER_SEQUENCE, data, signature);
+ case SIGN_ECDSA_256:
+ /* r||s -> Botan::IEEE_1363 */
+ return build_signature(this->key, "EMSA1(SHA-256)",
+ SIG_FORMAT_IEEE_1363, data, signature);
+ case SIGN_ECDSA_384:
+ /* r||s -> Botan::IEEE_1363 */
+ return build_signature(this->key, "EMSA1(SHA-384)",
+ SIG_FORMAT_IEEE_1363, data, signature);
+ case SIGN_ECDSA_521:
+ /* r||s -> Botan::IEEE_1363 */
+ return build_signature(this->key, "EMSA1(SHA-512)",
+ SIG_FORMAT_IEEE_1363, data, signature);
+ default:
+ DBG1(DBG_LIB, "signature scheme %N not supported via botan",
+ signature_scheme_names, scheme);
+ return FALSE;
+ }
+}
+
+METHOD(private_key_t, decrypt, bool,
+ private_botan_ec_private_key_t *this, encryption_scheme_t scheme,
+ chunk_t crypto, chunk_t *plain)
+{
+ DBG1(DBG_LIB, "EC private key decryption not implemented");
+ return FALSE;
+}
+
+METHOD(private_key_t, get_keysize, int,
+ private_botan_ec_private_key_t *this)
+{
+ botan_mp_t p;
+ if(botan_mp_init(&p))
+ {
+ return 0;
+ }
+
+ if(botan_privkey_get_field(p, this->key, "p"))
+ {
+ botan_mp_destroy(p);
+ return 0;
+ }
+
+ size_t bits = 0;
+ if(botan_mp_num_bits(p, &bits))
+ {
+ botan_mp_destroy(p);
+ return 0;
+ }
+
+ botan_mp_destroy(p);
+ return bits;
+}
+
+METHOD(private_key_t, get_type, key_type_t,
+ private_botan_ec_private_key_t *this)
+{
+ return KEY_ECDSA;
+}
+
+METHOD(private_key_t, get_public_key, public_key_t*,
+ private_botan_ec_private_key_t *this)
+{
+ public_key_t *public;
+ chunk_t key = chunk_empty;
+
+ botan_pubkey_t pubkey;
+ if (botan_privkey_export_pubkey(&pubkey, this->key))
+ {
+ return FALSE;
+ }
+
+ if (botan_pubkey_export(pubkey, NULL, &key.len,
+ BOTAN_PRIVKEY_EXPORT_FLAG_DER)
+ != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ botan_pubkey_destroy(pubkey);
+ return FALSE;
+ }
+
+ key = chunk_alloc(key.len);
+
+ if (botan_pubkey_export(pubkey, key.ptr, &key.len,
+ BOTAN_PRIVKEY_EXPORT_FLAG_DER))
+ {
+ chunk_free(&key);
+ botan_pubkey_destroy(pubkey);
+ return FALSE;
+ }
+
+ public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA,
+ BUILD_BLOB_ASN1_DER, key, BUILD_END);
+
+ chunk_free(&key);
+ botan_pubkey_destroy(pubkey);
+ return public;
+}
+
+METHOD(private_key_t, get_fingerprint, bool,
+ private_botan_ec_private_key_t *this, cred_encoding_type_t type,
+ chunk_t *fingerprint)
+{
+ bool success = FALSE;
+
+ botan_pubkey_t pubkey;
+ if (botan_privkey_export_pubkey(&pubkey, this->key))
+ {
+ return FALSE;
+ }
+
+ success = botan_ec_fingerprint(&pubkey, type, fingerprint);
+ botan_pubkey_destroy(pubkey);
+ return success;
+}
+
+METHOD(private_key_t, get_encoding, bool,
+ private_botan_ec_private_key_t *this, cred_encoding_type_t type,
+ chunk_t *encoding)
+{
+ switch (type)
+ {
+ case PRIVKEY_ASN1_DER:
+ case PRIVKEY_PEM:
+ {
+ bool success = TRUE;
+
+ botan_mp_t x;
+ if (botan_mp_init(&x))
+ {
+ return FALSE;
+ }
+
+ if (botan_privkey_get_field(x, this->key, "x"))
+ {
+ botan_mp_destroy(x);
+ return FALSE;
+ }
+
+ chunk_t pval = chunk_empty;
+ if (botan_mp_num_bytes(x, &pval.len))
+ {
+ botan_mp_destroy(x);
+ return FALSE;
+ }
+
+ pval = chunk_alloc(pval.len);
+
+ if (botan_mp_to_bin(x, pval.ptr))
+ {
+ botan_mp_destroy(x);
+ return FALSE;
+ }
+
+ chunk_t version = chunk_from_chars( 0x01 );
+ *encoding =
+ asn1_wrap(ASN1_SEQUENCE, "ms", asn1_integer("c", version),
+ asn1_wrap(ASN1_OCTET_STRING, "s", pval));
+
+ if (type == PRIVKEY_PEM)
+ {
+ chunk_t asn1_encoding = *encoding;
+
+ success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM,
+ NULL, encoding,
+ CRED_PART_ECDSA_PRIV_ASN1_DER,
+ asn1_encoding, CRED_PART_END);
+ chunk_clear(&asn1_encoding);
+ }
+
+ botan_mp_destroy(x);
+ return success;
+ }
+ default:
+ return FALSE;
+ }
+}
+
+METHOD(private_key_t, get_ref, private_key_t*,
+ private_botan_ec_private_key_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.key;
+}
+
+METHOD(private_key_t, destroy, void,
+ private_botan_ec_private_key_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ if (&this->key)
+ {
+ lib->encoding->clear_cache(lib->encoding, &this->key);
+ botan_privkey_destroy(this->key);
+ }
+ free(this);
+ }
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_botan_ec_private_key_t *create_empty()
+{
+ private_botan_ec_private_key_t *this;
+
+ INIT(this,
+ .public = {
+ .key = {
+ .get_type = _get_type,
+ .sign = _sign,
+ .decrypt = _decrypt,
+ .get_keysize = _get_keysize,
+ .get_public_key = _get_public_key,
+ .equals = private_key_equals,
+ .belongs_to = private_key_belongs_to,
+ .get_fingerprint = _get_fingerprint,
+ .has_fingerprint = private_key_has_fingerprint,
+ .get_encoding = _get_encoding,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ },
+ .ref = 1,
+ );
+
+ return this;
+}
+
+/*
+ * See header.
+ */
+botan_ec_private_key_t *botan_ec_private_key_gen(key_type_t type, va_list args)
+{
+ private_botan_ec_private_key_t *this;
+ u_int key_size = 0;
+ const char* curve;
+
+ while (TRUE)
+ {
+ switch (va_arg(args, builder_part_t))
+ {
+ case BUILD_KEY_SIZE:
+ key_size = va_arg(args, u_int);
+ continue;
+ case BUILD_END:
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ }
+
+ if (!key_size)
+ {
+ return NULL;
+ }
+
+ switch (key_size)
+ {
+ case 256:
+ curve = "secp256r1";
+ break;
+ case 384:
+ curve = "secp384r1";
+ break;
+ case 521:
+ curve = "secp521r1";
+ break;
+ default:
+ DBG1(DBG_LIB, "EC private key size %d not supported via botan",
+ key_size);
+ return NULL;
+ }
+
+ botan_rng_t rng;
+ if (botan_rng_init(&rng, "user"))
+ {
+ return NULL;
+ }
+
+ this = create_empty();
+
+ if(botan_privkey_create_ecdsa(&this->key, rng, curve))
+ {
+ DBG1(DBG_LIB, "EC private key generation failed", key_size);
+ botan_rng_destroy(rng);
+ destroy(this);
+ return NULL;
+ }
+
+ botan_rng_destroy(rng);
+ return &this->public;
+}
+
+/**
+ * ASN.1 definition of a ECPrivateKey structure (RFC 5915)
+ */
+static const asn1Object_t ecPrivateKeyObjects[] = {
+ { 0, "ECPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
+ { 1, "privateKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
+ { 1, "parameters", ASN1_EOC, ASN1_RAW }, /* 3 */
+ { 1, "publicKey", ASN1_BIT_STRING, ASN1_OPT }, /* 4 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+
+#define ECPK_PRIVATE_KEY 2
+#define ECPK_PRIVATE_KEY_PARAMS 3
+
+/**
+ * See header.
+ */
+botan_ec_private_key_t *botan_ec_private_key_load(key_type_t type, va_list args)
+{
+ private_botan_ec_private_key_t *this;
+ chunk_t params = chunk_empty, key = chunk_empty;
+ chunk_t object, pkcs8 = chunk_empty;
+
+ while (TRUE)
+ {
+ switch (va_arg(args, builder_part_t))
+ {
+ case BUILD_BLOB_ALGID_PARAMS:
+ params = va_arg(args, chunk_t);
+ continue;
+ case BUILD_BLOB_ASN1_DER:
+ key = va_arg(args, chunk_t);
+ continue;
+ case BUILD_END:
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ }
+
+ this = create_empty();
+
+ /*
+ * botan expects a PKCS#8 private key, so we build one
+ * RFC 5282 mandates ECParameters as part of the algorithmIdentifier
+ */
+ chunk_t alg_id = chunk_empty;
+ if(params.len != 0)
+ {
+ /* if ECDomainParameters is passed, just append it */
+ alg_id = asn1_wrap(ASN1_SEQUENCE, "mc",
+ asn1_build_known_oid(OID_EC_PUBLICKEY), params);
+ }
+ else
+ {
+ /*
+ * no explicit ECParameters passed, so we extract them from the
+ * ECPrivateKey structure and append it to the algorithmIdentifier
+ */
+ asn1_parser_t *parser;
+ int objectID;
+
+ parser = asn1_parser_create(ecPrivateKeyObjects, key);
+ parser->set_flags(parser, FALSE, TRUE);
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ if (objectID == ECPK_PRIVATE_KEY_PARAMS)
+ {
+ if (!asn1_parse_simple_object(&object, ASN1_CONTEXT_C_0, 0,
+ "parameters"))
+ {
+ parser->destroy(parser);
+ return NULL;
+ }
+
+ if (asn1_unwrap(&object, ¶ms) != ASN1_OID)
+ {
+ parser->destroy(parser);
+ return NULL;
+ }
+
+ break;
+ }
+ }
+
+ parser->destroy(parser);
+ alg_id = asn1_wrap(ASN1_SEQUENCE, "mc",
+ asn1_build_known_oid(OID_EC_PUBLICKEY),
+ asn1_simple_object(ASN1_OID, params));
+ }
+
+ pkcs8 = asn1_wrap(ASN1_SEQUENCE, "cms",
+ asn1_integer("c", chunk_from_chars(0x00)),
+ alg_id,
+ asn1_wrap(ASN1_OCTET_STRING, "c", key));
+
+ botan_rng_t rng;
+ if (botan_rng_init(&rng, "user"))
+ {
+ chunk_clear(&pkcs8);
+ destroy(this);
+ return NULL;
+ }
+
+ if (botan_privkey_load(&this->key, rng, pkcs8.ptr, pkcs8.len, NULL))
+ {
+ chunk_clear(&pkcs8);
+ botan_rng_destroy(rng);
+ destroy(this);
+ return NULL;
+ }
+
+ chunk_clear(&pkcs8);
+ botan_rng_destroy(rng);
+ return &this->public;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Copyright (C) 2018 Konstantinos Kolelis
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_ec_private_key botan_ec_private_key
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_EC_PRIVATE_KEY_H_
+#define BOTAN_EC_PRIVATE_KEY_H_
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_ECDSA
+
+#include <credentials/builder.h>
+#include <credentials/keys/private_key.h>
+
+typedef struct botan_ec_private_key_t botan_ec_private_key_t;
+
+/**
+ * private_key_t implementation of ECDSA using Botan.
+ */
+struct botan_ec_private_key_t {
+
+ /**
+ * Implements private_key_t interface
+ */
+ private_key_t key;
+};
+
+/**
+ * Generate a ECDSA private key using Botan.
+ *
+ * Accepts the BUILD_KEY_SIZE argument.
+ *
+ * @param type type of the key, must be KEY_ECDSA
+ * @param args builder_part_t argument list
+ * @return generated key, NULL on failure
+ */
+botan_ec_private_key_t *botan_ec_private_key_gen(key_type_t type, va_list args);
+
+/**
+ * Load a ECDSA private key using Botan.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type type of the key, must be KEY_ECDSA
+ * @param args builder_part_t argument list
+ * @return loaded key, NULL on failure
+ */
+botan_ec_private_key_t *botan_ec_private_key_load(key_type_t type,
+ va_list args);
+
+#endif
+
+#endif /** BOTAN_EC_PRIVATE_KEY_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Copyright (C) 2018 Konstantinos Kolelis
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_ec_public_key.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_ECDSA
+
+#include <asn1/asn1.h>
+#include <asn1/asn1_parser.h>
+
+#include <utils/debug.h>
+
+#include <botan/ffi.h>
+
+typedef struct private_botan_ec_public_key_t private_botan_ec_public_key_t;
+
+/**
+ * Private data structure with signing context.
+ */
+struct private_botan_ec_public_key_t {
+ /**
+ * Public interface for this signer
+ */
+ botan_ec_public_key_t public;
+
+ /**
+ * Botan ec public key
+ */
+ botan_pubkey_t key;
+
+ /**
+ * Reference counter
+ */
+ refcount_t ref;
+};
+
+#define SIG_FORMAT_IEEE_1363 0
+#define SIG_FORMAT_DER_SEQUENCE 1
+
+/**
+ * Verification of a DER encoded signature as in RFC 3279 or as in RFC 4754
+ */
+static bool verify_signature(private_botan_ec_public_key_t *this,
+ const char* hash_and_padding, int signature_format, size_t keylen,
+ chunk_t data, chunk_t signature)
+{
+ chunk_t sig;
+
+ if (signature_format == SIG_FORMAT_DER_SEQUENCE)
+ {
+ /*
+ * botan requires a signature in IEEE 1363 format (r||s)
+ * re-encode from ASN.1 sequence of two integers r,s
+ */
+ chunk_t parse, r, s;
+ parse = signature;
+
+ if (asn1_unwrap(&parse, &parse) != ASN1_SEQUENCE
+ || asn1_unwrap(&parse, &r) != ASN1_INTEGER
+ || asn1_unwrap(&parse, &s) != ASN1_INTEGER)
+ {
+ return FALSE;
+ }
+
+ r = chunk_skip_zero(r);
+ s = chunk_skip_zero(s);
+
+ /*
+ * r and s must be of size m_order.bytes()/2 each
+ */
+ if (r.len > keylen || s.len > keylen)
+ {
+ return FALSE;
+ }
+
+ sig = chunk_alloca(2 * keylen);
+ memset(sig.ptr, 0, sig.len);
+ memcpy(sig.ptr + (keylen - r.len), r.ptr, r.len);
+ memcpy(sig.ptr + keylen + (keylen - s.len), s.ptr, s.len);
+ }
+ else
+ {
+ sig.ptr = signature.ptr;
+ sig.len = signature.len;
+ }
+
+ {
+ botan_pk_op_verify_t verify_op;
+ bool valid = FALSE;
+
+ if (botan_pk_op_verify_create(&verify_op, this->key, hash_and_padding,
+ 0))
+ {
+ return FALSE;
+ }
+
+ if (botan_pk_op_verify_update(verify_op, data.ptr, data.len))
+ {
+ botan_pk_op_verify_destroy(verify_op);
+ return FALSE;
+ }
+
+ valid = !(botan_pk_op_verify_finish(verify_op, sig.ptr, sig.len));
+
+ botan_pk_op_verify_destroy(verify_op);
+
+ return valid;
+ }
+}
+
+METHOD(public_key_t, get_type, key_type_t,
+ private_botan_ec_public_key_t *this)
+{
+ return KEY_ECDSA;
+}
+
+METHOD(public_key_t, get_keysize, int,
+ private_botan_ec_public_key_t *this)
+{
+ botan_mp_t p;
+ if(botan_mp_init(&p))
+ {
+ return 0;
+ }
+
+ if(botan_pubkey_get_field(p, this->key, "p"))
+ {
+ botan_mp_destroy(p);
+ return 0;
+ }
+
+ size_t bits = 0;
+ if(botan_mp_num_bits(p, &bits))
+ {
+ botan_mp_destroy(p);
+ return 0;
+ }
+
+ botan_mp_destroy(p);
+ return bits;
+}
+
+METHOD(public_key_t, verify, bool,
+ private_botan_ec_public_key_t *this, signature_scheme_t scheme,
+ void *params, chunk_t data, chunk_t signature)
+{
+ size_t keylen = (get_keysize(this) + 7) / 8;
+ const char *hash_and_padding;
+ int sig_format;
+
+ switch (scheme)
+ {
+ case SIGN_ECDSA_WITH_NULL:
+ /* r||s -> Botan::IEEE_1363, data is the hash already */
+ hash_and_padding = "Raw";
+ sig_format = SIG_FORMAT_IEEE_1363;
+ break;
+ case SIGN_ECDSA_WITH_SHA1_DER:
+ /* DER SEQUENCE of two INTEGERS r,s -> Botan::DER_SEQUENCE */
+ hash_and_padding = "EMSA1(SHA-1)";
+ sig_format = SIG_FORMAT_DER_SEQUENCE;
+ break;
+ case SIGN_ECDSA_WITH_SHA256_DER:
+ hash_and_padding = "EMSA1(SHA-256)";
+ sig_format = SIG_FORMAT_DER_SEQUENCE;
+ break;
+ case SIGN_ECDSA_WITH_SHA384_DER:
+ hash_and_padding = "EMSA1(SHA-384)";
+ sig_format = SIG_FORMAT_DER_SEQUENCE;
+ break;
+ case SIGN_ECDSA_WITH_SHA512_DER:
+ hash_and_padding = "EMSA1(SHA-512)";
+ sig_format = SIG_FORMAT_DER_SEQUENCE;
+ break;
+ case SIGN_ECDSA_256:
+ /* r||s -> Botan::IEEE_1363 */
+ hash_and_padding = "EMSA1(SHA-256)";
+ sig_format = SIG_FORMAT_IEEE_1363;
+ break;
+ case SIGN_ECDSA_384:
+ /* r||s -> Botan::IEEE_1363 */
+ hash_and_padding = "EMSA1(SHA-384)";
+ sig_format = SIG_FORMAT_IEEE_1363;
+ break;
+ case SIGN_ECDSA_521:
+ /* r||s -> Botan::IEEE_1363 */
+ hash_and_padding = "EMSA1(SHA-512)";
+ sig_format = SIG_FORMAT_IEEE_1363;
+ break;
+ default:
+ DBG1(DBG_LIB, "signature scheme %N not supported via botan",
+ signature_scheme_names, scheme);
+ return FALSE;
+ }
+
+ return verify_signature(this, hash_and_padding,
+ sig_format, keylen, data, signature);
+}
+
+METHOD(public_key_t, encrypt, bool,
+ private_botan_ec_public_key_t *this, encryption_scheme_t scheme,
+ chunk_t crypto, chunk_t *plain)
+{
+ DBG1(DBG_LIB, "EC public key encryption not implemented");
+ return FALSE;
+}
+
+/**
+ * Calculate fingerprint from a botan_pubkey_t, also used in ec private key.
+ */
+bool botan_ec_fingerprint(botan_pubkey_t *ec, cred_encoding_type_t type,
+ chunk_t *fp)
+{
+ hasher_t *hasher;
+ chunk_t key;
+
+ if (lib->encoding->get_cache(lib->encoding, type, ec, fp))
+ {
+ return TRUE;
+ }
+
+ switch (type)
+ {
+ case KEYID_PUBKEY_SHA1:
+ /* subjectPublicKey -> use botan_pubkey_fingerprint() */
+ {
+ if (botan_pubkey_fingerprint(*ec, "SHA-1", NULL, &fp->len))
+ {
+ return FALSE;
+ }
+
+ *fp = chunk_alloc(fp->len);
+
+ if (botan_pubkey_fingerprint(*ec, "SHA-1", fp->ptr, &fp->len))
+ {
+ chunk_free(fp);
+ return FALSE;
+ }
+
+ break;
+ }
+ case KEYID_PUBKEY_INFO_SHA1:
+ /* subjectPublicKeyInfo -> use botan_pubkey_export(), then hash */
+ {
+ if (botan_pubkey_export(*ec, NULL, &key.len,
+ BOTAN_PRIVKEY_EXPORT_FLAG_DER))
+ {
+ return FALSE;
+ }
+
+ key = chunk_alloc(key.len);
+
+ if (botan_pubkey_export(*ec, key.ptr, &key.len,
+ BOTAN_PRIVKEY_EXPORT_FLAG_DER))
+ {
+ chunk_free(&key);
+ return FALSE;
+ }
+
+ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ if (!hasher || !hasher->allocate_hash(hasher, key, fp))
+ {
+ DBG1(DBG_LIB, "SHA1 hash algorithm not supported,"
+ " fingerprinting failed");
+ DESTROY_IF(hasher);
+ chunk_free(&key);
+ return FALSE;
+ }
+
+ hasher->destroy(hasher);
+ chunk_free(&key);
+ break;
+ }
+ default:
+ return FALSE;
+ }
+
+ lib->encoding->cache(lib->encoding, type, ec, *fp);
+ return TRUE;
+}
+
+METHOD(public_key_t, get_fingerprint, bool,
+ private_botan_ec_public_key_t *this, cred_encoding_type_t type,
+ chunk_t *fingerprint)
+{
+ return botan_ec_fingerprint(&this->key, type, fingerprint);
+}
+
+METHOD(public_key_t, get_encoding, bool,
+ private_botan_ec_public_key_t *this, cred_encoding_type_t type,
+ chunk_t *encoding)
+{
+ bool success = TRUE;
+
+ if (botan_pubkey_export(this->key, NULL, &encoding->len,
+ BOTAN_PRIVKEY_EXPORT_FLAG_DER))
+ {
+ return FALSE;
+ }
+
+ *encoding = chunk_alloc(encoding->len);
+
+ if (botan_pubkey_export(this->key, encoding->ptr, &encoding->len,
+ BOTAN_PRIVKEY_EXPORT_FLAG_DER))
+ {
+ chunk_free(encoding);
+ return FALSE;
+ }
+
+ if (type != PUBKEY_SPKI_ASN1_DER)
+ {
+ chunk_t asn1_encoding = *encoding;
+
+ success = lib->encoding->encode(lib->encoding, type, NULL, encoding,
+ CRED_PART_ECDSA_PUB_ASN1_DER,
+ asn1_encoding, CRED_PART_END);
+ chunk_free(&asn1_encoding);
+ }
+
+ return success;
+}
+
+METHOD(public_key_t, get_ref, public_key_t*,
+ private_botan_ec_public_key_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.key;
+}
+
+METHOD(public_key_t, destroy, void,
+ private_botan_ec_public_key_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ botan_pubkey_destroy(this->key);
+ free(this);
+ }
+}
+
+/**
+ * See header.
+ */
+botan_ec_public_key_t *botan_ec_public_key_load(key_type_t type, va_list args)
+{
+ private_botan_ec_public_key_t *this;
+ chunk_t blob = chunk_empty;
+
+ if (type != KEY_ECDSA)
+ {
+ return NULL;
+ }
+
+ while (TRUE)
+ {
+ switch (va_arg(args, builder_part_t))
+ {
+ case BUILD_BLOB_ASN1_DER:
+ blob = va_arg(args, chunk_t);
+ continue;
+ case BUILD_END:
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ }
+
+ INIT(this,
+ .public = {
+ .key = {
+ .get_type = _get_type,
+ .verify = _verify,
+ .encrypt = _encrypt,
+ .get_keysize = _get_keysize,
+ .equals = public_key_equals,
+ .get_fingerprint = _get_fingerprint,
+ .has_fingerprint = public_key_has_fingerprint,
+ .get_encoding = _get_encoding,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ },
+ .ref = 1,
+ );
+
+ if (botan_pubkey_load(&this->key, blob.ptr, blob.len))
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ size_t namesize = 0;
+ if (botan_pubkey_algo_name(this->key, NULL, &namesize) !=
+ BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ botan_pubkey_destroy(this->key);
+ destroy(this);
+ return NULL;
+ }
+
+ char* namebuf = malloc(namesize);
+ if (botan_pubkey_algo_name(this->key, namebuf, &namesize))
+ {
+ free(namebuf);
+ botan_pubkey_destroy(this->key);
+ destroy(this);
+ return NULL;
+ }
+
+ const char* algo_name = "ECDSA";
+ if (!strneq(namebuf, algo_name, sizeof(algo_name)))
+ {
+ free(namebuf);
+ botan_pubkey_destroy(this->key);
+ destroy(this);
+ return NULL;
+ }
+ free(namebuf);
+
+ botan_rng_t rng;
+ if (botan_rng_init(&rng, "user"))
+ {
+ return FALSE;
+ }
+
+ if (botan_pubkey_check_key(this->key, rng, BOTAN_CHECK_KEY_EXPENSIVE_TESTS))
+ {
+ DBG1(DBG_LIB, "public key failed key checks");
+ botan_rng_destroy(rng);
+ botan_pubkey_destroy(this->key);
+ destroy(this);
+ return NULL;
+ }
+
+ botan_rng_destroy(rng);
+ return &this->public;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Copyright (C) 2018 Konstantinos Kolelis
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef BOTAN_EC_PUBLIC_KEY_H_
+#define BOTAN_EC_PUBLIC_KEY_H_
+
+typedef struct botan_ec_public_key_t botan_ec_public_key_t;
+
+#include <credentials/builder.h>
+#include <credentials/keys/public_key.h>
+
+/**
+ * public_key_t implementation of ECDSA using botan.
+ */
+struct botan_ec_public_key_t {
+
+ /**
+ * Implements the public_key_t interface
+ */
+ public_key_t key;
+};
+
+/**
+ * Load a ECDSA public key using botan.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type type of the key, must be KEY_ECDSA
+ * @param args builder_part_t argument list
+ * @return loaded key, NULL on failure
+ */
+botan_ec_public_key_t *botan_ec_public_key_load(key_type_t type, va_list args);
+
+#endif /** BOTAN_EC_PUBLIC_KEY_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2018 Atanas Filyanov
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_gcm.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_AES
+#ifdef BOTAN_HAS_AEAD_GCM
+
+#include <crypto/iv/iv_gen_seq.h>
+
+#include <botan/ffi.h>
+
+/**
+ * as defined in RFC 4106
+ */
+#define IV_LEN 8
+#define SALT_LEN 4
+#define NONCE_LEN (IV_LEN + SALT_LEN)
+
+typedef struct private_aead_t private_aead_t;
+
+struct private_aead_t {
+
+ /**
+ * Public interface
+ */
+ aead_t public;
+
+ /**
+ * The encryption key
+ */
+ chunk_t key;
+
+ /**
+ * Salt value
+ */
+ char salt[SALT_LEN];
+
+ /**
+ * Size of the integrity check value
+ */
+ size_t icv_size;
+
+ /**
+ * IV generator
+ */
+ iv_gen_t *iv_gen;
+
+ /**
+ * The cipher to use
+ */
+ const char* cipher_name;
+};
+
+/**
+ * Do the actual en/decryption
+ */
+static bool crypt(private_aead_t *this, chunk_t data, chunk_t assoc, chunk_t iv,
+ u_char *out, uint32_t init_flag)
+{
+ botan_cipher_t cipher;
+ uint8_t nonce[NONCE_LEN];
+ size_t output_written = 0;
+ size_t input_consumed = 0;
+
+ memcpy(nonce, this->salt, SALT_LEN);
+ memcpy(nonce + SALT_LEN, iv.ptr, IV_LEN);
+
+ if (botan_cipher_init(&cipher, this->cipher_name, init_flag))
+ {
+ return FALSE;
+ }
+
+ if (botan_cipher_set_key(cipher, this->key.ptr, this->key.len))
+ {
+ botan_cipher_destroy(cipher);
+ return FALSE;
+ }
+
+ if (assoc.len
+ && botan_cipher_set_associated_data(cipher, assoc.ptr, assoc.len))
+ {
+ botan_cipher_destroy(cipher);
+ return FALSE;
+ }
+
+ if (botan_cipher_start(cipher, nonce, NONCE_LEN))
+ {
+ botan_cipher_destroy(cipher);
+ return FALSE;
+ }
+
+ if (init_flag == BOTAN_CIPHER_INIT_FLAG_ENCRYPT)
+ {
+ if (botan_cipher_update(cipher, BOTAN_CIPHER_UPDATE_FLAG_FINAL,
+ out, data.len + this->icv_size, &output_written,
+ data.ptr, data.len, &input_consumed))
+ {
+ botan_cipher_destroy(cipher);
+ return FALSE;
+ }
+ }
+ else if (init_flag == BOTAN_CIPHER_INIT_FLAG_DECRYPT)
+ {
+ if (botan_cipher_update(cipher, BOTAN_CIPHER_UPDATE_FLAG_FINAL,
+ out, data.len, &output_written,
+ data.ptr, data.len + this->icv_size, &input_consumed))
+ {
+ botan_cipher_destroy(cipher);
+ return FALSE;
+ }
+ }
+
+ botan_cipher_destroy(cipher);
+
+ return TRUE;
+}
+
+METHOD(aead_t, encrypt, bool,
+ private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
+ chunk_t *encrypted)
+{
+ u_char *out;
+
+ out = plain.ptr;
+ if (encrypted)
+ {
+ *encrypted = chunk_alloc(plain.len + this->icv_size);
+ out = encrypted->ptr;
+ }
+ return crypt(this, plain, assoc, iv, out, BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
+}
+
+METHOD(aead_t, decrypt, bool,
+ private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
+ chunk_t *plain)
+{
+ u_char *out;
+
+ if (encrypted.len < this->icv_size)
+ {
+ return FALSE;
+ }
+ encrypted.len -= this->icv_size;
+
+ out = encrypted.ptr;
+ if (plain)
+ {
+ *plain = chunk_alloc(encrypted.len);
+ out = plain->ptr;
+ }
+ return crypt(this, encrypted, assoc, iv, out,
+ BOTAN_CIPHER_INIT_FLAG_DECRYPT);
+}
+
+METHOD(aead_t, get_block_size, size_t,
+ private_aead_t *this)
+{
+ return 1;
+}
+
+METHOD(aead_t, get_icv_size, size_t,
+ private_aead_t *this)
+{
+ return this->icv_size;
+}
+
+METHOD(aead_t, get_iv_size, size_t,
+ private_aead_t *this)
+{
+ return IV_LEN;
+}
+
+METHOD(aead_t, get_iv_gen, iv_gen_t*,
+ private_aead_t *this)
+{
+ return this->iv_gen;
+}
+
+METHOD(aead_t, get_key_size, size_t,
+ private_aead_t *this)
+{
+ return this->key.len + SALT_LEN;
+}
+
+METHOD(aead_t, set_key, bool,
+ private_aead_t *this, chunk_t key)
+{
+ if (key.len != get_key_size(this))
+ {
+ return FALSE;
+ }
+ memcpy(this->salt, key.ptr + key.len - SALT_LEN, SALT_LEN);
+ memcpy(this->key.ptr, key.ptr, this->key.len);
+ return TRUE;
+}
+
+METHOD(aead_t, destroy, void,
+ private_aead_t *this)
+{
+ chunk_clear(&this->key);
+ this->iv_gen->destroy(this->iv_gen);
+ free(this);
+}
+
+aead_t *botan_gcm_create(encryption_algorithm_t algo,
+ size_t key_size, size_t salt_size)
+{
+ private_aead_t *this;
+
+ INIT(this,
+ .public = {
+ .encrypt = _encrypt,
+ .decrypt = _decrypt,
+ .get_block_size = _get_block_size,
+ .get_icv_size = _get_icv_size,
+ .get_iv_size = _get_iv_size,
+ .get_iv_gen = _get_iv_gen,
+ .get_key_size = _get_key_size,
+ .set_key = _set_key,
+ .destroy = _destroy,
+ },
+ );
+
+ switch (algo)
+ {
+ case ENCR_AES_GCM_ICV8:
+ this->icv_size = 8;
+ break;
+ case ENCR_AES_GCM_ICV12:
+ this->icv_size = 12;
+ break;
+ case ENCR_AES_GCM_ICV16:
+ this->icv_size = 16;
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+
+ if (salt_size && salt_size != SALT_LEN)
+ {
+ /* currently not supported */
+ free(this);
+ return NULL;
+ }
+
+ switch (algo)
+ {
+ case ENCR_AES_GCM_ICV8:
+ switch (key_size)
+ {
+ case 0:
+ key_size = 16;
+ case 16:
+ this->cipher_name = "AES-128/GCM(8)";
+ break;
+ case 24:
+ this->cipher_name = "AES-192/GCM(8)";
+ break;
+ case 32:
+ this->cipher_name = "AES-256/GCM(8)";
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+ break;
+ case ENCR_AES_GCM_ICV12:
+ switch (key_size)
+ {
+ case 0:
+ key_size = 16;
+ /* FALL */
+ case 16:
+ this->cipher_name = "AES-128/GCM(12)";
+ break;
+ case 24:
+ this->cipher_name = "AES-192/GCM(12)";
+ break;
+ case 32:
+ this->cipher_name = "AES-256/GCM(12)";
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+ break;
+ case ENCR_AES_GCM_ICV16:
+ switch (key_size)
+ {
+ case 0:
+ key_size = 16;
+ /* FALL */
+ case 16:
+ this->cipher_name = "AES-128/GCM";
+ break;
+ case 24:
+ this->cipher_name = "AES-192/GCM";
+ break;
+ case 32:
+ this->cipher_name = "AES-256/GCM";
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+ break;
+ default:
+ free(this);
+ return NULL;
+ }
+
+ if (!this->cipher_name)
+ {
+ free(this);
+ return NULL;
+ }
+
+ this->key = chunk_alloc(key_size);
+ this->iv_gen = iv_gen_seq_create();
+
+ return &this->public;
+}
+
+#endif
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2018 Atanas Filyanov
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Implements the aead_t interface using Botan in GCM mode.
+ *
+ * @defgroup botan_gcm botan_gcm
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_GCM_H_
+#define BOTAN_GCM_H_
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_AEAD_GCM
+
+#include <crypto/aead.h>
+
+/**
+ * Constructor to create aead_t implementation.
+ *
+ * @param algo algorithm to implement
+ * @param key_size key size in bytes
+ * @param salt_size size of implicit salt length
+ * @return aead_t object, NULL if not supported
+ */
+aead_t *botan_gcm_create(encryption_algorithm_t algo, size_t key_size,
+ size_t salt_size);
+
+#endif
+
+#endif /** BOTAN_GCM_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_hasher.h"
+
+#include <utils/debug.h>
+
+#include <botan/ffi.h>
+
+typedef struct private_botan_hasher_t private_botan_hasher_t;
+
+/**
+ * Private data of botan_hasher_t
+ */
+struct private_botan_hasher_t {
+
+ /**
+ * Public part of this class.
+ */
+ botan_hasher_t public;
+
+ /**
+ * botan hash instance
+ */
+ botan_hash_t hash;
+};
+
+METHOD(hasher_t, get_hash_size, size_t,
+ private_botan_hasher_t *this)
+{
+ size_t len = 0;
+ if (botan_hash_output_length(this->hash, &len))
+ {
+ return 0;
+ }
+ return len;
+}
+
+METHOD(hasher_t, reset, bool,
+ private_botan_hasher_t *this)
+{
+ if (botan_hash_clear(this->hash))
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(hasher_t, get_hash, bool,
+ private_botan_hasher_t *this, chunk_t chunk, uint8_t *hash)
+{
+ if (botan_hash_update(this->hash, chunk.ptr, chunk.len))
+ {
+ return FALSE;
+ }
+
+ if (hash)
+ {
+ if (botan_hash_final(this->hash, hash))
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+METHOD(hasher_t, allocate_hash, bool,
+ private_botan_hasher_t *this, chunk_t chunk, chunk_t *hash)
+{
+ if (hash)
+ {
+ *hash = chunk_alloc(get_hash_size(this));
+ return get_hash(this, chunk, hash->ptr);
+ }
+ return get_hash(this, chunk, NULL);
+}
+
+METHOD(hasher_t, destroy, void,
+ private_botan_hasher_t *this)
+{
+ botan_hash_destroy(this->hash);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+botan_hasher_t *botan_hasher_create(hash_algorithm_t algo)
+{
+ private_botan_hasher_t *this;
+ const char* hash_name;
+
+ switch (algo)
+ {
+ case HASH_SHA1:
+ hash_name = "SHA-1";
+ break;
+ case HASH_SHA224:
+ hash_name = "SHA-224";
+ break;
+ case HASH_SHA256:
+ hash_name = "SHA-256";
+ break;
+ case HASH_SHA384:
+ hash_name = "SHA-384";
+ break;
+ case HASH_SHA512:
+ hash_name = "SHA-512";
+ break;
+ default:
+ return NULL;
+ }
+
+ INIT(this,
+ .public = {
+ .hasher = {
+ .get_hash = _get_hash,
+ .allocate_hash = _allocate_hash,
+ .get_hash_size = _get_hash_size,
+ .reset = _reset,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ if (botan_hash_init(&this->hash, hash_name, 0))
+ {
+ return NULL;
+ }
+
+ return &this->public;
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_hasher botan_hasher
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_HASHER_H_
+#define BOTAN_HASHER_H_
+
+typedef struct botan_hasher_t botan_hasher_t;
+
+#include <crypto/hashers/hasher.h>
+
+/**
+ * Implementation of hashers using botan.
+ */
+struct botan_hasher_t {
+
+ /**
+ * The hasher_t interface.
+ */
+ hasher_t hasher;
+};
+
+/**
+ * Constructor to create botan_hasher_t.
+ *
+ * @param algo algorithm
+ * @return botan_hasher_t, NULL if not supported
+ */
+botan_hasher_t *botan_hasher_create(hash_algorithm_t algo);
+
+#endif /** BOTAN_HASHER_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_hmac.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_HMAC
+
+#include <crypto/mac.h>
+#include <crypto/prfs/mac_prf.h>
+#include <crypto/signers/mac_signer.h>
+
+#include <botan/ffi.h>
+
+typedef struct private_botan_mac_t private_botan_mac_t;
+
+/**
+ * Private data of a mac_t object.
+ */
+struct private_botan_mac_t {
+
+ /**
+ * Public interface
+ */
+ mac_t public;
+
+ /**
+ * HMAC
+ */
+ botan_mac_t hmac;
+};
+
+METHOD(mac_t, set_key, bool,
+ private_botan_mac_t *this, chunk_t key)
+{
+ if (botan_mac_set_key(this->hmac, key.ptr, key.len))
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(mac_t, get_mac, bool,
+ private_botan_mac_t *this, chunk_t data, uint8_t *out)
+{
+ if (botan_mac_update(this->hmac, data.ptr, data.len))
+ {
+ return FALSE;
+ }
+
+ if ( out == NULL)
+ {
+ return TRUE;
+ }
+
+ if (botan_mac_final(this->hmac, out))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+METHOD(mac_t, get_mac_size, size_t,
+ private_botan_mac_t *this)
+{
+ size_t len = 0;
+ if (botan_mac_output_length(this->hmac, &len))
+ {
+ return 0;
+ }
+ return len;
+}
+
+METHOD(mac_t, destroy, void,
+ private_botan_mac_t *this)
+{
+ botan_mac_destroy(this->hmac);
+ free(this);
+}
+
+/*
+ * Create a Botan-backed implementation of the mac_t interface
+ */
+static mac_t *hmac_create(hash_algorithm_t algo)
+{
+ private_botan_mac_t *this;
+ const char* hmac_name;
+
+ switch (algo)
+ {
+ case HASH_SHA1:
+ hmac_name = "HMAC(SHA-1)";
+ break;
+ case HASH_SHA256:
+ hmac_name = "HMAC(SHA-256)";
+ break;
+ case HASH_SHA384:
+ hmac_name = "HMAC(SHA-384)";
+ break;
+ case HASH_SHA512:
+ hmac_name = "HMAC(SHA-512)";
+ break;
+ default:
+ return NULL;
+ }
+
+ INIT(this,
+ .public = {
+ .get_mac = _get_mac,
+ .get_mac_size = _get_mac_size,
+ .set_key = _set_key,
+ .destroy = _destroy,
+ }
+ );
+
+ if (botan_mac_init(&this->hmac, hmac_name, 0))
+ {
+ free(this);
+ return NULL;
+ }
+
+ return &this->public;
+}
+
+/*
+ * Described in header
+ */
+prf_t *botan_hmac_prf_create(pseudo_random_function_t algo)
+{
+ mac_t *hmac;
+
+ hmac = hmac_create(hasher_algorithm_from_prf(algo));
+ if (hmac)
+ {
+ return mac_prf_create(hmac);
+ }
+ return NULL;
+}
+
+/*
+ * Described in header
+ */
+signer_t *botan_hmac_signer_create(integrity_algorithm_t algo)
+{
+ mac_t *hmac;
+ size_t trunc;
+
+ hmac = hmac_create(hasher_algorithm_from_integrity(algo, &trunc));
+ if (hmac)
+ {
+ return mac_signer_create(hmac, trunc);
+ }
+ return NULL;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Implements HMAC based PRF and signer using Botan's HMAC functions.
+ *
+ * @defgroup botan_hmac botan_hmac
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_HMAC_H_
+#define BOTAN_HMAC_H_
+
+#include <crypto/prfs/prf.h>
+#include <crypto/signers/signer.h>
+
+/**
+ * Creates a new prf_t object based on an HMAC.
+ *
+ * @param algo algorithm to implement
+ * @return prf_t object, NULL if not supported
+ */
+prf_t *botan_hmac_prf_create(pseudo_random_function_t algo);
+
+/**
+ * Creates a new signer_t object based on an HMAC.
+ *
+ * @param algo algorithm to implement
+ * @return signer_t, NULL if not supported
+ */
+signer_t *botan_hmac_signer_create(integrity_algorithm_t algo);
+
+#endif /** BOTAN_HMAC_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Copyright (C) 2018 Konstantinos Kolelis
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_plugin.h"
+#include "botan_rng.h"
+#include "botan_hasher.h"
+#include "botan_crypter.h"
+#include "botan_diffie_hellman.h"
+#include "botan_hmac.h"
+#include "botan_rsa_public_key.h"
+#include "botan_rsa_private_key.h"
+#include "botan_ec_diffie_hellman.h"
+#include "botan_ec_public_key.h"
+#include "botan_ec_private_key.h"
+#include "botan_gcm.h"
+
+#include <library.h>
+
+#include <botan/build.h>
+#include <botan/ffi.h>
+
+typedef struct private_botan_plugin_t private_botan_plugin_t;
+
+/**
+ * private data of botan_plugin
+ */
+struct private_botan_plugin_t {
+
+ /**
+ * public functions
+ */
+ botan_plugin_t public;
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_botan_plugin_t *this)
+{
+ return "botan";
+}
+
+METHOD(plugin_t, get_features, int,
+ private_botan_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+
+#ifdef BOTAN_HAS_DIFFIE_HELLMAN
+ /* MODP DH groups */
+ PLUGIN_REGISTER(DH, botan_diffie_hellman_create),
+ PLUGIN_PROVIDE(DH, MODP_3072_BIT),
+ PLUGIN_PROVIDE(DH, MODP_4096_BIT),
+ PLUGIN_PROVIDE(DH, MODP_6144_BIT),
+ PLUGIN_PROVIDE(DH, MODP_8192_BIT),
+ PLUGIN_PROVIDE(DH, MODP_2048_BIT),
+ PLUGIN_PROVIDE(DH, MODP_2048_224),
+ PLUGIN_PROVIDE(DH, MODP_2048_256),
+ PLUGIN_PROVIDE(DH, MODP_1536_BIT),
+ PLUGIN_PROVIDE(DH, MODP_1024_BIT),
+ PLUGIN_PROVIDE(DH, MODP_1024_160),
+ PLUGIN_PROVIDE(DH, MODP_768_BIT),
+ PLUGIN_REGISTER(DH, botan_diffie_hellman_create_custom),
+ PLUGIN_PROVIDE(DH, MODP_CUSTOM),
+#endif
+ /* crypters */
+ PLUGIN_REGISTER(CRYPTER, botan_crypter_create),
+#ifdef BOTAN_HAS_AES
+ #ifdef BOTAN_HAS_MODE_CBC
+ PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 16),
+ PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 24),
+ PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 32),
+ #endif
+ #ifdef BOTAN_HAS_AEAD_GCM
+ /* AES GCM */
+ PLUGIN_REGISTER(AEAD, botan_gcm_create),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 16),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 24),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 32),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV12, 16),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV12, 24),
+ PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV12, 32),
+ #endif
+#endif
+ /* hashers */
+ PLUGIN_REGISTER(HASHER, botan_hasher_create),
+#ifdef BOTAN_HAS_SHA1
+ PLUGIN_PROVIDE(HASHER, HASH_SHA1),
+#endif
+#ifdef BOTAN_HAS_SHA2_32
+ PLUGIN_PROVIDE(HASHER, HASH_SHA224),
+ PLUGIN_PROVIDE(HASHER, HASH_SHA256),
+#endif
+#ifdef BOTAN_HAS_SHA2_64
+ PLUGIN_PROVIDE(HASHER, HASH_SHA384),
+ PLUGIN_PROVIDE(HASHER, HASH_SHA512),
+#endif
+ /* prfs */
+#ifdef BOTAN_HAS_HMAC
+ PLUGIN_REGISTER(PRF, botan_hmac_prf_create),
+#ifdef BOTAN_HAS_SHA1
+ PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA1),
+#endif
+#ifdef BOTAN_HAS_SHA2_32
+ PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA2_256),
+#endif
+#ifdef BOTAN_HAS_SHA2_64
+ PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA2_384),
+ PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA2_512),
+#endif
+ /* signer */
+ PLUGIN_REGISTER(SIGNER, botan_hmac_signer_create),
+#ifdef BOTAN_HAS_SHA1
+ PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA1_96),
+ PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA1_128),
+ PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA1_160),
+#endif
+#ifdef BOTAN_HAS_SHA2_32
+ PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_256_128),
+ PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_256_256),
+#endif
+#ifdef BOTAN_HAS_SHA2_64
+ PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_384_192),
+ PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_384_384),
+ PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_256),
+ PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_512),
+#endif
+
+#ifdef BOTAN_HAS_ECDH
+ /* EC DH groups */
+ PLUGIN_REGISTER(DH, botan_ec_diffie_hellman_create),
+ PLUGIN_PROVIDE(DH, ECP_256_BIT),
+ PLUGIN_PROVIDE(DH, ECP_384_BIT),
+ PLUGIN_PROVIDE(DH, ECP_521_BIT),
+ PLUGIN_PROVIDE(DH, ECP_256_BP),
+ PLUGIN_PROVIDE(DH, ECP_384_BP),
+ PLUGIN_PROVIDE(DH, ECP_512_BP),
+#endif
+#endif
+ /* RSA */
+#ifdef BOTAN_HAS_RSA
+ /* public/private key loading/generation */
+ PLUGIN_REGISTER(PUBKEY, botan_rsa_public_key_load, TRUE),
+ PLUGIN_PROVIDE(PUBKEY, KEY_RSA),
+ PLUGIN_REGISTER(PRIVKEY, botan_rsa_private_key_load, TRUE),
+ PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
+ PLUGIN_REGISTER(PRIVKEY_GEN, botan_rsa_private_key_gen, FALSE),
+ PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_RSA),
+ /* encryption/signature schemes */
+#ifdef BOTAN_HAS_EMSA_PKCS1
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_NULL),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_NULL),
+#ifdef BOTAN_HAS_SHA1
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA1),
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA1),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA1),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA1),
+#endif
+#ifdef BOTAN_HAS_SHA2_32
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_224),
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_256),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_224),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_256),
+#endif
+#ifdef BOTAN_HAS_SHA2_64
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_384),
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_512),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_384),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_512),
+#endif
+#endif
+#ifdef BOTAN_HAS_EMSA_PSSR
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PSS),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PSS),
+#endif
+ PLUGIN_PROVIDE(PRIVKEY_DECRYPT, ENCRYPT_RSA_PKCS1),
+ PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_PKCS1),
+#ifdef BOTAN_HAS_EME_OAEP
+#ifdef BOTAN_HAS_SHA2_32
+ PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_OAEP_SHA224),
+ PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_OAEP_SHA256),
+#endif
+#ifdef BOTAN_HAS_SHA2_64
+ PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_OAEP_SHA384),
+ PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_OAEP_SHA512),
+#endif
+#endif
+#endif /* BOTAN_HAS_RSA */
+
+#ifdef BOTAN_HAS_ECDSA
+ /* EC private/public key loading */
+ PLUGIN_REGISTER(PRIVKEY, botan_ec_private_key_load, TRUE),
+ PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA),
+ PLUGIN_REGISTER(PRIVKEY_GEN, botan_ec_private_key_gen, FALSE),
+ PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_ECDSA),
+ PLUGIN_REGISTER(PUBKEY, botan_ec_public_key_load, TRUE),
+ PLUGIN_PROVIDE(PUBKEY, KEY_ECDSA),
+#ifdef BOTAN_HAS_EMSA_RAW
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_NULL),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_NULL),
+#endif
+#ifdef BOTAN_HAS_EMSA1
+#ifdef BOTAN_HAS_SHA1
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_SHA1_DER),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_SHA1_DER),
+#endif
+#ifdef BOTAN_HAS_SHA2_32
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_SHA256_DER),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_SHA256_DER),
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_256),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_256),
+#endif
+#ifndef BOTAN_HAS_SHA2_64
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_SHA384_DER),
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_SHA512_DER),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_SHA384_DER),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_SHA512_DER),
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_384),
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_521),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_384),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_521),
+#endif
+#endif /* BOTAN_HAS_EMSA1 */
+#endif /* BOTAN_HAS_ECDSA */
+
+ /* random numbers */
+#if BOTAN_HAS_SYSTEM_RNG
+#if BOTAN_HAS_HMAC_DRBG
+ PLUGIN_REGISTER(RNG, botan_rng_create),
+ PLUGIN_PROVIDE(RNG, RNG_WEAK),
+ PLUGIN_PROVIDE(RNG, RNG_STRONG),
+ PLUGIN_PROVIDE(RNG, RNG_TRUE)
+#endif
+#endif
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_botan_plugin_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *botan_plugin_create()
+{
+ private_botan_plugin_t *this;
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ return &this->public.plugin;
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_p botan
+ * @ingroup plugins
+ *
+ * @defgroup botan_plugin botan_plugin
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_PLUGIN_H_
+#define BOTAN_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct botan_plugin_t botan_plugin_t;
+
+/**
+ * Plugin implementing crypto functions using Botan.
+ */
+struct botan_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** BOTAN_PLUGIN_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_rng.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_HMAC_DRBG
+
+#include <botan/ffi.h>
+
+typedef struct private_botan_random_t private_botan_random_t;
+
+/**
+ * Private data of an botan_rng_t object.
+ */
+struct private_botan_random_t {
+
+ /**
+ * Public botan_rnd_t interface.
+ */
+ botan_random_t public;
+
+ /**
+ * RNG quality of this instance
+ */
+ rng_quality_t quality;
+
+ /**
+ * RNG type
+ */
+ const char* rng_name;
+};
+
+METHOD(rng_t, get_bytes, bool,
+ private_botan_random_t *this, size_t bytes, uint8_t *buffer)
+{
+ botan_rng_t rng;
+ if (botan_rng_init(&rng, this->rng_name))
+ {
+ return FALSE;
+ }
+
+ if (botan_rng_get(rng, buffer, bytes))
+ {
+ botan_rng_destroy(rng);
+ return FALSE;
+ }
+
+ botan_rng_destroy(rng);
+ return TRUE;
+}
+
+METHOD(rng_t, allocate_bytes, bool,
+ private_botan_random_t *this, size_t bytes, chunk_t *chunk)
+{
+ *chunk = chunk_alloc(bytes);
+ if (!get_bytes(this, chunk->len, chunk->ptr))
+ {
+ chunk_free(chunk);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(rng_t, destroy, void,
+ private_botan_random_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+botan_random_t *botan_rng_create(rng_quality_t quality)
+{
+ private_botan_random_t *this;
+ const char* rng_name;
+
+ switch (quality)
+ {
+ case RNG_WEAK:
+ case RNG_STRONG:
+ rng_name = "user";
+ break;
+ case RNG_TRUE:
+ rng_name = "system";
+ break;
+ default:
+ return NULL;
+ }
+
+ INIT(this,
+ .public = {
+ .rng = {
+ .get_bytes = _get_bytes,
+ .allocate_bytes = _allocate_bytes,
+ .destroy = _destroy,
+ },
+ },
+ .quality = quality,
+ .rng_name = rng_name,
+ );
+
+ return &this->public;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_rng botan_rng
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_RNG_H_
+#define BOTAN_RNG_H_
+
+typedef struct botan_random_t botan_random_t;
+
+#include <library.h>
+
+/**
+ * rng_t implementation using botan.
+ *
+ * @note botan_rng_t is a botan reserved type.
+ */
+struct botan_random_t {
+
+ /**
+ * Implements rng_t.
+ */
+ rng_t rng;
+};
+
+/**
+ * Creates a botan_random_t instance.
+ *
+ * @param quality required quality of randomness
+ * @return botan_random_t instance
+ */
+botan_random_t *botan_rng_create(rng_quality_t quality);
+
+#endif /** BOTAN_RNG_H_ @} */
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_rsa_private_key.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_RSA
+
+#include "botan_util.h"
+
+#include <botan/ffi.h>
+
+#include <utils/debug.h>
+
+typedef struct private_botan_rsa_private_key_t private_botan_rsa_private_key_t;
+
+/**
+ * Private data of a botan_rsa_private_key_t object.
+ */
+struct private_botan_rsa_private_key_t {
+ /**
+ * Public interface for this signer.
+ */
+ botan_rsa_private_key_t public;
+
+ /**
+ * Botan private key
+ */
+ botan_privkey_t key;
+
+
+ /**
+ * reference count
+ */
+ refcount_t ref;
+};
+
+/**
+ * Get the binary representation of a named RSA parameter
+ */
+static int botan_rsa_get_field(botan_privkey_t *key, const char *field_name,
+ chunk_t *value)
+{
+ botan_mp_t field;
+ if (botan_mp_init(&field))
+ {
+ return -1;
+ }
+
+ if (botan_privkey_get_field(field, *key, field_name))
+ {
+ botan_mp_destroy(field);
+ return -1;
+ }
+
+ size_t field_size = 0;
+ if (botan_mp_num_bytes(field, &field_size))
+ {
+ botan_mp_destroy(field);
+ return -1;
+ }
+
+ if (field_size == 0)
+ {
+ botan_mp_destroy(field);
+ return -1;
+ }
+
+ *value = chunk_alloc(field_size);
+ if (botan_mp_to_bin(field, value->ptr))
+ {
+ botan_mp_destroy(field);
+ chunk_clear(value);
+ return -1;
+ }
+
+ botan_mp_destroy(field);
+ return 0;
+}
+
+/**
+ * Build RSA signature
+ */
+static bool build_rsa_signature(private_botan_rsa_private_key_t *this,
+ const char* hash_and_padding, chunk_t data, chunk_t* signature)
+{
+ botan_pk_op_sign_t sign_op;
+
+ if (botan_pk_op_sign_create(&sign_op, this->key, hash_and_padding, 0))
+ {
+ return FALSE;
+ }
+
+ botan_rng_t rng;
+ if (botan_rng_init(&rng, "user"))
+ {
+ botan_pk_op_sign_destroy(sign_op);
+ return FALSE;
+ }
+
+ /* get size of signature first */
+ if (botan_pk_op_sign_update(sign_op, data.ptr, data.len))
+ {
+ botan_rng_destroy(rng);
+ botan_pk_op_sign_destroy(sign_op);
+ return FALSE;
+ }
+
+ signature->len = 0;
+ if (botan_pk_op_sign_finish(sign_op, rng, NULL, &signature->len)
+ != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ botan_rng_destroy(rng);
+ botan_pk_op_sign_destroy(sign_op);
+ return FALSE;
+ }
+
+ /* now get the signature */
+ *signature = chunk_alloc(signature->len);
+ if (botan_pk_op_sign_update(sign_op, data.ptr, data.len))
+ {
+ chunk_free(signature);
+ botan_rng_destroy(rng);
+ botan_pk_op_sign_destroy(sign_op);
+ return FALSE;
+ }
+
+ if (botan_pk_op_sign_finish(sign_op, rng, signature->ptr, &signature->len))
+ {
+ chunk_free(signature);
+ botan_rng_destroy(rng);
+ botan_pk_op_sign_destroy(sign_op);
+ return FALSE;
+ }
+
+ botan_rng_destroy(rng);
+ botan_pk_op_sign_destroy(sign_op);
+ return TRUE;
+}
+
+/**
+ * Build an EMSA PKCS1 signature described in PKCS#1
+ */
+static bool build_emsa_pkcs1_signature(private_botan_rsa_private_key_t *this,
+ const char* hash_and_padding, chunk_t data, chunk_t* signature)
+{
+ return build_rsa_signature(this, hash_and_padding, data, signature);
+}
+
+static bool botan_get_hash(hash_algorithm_t hash, char* hash_str)
+{
+ switch (hash)
+ {
+ case HASH_SHA1:
+ sprintf(hash_str, "SHA-1");
+ break;
+ case HASH_SHA224:
+ sprintf(hash_str, "SHA-224");
+ break;
+ case HASH_SHA256:
+ sprintf(hash_str, "SHA-256");
+ break;
+ case HASH_SHA384:
+ sprintf(hash_str, "SHA-384");
+ break;
+ case HASH_SHA512:
+ sprintf(hash_str, "SHA-512");
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * Build an EMSA PSS signature described in PKCS#1
+ */
+static bool build_emsa_pss_signature(private_botan_rsa_private_key_t *this,
+ rsa_pss_params_t *params, chunk_t data,
+ chunk_t *sig)
+{
+ char* hash_and_padding, *hash, *mgf1_hash;
+ char* salt_len = NULL;
+ size_t len;
+ bool success = FALSE;
+
+ if (!params)
+ {
+ return FALSE;
+ }
+
+ /* botan currently does not support passing the mgf1 hash */
+ if (params->hash != params->mgf1_hash)
+ {
+ DBG1(DBG_LIB, "passing mgf1 hash not supported via botan");
+ return FALSE;
+ }
+
+ hash = malloc(8);
+ if (!botan_get_hash(params->hash, hash))
+ {
+ free(hash);
+ return FALSE;
+ }
+
+ mgf1_hash = malloc(8);
+ if (!botan_get_hash(params->mgf1_hash, mgf1_hash))
+ {
+ free(hash);
+ free(mgf1_hash);
+ return FALSE;
+ }
+
+ if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
+ {
+ salt_len = malloc(6);
+ snprintf(salt_len, 5, "%d", params->salt_len);
+ }
+
+ len = 24 + strlen(hash) + strlen(mgf1_hash);
+ hash_and_padding = malloc(len+1);
+
+ if (salt_len)
+ {
+ snprintf(hash_and_padding, len, "EMSA-PSS(%s,MGF1,%s)", hash, salt_len);
+ }
+ else
+ {
+ snprintf(hash_and_padding, len, "EMSA-PSS(%s,MGF1)", hash);
+ }
+
+ if (build_rsa_signature(this, hash_and_padding, data, sig))
+ {
+ success = TRUE;
+ }
+
+ if (salt_len)
+ free(salt_len);
+ free(hash);
+ free(mgf1_hash);
+ free(hash_and_padding);
+ return success;
+}
+
+METHOD(private_key_t, get_type, key_type_t,
+ private_botan_rsa_private_key_t *this)
+{
+ return KEY_RSA;
+}
+
+METHOD(private_key_t, sign, bool,
+ private_botan_rsa_private_key_t *this, signature_scheme_t scheme,
+ void *params, chunk_t data, chunk_t *signature)
+{
+ switch (scheme)
+ {
+ case SIGN_RSA_EMSA_PKCS1_NULL:
+ return build_emsa_pkcs1_signature(this, "EMSA_PKCS1(Raw)", data,
+ signature);
+ case SIGN_RSA_EMSA_PKCS1_SHA1:
+ return build_emsa_pkcs1_signature(this, "EMSA_PKCS1(SHA-1)", data,
+ signature);
+ case SIGN_RSA_EMSA_PKCS1_SHA2_224:
+ return build_emsa_pkcs1_signature(this, "EMSA_PKCS1(SHA-224)", data,
+ signature);
+ case SIGN_RSA_EMSA_PKCS1_SHA2_256:
+ return build_emsa_pkcs1_signature(this, "EMSA_PKCS1(SHA-256)", data,
+ signature);
+ case SIGN_RSA_EMSA_PKCS1_SHA2_384:
+ return build_emsa_pkcs1_signature(this, "EMSA_PKCS1(SHA-384)", data,
+ signature);
+ case SIGN_RSA_EMSA_PKCS1_SHA2_512:
+ return build_emsa_pkcs1_signature(this, "EMSA_PKCS1(SHA-512)", data,
+ signature);
+ case SIGN_RSA_EMSA_PSS:
+ return build_emsa_pss_signature(this, params, data, signature);
+ default:
+ DBG1(DBG_LIB, "signature scheme %N not supported via botan",
+ signature_scheme_names, scheme);
+ return FALSE;
+ }
+}
+
+METHOD(private_key_t, decrypt, bool, private_botan_rsa_private_key_t *this,
+ encryption_scheme_t scheme, chunk_t crypto, chunk_t *plain)
+{
+ const char *padding;
+
+ switch (scheme)
+ {
+ case ENCRYPT_RSA_PKCS1:
+ padding = "PKCS1v15";
+ break;
+ case ENCRYPT_RSA_OAEP_SHA1:
+ padding = "OAEP(SHA-1)";
+ break;
+ case ENCRYPT_RSA_OAEP_SHA224:
+ padding = "OAEP(SHA-224)";
+ break;
+ case ENCRYPT_RSA_OAEP_SHA256:
+ padding = "OAEP(SHA-256)";
+ break;
+ case ENCRYPT_RSA_OAEP_SHA384:
+ padding = "OAEP(SHA-384)";
+ break;
+ case ENCRYPT_RSA_OAEP_SHA512:
+ padding = "OAEP(SHA-512)";
+ break;
+ default:
+ DBG1(DBG_LIB, "encryption scheme %N not supported via botan",
+ encryption_scheme_names, scheme);
+ return FALSE;
+ }
+
+ botan_pk_op_decrypt_t decrypt_op;
+ if (botan_pk_op_decrypt_create(&decrypt_op, this->key, padding, 0))
+ {
+ return FALSE;
+ }
+
+ /*
+ * get size of plaintext first
+ */
+ if (botan_pk_op_decrypt(decrypt_op, NULL, &plain->len, crypto.ptr,
+ crypto.len)
+ != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ botan_pk_op_decrypt_destroy(decrypt_op);
+ return FALSE;
+ }
+
+ /*
+ * now get the plaintext
+ */
+ *plain = chunk_alloc(plain->len);
+ if (botan_pk_op_decrypt(decrypt_op, plain->ptr, &plain->len, crypto.ptr,
+ crypto.len))
+ {
+ chunk_free(plain);
+ botan_pk_op_decrypt_destroy(decrypt_op);
+ return FALSE;
+ }
+
+ botan_pk_op_decrypt_destroy(decrypt_op);
+ return TRUE;
+}
+
+METHOD(private_key_t, get_keysize, int,
+ private_botan_rsa_private_key_t *this)
+{
+ botan_mp_t n;
+ if (botan_mp_init(&n))
+ {
+ return -1;
+ }
+
+ if (botan_privkey_rsa_get_n(n, this->key))
+ {
+ return -1;
+ }
+
+ size_t bits = 0;
+ if (botan_mp_num_bits(n, &bits))
+ {
+ botan_mp_destroy(n);
+ return -1;
+ }
+
+ botan_mp_destroy(n);
+ return bits;
+}
+
+METHOD(private_key_t, get_public_key, public_key_t*,
+ private_botan_rsa_private_key_t *this)
+{
+ chunk_t n, e;
+
+ if (botan_rsa_get_field(&this->key, "n", &n))
+ {
+ return NULL;
+ }
+
+ if (botan_rsa_get_field(&this->key, "e", &e))
+ {
+ chunk_clear(&n);
+ return NULL;
+ }
+
+ public_key_t *pub_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
+ KEY_RSA, BUILD_RSA_MODULUS, n,
+ BUILD_RSA_PUB_EXP, e, BUILD_END);
+
+ chunk_free(&n);
+ chunk_free(&e);
+ return pub_key;
+}
+
+METHOD(private_key_t, get_fingerprint, bool,
+ private_botan_rsa_private_key_t *this, cred_encoding_type_t type,
+ chunk_t *fingerprint)
+{
+ chunk_t n, e;
+ bool success;
+
+ if (lib->encoding->get_cache(lib->encoding, type, &this->key, fingerprint))
+ {
+ return TRUE;
+ }
+
+ if (botan_rsa_get_field(&this->key, "n", &n))
+ {
+ return FALSE;
+ }
+
+ if (botan_rsa_get_field(&this->key, "e", &e))
+ {
+ chunk_clear(&n);
+ return FALSE;
+ }
+
+ success = lib->encoding->encode(lib->encoding, type, &this->key,
+ fingerprint, CRED_PART_RSA_MODULUS, n,
+ CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
+ chunk_free(&n);
+ chunk_free(&e);
+ return success;
+
+}
+
+METHOD(private_key_t, get_encoding, bool,
+ private_botan_rsa_private_key_t *this, cred_encoding_type_t type,
+ chunk_t *encoding)
+{
+ switch (type)
+ {
+ case PRIVKEY_ASN1_DER:
+ case PRIVKEY_PEM:
+ {
+ bool success = TRUE;
+
+ uint32_t format = BOTAN_PRIVKEY_EXPORT_FLAG_DER;
+ if (type == PRIVKEY_PEM)
+ {
+ format = BOTAN_PRIVKEY_EXPORT_FLAG_PEM;
+ }
+
+ size_t bits = 0;
+ if(botan_privkey_rsa_get_privkey(this->key, NULL, &bits, format))
+ {
+ return FALSE;
+ }
+
+ *encoding = chunk_alloc(bits);
+ if(botan_privkey_rsa_get_privkey(this->key, encoding->ptr, &bits, format))
+ {
+ chunk_clear(encoding);
+ return FALSE;
+ }
+
+ return success;
+ }
+ default:
+ return FALSE;
+ }
+}
+
+METHOD(private_key_t, get_ref, private_key_t*,
+ private_botan_rsa_private_key_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.key;
+}
+
+METHOD(private_key_t, destroy, void,
+ private_botan_rsa_private_key_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ if (&this->key)
+ {
+ lib->encoding->clear_cache(lib->encoding, &this->key);
+ botan_privkey_destroy(this->key);
+ }
+ free(this);
+ }
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_botan_rsa_private_key_t *create_empty()
+{
+ private_botan_rsa_private_key_t *this;
+
+ INIT(this,
+ .public = {
+ .key = {
+ .get_type = _get_type,
+ .sign = _sign,
+ .decrypt = _decrypt,
+ .get_keysize = _get_keysize,
+ .get_public_key = _get_public_key,
+ .equals = private_key_equals,
+ .belongs_to = private_key_belongs_to,
+ .get_fingerprint = _get_fingerprint,
+ .has_fingerprint = private_key_has_fingerprint,
+ .get_encoding = _get_encoding,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ },
+ .ref = 1,
+ );
+
+ return this;
+}
+
+/*
+ * See header.
+ */
+botan_rsa_private_key_t *botan_rsa_private_key_gen(key_type_t type,
+ va_list args)
+{
+ private_botan_rsa_private_key_t *this;
+
+ u_int key_size = 0;
+
+ while (TRUE)
+ {
+ switch (va_arg(args, builder_part_t))
+ {
+ case BUILD_KEY_SIZE:
+ key_size = va_arg(args, u_int);
+ continue;
+ case BUILD_END:
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ }
+
+ if (!key_size)
+ {
+ return NULL;
+ }
+
+ botan_rng_t rng;
+ if (botan_rng_init(&rng, "user"))
+ {
+ return NULL;
+ }
+
+ this = create_empty();
+
+ if(botan_privkey_create_rsa(&this->key, rng, key_size))
+ {
+ botan_rng_destroy(rng);
+ destroy(this);
+ return NULL;
+ }
+
+ botan_rng_destroy(rng);
+ return &this->public;
+}
+
+/**
+ * Recover the primes from n, e and d using the algorithm described in
+ * Appendix C of NIST SP 800-56B.
+ */
+static bool calculate_pq(botan_mp_t *n, botan_mp_t *e, botan_mp_t *d,
+ botan_mp_t *p, botan_mp_t *q)
+{
+ botan_mp_t k, one, r, zero, two, n1, x, y, g, rem;
+ int i, t, j;
+ bool success = TRUE;
+
+ if (botan_mp_init(&k))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_init(&one))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_set_from_int(one, 1))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ /* 1. k = de - 1 */
+ if (botan_mp_mul(k, *d, *e) || botan_mp_sub(k, k, one))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ /* k must be even */
+ if (!botan_mp_is_even(k))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ /* 2. k = 2^t * r, where r is the largest odd integer dividing k, and t >= 1 */
+ if (botan_mp_init(&r))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_set_from_mp(r, k))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ for (t = 0; !botan_mp_is_odd(r); t++)
+ {
+ if (botan_mp_rshift(r, r, 1))
+ {
+ success = FALSE;
+ goto error;
+ }
+ }
+
+ /* need 0, 2, n-1 below */
+ if (botan_mp_init(&zero))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_set_from_int(zero, 0))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_init(&n1))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_sub(n1, *n, one))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_init(&g))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ botan_rng_t rng;
+ if (botan_rng_init(&rng, "user"))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_init(&two))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_set_from_int(two, 2))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ for (i = 0; i < 100; i++)
+ {
+ /* 3a. generate a random integer g in the range [0, n-1] */
+ if (botan_mp_rand_range(g, rng, zero, n1))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ /* 3b. y = g^r mod n */
+ if (botan_mp_init(&y))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_powmod(y, g, r, *n))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ /* 3c. If y = 1 or y = n – 1, try again */
+ if (botan_mp_equal(y, one) || botan_mp_equal(y, n1))
+ {
+ continue;
+ }
+
+ if (botan_mp_init(&x))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ for (j = 0; j < t; j++)
+ {
+ /* x = y^2 mod n */
+ if (botan_mp_powmod(x, y, two, *n))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ /* stop if x == 1 */
+ if (botan_mp_equal(x, one))
+ {
+ goto done;
+ }
+
+ /* retry with new g if x = n-1 */
+ if (botan_mp_equal(x, n1))
+ {
+ break;
+ }
+
+ /* let y = x */
+ if(botan_mp_set_from_mp(y, x))
+ {
+ success = FALSE;
+ goto error;
+ }
+ }
+ }
+
+done:
+ /* 5. p = GCD(y – 1, n) and q = n/p */
+ if (botan_mp_sub(y, y, one))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_init(p))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_gcd(*p, y, *n))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_init(q))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_init(&rem))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (botan_mp_div(*q, rem, *n, *p))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+ if (!botan_mp_is_zero(rem))
+ {
+ success = FALSE;
+ goto error;
+ }
+
+error:
+ if (!success)
+ {
+ botan_mp_destroy(*p);
+ botan_mp_destroy(*q);
+ }
+
+ botan_mp_destroy(k);
+ botan_mp_destroy(one);
+ botan_mp_destroy(r);
+ botan_mp_destroy(zero);
+ botan_mp_destroy(two);
+ botan_mp_destroy(n1);
+ botan_mp_destroy(x);
+ botan_mp_destroy(y);
+ botan_mp_destroy(rem);
+ return success;
+}
+
+/*
+ * See header
+ */
+botan_rsa_private_key_t *botan_rsa_private_key_load(key_type_t type,
+ va_list args)
+{
+ private_botan_rsa_private_key_t *this;
+ chunk_t n, e, d, p, q, blob;
+
+ n = e = d = p = q = blob = chunk_empty;
+ while (TRUE)
+ {
+ switch (va_arg(args, builder_part_t))
+ {
+ case BUILD_BLOB_ASN1_DER:
+ blob = va_arg(args, chunk_t);
+ continue;
+ case BUILD_RSA_MODULUS:
+ n = va_arg(args, chunk_t);
+ continue;
+ case BUILD_RSA_PUB_EXP:
+ e = va_arg(args, chunk_t);
+ continue;
+ case BUILD_RSA_PRIV_EXP:
+ d = va_arg(args, chunk_t);
+ continue;
+ case BUILD_RSA_PRIME1:
+ p = va_arg(args, chunk_t);
+ continue;
+ case BUILD_RSA_PRIME2:
+ q = va_arg(args, chunk_t);
+ continue;
+ case BUILD_RSA_EXP1:
+ case BUILD_RSA_EXP2:
+ case BUILD_RSA_COEFF:
+ /* not required for botan */
+ va_arg(args, chunk_t);
+ continue;
+ case BUILD_END:
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ }
+
+ if (blob.ptr)
+ {
+ this = create_empty();
+
+ if (botan_privkey_load_rsa_pkcs1(&this->key, blob.ptr, blob.len))
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ return &this->public;
+ }
+
+ if (n.ptr && e.ptr && d.ptr)
+ {
+ botan_mp_t n_mp, e_mp, d_mp;
+ if (chunk_to_botan_mp(n, &n_mp))
+ {
+ return NULL;
+ }
+
+ if (chunk_to_botan_mp(e, &e_mp))
+ {
+ botan_mp_destroy(n_mp);
+ return NULL;
+ }
+
+ if (chunk_to_botan_mp(d, &d_mp))
+ {
+ botan_mp_destroy(n_mp);
+ botan_mp_destroy(e_mp);
+ return NULL;
+ }
+
+ botan_mp_t p_mp, q_mp;
+ if (p.ptr && q.ptr)
+ {
+ if (chunk_to_botan_mp(p, &p_mp))
+ {
+ botan_mp_destroy(n_mp);
+ botan_mp_destroy(e_mp);
+ botan_mp_destroy(d_mp);
+ return NULL;
+ }
+
+ if (chunk_to_botan_mp(q, &q_mp))
+ {
+ botan_mp_destroy(n_mp);
+ botan_mp_destroy(e_mp);
+ botan_mp_destroy(d_mp);
+ botan_mp_destroy(p_mp);
+ return NULL;
+ }
+ }
+ else
+ {
+ // calculate p,q from n, e, d
+ if (!calculate_pq(&n_mp, &e_mp, &d_mp, &p_mp, &q_mp))
+ {
+ botan_mp_destroy(n_mp);
+ botan_mp_destroy(e_mp);
+ botan_mp_destroy(d_mp);
+ return NULL;
+ }
+ }
+
+ this = create_empty();
+
+ if (botan_privkey_load_rsa(&this->key, p_mp, q_mp, e_mp))
+ {
+ botan_mp_destroy(e_mp);
+ botan_mp_destroy(p_mp);
+ botan_mp_destroy(q_mp);
+ destroy(this);
+ return NULL;
+ }
+
+ botan_mp_destroy(e_mp);
+ botan_mp_destroy(p_mp);
+ botan_mp_destroy(q_mp);
+
+ return &this->public;
+ }
+
+ return NULL;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_rsa_private_key botan_rsa_private_key
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_RSA_PRIVATE_KEY_H_
+#define BOTAN_RSA_PRIVATE_KEY_H_
+
+#include <credentials/builder.h>
+#include <credentials/keys/private_key.h>
+
+typedef struct botan_rsa_private_key_t botan_rsa_private_key_t;
+
+/**
+ * private_key_t implementation of RSA algorithm using Botan.
+ */
+struct botan_rsa_private_key_t {
+
+ /**
+ * Implements private_key_t interface
+ */
+ private_key_t key;
+};
+
+/**
+ * Generate a RSA private key using Botan.
+ *
+ * Accepts the BUILD_KEY_SIZE argument.
+ *
+ * @param type type of the key, must be KEY_RSA
+ * @param args builder_part_t argument list
+ * @return generated key, NULL on failure
+ */
+botan_rsa_private_key_t *botan_rsa_private_key_gen(key_type_t type,
+ va_list args);
+
+/**
+ * Load a RSA private key using Botan.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type type of the key, must be KEY_RSA
+ * @param args builder_part_t argument list
+ * @return loaded key, NULL on failure
+ */
+botan_rsa_private_key_t *botan_rsa_private_key_load(key_type_t type,
+ va_list args);
+
+#endif /** BOTAN_RSA_PRIVATE_KEY_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_rsa_public_key.h"
+
+#include <botan/build.h>
+
+#ifdef BOTAN_HAS_RSA
+
+#include "botan_util.h"
+
+#include <asn1/oid.h>
+#include <asn1/asn1.h>
+#include <asn1/asn1_parser.h>
+
+#include <utils/debug.h>
+
+#include <botan/ffi.h>
+
+typedef struct private_botan_rsa_public_key_t private_botan_rsa_public_key_t;
+
+/**
+ * Private data structure with signing context.
+ */
+struct private_botan_rsa_public_key_t {
+ /**
+ * Public interface for this signer
+ */
+ botan_rsa_public_key_t public;
+
+ /**
+ * Botan public key
+ */
+ botan_pubkey_t key;
+
+ /**
+ * Reference counter
+ */
+ refcount_t ref;
+};
+
+/**
+ * Get the binary representation of a named RSA parameter
+ */
+static int botan_rsa_get_field(botan_pubkey_t *key, const char *field_name,
+ chunk_t *value)
+{
+ botan_mp_t field;
+ size_t field_size = 0;
+
+ if (botan_mp_init(&field))
+ {
+ return -1;
+ }
+
+ if (botan_pubkey_get_field(field, *key, field_name))
+ {
+ return -1;
+ }
+
+ if (botan_mp_num_bytes(field, &field_size))
+ {
+ botan_mp_destroy(field);
+ return -1;
+ }
+
+ if (field_size == 0)
+ {
+ botan_mp_destroy(field);
+ return -1;
+ }
+
+ *value = chunk_empty;
+ *value = chunk_alloc(field_size);
+ if (botan_mp_to_bin(field, value->ptr))
+ {
+ botan_mp_destroy(field);
+ chunk_clear(value);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Verify RSA signature
+ */
+static bool verify_rsa_signature(private_botan_rsa_public_key_t *this,
+ const char* hash_and_padding, chunk_t data, chunk_t signature)
+{
+ botan_pk_op_verify_t verify_op;
+ bool valid = FALSE;
+
+ if (botan_pk_op_verify_create(&verify_op, this->key, hash_and_padding, 0))
+ {
+ return FALSE;
+ }
+
+ if (botan_pk_op_verify_update(verify_op, data.ptr, data.len))
+ {
+ botan_pk_op_verify_destroy(verify_op);
+ return FALSE;
+ }
+
+ valid =
+ !(botan_pk_op_verify_finish(verify_op, signature.ptr, signature.len));
+
+ botan_pk_op_verify_destroy(verify_op);
+ return valid;
+}
+
+/**
+ * Verification of an EMSA PKCS1 signature described in PKCS#1
+ */
+static bool verify_emsa_pkcs1_signature(private_botan_rsa_public_key_t *this,
+ const char* hash_and_padding, chunk_t data, chunk_t signature)
+{
+ return verify_rsa_signature(this, hash_and_padding, data, signature);
+}
+
+static bool botan_get_hash(hash_algorithm_t hash, char* hash_str)
+{
+ switch (hash)
+ {
+ case HASH_SHA1:
+ sprintf(hash_str, "SHA-1");
+ break;
+ case HASH_SHA224:
+ sprintf(hash_str, "SHA-224");
+ break;
+ case HASH_SHA256:
+ sprintf(hash_str, "SHA-256");
+ break;
+ case HASH_SHA384:
+ sprintf(hash_str, "SHA-384");
+ break;
+ case HASH_SHA512:
+ sprintf(hash_str, "SHA-512");
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * Verification of an EMSA PSS signature described in PKCS#1
+ */
+static bool verify_emsa_pss_signature(private_botan_rsa_public_key_t *this,
+ rsa_pss_params_t *params, chunk_t data,
+ chunk_t signature)
+{
+ char* hash_and_padding, *hash, *mgf1_hash;
+ char* salt_len = NULL;
+ size_t len;
+ bool success = FALSE;
+
+ if (!params)
+ {
+ return FALSE;
+ }
+
+ // botan currently does not support passing the mgf1 hash
+ if (params->hash != params->mgf1_hash)
+ {
+ DBG1(DBG_LIB, "passing mgf1 hash not supported via botan");
+ return FALSE;
+ }
+
+ hash = malloc(8);
+ if(!botan_get_hash(params->hash, hash))
+ {
+ free(hash);
+ return FALSE;
+ }
+
+ mgf1_hash = malloc(8);
+ if(!botan_get_hash(params->mgf1_hash, mgf1_hash))
+ {
+ free(hash);
+ free(mgf1_hash);
+ return FALSE;
+ }
+
+ if(params->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
+ {
+ salt_len = malloc(6);
+ snprintf(salt_len, 5, "%d", params->salt_len);
+ }
+
+ len = 24 + strlen(hash) + strlen(mgf1_hash);
+ hash_and_padding = malloc(len+1);
+
+ if(salt_len)
+ {
+ snprintf(hash_and_padding, len, "EMSA-PSS(%s,MGF1,%s)", hash, salt_len);
+ }
+ else
+ {
+ snprintf(hash_and_padding, len, "EMSA-PSS(%s,MGF1)", hash);
+ }
+
+ if (verify_rsa_signature(this, hash_and_padding, data, signature))
+ {
+ success = TRUE;
+ }
+
+ if(salt_len)
+ free(salt_len);
+ free(hash);
+ free(mgf1_hash);
+ free(hash_and_padding);
+ return success;
+}
+
+METHOD(public_key_t, get_type, key_type_t,
+ private_botan_rsa_public_key_t *this)
+{
+ return KEY_RSA;
+}
+
+METHOD(public_key_t, verify, bool,
+ private_botan_rsa_public_key_t *this, signature_scheme_t scheme,
+ void *params, chunk_t data, chunk_t signature)
+{
+ switch (scheme)
+ {
+ case SIGN_RSA_EMSA_PKCS1_NULL:
+ return verify_emsa_pkcs1_signature(this, "EMSA_PKCS1(Raw)", data,
+ signature);
+ case SIGN_RSA_EMSA_PKCS1_SHA1:
+ return verify_emsa_pkcs1_signature(this, "EMSA_PKCS1(SHA-1)", data,
+ signature);
+ case SIGN_RSA_EMSA_PKCS1_SHA2_224:
+ return verify_emsa_pkcs1_signature(this, "EMSA_PKCS1(SHA-224)",
+ data, signature);
+ case SIGN_RSA_EMSA_PKCS1_SHA2_256:
+ return verify_emsa_pkcs1_signature(this, "EMSA_PKCS1(SHA-256)",
+ data, signature);
+ case SIGN_RSA_EMSA_PKCS1_SHA2_384:
+ return verify_emsa_pkcs1_signature(this, "EMSA_PKCS1(SHA-384)",
+ data, signature);
+ case SIGN_RSA_EMSA_PKCS1_SHA2_512:
+ return verify_emsa_pkcs1_signature(this, "EMSA_PKCS1(SHA-512)",
+ data, signature);
+ case SIGN_RSA_EMSA_PSS:
+ return verify_emsa_pss_signature(this, params, data, signature);
+ default:
+ DBG1(DBG_LIB, "signature scheme %N not supported via botan",
+ signature_scheme_names, scheme);
+ return FALSE;
+ }
+}
+
+METHOD(public_key_t, encrypt, bool,
+ private_botan_rsa_public_key_t *this, encryption_scheme_t scheme,
+ chunk_t plain, chunk_t *crypto)
+{
+ const char* padding;
+
+ switch (scheme)
+ {
+ case ENCRYPT_RSA_PKCS1:
+ padding = "PKCS1v15";
+ break;
+ case ENCRYPT_RSA_OAEP_SHA1:
+ padding = "OAEP(SHA-1)";
+ break;
+ case ENCRYPT_RSA_OAEP_SHA224:
+ padding = "OAEP(SHA-224)";
+ break;
+ case ENCRYPT_RSA_OAEP_SHA256:
+ padding = "OAEP(SHA-256)";
+ break;
+ case ENCRYPT_RSA_OAEP_SHA384:
+ padding = "OAEP(SHA-384)";
+ break;
+ case ENCRYPT_RSA_OAEP_SHA512:
+ padding = "OAEP(SHA-512)";
+ break;
+ default:
+ DBG1(DBG_LIB, "encryption scheme %N not supported via botan",
+ encryption_scheme_names, scheme);
+ return FALSE;
+ }
+
+ botan_rng_t rng;
+ if (botan_rng_init(&rng, "user"))
+ {
+ return FALSE;
+ }
+
+ botan_pk_op_encrypt_t encrypt_op;
+ if (botan_pk_op_encrypt_create(&encrypt_op, this->key, padding, 0))
+ {
+ botan_rng_destroy(rng);
+ return FALSE;
+ }
+
+ /*
+ * get size of ciphertext first
+ */
+ if (botan_pk_op_encrypt(encrypt_op, rng, NULL, &crypto->len, plain.ptr,
+ plain.len)
+ != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ botan_rng_destroy(rng);
+ botan_pk_op_encrypt_destroy(encrypt_op);
+ return FALSE;
+ }
+
+ /*
+ * now get the ciphertext
+ */
+ *crypto = chunk_alloc(crypto->len);
+ if (botan_pk_op_encrypt(encrypt_op, rng, crypto->ptr, &crypto->len,
+ plain.ptr, plain.len))
+ {
+ chunk_free(crypto);
+ botan_rng_destroy(rng);
+ botan_pk_op_encrypt_destroy(encrypt_op);
+ return FALSE;
+ }
+
+ botan_rng_destroy(rng);
+ botan_pk_op_encrypt_destroy(encrypt_op);
+ return TRUE;
+}
+
+METHOD(public_key_t, get_keysize, int,
+ private_botan_rsa_public_key_t *this)
+{
+ botan_mp_t n;
+ size_t bits = 0;
+
+ if (botan_mp_init(&n))
+ {
+ return -1;
+ }
+
+ if (botan_pubkey_rsa_get_n(n, this->key))
+ {
+ return -1;
+ }
+
+ if (botan_mp_num_bits(n, &bits))
+ {
+ botan_mp_destroy(n);
+ return -1;
+ }
+
+ botan_mp_destroy(n);
+ return bits;
+}
+
+METHOD(public_key_t, get_fingerprint, bool,
+ private_botan_rsa_public_key_t *this, cred_encoding_type_t type,
+ chunk_t *fp)
+{
+ chunk_t n, e;
+ bool success = FALSE;
+
+ if (lib->encoding->get_cache(lib->encoding, type, &this->key, fp))
+ {
+ return TRUE;
+ }
+
+ if (botan_rsa_get_field(&this->key, "n", &n))
+ {
+ return FALSE;
+ }
+
+ if (botan_rsa_get_field(&this->key, "e", &e))
+ {
+ chunk_free(&n);
+ return FALSE;
+ }
+
+ success = lib->encoding->encode(lib->encoding, type, &this->key, fp,
+ CRED_PART_RSA_MODULUS, n,
+ CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
+
+ chunk_free(&n);
+ chunk_free(&e);
+ return success;
+}
+
+METHOD(public_key_t, get_encoding, bool,
+ private_botan_rsa_public_key_t *this, cred_encoding_type_t type,
+ chunk_t *encoding)
+{
+ chunk_t n, e;
+ bool success = FALSE;
+
+ if (botan_rsa_get_field(&this->key, "n", &n))
+ {
+ return FALSE;
+ }
+
+ if (botan_rsa_get_field(&this->key, "e", &e))
+ {
+ chunk_free(&n);
+ return FALSE;
+ }
+
+ success = lib->encoding->encode(lib->encoding, type, NULL, encoding,
+ CRED_PART_RSA_MODULUS, n,
+ CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
+
+ chunk_free(&n);
+ chunk_free(&e);
+ return success;
+}
+
+METHOD(public_key_t, get_ref, public_key_t*,
+ private_botan_rsa_public_key_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.key;
+}
+
+METHOD(public_key_t, destroy, void,
+ private_botan_rsa_public_key_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ if (&this->key)
+ {
+ lib->encoding->clear_cache(lib->encoding, &this->key);
+ botan_pubkey_destroy(this->key);
+ }
+ free(this);
+ }
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_botan_rsa_public_key_t *create_empty()
+{
+ private_botan_rsa_public_key_t *this;
+
+ INIT(this,
+ .public = {
+ .key = {
+ .get_type = _get_type,
+ .verify = _verify,
+ .encrypt = _encrypt,
+ .equals = public_key_equals,
+ .get_keysize = _get_keysize,
+ .get_fingerprint = _get_fingerprint,
+ .has_fingerprint = public_key_has_fingerprint,
+ .get_encoding = _get_encoding,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ },
+ .ref = 1,
+ );
+
+ return this;
+}
+
+/**
+ * See header.
+ */
+botan_rsa_public_key_t *botan_rsa_public_key_load(key_type_t type,
+ va_list args)
+{
+ private_botan_rsa_public_key_t *this = NULL;
+
+ chunk_t blob, n, e;
+
+ n = e = blob = chunk_empty;
+ while (TRUE)
+ {
+ switch (va_arg(args, builder_part_t))
+ {
+ case BUILD_BLOB_ASN1_DER:
+ blob = va_arg(args, chunk_t);
+ continue;
+ case BUILD_RSA_MODULUS:
+ n = va_arg(args, chunk_t);
+ continue;
+ case BUILD_RSA_PUB_EXP:
+ e = va_arg(args, chunk_t);
+ continue;
+ case BUILD_END:
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ }
+
+ if (blob.ptr)
+ {
+ switch (type)
+ {
+ /* SubjectPublicKeyInfo */
+ case KEY_ANY:
+ {
+ this = create_empty();
+
+ if (botan_pubkey_load(&this->key, blob.ptr, blob.len))
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ size_t namesize = 0;
+ if (botan_pubkey_algo_name(this->key, NULL, &namesize)
+ != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+ {
+ botan_pubkey_destroy(this->key);
+ destroy(this);
+ return NULL;
+ }
+
+ char* namebuf = malloc(namesize);
+ if (botan_pubkey_algo_name(this->key, namebuf, &namesize))
+ {
+ free(namebuf);
+ botan_pubkey_destroy(this->key);
+ destroy(this);
+ return NULL;
+ }
+
+ const char* algo_name = "RSA";
+ if (!strneq(namebuf, algo_name, sizeof(algo_name)))
+ {
+ free(namebuf);
+ botan_pubkey_destroy(this->key);
+ destroy(this);
+ return NULL;
+ }
+
+ free(namebuf);
+ break;
+ }
+ default:
+ return NULL;
+ }
+ }
+ else if(n.ptr && e.ptr && type == KEY_RSA)
+ {
+
+ botan_mp_t mp_n, mp_e;
+ if (chunk_to_botan_mp(n, &mp_n))
+ {
+ return NULL;
+ }
+
+ if (chunk_to_botan_mp(e, &mp_e))
+ {
+ botan_mp_destroy(mp_n);
+ return NULL;
+ }
+
+ this = create_empty();
+
+ if (botan_pubkey_load_rsa(&this->key, mp_n, mp_e))
+ {
+ botan_mp_destroy(mp_n);
+ botan_mp_destroy(mp_e);
+ destroy(this);
+ return NULL;
+ }
+
+ botan_mp_destroy(mp_n);
+ botan_mp_destroy(mp_e);
+ }
+ if (this != NULL)
+ {
+ return &this->public;
+ }
+ return NULL;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_rsa_public_key botan_rsa_public_key
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_RSA_PUBLIC_KEY_H_
+#define BOTAN_RSA_PUBLIC_KEY_H_
+
+typedef struct botan_rsa_public_key_t botan_rsa_public_key_t;
+
+#include <credentials/keys/public_key.h>
+
+/**
+ * public_key_t implementation of RSA algorithm using Botan.
+ */
+struct botan_rsa_public_key_t {
+
+ /**
+ * Implements the public_key_t interface
+ */
+ public_key_t key;
+};
+
+/**
+ * Load a RSA public key using Botan.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type type of the key, must be KEY_RSA
+ * @param args builder_part_t argument list
+ * @return loaded key, NULL on failure
+ */
+botan_rsa_public_key_t *botan_rsa_public_key_load(key_type_t type,
+ va_list args);
+
+#endif /** BOTAN_RSA_PUBLIC_KEY_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_util.h"
+
+#include <utils/debug.h>
+
+#include <botan/ffi.h>
+
+int chunk_to_botan_mp(chunk_t value, botan_mp_t *mp)
+{
+ if (botan_mp_init(mp))
+ {
+ return -1;
+ }
+
+ if (botan_mp_from_bin(*mp, value.ptr, value.len))
+ {
+ botan_mp_destroy(*mp);
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 René Korthaus
+ * Rohde & Schwarz Cybersecurity GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup botan_util botan_util
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_UTIL_H_
+#define BOTAN_UTIL_H_
+
+#include <library.h>
+
+#include <botan/ffi.h>
+
+/**
+ * Converts chunk_t to botan_mp_t
+ */
+int chunk_to_botan_mp(chunk_t value, botan_mp_t *mp);
+
+#endif /** BOTAN_UTIL_H_ @}*/