aboutsummaryrefslogtreecommitdiffstats
path: root/SoftHSMv2/src/lib/crypto/OSSLDSA.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SoftHSMv2/src/lib/crypto/OSSLDSA.cpp')
-rw-r--r--SoftHSMv2/src/lib/crypto/OSSLDSA.cpp695
1 files changed, 695 insertions, 0 deletions
diff --git a/SoftHSMv2/src/lib/crypto/OSSLDSA.cpp b/SoftHSMv2/src/lib/crypto/OSSLDSA.cpp
new file mode 100644
index 0000000..06b5d50
--- /dev/null
+++ b/SoftHSMv2/src/lib/crypto/OSSLDSA.cpp
@@ -0,0 +1,695 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ OSSLDSA.cpp
+
+ OpenSSL DSA asymmetric algorithm implementation
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "OSSLDSA.h"
+#include "CryptoFactory.h"
+#include "DSAParameters.h"
+#include "OSSLDSAKeyPair.h"
+#include "OSSLComp.h"
+#include "OSSLUtil.h"
+#include <algorithm>
+#include <openssl/dsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+// Constructor
+OSSLDSA::OSSLDSA()
+{
+ pCurrentHash = NULL;
+}
+
+// Destructor
+OSSLDSA::~OSSLDSA()
+{
+ if (pCurrentHash != NULL)
+ {
+ delete pCurrentHash;
+ }
+}
+
+// Signing functions
+bool OSSLDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
+ ByteString& signature, const AsymMech::Type mechanism,
+ const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+ if (mechanism == AsymMech::DSA)
+ {
+ // Separate implementation for DSA signing without hash computation
+
+ // Check if the private key is the right type
+ if (!privateKey->isOfType(OSSLDSAPrivateKey::type))
+ {
+ ERROR_MSG("Invalid key type supplied");
+
+ return false;
+ }
+
+ OSSLDSAPrivateKey* pk = (OSSLDSAPrivateKey*) privateKey;
+ DSA* dsa = pk->getOSSLKey();
+
+ // Perform the signature operation
+ unsigned int sigLen = pk->getOutputLength();
+ signature.resize(sigLen);
+ memset(&signature[0], 0, sigLen);
+ int dLen = dataToSign.size();
+ DSA_SIG* sig = DSA_do_sign(dataToSign.const_byte_str(), dLen, dsa);
+ if (sig == NULL)
+ return false;
+ // Store the 2 values with padding
+ const BIGNUM* bn_r = NULL;
+ const BIGNUM* bn_s = NULL;
+ DSA_SIG_get0(sig, &bn_r, &bn_s);
+ BN_bn2bin(bn_r, &signature[sigLen / 2 - BN_num_bytes(bn_r)]);
+ BN_bn2bin(bn_s, &signature[sigLen - BN_num_bytes(bn_s)]);
+ DSA_SIG_free(sig);
+ return true;
+ }
+ else
+ {
+ // Call default implementation
+ return AsymmetricAlgorithm::sign(privateKey, dataToSign, signature, mechanism, param, paramLen);
+ }
+}
+
+bool OSSLDSA::signInit(PrivateKey* privateKey, const AsymMech::Type mechanism,
+ const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+ if (!AsymmetricAlgorithm::signInit(privateKey, mechanism, param, paramLen))
+ {
+ return false;
+ }
+
+ // Check if the private key is the right type
+ if (!privateKey->isOfType(OSSLDSAPrivateKey::type))
+ {
+ ERROR_MSG("Invalid key type supplied");
+
+ ByteString dummy;
+ AsymmetricAlgorithm::signFinal(dummy);
+
+ return false;
+ }
+
+ HashAlgo::Type hash = HashAlgo::Unknown;
+
+ switch (mechanism)
+ {
+ case AsymMech::DSA_SHA1:
+ hash = HashAlgo::SHA1;
+ break;
+ case AsymMech::DSA_SHA224:
+ hash = HashAlgo::SHA224;
+ break;
+ case AsymMech::DSA_SHA256:
+ hash = HashAlgo::SHA256;
+ break;
+ case AsymMech::DSA_SHA384:
+ hash = HashAlgo::SHA384;
+ break;
+ case AsymMech::DSA_SHA512:
+ hash = HashAlgo::SHA512;
+ break;
+ default:
+ ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+ ByteString dummy;
+ AsymmetricAlgorithm::signFinal(dummy);
+
+ return false;
+ }
+
+ pCurrentHash = CryptoFactory::i()->getHashAlgorithm(hash);
+
+ if (pCurrentHash == NULL)
+ {
+ ByteString dummy;
+ AsymmetricAlgorithm::signFinal(dummy);
+
+ return false;
+ }
+
+ if (!pCurrentHash->hashInit())
+ {
+ delete pCurrentHash;
+ pCurrentHash = NULL;
+
+ ByteString dummy;
+ AsymmetricAlgorithm::signFinal(dummy);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool OSSLDSA::signUpdate(const ByteString& dataToSign)
+{
+ if (!AsymmetricAlgorithm::signUpdate(dataToSign))
+ {
+ return false;
+ }
+
+ if (!pCurrentHash->hashUpdate(dataToSign))
+ {
+ delete pCurrentHash;
+ pCurrentHash = NULL;
+
+ ByteString dummy;
+ AsymmetricAlgorithm::signFinal(dummy);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool OSSLDSA::signFinal(ByteString& signature)
+{
+ // Save necessary state before calling super class signFinal
+ OSSLDSAPrivateKey* pk = (OSSLDSAPrivateKey*) currentPrivateKey;
+
+ if (!AsymmetricAlgorithm::signFinal(signature))
+ {
+ return false;
+ }
+
+ ByteString hash;
+
+ bool bFirstResult = pCurrentHash->hashFinal(hash);
+
+ delete pCurrentHash;
+ pCurrentHash = NULL;
+
+ if (!bFirstResult)
+ {
+ return false;
+ }
+
+ DSA* dsa = pk->getOSSLKey();
+
+ // Perform the signature operation
+ unsigned int sigLen = pk->getOutputLength();
+ signature.resize(sigLen);
+ memset(&signature[0], 0, sigLen);
+ DSA_SIG* sig = DSA_do_sign(&hash[0], hash.size(), dsa);
+ if (sig == NULL)
+ return false;
+ // Store the 2 values with padding
+ const BIGNUM* bn_r = NULL;
+ const BIGNUM* bn_s = NULL;
+ DSA_SIG_get0(sig, &bn_r, &bn_s);
+ BN_bn2bin(bn_r, &signature[sigLen / 2 - BN_num_bytes(bn_r)]);
+ BN_bn2bin(bn_s, &signature[sigLen - BN_num_bytes(bn_s)]);
+ DSA_SIG_free(sig);
+ return true;
+}
+
+// Verification functions
+bool OSSLDSA::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::DSA)
+ {
+ // Separate implementation for DSA verification without hash computation
+
+ // Check if the private key is the right type
+ if (!publicKey->isOfType(OSSLDSAPublicKey::type))
+ {
+ ERROR_MSG("Invalid key type supplied");
+
+ return false;
+ }
+
+ // Perform the verify operation
+ OSSLDSAPublicKey* pk = (OSSLDSAPublicKey*) publicKey;
+ unsigned int sigLen = pk->getOutputLength();
+ if (signature.size() != sigLen)
+ return false;
+ DSA_SIG* sig = DSA_SIG_new();
+ if (sig == NULL)
+ return false;
+ const unsigned char *s = signature.const_byte_str();
+ BIGNUM* bn_r = BN_bin2bn(s, sigLen / 2, NULL);
+ BIGNUM* bn_s = BN_bin2bn(s + sigLen / 2, sigLen / 2, NULL);
+ if (bn_r == NULL || bn_s == NULL ||
+ !DSA_SIG_set0(sig, bn_r, bn_s))
+ {
+ DSA_SIG_free(sig);
+ return false;
+ }
+ int dLen = originalData.size();
+ int ret = DSA_do_verify(originalData.const_byte_str(), dLen, sig, pk->getOSSLKey());
+ if (ret != 1)
+ {
+ if (ret < 0)
+ ERROR_MSG("DSA verify failed (0x%08X)", ERR_get_error());
+
+ DSA_SIG_free(sig);
+ return false;
+ }
+
+ DSA_SIG_free(sig);
+ return true;
+ }
+ else
+ {
+ // Call the generic function
+ return AsymmetricAlgorithm::verify(publicKey, originalData, signature, mechanism, param, paramLen);
+ }
+}
+
+bool OSSLDSA::verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism,
+ const void* param /* = NULL */, const size_t paramLen /* = 0 */)
+{
+ if (!AsymmetricAlgorithm::verifyInit(publicKey, mechanism, param, paramLen))
+ {
+ return false;
+ }
+
+ // Check if the private key is the right type
+ if (!publicKey->isOfType(OSSLDSAPublicKey::type))
+ {
+ ERROR_MSG("Invalid key type supplied");
+
+ ByteString dummy;
+ AsymmetricAlgorithm::verifyFinal(dummy);
+
+ return false;
+ }
+
+ HashAlgo::Type hash = HashAlgo::Unknown;
+
+ switch (mechanism)
+ {
+ case AsymMech::DSA_SHA1:
+ hash = HashAlgo::SHA1;
+ break;
+ case AsymMech::DSA_SHA224:
+ hash = HashAlgo::SHA224;
+ break;
+ case AsymMech::DSA_SHA256:
+ hash = HashAlgo::SHA256;
+ break;
+ case AsymMech::DSA_SHA384:
+ hash = HashAlgo::SHA384;
+ break;
+ case AsymMech::DSA_SHA512:
+ hash = HashAlgo::SHA512;
+ break;
+ default:
+ ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
+
+ ByteString dummy;
+ AsymmetricAlgorithm::verifyFinal(dummy);
+
+ return false;
+ }
+
+ pCurrentHash = CryptoFactory::i()->getHashAlgorithm(hash);
+
+
+ if (pCurrentHash == NULL)
+ {
+ ByteString dummy;
+ AsymmetricAlgorithm::verifyFinal(dummy);
+
+ return false;
+ }
+
+ if (!pCurrentHash->hashInit())
+ {
+ delete pCurrentHash;
+ pCurrentHash = NULL;
+
+ ByteString dummy;
+ AsymmetricAlgorithm::verifyFinal(dummy);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool OSSLDSA::verifyUpdate(const ByteString& originalData)
+{
+ if (!AsymmetricAlgorithm::verifyUpdate(originalData))
+ {
+ return false;
+ }
+
+ if (!pCurrentHash->hashUpdate(originalData))
+ {
+ delete pCurrentHash;
+ pCurrentHash = NULL;
+
+ ByteString dummy;
+ AsymmetricAlgorithm::verifyFinal(dummy);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool OSSLDSA::verifyFinal(const ByteString& signature)
+{
+ // Save necessary state before calling super class verifyFinal
+ OSSLDSAPublicKey* pk = (OSSLDSAPublicKey*) currentPublicKey;
+
+ if (!AsymmetricAlgorithm::verifyFinal(signature))
+ {
+ return false;
+ }
+
+ ByteString hash;
+
+ bool bFirstResult = pCurrentHash->hashFinal(hash);
+
+ delete pCurrentHash;
+ pCurrentHash = NULL;
+
+ if (!bFirstResult)
+ {
+ return false;
+ }
+
+ // Perform the verify operation
+ unsigned int sigLen = pk->getOutputLength();
+ if (signature.size() != sigLen)
+ return false;
+ DSA_SIG* sig = DSA_SIG_new();
+ if (sig == NULL)
+ return false;
+ const unsigned char *s = signature.const_byte_str();
+ BIGNUM* bn_r = BN_bin2bn(s, sigLen / 2, NULL);
+ BIGNUM* bn_s = BN_bin2bn(s + sigLen / 2, sigLen / 2, NULL);
+ if (bn_r == NULL || bn_s == NULL ||
+ !DSA_SIG_set0(sig, bn_r, bn_s))
+ {
+ DSA_SIG_free(sig);
+ return false;
+ }
+ int ret = DSA_do_verify(&hash[0], hash.size(), sig, pk->getOSSLKey());
+ if (ret != 1)
+ {
+ if (ret < 0)
+ ERROR_MSG("DSA verify failed (0x%08X)", ERR_get_error());
+
+ DSA_SIG_free(sig);
+ return false;
+ }
+
+ DSA_SIG_free(sig);
+ return true;
+}
+
+// Encryption functions
+bool OSSLDSA::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
+ ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
+{
+ ERROR_MSG("DSA does not support encryption");
+
+ return false;
+}
+
+// Decryption functions
+bool OSSLDSA::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
+ ByteString& /*data*/, const AsymMech::Type /*padding*/)
+{
+ ERROR_MSG("DSA does not support decryption");
+
+ return false;
+}
+
+// Key factory
+bool OSSLDSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
+{
+ // Check parameters
+ if ((ppKeyPair == NULL) ||
+ (parameters == NULL))
+ {
+ return false;
+ }
+
+ if (!parameters->areOfType(DSAParameters::type))
+ {
+ ERROR_MSG("Invalid parameters supplied for DSA key generation");
+
+ return false;
+ }
+
+ DSAParameters* params = (DSAParameters*) parameters;
+
+ // Generate the key-pair
+ DSA* dsa = DSA_new();
+ if (dsa == NULL)
+ {
+ ERROR_MSG("Failed to instantiate OpenSSL DSA object");
+
+ return false;
+ }
+
+ // Use the OpenSSL implementation and not any engine
+ DSA_set_method(dsa, DSA_get_default_method());
+
+ BIGNUM* bn_p = OSSL::byteString2bn(params->getP());
+ BIGNUM* bn_q = OSSL::byteString2bn(params->getQ());
+ BIGNUM* bn_g = OSSL::byteString2bn(params->getG());
+ DSA_set0_pqg(dsa, bn_p, bn_q, bn_g);
+
+ if (DSA_generate_key(dsa) != 1)
+ {
+ ERROR_MSG("DSA key generation failed (0x%08X)", ERR_get_error());
+
+ DSA_free(dsa);
+
+ return false;
+ }
+
+ // Create an asymmetric key-pair object to return
+ OSSLDSAKeyPair* kp = new OSSLDSAKeyPair();
+
+ ((OSSLDSAPublicKey*) kp->getPublicKey())->setFromOSSL(dsa);
+ ((OSSLDSAPrivateKey*) kp->getPrivateKey())->setFromOSSL(dsa);
+
+ *ppKeyPair = kp;
+
+ // Release the key
+ DSA_free(dsa);
+
+ return true;
+}
+
+unsigned long OSSLDSA::getMinKeySize()
+{
+#ifdef WITH_FIPS
+ // OPENSSL_DSA_FIPS_MIN_MODULUS_BITS is 1024
+ return 1024;
+#else
+ return 512;
+#endif
+}
+
+unsigned long OSSLDSA::getMaxKeySize()
+{
+ return OPENSSL_DSA_MAX_MODULUS_BITS;
+}
+
+bool OSSLDSA::generateParameters(AsymmetricParameters** ppParams, void* parameters /* = NULL */, RNG* /*rng = NULL*/)
+{
+ if ((ppParams == NULL) || (parameters == NULL))
+ {
+ return false;
+ }
+
+ size_t bitLen = (size_t) parameters;
+
+ if (bitLen < getMinKeySize() || bitLen > getMaxKeySize())
+ {
+ ERROR_MSG("This DSA key size is not supported");
+
+ return false;
+ }
+
+ DSA* dsa = DSA_new();
+
+ if (dsa == NULL ||
+ !DSA_generate_parameters_ex(dsa, bitLen, NULL, 0, NULL, NULL, NULL))
+ {
+ ERROR_MSG("Failed to generate %d bit DSA parameters", bitLen);
+
+ return false;
+ }
+
+ // Store the DSA parameters
+ DSAParameters* params = new DSAParameters();
+
+ const BIGNUM* bn_p = NULL;
+ const BIGNUM* bn_q = NULL;
+ const BIGNUM* bn_g = NULL;
+ DSA_get0_pqg(dsa, &bn_p, &bn_q, &bn_g);
+
+ ByteString p = OSSL::bn2ByteString(bn_p); params->setP(p);
+ ByteString q = OSSL::bn2ByteString(bn_q); params->setQ(q);
+ ByteString g = OSSL::bn2ByteString(bn_g); params->setG(g);
+
+ *ppParams = params;
+
+ DSA_free(dsa);
+
+ return true;
+}
+
+bool OSSLDSA::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);
+
+ OSSLDSAKeyPair* kp = new OSSLDSAKeyPair();
+
+ bool rv = true;
+
+ if (!((DSAPublicKey*) kp->getPublicKey())->deserialise(dPub))
+ {
+ rv = false;
+ }
+
+ if (!((DSAPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
+ {
+ rv = false;
+ }
+
+ if (!rv)
+ {
+ delete kp;
+
+ return false;
+ }
+
+ *ppKeyPair = kp;
+
+ return true;
+}
+
+bool OSSLDSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
+{
+ // Check input
+ if ((ppPublicKey == NULL) ||
+ (serialisedData.size() == 0))
+ {
+ return false;
+ }
+
+ OSSLDSAPublicKey* pub = new OSSLDSAPublicKey();
+
+ if (!pub->deserialise(serialisedData))
+ {
+ delete pub;
+
+ return false;
+ }
+
+ *ppPublicKey = pub;
+
+ return true;
+}
+
+bool OSSLDSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
+{
+ // Check input
+ if ((ppPrivateKey == NULL) ||
+ (serialisedData.size() == 0))
+ {
+ return false;
+ }
+
+ OSSLDSAPrivateKey* priv = new OSSLDSAPrivateKey();
+
+ if (!priv->deserialise(serialisedData))
+ {
+ delete priv;
+
+ return false;
+ }
+
+ *ppPrivateKey = priv;
+
+ return true;
+}
+
+PublicKey* OSSLDSA::newPublicKey()
+{
+ return (PublicKey*) new OSSLDSAPublicKey();
+}
+
+PrivateKey* OSSLDSA::newPrivateKey()
+{
+ return (PrivateKey*) new OSSLDSAPrivateKey();
+}
+
+AsymmetricParameters* OSSLDSA::newParameters()
+{
+ return (AsymmetricParameters*) new DSAParameters();
+}
+
+bool OSSLDSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
+{
+ // Check input parameters
+ if ((ppParams == NULL) || (serialisedData.size() == 0))
+ {
+ return false;
+ }
+
+ DSAParameters* params = new DSAParameters();
+
+ if (!params->deserialise(serialisedData))
+ {
+ delete params;
+
+ return false;
+ }
+
+ *ppParams = params;
+
+ return true;
+}
+