qca/plugins/qca-pkcs11/qca-pkcs11.cpp
Alon Bar-Lev c4351c35e3 Ignore none qca-pkcs11 serialization
svn path=/trunk/kdesupport/qca/; revision=664883
2007-05-15 04:33:39 +00:00

3052 lines
58 KiB
C++

/*
* Copyright (C) 2004 Justin Karneges <justin@affinix.com>
* Copyright (C) 2006-2007 Alon Bar-Lev <alon.barlev@gmail.com>
*
* 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 WITHANY 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 <QtCrypto>
#include <qplatformdefs.h>
#include <QHash>
#include <QMutexLocker>
#include <QtPlugin>
#include <pkcs11-helper-1.0/pkcs11h-token.h>
#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
using namespace QCA;
// qPrintable is ASCII only!!!
#define myPrintable(s) (s).toUtf8 ().constData ()
static
inline
QString
certificateHash (
const Certificate &cert
) {
if (cert.isNull ()) {
return QString();
}
else {
return Hash ("sha1").hashToString (cert.toDER ());
}
}
//----------------------------------------------------------------------------
// pkcs11Provider
//----------------------------------------------------------------------------
class pkcs11Provider : public Provider
{
private:
static const int _CONFIG_MAX_PROVIDERS;
bool _lowLevelInitialized;
bool _slotEventsActive;
bool _slotEventsLowLevelActive;
QStringList _providers;
public:
bool _allowLoadRootCA;
public:
pkcs11Provider ();
~pkcs11Provider ();
public:
virtual
int
version() const;
virtual
void
init ();
virtual
QString
name () const;
virtual
QStringList
features () const;
virtual
Context *
createContext (
const QString &type
);
void
startSlotEvents ();
void
stopSlotEvents ();
virtual
QVariantMap
defaultConfig () const;
virtual
void
configChanged (const QVariantMap &config);
protected:
static
void
__logHook (
void * const global_data,
const unsigned flags,
const char * const format,
va_list args
);
static
void
__slotEventHook (
void * const global_data
);
static
PKCS11H_BOOL
__tokenPromptHook (
void * const global_data,
void * const user_data,
const pkcs11h_token_id_t token,
const unsigned retry
);
static
PKCS11H_BOOL
__pinPromptHook (
void * const global_data,
void * const user_data,
const pkcs11h_token_id_t token,
const unsigned retry,
char * const pin,
const size_t pin_max
);
void
_logHook (
const unsigned flags,
const char * const format,
va_list args
);
void
_slotEventHook ();
PKCS11H_BOOL
_tokenPromptHook (
void * const user_data,
const pkcs11h_token_id_t token
);
PKCS11H_BOOL
_pinPromptHook (
void * const user_data,
const pkcs11h_token_id_t token,
char * const pin,
const size_t pin_max
);
};
namespace pkcs11QCAPlugin {
class pkcs11KeyStoreEntryContext;
//----------------------------------------------------------------------------
// pkcs11KeyStoreListContext
//----------------------------------------------------------------------------
class pkcs11KeyStoreListContext : public KeyStoreListContext
{
Q_OBJECT
private:
struct pkcs11KeyStoreItem {
protected:
int _id;
pkcs11h_token_id_t _token_id;
QList<Certificate> _certs;
public:
pkcs11KeyStoreItem (
const int id,
const pkcs11h_token_id_t token_id
) {
_id = id;;
pkcs11h_token_duplicateTokenId (&_token_id, token_id);
}
~pkcs11KeyStoreItem () {
if (_token_id != NULL) {
pkcs11h_token_freeTokenId (_token_id);
}
}
inline int id () const {
return _id;
}
inline pkcs11h_token_id_t tokenId () const {
return _token_id;
}
void
registerCertificates (
const QList<Certificate> &certs
) {
foreach (Certificate i, certs) {
if (qFind (_certs.begin (), _certs.end (), i) == _certs.end ()) {
_certs += i;
}
}
}
QMap<QString, QString>
friendlyNames () {
QStringList names = makeFriendlyNames (_certs);
QMap<QString, QString> friendlyNames;
for (int i=0;i<names.size ();i++) {
friendlyNames.insert (certificateHash (_certs[i]), names[i]);
}
return friendlyNames;
}
};
int _last_id;
typedef QList<pkcs11KeyStoreItem *> _stores_t;
_stores_t _stores;
QHash<int, pkcs11KeyStoreItem *> _storesById;
QMutex _mutexStores;
bool _initialized;
public:
pkcs11KeyStoreListContext (Provider *p);
~pkcs11KeyStoreListContext ();
virtual
Provider::Context *
clone () const;
public:
virtual
void
start ();
virtual
void
setUpdatesEnabled (bool enabled);
virtual
KeyStoreEntryContext *
entry (
int id,
const QString &entryId
);
virtual
KeyStoreEntryContext *
entryPassive (
const QString &serialized
);
virtual
KeyStore::Type
type (int id) const;
virtual
QString
storeId (int id) const;
virtual
QString
name (int id) const;
virtual
QList<KeyStoreEntry::Type>
entryTypes (int id) const;
virtual
QList<int>
keyStores ();
virtual
QList<KeyStoreEntryContext *>
entryList (int id);
bool
_tokenPrompt (
void * const user_data,
const pkcs11h_token_id_t token_id
);
bool
_pinPrompt (
void * const user_data,
const pkcs11h_token_id_t token_id,
SecureArray &pin
);
void
_emit_diagnosticText (
const QString &t
);
private slots:
void
doReady ();
void
doUpdated ();
private:
pkcs11KeyStoreItem *
_registerTokenId (
const pkcs11h_token_id_t token_id
);
void
_clearStores ();
pkcs11KeyStoreEntryContext *
_keyStoreEntryByCertificateId (
const pkcs11h_certificate_id_t certificate_id,
const bool has_private,
const CertificateChain &chain,
const QString &description
) const;
QString
_tokenId2storeId (
const pkcs11h_token_id_t token_id
) const;
QString
_serializeCertificate (
const pkcs11h_certificate_id_t certificate_id,
const CertificateChain &chain,
const bool has_private
) const;
void
_deserializeCertificate (
const QString &from,
pkcs11h_certificate_id_t * const p_certificate_id,
bool * const p_has_private,
CertificateChain &chain
) const;
QString
_escapeString (
const QString &from
) const;
QString
_unescapeString (
const QString &from
) const;
};
static pkcs11KeyStoreListContext *s_keyStoreList = NULL;
//----------------------------------------------------------------------------
// pkcs11Exception
//----------------------------------------------------------------------------
class pkcs11Exception {
private:
CK_RV _rv;
QString _msg;
private:
pkcs11Exception () {}
public:
pkcs11Exception (const CK_RV rv, const QString &msg) {
_rv = rv;
_msg = msg;
}
pkcs11Exception (const pkcs11Exception &other) {
*this = other;
}
pkcs11Exception &
operator = (const pkcs11Exception &other) {
_rv = other._rv;
_msg = other._msg;
return *this;
}
CK_RV
rv () const {
return _rv;
}
QString
message () const {
return _msg + QString (" ") + pkcs11h_getMessage (_rv);
}
};
//----------------------------------------------------------------------------
// pkcs11RSAContext
//----------------------------------------------------------------------------
class pkcs11RSAContext : public RSAContext
{
Q_OBJECT
private:
bool _has_privateKeyRole;
pkcs11h_certificate_id_t _pkcs11h_certificate_id;
pkcs11h_certificate_t _pkcs11h_certificate;
RSAPublicKey _pubkey;
QString _serialized;
struct _sign_data_s {
SignatureAlgorithm alg;
Hash *hash;
SecureArray raw;
_sign_data_s() {
hash = NULL;
}
} _sign_data;
public:
pkcs11RSAContext (
Provider *p,
const pkcs11h_certificate_id_t pkcs11h_certificate_id,
const QString &serialized,
const RSAPublicKey &pubkey
) : RSAContext (p) {
CK_RV rv;
QCA_logTextMessage (
"pkcs11RSAContext::pkcs11RSAContext1 - entry",
Logger::Debug
);
_has_privateKeyRole = true;
_pkcs11h_certificate_id = NULL;
_pkcs11h_certificate = NULL;
_pubkey = pubkey;
_serialized = serialized;
_clearSign ();
if (
(rv = pkcs11h_certificate_duplicateCertificateId (
&_pkcs11h_certificate_id,
pkcs11h_certificate_id
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Memory error");
}
QCA_logTextMessage (
"pkcs11RSAContext::pkcs11RSAContext1 - return",
Logger::Debug
);
}
pkcs11RSAContext (const pkcs11RSAContext &from) : RSAContext (from.provider ()) {
CK_RV rv;
QCA_logTextMessage (
"pkcs11RSAContext::pkcs11RSAContextC - entry",
Logger::Debug
);
_has_privateKeyRole = from._has_privateKeyRole;
_pkcs11h_certificate_id = NULL;
_pkcs11h_certificate = NULL;
_pubkey = from._pubkey;
_serialized = from._serialized;
_sign_data.hash = NULL;
_clearSign ();
if (
(rv = pkcs11h_certificate_duplicateCertificateId (
&_pkcs11h_certificate_id,
from._pkcs11h_certificate_id
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Memory error");
}
QCA_logTextMessage (
"pkcs11RSAContext::pkcs11RSAContextC - return",
Logger::Debug
);
}
~pkcs11RSAContext () {
QCA_logTextMessage (
"pkcs11RSAContext::~pkcs11RSAContext - entry",
Logger::Debug
);
_clearSign ();
if (_pkcs11h_certificate != NULL) {
pkcs11h_certificate_freeCertificate (_pkcs11h_certificate);
_pkcs11h_certificate = NULL;
}
if (_pkcs11h_certificate_id != NULL) {
pkcs11h_certificate_freeCertificateId (_pkcs11h_certificate_id);
_pkcs11h_certificate_id = NULL;
}
QCA_logTextMessage (
"pkcs11RSAContext::~pkcs11RSAContext - return",
Logger::Debug
);
}
virtual
Provider::Context *
clone () const {
return new pkcs11RSAContext (*this);
}
public:
virtual
bool
isNull () const {
return _pubkey.isNull ();
}
virtual
PKey::Type
type () const {
return _pubkey.type ();
}
virtual
bool
isPrivate () const {
return _has_privateKeyRole;
}
virtual
bool
canExport () const {
return !_has_privateKeyRole;
}
virtual
void
convertToPublic () {
QCA_logTextMessage (
"pkcs11RSAContext::convertToPublic - entry",
Logger::Debug
);
if (_has_privateKeyRole) {
if (_pkcs11h_certificate != NULL) {
pkcs11h_certificate_freeCertificate (_pkcs11h_certificate);
_pkcs11h_certificate = NULL;
}
_has_privateKeyRole = false;
}
QCA_logTextMessage (
"pkcs11RSAContext::convertToPublic - return",
Logger::Debug
);
}
virtual
int
bits () const {
return _pubkey.bitSize ();
}
virtual
int
maximumEncryptSize (
EncryptionAlgorithm alg
) const {
return _pubkey.maximumEncryptSize (alg);
}
virtual
SecureArray
encrypt (
const SecureArray &in,
EncryptionAlgorithm alg
) {
return _pubkey.encrypt (in, alg);
}
virtual
bool
decrypt (
const SecureArray &in,
SecureArray *out,
EncryptionAlgorithm alg
) {
bool session_locked = false;
bool ret = false;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11RSAContext::decrypt - decrypt in.size()=%d, alg=%d",
in.size (),
(int)alg
),
Logger::Debug
);
try {
CK_MECHANISM_TYPE mech;
CK_RV rv;
size_t my_size;
switch (alg) {
case EME_PKCS1v15:
mech = CKM_RSA_PKCS;
break;
case EME_PKCS1_OAEP:
mech = CKM_RSA_PKCS_OAEP;
break;
default:
throw pkcs11Exception (CKR_FUNCTION_NOT_SUPPORTED, "Invalid algorithm");
break;
}
_ensureCertificate ();
if (
(rv = pkcs11h_certificate_lockSession (
_pkcs11h_certificate
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Cannot lock session");
}
session_locked = true;
if (
(rv = pkcs11h_certificate_decryptAny (
_pkcs11h_certificate,
mech,
(const unsigned char *)in.constData (),
in.size (),
NULL,
&my_size
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Decryption error");
}
out->resize (my_size);
if (
(rv = pkcs11h_certificate_decryptAny (
_pkcs11h_certificate,
mech,
(const unsigned char *)in.constData (),
in.size (),
(unsigned char *)out->data (),
&my_size
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Decryption error");
}
rv = out->resize (my_size);
if (
(rv = pkcs11h_certificate_releaseSession (
_pkcs11h_certificate
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Cannot release session");
}
session_locked = false;
ret = true;
}
catch (const pkcs11Exception &e) {
if (session_locked) {
pkcs11h_certificate_releaseSession (
_pkcs11h_certificate
);
session_locked = false;
}
if (s_keyStoreList != NULL) {
s_keyStoreList->_emit_diagnosticText (
QString ().sprintf (
"PKCS#11: Cannot decrypt: %lu-'%s'.\n",
e.rv (),
myPrintable (e.message ())
)
);
}
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11RSAContext::decrypt - decrypt out->size()=%d",
out->size ()
),
Logger::Debug
);
return ret;
}
virtual
void
startSign (
SignatureAlgorithm alg,
SignatureFormat
) {
_clearSign ();
_sign_data.alg = alg;
switch (_sign_data.alg) {
case EMSA3_SHA1:
_sign_data.hash = new Hash ("sha1");
break;
case EMSA3_MD5:
_sign_data.hash = new Hash ("md5");
break;
case EMSA3_MD2:
_sign_data.hash = new Hash ("md2");
break;
case EMSA3_Raw:
break;
case SignatureUnknown:
case EMSA1_SHA1:
case EMSA3_RIPEMD160:
default:
QCA_logTextMessage (
QString().sprintf (
"PKCS#11: Invalid hash algorithm %d",
_sign_data.alg
),
Logger::Warning
);
break;
}
}
virtual
void
startVerify (
SignatureAlgorithm alg,
SignatureFormat sf
) {
_pubkey.startVerify (alg, sf);
}
virtual
void
update (
const SecureArray &in
) {
if (_has_privateKeyRole) {
if (_sign_data.hash != NULL) {
_sign_data.hash->update (in);
}
else {
_sign_data.raw.append (in);
}
}
else {
_pubkey.update (in);
}
}
virtual
SecureArray
endSign () {
SecureArray result;
bool session_locked = false;
QCA_logTextMessage (
"pkcs11RSAContext::endSign - entry",
Logger::Debug
);
try {
SecureArray final;
CK_RV rv;
// from some strange reason I got 2047... (for some) <---- BUG?!?!?!
int myrsa_size=(_pubkey.bitSize () + 7) / 8;
if (_sign_data.hash != NULL) {
final = emsa3Encode (
_sign_data.hash->type (),
_sign_data.hash->final (),
myrsa_size
);
}
else {
final = _sign_data.raw;
}
if (final.size () == 0) {
throw pkcs11Exception (CKR_FUNCTION_FAILED, "Cannot encode signature");
}
_ensureCertificate ();
size_t my_size;
if (
(rv = pkcs11h_certificate_lockSession (
_pkcs11h_certificate
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Cannot lock session");
}
session_locked = true;
if (
(rv = pkcs11h_certificate_signAny (
_pkcs11h_certificate,
CKM_RSA_PKCS,
(const unsigned char *)final.constData (),
(size_t)final.size (),
NULL,
&my_size
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Signature failed");
}
result.resize (my_size);
if (
(rv = pkcs11h_certificate_signAny (
_pkcs11h_certificate,
CKM_RSA_PKCS,
(const unsigned char *)final.constData (),
(size_t)final.size (),
(unsigned char *)result.data (),
&my_size
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Signature failed");
}
result.resize (my_size);
if (
(rv = pkcs11h_certificate_releaseSession (
_pkcs11h_certificate
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Cannot release session");
}
session_locked = false;
}
catch (const pkcs11Exception &e) {
result.clear ();
if (session_locked) {
pkcs11h_certificate_releaseSession (
_pkcs11h_certificate
);
session_locked = false;
}
if (s_keyStoreList != NULL) {
s_keyStoreList->_emit_diagnosticText (
QString ().sprintf (
"PKCS#11: Cannot sign: %lu-'%s'.\n",
e.rv (),
myPrintable (e.message ())
)
);
}
}
_clearSign ();
QCA_logTextMessage (
QString ().sprintf (
"pkcs11RSAContext::endSign - return result.size ()=%d",
result.size ()
),
Logger::Debug
);
return result;
}
virtual
bool
validSignature (
const SecureArray &sig
) {
return _pubkey.validSignature (sig);
}
virtual
void
createPrivate (
int bits,
int exp,
bool block
) {
Q_UNUSED(bits);
Q_UNUSED(exp);
Q_UNUSED(block);
}
virtual
void
createPrivate (
const BigInteger &n,
const BigInteger &e,
const BigInteger &p,
const BigInteger &q,
const BigInteger &d
) {
Q_UNUSED(n);
Q_UNUSED(e);
Q_UNUSED(p);
Q_UNUSED(q);
Q_UNUSED(d);
}
virtual
void
createPublic (
const BigInteger &n,
const BigInteger &e
) {
Q_UNUSED(n);
Q_UNUSED(e);
}
virtual
BigInteger
n () const {
return _pubkey.n ();
}
virtual
BigInteger
e () const {
return _pubkey.e ();
}
virtual
BigInteger
p () const {
return BigInteger();
}
virtual
BigInteger
q () const {
return BigInteger();
}
virtual
BigInteger
d () const {
return BigInteger();
}
public:
PublicKey
_publicKey () const {
return _pubkey;
}
bool
_ensureTokenAccess () {
bool ret;
QCA_logTextMessage (
"pkcs11RSAContext::_ensureTokenAccess - entry",
Logger::Debug
);
ret = pkcs11h_token_ensureAccess (
_pkcs11h_certificate_id->token_id,
NULL,
0
) == CKR_OK;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11RSAContext::_ensureTokenAccess - return ret=%d",
ret ? 1 : 0
),
Logger::Debug
);
return ret;
}
private:
void
_clearSign () {
_sign_data.raw.clear ();
_sign_data.alg = SignatureUnknown;
delete _sign_data.hash;
_sign_data.hash = NULL;
}
void
_ensureCertificate () {
CK_RV rv;
QCA_logTextMessage (
"pkcs11RSAContext::_ensureCertificate - entry",
Logger::Debug
);
if (_pkcs11h_certificate == NULL) {
if (
(rv = pkcs11h_certificate_create (
_pkcs11h_certificate_id,
&_serialized,
PKCS11H_PROMPT_MASK_ALLOW_ALL,
PKCS11H_PIN_CACHE_INFINITE,
&_pkcs11h_certificate
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Cannot create low-level certificate");
}
}
QCA_logTextMessage (
"pkcs11RSAContext::_ensureCertificate - return",
Logger::Debug
);
}
};
//----------------------------------------------------------------------------
// pkcs11PKeyContext
//----------------------------------------------------------------------------
class pkcs11PKeyContext : public PKeyContext
{
private:
PKeyBase *_k;
public:
pkcs11PKeyContext (Provider *p) : PKeyContext (p) {
_k = NULL;
}
~pkcs11PKeyContext () {
delete _k;
_k = NULL;
}
virtual
Provider::Context *
clone () const {
pkcs11PKeyContext *c = new pkcs11PKeyContext (*this);
c->_k = (PKeyBase *)_k->clone();
return c;
}
public:
virtual
QList<PKey::Type>
supportedTypes () const {
QList<PKey::Type> list;
list += PKey::RSA;
return list;
}
virtual
QList<PKey::Type>
supportedIOTypes () const {
QList<PKey::Type> list;
list += PKey::RSA;
return list;
}
virtual
QList<PBEAlgorithm>
supportedPBEAlgorithms () const {
QList<PBEAlgorithm> list;
return list;
}
virtual
PKeyBase *
key () {
return _k;
}
virtual
const PKeyBase *
key () const {
return _k;
}
virtual
void
setKey (PKeyBase *key) {
delete _k;
_k = key;
}
virtual
bool
importKey (
const PKeyBase *key
) {
Q_UNUSED(key);
return false;
}
static
int
passphrase_cb (
char *buf,
int size,
int rwflag,
void *u
) {
Q_UNUSED(buf);
Q_UNUSED(size);
Q_UNUSED(rwflag);
Q_UNUSED(u);
return 0;
}
virtual
SecureArray
publicToDER () const {
return static_cast<pkcs11RSAContext *>(_k)->_publicKey ().toDER ();
}
virtual
QString
publicToPEM () const {
return static_cast<pkcs11RSAContext *>(_k)->_publicKey ().toPEM ();
}
virtual
ConvertResult
publicFromDER (
const SecureArray &in
) {
Q_UNUSED(in);
return ErrorDecode;
}
virtual
ConvertResult
publicFromPEM (
const QString &s
) {
Q_UNUSED(s);
return ErrorDecode;
}
virtual
SecureArray
privateToDER(
const SecureArray &passphrase,
PBEAlgorithm pbe
) const {
Q_UNUSED(passphrase);
Q_UNUSED(pbe);
return SecureArray ();
}
virtual
QString
privateToPEM (
const SecureArray &passphrase,
PBEAlgorithm pbe
) const {
Q_UNUSED(passphrase);
Q_UNUSED(pbe);
return QString ();
}
virtual
ConvertResult
privateFromDER (
const SecureArray &in,
const SecureArray &passphrase
) {
Q_UNUSED(in);
Q_UNUSED(passphrase);
return ErrorDecode;
}
virtual
ConvertResult
privateFromPEM (
const QString &s,
const SecureArray &passphrase
) {
Q_UNUSED(s);
Q_UNUSED(passphrase);
return ErrorDecode;
}
};
//----------------------------------------------------------------------------
// pkcs11KeyStoreEntryContext
//----------------------------------------------------------------------------
class pkcs11KeyStoreEntryContext : public KeyStoreEntryContext
{
private:
KeyStoreEntry::Type _item_type;
KeyBundle _key;
Certificate _cert;
QString _storeId;
QString _id;
QString _serialized;
QString _storeName;
QString _name;
public:
pkcs11KeyStoreEntryContext (
const Certificate &cert,
const QString &storeId,
const QString &serialized,
const QString &storeName,
const QString &name,
Provider *p
) : KeyStoreEntryContext(p) {
_item_type = KeyStoreEntry::TypeCertificate;
_cert = cert;
_storeId = storeId;
_id = certificateHash (_cert);
_serialized = serialized;
_storeName = storeName;
_name = name;
}
pkcs11KeyStoreEntryContext (
const KeyBundle &key,
const QString &storeId,
const QString &serialized,
const QString &storeName,
const QString &name,
Provider *p
) : KeyStoreEntryContext(p) {
_item_type = KeyStoreEntry::TypeKeyBundle;
_key = key;
_storeId = storeId,
_id = certificateHash (key.certificateChain ().primary ());
_serialized = serialized;
_storeName = storeName;
_name = name;
}
pkcs11KeyStoreEntryContext (
const pkcs11KeyStoreEntryContext &from
) : KeyStoreEntryContext(from) {
_item_type = from._item_type;
_key = from._key;
_storeId = from._storeId;
_id = from._id;
_serialized = from._serialized;
_storeName = from._storeName;
_name = from._name;
}
virtual
Provider::Context *
clone () const {
return new pkcs11KeyStoreEntryContext (*this);
}
public:
virtual
KeyStoreEntry::Type
type () const {
return _item_type;
}
virtual
QString
name () const {
return _name;
}
virtual
QString
id () const {
return _id;
}
virtual
KeyBundle
keyBundle () const {
return _key;
}
virtual
Certificate
certificate () const {
return _cert;
}
virtual
QString
storeId () const {
return _storeId;
}
virtual
QString
storeName () const {
return _storeName;
}
virtual
bool
ensureAccess () {
return static_cast<pkcs11RSAContext *>(static_cast<PKeyContext *>(_key.privateKey ().context ())->key ())->_ensureTokenAccess ();
}
virtual
QString
serialize () const {
return _serialized;
}
};
//----------------------------------------------------------------------------
// pkcs11QCACrypto
//----------------------------------------------------------------------------
class pkcs11QCACrypto {
private:
static
int
_pkcs11h_crypto_qca_initialize (
void * const global_data
) {
Q_UNUSED(global_data);
return TRUE; //krazy:exclude=captruefalse
}
static
int
_pkcs11h_crypto_qca_uninitialize (
void * const global_data
) {
Q_UNUSED(global_data);
return TRUE; //krazy:exclude=captruefalse
}
static
int
_pkcs11h_crypto_qca_certificate_get_expiration (
void * const global_data,
const unsigned char * const blob,
const size_t blob_size,
time_t * const expiration
) {
Q_UNUSED(global_data);
Certificate cert = Certificate::fromDER (
QByteArray (
(char *)blob,
blob_size
)
);
*expiration = cert.notValidAfter ().toTime_t ();
return TRUE; //krazy:exclude=captruefalse
}
static
int
_pkcs11h_crypto_qca_certificate_get_dn (
void * const global_data,
const unsigned char * const blob,
const size_t blob_size,
char * const dn,
const size_t dn_max
) {
Q_UNUSED(global_data);
Certificate cert = Certificate::fromDER (
QByteArray (
(char *)blob,
blob_size
)
);
QString qdn = cert.subjectInfoOrdered ().toString ();
if ((size_t)qdn.length () > dn_max-1) {
return FALSE; //krazy:exclude=captruefalse
}
else {
strcpy (dn, myPrintable (qdn));
return TRUE; //krazy:exclude=captruefalse
}
}
static
int
_pkcs11h_crypto_qca_certificate_is_issuer (
void * const global_data,
const unsigned char * const signer_blob,
const size_t signer_blob_size,
const unsigned char * const cert_blob,
const size_t cert_blob_size
) {
Q_UNUSED(global_data);
Certificate signer = Certificate::fromDER (
QByteArray (
(char *)signer_blob,
signer_blob_size
)
);
Certificate cert = Certificate::fromDER (
QByteArray (
(char *)cert_blob,
cert_blob_size
)
);
return signer.isIssuerOf (cert);
}
public:
static pkcs11h_engine_crypto_t crypto;
};
pkcs11h_engine_crypto_t pkcs11QCACrypto::crypto = {
NULL,
_pkcs11h_crypto_qca_initialize,
_pkcs11h_crypto_qca_uninitialize,
_pkcs11h_crypto_qca_certificate_get_expiration,
_pkcs11h_crypto_qca_certificate_get_dn,
_pkcs11h_crypto_qca_certificate_is_issuer
};
//----------------------------------------------------------------------------
// pkcs11KeyStoreListContext
//----------------------------------------------------------------------------
pkcs11KeyStoreListContext::pkcs11KeyStoreListContext (Provider *p) : KeyStoreListContext(p) {
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::pkcs11KeyStoreListContext - entry Provider=%p",
(void *)p
),
Logger::Debug
);
_last_id = 0;
_initialized = false;
QCA_logTextMessage (
"pkcs11KeyStoreListContext::pkcs11KeyStoreListContext - return",
Logger::Debug
);
}
pkcs11KeyStoreListContext::~pkcs11KeyStoreListContext () {
QCA_logTextMessage (
"pkcs11KeyStoreListContext::~pkcs11KeyStoreListContext - entry",
Logger::Debug
);
s_keyStoreList = NULL;
_clearStores ();
QCA_logTextMessage (
"pkcs11KeyStoreListContext::~pkcs11KeyStoreListContext - return",
Logger::Debug
);
}
Provider::Context *
pkcs11KeyStoreListContext::clone () const {
QCA_logTextMessage (
"pkcs11KeyStoreListContext::clone - entry/return",
Logger::Debug
);
return NULL;
}
void
pkcs11KeyStoreListContext::start () {
QCA_logTextMessage (
"pkcs11KeyStoreListContext::start - entry",
Logger::Debug
);
QMetaObject::invokeMethod(this, "doReady", Qt::QueuedConnection);
QCA_logTextMessage (
"pkcs11KeyStoreListContext::start - return",
Logger::Debug
);
}
void
pkcs11KeyStoreListContext::setUpdatesEnabled (bool enabled) {
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::setUpdatesEnabled - entry enabled=%d",
enabled ? 1 : 0
),
Logger::Debug
);
try {
pkcs11Provider *p = static_cast<pkcs11Provider *>(provider ());
if (enabled) {
p->startSlotEvents ();
}
else {
p->stopSlotEvents ();
}
}
catch (const pkcs11Exception &e) {
s_keyStoreList->_emit_diagnosticText (
QString ().sprintf (
"PKCS#11: Start event failed %lu-'%s'.\n",
e.rv (),
myPrintable (e.message ())
)
);
}
QCA_logTextMessage (
"pkcs11KeyStoreListContext::setUpdatesEnabled - return",
Logger::Debug
);
}
KeyStoreEntryContext *
pkcs11KeyStoreListContext::entry (
int id,
const QString &entryId
) {
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::entry - entry/return id=%d entryId='%s'",
id,
myPrintable (entryId)
),
Logger::Debug
);
Q_UNUSED(id);
Q_UNUSED(entryId);
return NULL;
}
KeyStoreEntryContext *
pkcs11KeyStoreListContext::entryPassive (
const QString &serialized
) {
KeyStoreEntryContext *entry = NULL;
pkcs11h_certificate_id_t certificate_id = NULL;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::entryPassive - entry serialized='%s'",
myPrintable (serialized)
),
Logger::Debug
);
try {
if (serialized.startsWith ("qca-pkcs11/")) {
CertificateChain chain;
bool has_private;
_deserializeCertificate (serialized, &certificate_id, &has_private, chain);
pkcs11KeyStoreItem *sentry = _registerTokenId (certificate_id->token_id);
sentry->registerCertificates (chain);
QMap<QString, QString> friendlyNames = sentry->friendlyNames ();
entry = _keyStoreEntryByCertificateId (
certificate_id,
has_private,
chain,
friendlyNames[certificateHash (chain.primary ())]
);
}
}
catch (const pkcs11Exception &e) {
s_keyStoreList->_emit_diagnosticText (
QString ().sprintf (
"PKCS#11: Add key store entry %lu-'%s'.\n",
e.rv (),
myPrintable (e.message ())
)
);
}
if (certificate_id != NULL) {
pkcs11h_certificate_freeCertificateId (certificate_id);
certificate_id = NULL;
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::entryPassive - return entry=%p",
(void *)entry
),
Logger::Debug
);
return entry;
}
KeyStore::Type
pkcs11KeyStoreListContext::type (int id) const {
Q_UNUSED(id);
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::type - entry/return id=%d",
id
),
Logger::Debug
);
return KeyStore::SmartCard;
}
QString
pkcs11KeyStoreListContext::storeId (int id) const {
QString ret;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::storeId - entry id=%d",
id
),
Logger::Debug
);
if (_storesById.contains (id)) {
ret = _tokenId2storeId (_storesById[id]->tokenId ());
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::storeId - return ret=%s",
myPrintable (ret)
),
Logger::Debug
);
return ret;
}
QString
pkcs11KeyStoreListContext::name (int id) const {
QString ret;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::name - entry id=%d",
id
),
Logger::Debug
);
if (_storesById.contains (id)) {
ret = _storesById[id]->tokenId ()->label;
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::name - return ret=%s",
myPrintable (ret)
),
Logger::Debug
);
return ret;
}
QList<KeyStoreEntry::Type>
pkcs11KeyStoreListContext::entryTypes (int id) const {
Q_UNUSED(id);
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::entryTypes - entry/return id=%d",
id
),
Logger::Debug
);
QList<KeyStoreEntry::Type> list;
list += KeyStoreEntry::TypeKeyBundle;
list += KeyStoreEntry::TypeCertificate;
return list;
}
QList<int>
pkcs11KeyStoreListContext::keyStores () {
pkcs11h_token_id_list_t tokens = NULL;
QList<int> out;
QCA_logTextMessage (
"pkcs11KeyStoreListContext::keyStores - entry",
Logger::Debug
);
try {
CK_RV rv;
/*
* Get available tokens
*/
if (
(rv = pkcs11h_token_enumTokenIds (
PKCS11H_ENUM_METHOD_CACHE,
&tokens
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Enumerating tokens");
}
/*
* Register all tokens, unmark
* them from remove list
*/
QList<int> to_remove = _storesById.keys ();
for (
pkcs11h_token_id_list_t entry = tokens;
entry != NULL;
entry = entry->next
) {
pkcs11KeyStoreItem *item = _registerTokenId (entry->token_id);
out += item->id ();
to_remove.removeAll (item->id ());
}
/*
* Remove all items
* that were not discovered
*/
{
QMutexLocker l(&_mutexStores);
foreach (int i, to_remove) {
pkcs11KeyStoreItem *item = _storesById[i];
_storesById.remove (item->id ());
_stores.removeAll (item);
delete item;
item = NULL;
}
}
}
catch (const pkcs11Exception &e) {
s_keyStoreList->_emit_diagnosticText (
QString ().sprintf (
"PKCS#11: Cannot get key stores: %lu-'%s'.\n",
e.rv (),
myPrintable (e.message ())
)
);
}
if (tokens != NULL) {
pkcs11h_token_freeTokenIdList (tokens);
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::keyStores - return out.size()=%d",
out.size ()
),
Logger::Debug
);
return out;
}
QList<KeyStoreEntryContext*>
pkcs11KeyStoreListContext::entryList (int id) {
pkcs11h_certificate_id_list_t certs = NULL;
QList<KeyStoreEntryContext*> out;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::entryList - entry id=%d",
id
),
Logger::Debug
);
try {
CK_RV rv;
if (_storesById.contains (id)) {
pkcs11KeyStoreItem *entry = _storesById[id];
pkcs11h_certificate_id_list_t issuers = NULL;
pkcs11h_certificate_id_list_t current = NULL;
QList<Certificate> listCerts;
QList<Certificate> listIssuers;
QList<pkcs11h_certificate_id_list_t> listIds;
int i = 0;
if (
(rv = pkcs11h_certificate_enumTokenCertificateIds (
entry->tokenId (),
PKCS11H_ENUM_METHOD_CACHE,
NULL,
PKCS11H_PROMPT_MASK_ALLOW_ALL,
&issuers,
&certs
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Enumerate certificates");
}
for (
current=certs;
current!=NULL;
current=current->next
) {
if (current->certificate_id->certificate_blob_size > 0) {
listCerts += Certificate::fromDER (
QByteArray (
(char *)current->certificate_id->certificate_blob,
current->certificate_id->certificate_blob_size
)
);
}
}
for (
current=issuers;
current!=NULL;
current=current->next
) {
if (current->certificate_id->certificate_blob_size > 0) {
listIssuers += Certificate::fromDER (
QByteArray (
(char *)current->certificate_id->certificate_blob,
current->certificate_id->certificate_blob_size
)
);
}
}
entry->registerCertificates (listIssuers + listCerts);
QMap<QString, QString> friendlyNames = entry->friendlyNames ();
QList<Certificate> listIssuersForComplete;
if (dynamic_cast<pkcs11Provider *> (provider ())->_allowLoadRootCA) {
listIssuersForComplete = listIssuers;
}
else {
foreach (Certificate c, listIssuers) {
if (!c.isSelfSigned ()) {
listIssuersForComplete += c;
}
}
}
for (
i=0, current=issuers;
current!=NULL;
i++, current=current->next
) {
try {
if (listIssuers[i].isNull ()) {
throw pkcs11Exception (CKR_ARGUMENTS_BAD, "Invalid certificate");
}
if (
listIssuers[i].isSelfSigned () &&
dynamic_cast<pkcs11Provider *> (provider ())->_allowLoadRootCA
) {
CertificateChain chain = CertificateChain (listIssuers[i]).complete (listIssuersForComplete);
out += _keyStoreEntryByCertificateId (
current->certificate_id,
false,
chain,
friendlyNames[certificateHash (chain.primary ())]
);
}
}
catch (const pkcs11Exception &e) {
s_keyStoreList->_emit_diagnosticText (
QString ().sprintf (
"PKCS#11: Add key store entry %lu-'%s'.\n",
e.rv (),
myPrintable (e.message ())
)
);
}
}
for (
i=0, current=certs;
current!=NULL;
i++, current=current->next
) {
try {
if (listCerts[i].isNull ()) {
throw pkcs11Exception (CKR_ARGUMENTS_BAD, "Invalid certificate");
}
CertificateChain chain = CertificateChain (listCerts[i]).complete (listIssuersForComplete);
out += _keyStoreEntryByCertificateId (
current->certificate_id,
true,
chain,
friendlyNames[certificateHash (chain.primary ())]
);
}
catch (const pkcs11Exception &e) {
s_keyStoreList->_emit_diagnosticText (
QString ().sprintf (
"PKCS#11: Add key store entry %lu-'%s'.\n",
e.rv (),
myPrintable (e.message ())
)
);
}
}
}
}
catch (const pkcs11Exception &e) {
s_keyStoreList->_emit_diagnosticText (
QString ().sprintf (
"PKCS#11: Enumerating store failed %lu-'%s'.\n",
e.rv (),
myPrintable (e.message ())
)
);
}
if (certs != NULL) {
pkcs11h_certificate_freeCertificateIdList (certs);
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::entryList - return out.size()=%d",
out.size ()
),
Logger::Debug
);
return out;
}
bool
pkcs11KeyStoreListContext::_tokenPrompt (
void * const user_data,
const pkcs11h_token_id_t token_id
) {
KeyStoreEntry entry;
KeyStoreEntryContext *context = NULL;
QString storeId, storeName;
bool ret = false;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_tokenPrompt - entry user_data=%p, token_id=%p",
user_data,
(void *)token_id
),
Logger::Debug
);
if (user_data != NULL) {
QString *serialized = (QString *)user_data;
context = entryPassive (*serialized);
storeId = context->storeId ();
storeName = context->storeName ();
entry.change (context);
}
else {
_registerTokenId (token_id);
storeId = _tokenId2storeId (token_id);
storeName = token_id->label;
}
TokenAsker asker;
asker.ask (
KeyStoreInfo (KeyStore::SmartCard, storeId, storeName),
entry,
context
);
asker.waitForResponse ();
if (asker.accepted ()) {
ret = true;
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_tokenPrompt - return ret=%d",
ret ? 1 : 0
),
Logger::Debug
);
return ret;
}
bool
pkcs11KeyStoreListContext::_pinPrompt (
void * const user_data,
const pkcs11h_token_id_t token_id,
SecureArray &pin
) {
KeyStoreEntry entry;
KeyStoreEntryContext *context = NULL;
QString storeId, storeName;
bool ret = false;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_pinPrompt - entry user_data=%p, token_id=%p",
user_data,
(void *)token_id
),
Logger::Debug
);
pin = SecureArray();
if (user_data != NULL) {
QString *serialized = (QString *)user_data;
context = entryPassive (*serialized);
storeId = context->storeId ();
storeName = context->storeName ();
entry.change (context);
}
else {
_registerTokenId (token_id);
storeId = _tokenId2storeId (token_id);
storeName = token_id->label;
}
PasswordAsker asker;
asker.ask (
Event::StylePIN,
KeyStoreInfo (KeyStore::SmartCard, storeId, storeName),
entry,
context
);
asker.waitForResponse ();
if (asker.accepted ()) {
ret = true;
pin = asker.password ();
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_pinPrompt - return ret=%d",
ret ? 1 : 0
),
Logger::Debug
);
return ret;
}
void
pkcs11KeyStoreListContext::_emit_diagnosticText (
const QString &t
) {
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_emit_diagnosticText - entry t='%s'",
myPrintable (t)
),
Logger::Debug
);
QCA_logTextMessage (t, Logger::Warning);
emit diagnosticText (t);
QCA_logTextMessage (
"pkcs11KeyStoreListContext::_emit_diagnosticText - return",
Logger::Debug
);
}
void
pkcs11KeyStoreListContext::doReady () {
QCA_logTextMessage (
"pkcs11KeyStoreListContext::doReady - entry",
Logger::Debug
);
emit busyEnd ();
QCA_logTextMessage (
"pkcs11KeyStoreListContext::doReady - return",
Logger::Debug
);
}
void
pkcs11KeyStoreListContext::doUpdated () {
QCA_logTextMessage (
"pkcs11KeyStoreListContext::doUpdated - entry",
Logger::Debug
);
emit updated ();
QCA_logTextMessage (
"pkcs11KeyStoreListContext::doUpdated - return",
Logger::Debug
);
}
pkcs11KeyStoreListContext::pkcs11KeyStoreItem *
pkcs11KeyStoreListContext::_registerTokenId (
const pkcs11h_token_id_t token_id
) {
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_registerTokenId - entry token_id=%p",
(void *)token_id
),
Logger::Debug
);
QMutexLocker l(&_mutexStores);
_stores_t::iterator i=_stores.begin ();
while (
i != _stores.end () &&
!pkcs11h_token_sameTokenId (
token_id,
(*i)->tokenId ()
)
) {
i++;
}
pkcs11KeyStoreItem *entry = NULL;
if (i == _stores.end ()) {
/*
* Deal with last_id overlap
*/
while (_storesById.find (++_last_id) != _storesById.end ());
entry = new pkcs11KeyStoreItem (_last_id, token_id);
_stores += entry;
_storesById.insert (entry->id (), entry);
}
else {
entry = (*i);
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_registerTokenId - return entry=%p",
(void *)token_id
),
Logger::Debug
);
return entry;
}
void
pkcs11KeyStoreListContext::_clearStores () {
QCA_logTextMessage (
"pkcs11KeyStoreListContext::_clearStores - entry",
Logger::Debug
);
QMutexLocker l(&_mutexStores);
_storesById.clear ();
foreach (pkcs11KeyStoreItem *i, _stores) {
delete i;
}
_stores.clear ();
QCA_logTextMessage (
"pkcs11KeyStoreListContext::_clearStores - return",
Logger::Debug
);
}
pkcs11KeyStoreEntryContext *
pkcs11KeyStoreListContext::_keyStoreEntryByCertificateId (
const pkcs11h_certificate_id_t certificate_id,
const bool has_private,
const CertificateChain &chain,
const QString &_description
) const {
pkcs11KeyStoreEntryContext *entry = NULL;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_keyStoreEntryByCertificateId - entry certificate_id=%p, has_private=%d, chain.size()=%d",
(void *)certificate_id,
has_private ? 1 : 0,
chain.size ()
),
Logger::Debug
);
if (certificate_id == NULL) {
throw pkcs11Exception (CKR_ARGUMENTS_BAD, "Missing certificate object");
}
QString serialized = _serializeCertificate (
certificate_id,
chain,
has_private
);
QString description = _description;
Certificate cert = chain.primary ();
if (description.isEmpty ()) {
description = cert.subjectInfoOrdered ().toString () + " by " + cert.issuerInfo ().value (CommonName, "Unknown");
}
if (has_private) {
pkcs11RSAContext *rsakey = new pkcs11RSAContext (
provider(),
certificate_id,
serialized,
cert.subjectPublicKey ().toRSA ()
);
pkcs11PKeyContext *pkc = new pkcs11PKeyContext (provider ());
pkc->setKey (rsakey);
PrivateKey privkey;
privkey.change (pkc);
KeyBundle key;
key.setCertificateChainAndKey (
chain,
privkey
);
entry = new pkcs11KeyStoreEntryContext (
key,
_tokenId2storeId (certificate_id->token_id),
serialized,
certificate_id->token_id->label,
description,
provider ()
);
}
else {
entry = new pkcs11KeyStoreEntryContext (
cert,
_tokenId2storeId (certificate_id->token_id),
serialized,
certificate_id->token_id->label,
description,
provider()
);
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_keyStoreEntryByCertificateId - return entry=%p",
(void *)entry
),
Logger::Debug
);
return entry;
}
QString
pkcs11KeyStoreListContext::_tokenId2storeId (
const pkcs11h_token_id_t token_id
) const {
QString storeId;
size_t len;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_tokenId2storeId - entry token_id=%p",
(void *)token_id
),
Logger::Debug
);
if (
pkcs11h_token_serializeTokenId (
NULL,
&len,
token_id
) != CKR_OK
) {
throw pkcs11Exception (CKR_FUNCTION_FAILED, "Cannot serialize token id");
}
QByteArray buf;
buf.resize ((int)len);
if (
pkcs11h_token_serializeTokenId (
buf.data (),
&len,
token_id
) != CKR_OK
) {
throw pkcs11Exception (CKR_FUNCTION_FAILED, "Cannot serialize token id");
}
buf.resize ((int)len);
storeId = "qca-pkcs11/" + _escapeString (QString::fromUtf8 (buf));
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_tokenId2storeId - return storeId='%s'",
myPrintable (storeId)
),
Logger::Debug
);
return storeId;
}
QString
pkcs11KeyStoreListContext::_serializeCertificate (
const pkcs11h_certificate_id_t certificate_id,
const CertificateChain &chain,
const bool has_private
) const {
QString serialized;
size_t len;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_serializeCertificate - entry certificate_id=%p, xx, has_private=%d",
(void *)certificate_id,
has_private ? 1 : 0
),
Logger::Debug
);
if (
pkcs11h_certificate_serializeCertificateId (
NULL,
&len,
certificate_id
) != CKR_OK
) {
throw pkcs11Exception (CKR_FUNCTION_FAILED, "Cannot serialize certificate id");
}
QByteArray buf;
buf.resize ((int)len);
if (
pkcs11h_certificate_serializeCertificateId (
buf.data (),
&len,
certificate_id
) != CKR_OK
) {
throw pkcs11Exception (CKR_FUNCTION_FAILED, "Cannot serialize certificate id");
}
buf.resize ((int)len);
serialized = QString ().sprintf (
"qca-pkcs11/0/%s/%d/",
myPrintable(_escapeString (QString::fromUtf8 (buf))),
has_private ? 1 : 0
);
QStringList list;
foreach (Certificate i, chain) {
list += _escapeString (Base64 ().arrayToString (i.toDER ()));
}
serialized.append (list.join ("/"));
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_serializeCertificate - return serialized='%s'",
myPrintable (serialized)
),
Logger::Debug
);
return serialized;
}
void
pkcs11KeyStoreListContext::_deserializeCertificate (
const QString &from,
pkcs11h_certificate_id_t * const p_certificate_id,
bool * const p_has_private,
CertificateChain &chain
) const {
pkcs11h_certificate_id_t certificate_id = NULL;
chain.clear ();
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_deserializeCertificate - entry from='%s', p_certificate_id=%p, p_has_private=%p",
myPrintable (from),
(void *)p_certificate_id,
(void *)p_has_private
),
Logger::Debug
);
try {
int n = 0;
CK_RV rv;
*p_certificate_id = NULL;
*p_has_private = false;
QStringList list = from.split ("/");
if (list.size () < 5) {
throw pkcs11Exception (CKR_FUNCTION_FAILED, "Invalid serialization");
}
if (list[n++] != "qca-pkcs11") {
throw pkcs11Exception (CKR_FUNCTION_FAILED, "Invalid serialization");
}
if (list[n++].toInt () != 0) {
throw pkcs11Exception (CKR_FUNCTION_FAILED, "Invalid serialization version");
}
if (
(rv = pkcs11h_certificate_deserializeCertificateId (
&certificate_id,
myPrintable (_unescapeString (list[n++]))
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Invalid serialization");
}
*p_has_private = list[n++].toInt () != 0;
SecureArray endCertificateBytes = Base64 ().stringToArray (_unescapeString (list[n++]));
Certificate endCertificate = Certificate::fromDER (endCertificateBytes);
if (endCertificate.isNull ()) {
throw pkcs11Exception (rv, "Invalid certificate");
}
if (
(rv = pkcs11h_certificate_setCertificateIdCertificateBlob (
certificate_id,
(unsigned char *)endCertificateBytes.data (),
(size_t)endCertificateBytes.size ()
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Invalid serialization");
}
chain = endCertificate;
while (n < list.size ()) {
Certificate cert = Certificate::fromDER (
Base64 ().stringToArray (_unescapeString (list[n++]))
);
if (cert.isNull ()) {
throw pkcs11Exception (rv, "Invalid certificate");
}
chain += cert;
}
*p_certificate_id = certificate_id;
certificate_id = NULL;
}
catch (...) {
if (certificate_id != NULL) {
pkcs11h_certificate_freeCertificateId (certificate_id);
certificate_id = NULL;
}
throw;
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11KeyStoreListContext::_deserializeCertificate - return *p_certificate_id=%p, chain.size()=%d",
(void *)*p_certificate_id,
chain.size ()
),
Logger::Debug
);
}
QString
pkcs11KeyStoreListContext::_escapeString (
const QString &from
) const {
QString to;
foreach (QChar c, from) {
if (c == '/' || c == '\\') {
to += QString ().sprintf ("\\x%04x", c.unicode ());
}
else {
to += c;
}
}
return to;
}
QString
pkcs11KeyStoreListContext::_unescapeString (
const QString &from
) const {
QString to;
for (int i=0;i<from.size ();i++) {
QChar c = from[i];
if (c == '\\') {
to += QChar ((ushort)from.mid (i+2, 4).toInt (0, 16));
i+=5;
}
else {
to += c;
}
}
return to;
}
}
using namespace pkcs11QCAPlugin;
const int pkcs11Provider::_CONFIG_MAX_PROVIDERS = 10;
//----------------------------------------------------------------------------
// pkcs11Provider
//----------------------------------------------------------------------------
pkcs11Provider::pkcs11Provider () {
QCA_logTextMessage (
"pkcs11Provider::pkcs11Provider - entry",
Logger::Debug
);
_lowLevelInitialized = false;
_slotEventsActive = false;
_slotEventsLowLevelActive = false;
_allowLoadRootCA = false;
QCA_logTextMessage (
"pkcs11Provider::pkcs11Provider - return",
Logger::Debug
);
}
pkcs11Provider::~pkcs11Provider () {
QCA_logTextMessage (
"pkcs11Provider::~pkcs11Provider - entry",
Logger::Debug
);
delete s_keyStoreList;
s_keyStoreList = NULL;
pkcs11h_terminate ();
QCA_logTextMessage (
"pkcs11Provider::~pkcs11Provider - return",
Logger::Debug
);
}
int pkcs11Provider::version() const
{
QCA_logTextMessage (
"pkcs11Provider::version - entry/return",
Logger::Debug
);
return QCA_VERSION;
}
void pkcs11Provider::init () {
QCA_logTextMessage (
"pkcs11Provider::init - entry",
Logger::Debug
);
try {
CK_RV rv;
if ((rv = pkcs11h_engine_setCrypto (&pkcs11QCACrypto::crypto)) != CKR_OK) {
throw pkcs11Exception (rv, "Cannot set crypto");
}
if ((rv = pkcs11h_initialize ()) != CKR_OK) {
throw pkcs11Exception (rv, "Cannot initialize");
}
if (
(rv = pkcs11h_setLogHook (
__logHook,
this
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Cannot set hook");
}
pkcs11h_setLogLevel (0);
if (
(rv = pkcs11h_setTokenPromptHook (
__tokenPromptHook,
this
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Cannot set hook");
}
if (
(rv = pkcs11h_setPINPromptHook (
__pinPromptHook,
this
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Cannot set hook");
}
_lowLevelInitialized = true;
}
catch (const pkcs11Exception &e) {
QCA_logTextMessage (e.message (), Logger::Error);
}
catch (...) {
QCA_logTextMessage ("PKCS#11: Unknown error during provider initialization", Logger::Error);
}
QCA_logTextMessage (
"pkcs11Provider::init - return",
Logger::Debug
);
}
QString
pkcs11Provider::name () const {
QCA_logTextMessage (
"pkcs11Provider::name - entry/return",
Logger::Debug
);
return "qca-pkcs11";
}
QStringList
pkcs11Provider::features() const {
QCA_logTextMessage (
"pkcs11Provider::features - entry/return",
Logger::Debug
);
QStringList list;
list += "smartcard"; // indicator, not algorithm
list += "pkey";
list += "keystorelist";
return list;
}
Provider::Context *
pkcs11Provider::createContext (const QString &type) {
Provider::Context *context = NULL;
QCA_logTextMessage (
QString ().sprintf (
"pkcs11Provider::createContext - entry type='%s'",
myPrintable (type)
),
Logger::Debug
);
if (_lowLevelInitialized) {
if (type == "keystorelist") {
if (s_keyStoreList == NULL) {
s_keyStoreList = new pkcs11KeyStoreListContext (this);
}
context = s_keyStoreList;
}
}
QCA_logTextMessage (
QString ().sprintf (
"pkcs11Provider::createContext - return context=%p",
(void *)context
),
Logger::Debug
);
return context;
}
void
pkcs11Provider::startSlotEvents () {
CK_RV rv;
QCA_logTextMessage (
"pkcs11Provider::startSlotEvents - entry",
Logger::Debug
);
if (_lowLevelInitialized) {
if (!_slotEventsLowLevelActive) {
if (
(rv = pkcs11h_setSlotEventHook (
__slotEventHook,
this
)) != CKR_OK
) {
throw pkcs11Exception (rv, "Cannot start slot events");
}
_slotEventsLowLevelActive = true;
}
_slotEventsActive = true;
}
QCA_logTextMessage (
"pkcs11Provider::startSlotEvents - return",
Logger::Debug
);
}
void
pkcs11Provider::stopSlotEvents () {
QCA_logTextMessage (
"pkcs11Provider::stopSlotEvents - entry/return",
Logger::Debug
);
_slotEventsActive = false;
}
QVariantMap
pkcs11Provider::defaultConfig () const {
QVariantMap mytemplate;
QCA_logTextMessage (
"pkcs11Provider::defaultConfig - entry/return",
Logger::Debug
);
mytemplate["formtype"] = "http://affinix.com/qca/forms/qca-pkcs11#1.0";
mytemplate["allow_load_rootca"] = false;
mytemplate["allow_protected_authentication"] = true;
mytemplate["pin_cache"] = PKCS11H_PIN_CACHE_INFINITE;
mytemplate["log_level"] = 0;
for (int i=0;i<_CONFIG_MAX_PROVIDERS;i++) {
mytemplate[QString ().sprintf ("provider_%02d_enabled", i)] = false;
mytemplate[QString ().sprintf ("provider_%02d_name", i)] = "";
mytemplate[QString ().sprintf ("provider_%02d_library", i)] = "";
mytemplate[QString ().sprintf ("provider_%02d_allow_protected_authentication", i)] = true;
mytemplate[QString ().sprintf ("provider_%02d_cert_private", i)] = false;
mytemplate[QString ().sprintf ("provider_%02d_private_mask", i)] = PKCS11H_PRIVATEMODE_MASK_AUTO;
mytemplate[QString ().sprintf ("provider_%02d_slotevent_method", i)] = "auto";
mytemplate[QString ().sprintf ("provider_%02d_slotevent_timeout", i)] = 0;
}
return mytemplate;
}
void
pkcs11Provider::configChanged (const QVariantMap &config) {
CK_RV rv = CKR_OK;
QCA_logTextMessage (
"pkcs11Provider::configChanged - entry",
Logger::Debug
);
if (!_lowLevelInitialized) {
QCA_logTextMessage ("PKCS#11: Not initialized", Logger::Error);
return;
}
_allowLoadRootCA = config["allow_load_rootca"].toBool ();
pkcs11h_setLogLevel (config["log_level"].toInt ());
pkcs11h_setProtectedAuthentication (
config["allow_protected_authentication"].toBool () != false ? TRUE : FALSE //krazy:exclude=captruefalse
);
pkcs11h_setPINCachePeriod (config["pin_cache"].toInt ());
/*
* Remove current providers
*/
foreach (QString i, _providers) {
pkcs11h_removeProvider (myPrintable (i));
}
_providers.clear ();
/*
* Add new providers
*/
for (int i=0;i<_CONFIG_MAX_PROVIDERS;i++) {
bool enabled = config[QString ().sprintf ("provider_%02d_enabled", i)].toBool ();
QString provider = config[QString ().sprintf ("provider_%02d_library", i)].toString ();
QString name = config[QString ().sprintf ("provider_%02d_name", i)].toString ();
QString qslotevent = config[QString ().sprintf ("provider_%02d_slotevent_method", i)].toString ();
unsigned slotevent = PKCS11H_SLOTEVENT_METHOD_AUTO;
if (qslotevent == "trigger") {
slotevent = PKCS11H_SLOTEVENT_METHOD_TRIGGER;
}
else if (qslotevent == "poll") {
slotevent = PKCS11H_SLOTEVENT_METHOD_POLL;
}
if (name.isEmpty ()) {
name = provider;
}
if (enabled && !provider.isEmpty()) {
QCA_logTextMessage (
QString ().sprintf (
"Loading PKCS#11 provider '%s' (%s)",
myPrintable (name),
myPrintable (provider)
),
Logger::Information
);
if (
(rv = pkcs11h_addProvider (
myPrintable (name),
myPrintable (provider),
config[
QString ().sprintf ("provider_%02d_allow_protected_authentication", i)
].toBool () != false ? TRUE : FALSE, //krazy:exclude=captruefalse
(unsigned)config[
QString ().sprintf ("provider_%02d_private_mask", i)
].toInt (),
slotevent,
(unsigned)config[
QString ().sprintf ("provider_%02d_slotevent_timeout", i)
].toInt (),
config[
QString ().sprintf ("provider_%02d_cert_private", i)
].toBool () != false ? TRUE : FALSE //krazy:exclude=captruefalse
)) != CKR_OK
) {
QCA_logTextMessage (
QString ().sprintf (
"PKCS#11: Cannot log provider '%s'-'%s' %lu-'%s'.\n",
myPrintable (name),
myPrintable (provider),
rv,
pkcs11h_getMessage (rv)
),
Logger::Error
);
}
else {
_providers += provider;
}
}
}
QCA_logTextMessage (
"pkcs11Provider::configChanged - return",
Logger::Debug
);
}
void
pkcs11Provider::__logHook (
void * const global_data,
const unsigned flags,
const char * const format,
va_list args
) {
pkcs11Provider *me = (pkcs11Provider *)global_data;
me->_logHook (flags, format, args);
}
void
pkcs11Provider::__slotEventHook (
void * const global_data
) {
pkcs11Provider *me = (pkcs11Provider *)global_data;
me->_slotEventHook ();
}
PKCS11H_BOOL
pkcs11Provider::__tokenPromptHook (
void * const global_data,
void * const user_data,
const pkcs11h_token_id_t token,
const unsigned retry
) {
Q_UNUSED(retry);
pkcs11Provider *me = (pkcs11Provider *)global_data;
return me->_tokenPromptHook (user_data, token);
}
PKCS11H_BOOL
pkcs11Provider::__pinPromptHook (
void * const global_data,
void * const user_data,
const pkcs11h_token_id_t token,
const unsigned retry,
char * const pin,
const size_t pin_max
) {
Q_UNUSED(retry);
pkcs11Provider *me = (pkcs11Provider *)global_data;
return me->_pinPromptHook (user_data, token, pin, pin_max);
}
void
pkcs11Provider::_logHook (
const unsigned flags,
const char * const format,
va_list args
) {
Logger::Severity severity;
switch (flags) {
case PKCS11H_LOG_DEBUG2:
case PKCS11H_LOG_DEBUG1:
severity = Logger::Debug;
break;
case PKCS11H_LOG_INFO:
severity = Logger::Information;
break;
case PKCS11H_LOG_WARN:
severity = Logger::Warning;
break;
case PKCS11H_LOG_ERROR:
severity = Logger::Error;
break;
default:
severity = Logger::Debug;
break;
}
//@BEGIN-WORKAROUND
// Qt vsprintf cannot can NULL for %s as vsprintf does.
// QCA_logTextMessage (QString ().vsprintf (format, args), severity);
char buffer[2048];
QT_VSNPRINTF (buffer, sizeof (buffer)-1, format, args);
buffer[sizeof (buffer)-1] = '\x0';
QCA_logTextMessage (buffer, severity);
//@END-WORKAROUND
}
void
pkcs11Provider::_slotEventHook () {
/*
* This is called from a separate
* thread.
*/
if (s_keyStoreList != NULL && _slotEventsActive) {
QMetaObject::invokeMethod(s_keyStoreList, "doUpdated", Qt::QueuedConnection);
}
}
PKCS11H_BOOL
pkcs11Provider::_tokenPromptHook (
void * const user_data,
const pkcs11h_token_id_t token
) {
if (s_keyStoreList != NULL) {
return s_keyStoreList->_tokenPrompt (user_data, token) ? TRUE : FALSE; //krazy:exclude=captruefalse
}
return FALSE; //krazy:exclude=captruefalse
}
PKCS11H_BOOL
pkcs11Provider::_pinPromptHook (
void * const user_data,
const pkcs11h_token_id_t token,
char * const pin,
const size_t pin_max
) {
PKCS11H_BOOL ret = FALSE; //krazy:exclude=captruefalse
if (s_keyStoreList != NULL) {
SecureArray qpin;
if (s_keyStoreList->_pinPrompt (user_data, token, qpin)) {
if ((size_t)qpin.size () < pin_max-1) {
memmove (pin, qpin.constData (), qpin.size ());
pin[qpin.size ()] = '\0';
ret = TRUE; //krazy:exclude=captruefalse
}
}
}
return ret; //krazy:exclude=captruefalse
}
class pkcs11Plugin : public QObject, public QCAPlugin
{
Q_OBJECT
Q_INTERFACES(QCAPlugin)
public:
virtual Provider *createProvider() { return new pkcs11Provider; }
};
#include "qca-pkcs11.moc"
Q_EXPORT_PLUGIN2(qca_pkcs11, pkcs11Plugin)