aboutsummaryrefslogtreecommitdiffstats
path: root/SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp')
-rw-r--r--SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp457
1 files changed, 457 insertions, 0 deletions
diff --git a/SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp b/SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp
new file mode 100644
index 0000000..7387367
--- /dev/null
+++ b/SoftHSMv2/src/lib/crypto/OSSLECDSA.cpp
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2010 SURFnet bv
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ OSSLECDSA.cpp
+
+ OpenSSL ECDSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#ifdef WITH_ECC
+#include "log.h"
+#include "OSSLECDSA.h"
+#include "CryptoFactory.h"
+#include "ECParameters.h"
+#include "OSSLECKeyPair.h"
+#include "OSSLComp.h"
+#include "OSSLUtil.h"
+#include <algorithm>
+#include <openssl/ecdsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#ifdef WITH_FIPS
+#include <openssl/fips.h>
+#endif
+#include <string.h>
+
+// Signing functions
+bool OSSLECDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
+ ByteString& signature, const AsymMech::Type mechanism,
+ const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+ if (mechanism != AsymMech::ECDSA)
+ {
+ ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+ return false;
+ }
+
+ // Check if the private key is the right type
+ if (!privateKey->isOfType(OSSLECPrivateKey::type))
+ {
+ ERROR_MSG("Invalid key type supplied");
+
+ return false;
+ }
+
+ OSSLECPrivateKey* pk = (OSSLECPrivateKey*) privateKey;
+ EC_KEY* eckey = pk->getOSSLKey();
+
+ if (eckey == NULL)
+ {
+ ERROR_MSG("Could not get the OpenSSL private key");
+
+ return false;
+ }
+
+ // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+ if (FIPS_mode())
+ ECDSA_set_method(eckey, FIPS_ecdsa_openssl());
+ else
+ ECDSA_set_method(eckey, ECDSA_OpenSSL());
+#else
+ ECDSA_set_method(eckey, ECDSA_OpenSSL());
+#endif
+
+#else
+ EC_KEY_set_method(eckey, EC_KEY_OpenSSL());
+#endif
+
+ // Perform the signature operation
+ size_t len = pk->getOrderLength();
+ if (len == 0)
+ {
+ ERROR_MSG("Could not get the order length");
+ return false;
+ }
+ signature.resize(2 * len);
+ memset(&signature[0], 0, 2 * len);
+ ECDSA_SIG *sig = ECDSA_do_sign(dataToSign.const_byte_str(), dataToSign.size(), eckey);
+ if (sig == NULL)
+ {
+ ERROR_MSG("ECDSA sign failed (0x%08X)", ERR_get_error());
+ return false;
+ }
+ // Store the 2 values with padding
+ const BIGNUM* bn_r = NULL;
+ const BIGNUM* bn_s = NULL;
+ ECDSA_SIG_get0(sig, &bn_r, &bn_s);
+ BN_bn2bin(bn_r, &signature[len - BN_num_bytes(bn_r)]);
+ BN_bn2bin(bn_s, &signature[2 * len - BN_num_bytes(bn_s)]);
+ ECDSA_SIG_free(sig);
+ return true;
+}
+
+bool OSSLECDSA::signInit(PrivateKey* /*privateKey*/, const AsymMech::Type /*mechanism*/,
+ const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+ ERROR_MSG("ECDSA does not support multi part signing");
+
+ return false;
+}
+
+bool OSSLECDSA::signUpdate(const ByteString& /*dataToSign*/)
+{
+ ERROR_MSG("ECDSA does not support multi part signing");
+
+ return false;
+}
+
+bool OSSLECDSA::signFinal(ByteString& /*signature*/)
+{
+ ERROR_MSG("ECDSA does not support multi part signing");
+
+ return false;
+}
+
+// Verification functions
+bool OSSLECDSA::verify(PublicKey* publicKey, const ByteString& originalData,
+ const ByteString& signature, const AsymMech::Type mechanism,
+ const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+ if (mechanism != AsymMech::ECDSA)
+ {
+ ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+ return false;
+ }
+
+ // Check if the private key is the right type
+ if (!publicKey->isOfType(OSSLECPublicKey::type))
+ {
+ ERROR_MSG("Invalid key type supplied");
+
+ return false;
+ }
+
+ OSSLECPublicKey* pk = (OSSLECPublicKey*) publicKey;
+ EC_KEY* eckey = pk->getOSSLKey();
+
+ if (eckey == NULL)
+ {
+ ERROR_MSG("Could not get the OpenSSL public key");
+
+ return false;
+ }
+
+ // Use the OpenSSL implementation and not any engine
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+#ifdef WITH_FIPS
+ if (FIPS_mode())
+ ECDSA_set_method(eckey, FIPS_ecdsa_openssl());
+ else
+ ECDSA_set_method(eckey, ECDSA_OpenSSL());
+#else
+ ECDSA_set_method(eckey, ECDSA_OpenSSL());
+#endif
+
+#else
+ EC_KEY_set_method(eckey, EC_KEY_OpenSSL());
+#endif
+
+ // Perform the verify operation
+ size_t len = pk->getOrderLength();
+ if (len == 0)
+ {
+ ERROR_MSG("Could not get the order length");
+ return false;
+ }
+ if (signature.size() != 2 * len)
+ {
+ ERROR_MSG("Invalid buffer length");
+ return false;
+ }
+ ECDSA_SIG* sig = ECDSA_SIG_new();
+ if (sig == NULL)
+ {
+ ERROR_MSG("Could not create an ECDSA_SIG object");
+ return false;
+ }
+ const unsigned char *s = signature.const_byte_str();
+ BIGNUM* bn_r = BN_bin2bn(s, len, NULL);
+ BIGNUM* bn_s = BN_bin2bn(s + len, len, NULL);
+ if (bn_r == NULL || bn_s == NULL ||
+ !ECDSA_SIG_set0(sig, bn_r, bn_s))
+ {
+ ERROR_MSG("Could not add data to the ECDSA_SIG object");
+ ECDSA_SIG_free(sig);
+ return false;
+ }
+ int ret = ECDSA_do_verify(originalData.const_byte_str(), originalData.size(), sig, eckey);
+ if (ret != 1)
+ {
+ if (ret < 0)
+ ERROR_MSG("ECDSA verify failed (0x%08X)", ERR_get_error());
+
+ ECDSA_SIG_free(sig);
+ return false;
+ }
+
+ ECDSA_SIG_free(sig);
+ return true;
+}
+
+bool OSSLECDSA::verifyInit(PublicKey* /*publicKey*/, const AsymMech::Type /*mechanism*/,
+ const void* /* param = NULL */, const size_t /* paramLen = 0 */)
+{
+ ERROR_MSG("ECDSA does not support multi part verifying");
+
+ return false;
+}
+
+bool OSSLECDSA::verifyUpdate(const ByteString& /*originalData*/)
+{
+ ERROR_MSG("ECDSA does not support multi part verifying");
+
+ return false;
+}
+
+bool OSSLECDSA::verifyFinal(const ByteString& /*signature*/)
+{
+ ERROR_MSG("ECDSA does not support multi part verifying");
+
+ return false;
+}
+
+// Encryption functions
+bool OSSLECDSA::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+ ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+ ERROR_MSG("ECDSA does not support encryption");
+
+ return false;
+}
+
+// Decryption functions
+bool OSSLECDSA::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+ ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+ ERROR_MSG("ECDSA does not support decryption");
+
+ return false;
+}
+
+// Key factory
+bool OSSLECDSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+ // Check parameters
+ if ((ppKeyPair == NULL) ||
+ (parameters == NULL))
+ {
+ return false;
+ }
+
+ if (!parameters->areOfType(ECParameters::type))
+ {
+ ERROR_MSG("Invalid parameters supplied for ECDSA key generation");
+
+ return false;
+ }
+
+ ECParameters* params = (ECParameters*) parameters;
+
+ // Generate the key-pair
+ EC_KEY* eckey = EC_KEY_new();
+ if (eckey == NULL)
+ {
+ ERROR_MSG("Failed to instantiate OpenSSL ECDSA object");
+
+ return false;
+ }
+
+ EC_GROUP* grp = OSSL::byteString2grp(params->getEC());
+ EC_KEY_set_group(eckey, grp);
+ EC_GROUP_free(grp);
+
+ if (!EC_KEY_generate_key(eckey))
+ {
+ ERROR_MSG("ECDSA key generation failed (0x%08X)", ERR_get_error());
+
+ EC_KEY_free(eckey);
+
+ return false;
+ }
+
+ // Create an asymmetric key-pair object to return
+ OSSLECKeyPair* kp = new OSSLECKeyPair();
+
+ ((OSSLECPublicKey*) kp->getPublicKey())->setFromOSSL(eckey);
+ ((OSSLECPrivateKey*) kp->getPrivateKey())->setFromOSSL(eckey);
+
+ *ppKeyPair = kp;
+
+ // Release the key
+ EC_KEY_free(eckey);
+
+ return true;
+}
+
+unsigned long OSSLECDSA::getMinKeySize()
+{
+ // Smallest EC group is secp112r1
+ return 112;
+}
+
+unsigned long OSSLECDSA::getMaxKeySize()
+{
+ // Biggest EC group is secp521r1
+ return 521;
+}
+
+bool OSSLECDSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
+{
+ // Check input
+ if ((ppKeyPair == NULL) ||
+ (serialisedData.size() == 0))
+ {
+ return false;
+ }
+
+ ByteString dPub = ByteString::chainDeserialise(serialisedData);
+ ByteString dPriv = ByteString::chainDeserialise(serialisedData);
+
+ OSSLECKeyPair* kp = new OSSLECKeyPair();
+
+ bool rv = true;
+
+ if (!((ECPublicKey*) kp->getPublicKey())->deserialise(dPub))
+ {
+ rv = false;
+ }
+
+ if (!((ECPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+ {
+ rv = false;
+ }
+
+ if (!rv)
+ {
+ delete kp;
+
+ return false;
+ }
+
+ *ppKeyPair = kp;
+
+ return true;
+}
+
+bool OSSLECDSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+ // Check input
+ if ((ppPublicKey == NULL) ||
+ (serialisedData.size() == 0))
+ {
+ return false;
+ }
+
+ OSSLECPublicKey* pub = new OSSLECPublicKey();
+
+ if (!pub->deserialise(serialisedData))
+ {
+ delete pub;
+
+ return false;
+ }
+
+ *ppPublicKey = pub;
+
+ return true;
+}
+
+bool OSSLECDSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+ // Check input
+ if ((ppPrivateKey == NULL) ||
+ (serialisedData.size() == 0))
+ {
+ return false;
+ }
+
+ OSSLECPrivateKey* priv = new OSSLECPrivateKey();
+
+ if (!priv->deserialise(serialisedData))
+ {
+ delete priv;
+
+ return false;
+ }
+
+ *ppPrivateKey = priv;
+
+ return true;
+}
+
+PublicKey* OSSLECDSA::newPublicKey()
+{
+ return (PublicKey*) new OSSLECPublicKey();
+}
+
+PrivateKey* OSSLECDSA::newPrivateKey()
+{
+ return (PrivateKey*) new OSSLECPrivateKey();
+}
+
+AsymmetricParameters* OSSLECDSA::newParameters()
+{
+ return (AsymmetricParameters*) new ECParameters();
+}
+
+bool OSSLECDSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+ // Check input parameters
+ if ((ppParams == NULL) || (serialisedData.size() == 0))
+ {
+ return false;
+ }
+
+ ECParameters* params = new ECParameters();
+
+ if (!params->deserialise(serialisedData))
+ {
+ delete params;
+
+ return false;
+ }
+
+ *ppParams = params;
+
+ return true;
+}
+#endif