qca/plugins/qca-nss/qca-nss.cpp
Albert Astals Cid f62a8ee8f7 Run clang-format
find . \( -name "*.cpp" -or -name "*.h"  -or -name "*.c"  -or -name "*.cc" \) -exec clang-format -i {} \;

If you reached this file doing a git blame, please see README.clang-format (added 2 commits in the future of this one)
2020-09-07 02:13:47 +02:00

524 lines
15 KiB
C++

/*
* Copyright (C) 2006 Brad Hards <bradh@frogmouth.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
#include "hasht.h"
#include "nss.h"
#include "pk11func.h"
#include <QtCrypto>
#include <QDebug>
#include <QStringList>
#include <QtPlugin>
//-----------------------------------------------------------
class nssHashContext : public QCA::HashContext
{
Q_OBJECT
public:
nssHashContext(QCA::Provider *p, const QString &type)
: QCA::HashContext(p, type)
{
SECStatus s;
NSS_NoDB_Init(".");
m_status = 0;
/* Get a slot to use for the crypto operations */
m_slot = PK11_GetInternalKeySlot();
if (!m_slot) {
qDebug() << "GetInternalKeySlot failed";
m_status = 1;
return;
}
if (QLatin1String("md2") == type) {
m_hashAlgo = SEC_OID_MD2;
} else if (QLatin1String("md5") == type) {
m_hashAlgo = SEC_OID_MD5;
} else if (QLatin1String("sha1") == type) {
m_hashAlgo = SEC_OID_SHA1;
} else if (QLatin1String("sha256") == type) {
m_hashAlgo = SEC_OID_SHA256;
} else if (QLatin1String("sha384") == type) {
m_hashAlgo = SEC_OID_SHA384;
} else if (QLatin1String("sha512") == type) {
m_hashAlgo = SEC_OID_SHA512;
} else {
qDebug() << "Unknown provider type: " << type;
return; /* this will probably cause a segfault... */
}
m_context = PK11_CreateDigestContext(m_hashAlgo);
if (!m_context) {
qDebug() << "CreateDigestContext failed";
return;
}
s = PK11_DigestBegin(m_context);
if (s != SECSuccess) {
qDebug() << "DigestBegin failed";
return;
}
}
~nssHashContext() override
{
PK11_DestroyContext(m_context, PR_TRUE);
if (m_slot)
PK11_FreeSlot(m_slot);
}
Context *clone() const override
{
return new nssHashContext(provider(), type());
}
void clear() override
{
SECStatus s;
PK11_DestroyContext(m_context, PR_TRUE);
m_context = PK11_CreateDigestContext(m_hashAlgo);
if (!m_context) {
qDebug() << "CreateDigestContext failed";
return;
}
s = PK11_DigestBegin(m_context);
if (s != SECSuccess) {
qDebug() << "DigestBegin failed";
return;
}
}
void update(const QCA::MemoryRegion &a) override
{
PK11_DigestOp(m_context, (const unsigned char *)a.data(), a.size());
}
QCA::MemoryRegion final() override
{
unsigned int len = 0;
QCA::SecureArray a(64);
PK11_DigestFinal(m_context, (unsigned char *)a.data(), &len, a.size());
a.resize(len);
return a;
}
private:
PK11SlotInfo *m_slot;
int m_status;
PK11Context * m_context;
SECOidTag m_hashAlgo;
};
//-----------------------------------------------------------
class nssHmacContext : public QCA::MACContext
{
Q_OBJECT
public:
nssHmacContext(QCA::Provider *p, const QString &type)
: QCA::MACContext(p, type)
{
NSS_NoDB_Init(".");
m_context = nullptr;
m_status = 0;
/* Get a slot to use for the crypto operations */
m_slot = PK11_GetInternalKeySlot();
if (!m_slot) {
qDebug() << "GetInternalKeySlot failed";
m_status = 1;
return;
}
if (QLatin1String("hmac(md5)") == type) {
m_macAlgo = CKM_MD5_HMAC;
} else if (QLatin1String("hmac(sha1)") == type) {
m_macAlgo = CKM_SHA_1_HMAC;
} else if (QLatin1String("hmac(sha256)") == type) {
m_macAlgo = CKM_SHA256_HMAC;
} else if (QLatin1String("hmac(sha384)") == type) {
m_macAlgo = CKM_SHA384_HMAC;
} else if (QLatin1String("hmac(sha512)") == type) {
m_macAlgo = CKM_SHA512_HMAC;
} else if (QLatin1String("hmac(ripemd160)") == type) {
m_macAlgo = CKM_RIPEMD160_HMAC;
} else {
qDebug() << "Unknown provider type: " << type;
return; /* this will probably cause a segfault... */
}
}
~nssHmacContext() override
{
if (m_context)
PK11_DestroyContext(m_context, PR_TRUE);
if (m_slot)
PK11_FreeSlot(m_slot);
}
Context *clone() const override
{
return new nssHmacContext(provider(), type());
}
void clear()
{
PK11_DestroyContext(m_context, PR_TRUE);
SECItem noParams;
noParams.data = nullptr;
noParams.len = 0;
m_context = PK11_CreateContextBySymKey(m_macAlgo, CKA_SIGN, m_nssKey, &noParams);
if (!m_context) {
qDebug() << "CreateContextBySymKey failed";
return;
}
SECStatus s = PK11_DigestBegin(m_context);
if (s != SECSuccess) {
qDebug() << "DigestBegin failed";
return;
}
}
QCA::KeyLength keyLength() const override
{
return anyKeyLength();
}
void setup(const QCA::SymmetricKey &key) override
{
/* turn the raw key into a SECItem */
SECItem keyItem;
keyItem.data = (unsigned char *)key.data();
keyItem.len = key.size();
m_nssKey = PK11_ImportSymKey(m_slot, m_macAlgo, PK11_OriginUnwrap, CKA_SIGN, &keyItem, nullptr);
SECItem noParams;
noParams.data = nullptr;
noParams.len = 0;
m_context = PK11_CreateContextBySymKey(m_macAlgo, CKA_SIGN, m_nssKey, &noParams);
if (!m_context) {
qDebug() << "CreateContextBySymKey failed";
return;
}
SECStatus s = PK11_DigestBegin(m_context);
if (s != SECSuccess) {
qDebug() << "DigestBegin failed";
return;
}
}
void update(const QCA::MemoryRegion &a) override
{
PK11_DigestOp(m_context, (const unsigned char *)a.data(), a.size());
}
void final(QCA::MemoryRegion *out) override
{
// NSS doesn't appear to be able to tell us how big the digest will
// be for a given algorithm until after we finalise it, so we work
// around the problem a bit.
QCA::SecureArray sa(HASH_LENGTH_MAX, 0); // assume the biggest hash size we know
unsigned int len = 0;
PK11_DigestFinal(m_context, (unsigned char *)sa.data(), &len, sa.size());
sa.resize(len); // and fix it up later
*out = sa;
}
private:
PK11SlotInfo * m_slot;
int m_status;
PK11Context * m_context;
CK_MECHANISM_TYPE m_macAlgo;
PK11SymKey * m_nssKey;
};
//-----------------------------------------------------------
class nssCipherContext : public QCA::CipherContext
{
Q_OBJECT
public:
nssCipherContext(QCA::Provider *p, const QString &type)
: QCA::CipherContext(p, type)
{
NSS_NoDB_Init(".");
if (QLatin1String("aes128-ecb") == type) {
m_cipherMechanism = CKM_AES_ECB;
} else if (QLatin1String("aes128-cbc") == type) {
m_cipherMechanism = CKM_AES_CBC;
} else if (QLatin1String("des-ecb") == type) {
m_cipherMechanism = CKM_DES_ECB;
} else if (QLatin1String("des-cbc") == type) {
m_cipherMechanism = CKM_DES_CBC;
} else if (QLatin1String("des-cbc-pkcs7") == type) {
m_cipherMechanism = CKM_DES_CBC_PAD;
} else if (QLatin1String("tripledes-ecb") == type) {
m_cipherMechanism = CKM_DES3_ECB;
} else {
qDebug() << "Unknown provider type: " << type;
return; /* this will probably cause a segfault... */
}
}
~nssCipherContext() override
{
}
void setup(QCA::Direction dir,
const QCA::SymmetricKey & key,
const QCA::InitializationVector &iv,
const QCA::AuthTag & tag) override
{
Q_UNUSED(tag);
/* Get a slot to use for the crypto operations */
m_slot = PK11_GetBestSlot(m_cipherMechanism, nullptr);
if (!m_slot) {
qDebug() << "GetBestSlot failed";
return;
}
/* turn the raw key into a SECItem */
SECItem keyItem;
keyItem.data = (unsigned char *)key.data();
keyItem.len = key.size();
if (QCA::Encode == dir) {
m_nssKey = PK11_ImportSymKey(m_slot, m_cipherMechanism, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr);
} else {
// decryption
m_nssKey = PK11_ImportSymKey(m_slot, m_cipherMechanism, PK11_OriginUnwrap, CKA_DECRYPT, &keyItem, nullptr);
}
SECItem ivItem;
ivItem.data = (unsigned char *)iv.data();
ivItem.len = iv.size();
m_params = PK11_ParamFromIV(m_cipherMechanism, &ivItem);
if (QCA::Encode == dir) {
m_context = PK11_CreateContextBySymKey(m_cipherMechanism, CKA_ENCRYPT, m_nssKey, m_params);
} else {
// decryption
m_context = PK11_CreateContextBySymKey(m_cipherMechanism, CKA_DECRYPT, m_nssKey, m_params);
}
if (!m_context) {
qDebug() << "CreateContextBySymKey failed";
return;
}
}
QCA::Provider::Context *clone() const override
{
return new nssCipherContext(*this);
}
int blockSize() const override
{
return PK11_GetBlockSize(m_cipherMechanism, m_params);
}
QCA::AuthTag tag() const override
{
// For future implementation
return QCA::AuthTag();
}
bool update(const QCA::SecureArray &in, QCA::SecureArray *out) override
{
out->resize(in.size() + blockSize());
int resultLength;
PK11_CipherOp(
m_context, (unsigned char *)out->data(), &resultLength, out->size(), (unsigned char *)in.data(), in.size());
out->resize(resultLength);
return true;
}
bool final(QCA::SecureArray *out) override
{
out->resize(blockSize());
unsigned int resultLength;
PK11_DigestFinal(m_context, (unsigned char *)out->data(), &resultLength, out->size());
out->resize(resultLength);
return true;
}
QCA::KeyLength keyLength() const override
{
int min = 0;
int max = 0;
int multiple = 0;
switch (m_cipherMechanism) {
case CKM_AES_ECB:
case CKM_AES_CBC:
min = max = 16;
multiple = 1;
break;
case CKM_DES_ECB:
case CKM_DES_CBC:
case CKM_DES_CBC_PAD:
min = max = 8;
multiple = 1;
break;
case CKM_DES3_ECB:
min = 16;
max = 24;
multiple = 1;
break;
}
return QCA::KeyLength(min, max, multiple);
}
private:
PK11SymKey * m_nssKey;
CK_MECHANISM_TYPE m_cipherMechanism;
PK11SlotInfo * m_slot;
PK11Context * m_context;
SECItem * m_params;
};
//==========================================================
class nssProvider : public QCA::Provider
{
public:
void init() override
{
}
~nssProvider() override
{
}
int qcaVersion() const override
{
return QCA_VERSION;
}
QString name() const override
{
return QStringLiteral("qca-nss");
}
QStringList features() const override
{
QStringList list;
list += QStringLiteral("md2");
list += QStringLiteral("md5");
list += QStringLiteral("sha1");
list += QStringLiteral("sha256");
list += QStringLiteral("sha384");
list += QStringLiteral("sha512");
list += QStringLiteral("hmac(md5)");
list += QStringLiteral("hmac(sha1)");
list += QStringLiteral("hmac(sha256)");
list += QStringLiteral("hmac(sha384)");
list += QStringLiteral("hmac(sha512)");
// appears to not be implemented in NSS yet
// list += QStringLiteral("hmac(ripemd160)");
list += QStringLiteral("aes128-ecb");
list += QStringLiteral("aes128-cbc");
list += QStringLiteral("des-ecb");
list += QStringLiteral("des-cbc");
list += QStringLiteral("des-cbc-pkcs7");
list += QStringLiteral("tripledes-ecb");
return list;
}
Context *createContext(const QString &type) override
{
if (type == QLatin1String("md2"))
return new nssHashContext(this, type);
if (type == QLatin1String("md5"))
return new nssHashContext(this, type);
if (type == QLatin1String("sha1"))
return new nssHashContext(this, type);
if (type == QLatin1String("sha256"))
return new nssHashContext(this, type);
if (type == QLatin1String("sha384"))
return new nssHashContext(this, type);
if (type == QLatin1String("sha512"))
return new nssHashContext(this, type);
if (type == QLatin1String("hmac(md5)"))
return new nssHmacContext(this, type);
if (type == QLatin1String("hmac(sha1)"))
return new nssHmacContext(this, type);
if (type == QLatin1String("hmac(sha256)"))
return new nssHmacContext(this, type);
if (type == QLatin1String("hmac(sha384)"))
return new nssHmacContext(this, type);
if (type == QLatin1String("hmac(sha512)"))
return new nssHmacContext(this, type);
if (type == QLatin1String("hmac(ripemd160)"))
return new nssHmacContext(this, type);
if (type == QLatin1String("aes128-ecb"))
return new nssCipherContext(this, type);
if (type == QLatin1String("aes128-cbc"))
return new nssCipherContext(this, type);
if (type == QLatin1String("des-ecb"))
return new nssCipherContext(this, type);
if (type == QLatin1String("des-cbc"))
return new nssCipherContext(this, type);
if (type == QLatin1String("des-cbc-pkcs7"))
return new nssCipherContext(this, type);
if (type == QLatin1String("tripledes-ecb"))
return new nssCipherContext(this, type);
else
return nullptr;
}
};
class nssPlugin : public QObject, public QCAPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0")
Q_INTERFACES(QCAPlugin)
public:
QCA::Provider *createProvider() override
{
return new nssProvider;
}
};
#include "qca-nss.moc"