mirror of
https://github.com/QuasarApp/qca.git
synced 2025-04-27 20:14:32 +00:00
1532 lines
28 KiB
C++
1532 lines
28 KiB
C++
/*
|
|
* Copyright (C) 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 <QtPlugin>
|
|
#include <QHash>
|
|
#include <QFile>
|
|
|
|
using namespace QCA;
|
|
|
|
// qPrintable is ASCII only!!!
|
|
#define myPrintable(s) (s).toUtf8 ().constData ()
|
|
|
|
namespace softstoreQCAPlugin {
|
|
|
|
class softstoreKeyStoreListContext;
|
|
static softstoreKeyStoreListContext *s_keyStoreList = NULL;
|
|
|
|
enum KeyType {
|
|
keyTypeInvalid,
|
|
keyTypePKCS12,
|
|
keyTypePKCS8Inline,
|
|
keyTypePKCS8FilePEM,
|
|
keyTypePKCS8FileDER
|
|
};
|
|
|
|
enum PublicType {
|
|
publicTypeInvalid,
|
|
publicTypeX509Chain
|
|
};
|
|
|
|
struct SoftStoreEntry {
|
|
QString name;
|
|
CertificateChain chain;
|
|
KeyType keyReferenceType;
|
|
QString keyReference;
|
|
bool noPassphrase;
|
|
int unlockTimeout;
|
|
};
|
|
|
|
class softstoreRSAContext : public RSAContext
|
|
{
|
|
Q_OBJECT
|
|
|
|
private:
|
|
bool _has_privateKeyRole;
|
|
SoftStoreEntry _entry;
|
|
QString _serialized;
|
|
RSAPrivateKey _privkey;
|
|
RSAPrivateKey _privkeySign;
|
|
RSAPublicKey _pubkey;
|
|
QDateTime dueTime;
|
|
|
|
public:
|
|
softstoreRSAContext (
|
|
const SoftStoreEntry &entry,
|
|
const QString &serialized,
|
|
Provider *p
|
|
) : RSAContext (p) {
|
|
QCA_logTextMessage (
|
|
"softstoreRSAContext::softstoreRSAContext1 - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
_has_privateKeyRole = true;
|
|
_entry = entry;
|
|
_serialized = serialized;
|
|
_pubkey = _entry.chain.primary ().subjectPublicKey ().toRSA ();
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreRSAContext::softstoreRSAContext1 - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
softstoreRSAContext (const softstoreRSAContext &from) : RSAContext (from.provider ()) {
|
|
QCA_logTextMessage (
|
|
"softstoreRSAContext::softstoreRSAContextC - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
_has_privateKeyRole = from._has_privateKeyRole;
|
|
_entry = from._entry;
|
|
_serialized = from._serialized;
|
|
_pubkey = from._pubkey;
|
|
_privkey = from._privkey;
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreRSAContext::softstoreRSAContextC - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
~softstoreRSAContext () {
|
|
QCA_logTextMessage (
|
|
"softstoreRSAContext::~softstoreRSAContext - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreRSAContext::~softstoreRSAContext - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
virtual
|
|
Provider::Context *
|
|
clone () const {
|
|
return new softstoreRSAContext (*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 (
|
|
"softstoreRSAContext::convertToPublic - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
if (_has_privateKeyRole) {
|
|
_has_privateKeyRole = false;
|
|
}
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreRSAContext::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
|
|
) {
|
|
if (_ensureAccess ()) {
|
|
return _privkey.decrypt (in, out, alg);
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
virtual
|
|
void
|
|
startSign (
|
|
SignatureAlgorithm alg,
|
|
SignatureFormat format
|
|
) {
|
|
if (_ensureAccess ()) {
|
|
/*
|
|
* We must use one object thought
|
|
* signing, so it won't expire by
|
|
* it-self or during passphrase.
|
|
*/
|
|
_privkeySign = _privkey;
|
|
_privkeySign.startSign (alg, format);
|
|
}
|
|
}
|
|
|
|
virtual
|
|
void
|
|
startVerify (
|
|
SignatureAlgorithm alg,
|
|
SignatureFormat sf
|
|
) {
|
|
_pubkey.startVerify (alg, sf);
|
|
}
|
|
|
|
virtual
|
|
void
|
|
update (
|
|
const SecureArray &in
|
|
) {
|
|
if (_has_privateKeyRole) {
|
|
_privkeySign.update (in);
|
|
}
|
|
else {
|
|
_pubkey.update (in);
|
|
}
|
|
}
|
|
|
|
virtual
|
|
SecureArray
|
|
endSign () {
|
|
SecureArray r = _privkeySign.signature ();
|
|
_privkeySign = RSAPrivateKey ();
|
|
return r;
|
|
}
|
|
|
|
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
|
|
_ensureAccess () {
|
|
bool ret = false;
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreRSAContext::_ensureAccess - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
if (_entry.unlockTimeout != -1) {
|
|
if (dueTime >= QDateTime::currentDateTime ()) {
|
|
QCA_logTextMessage (
|
|
"softstoreRSAContext::_ensureAccess - dueTime reached, clearing",
|
|
Logger::Debug
|
|
);
|
|
_privkey = RSAPrivateKey ();
|
|
}
|
|
}
|
|
|
|
if (!_privkey.isNull ()) {
|
|
ret = true;
|
|
}
|
|
else {
|
|
KeyStoreEntry entry;
|
|
KeyStoreEntryContext *context = NULL;
|
|
QString storeId, storeName;
|
|
ConvertResult cresult;
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreRSAContext::_ensureAccess - no current key, creating",
|
|
Logger::Debug
|
|
);
|
|
|
|
// too lazy to create scope
|
|
context = reinterpret_cast<KeyStoreListContext *> (s_keyStoreList)->entryPassive (_serialized);
|
|
if (context != NULL) {
|
|
storeId = context->storeId ();
|
|
storeName = context->storeName ();
|
|
entry.change (context);
|
|
}
|
|
|
|
while (!ret) {
|
|
|
|
SecureArray passphrase;
|
|
|
|
switch (_entry.keyReferenceType) {
|
|
case keyTypeInvalid:
|
|
case keyTypePKCS8Inline:
|
|
break;
|
|
case keyTypePKCS12:
|
|
case keyTypePKCS8FilePEM:
|
|
case keyTypePKCS8FileDER:
|
|
{
|
|
QFile file (_entry.keyReference);
|
|
while (!file.open (QIODevice::ReadOnly)) {
|
|
TokenAsker asker;
|
|
asker.ask (
|
|
KeyStoreInfo (KeyStore::SmartCard, storeId, storeName),
|
|
entry,
|
|
context
|
|
);
|
|
asker.waitForResponse ();
|
|
if (!asker.accepted ()) {
|
|
goto cleanup1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!_entry.noPassphrase) {
|
|
PasswordAsker asker;
|
|
asker.ask (
|
|
Event::StylePassphrase,
|
|
KeyStoreInfo (KeyStore::User, storeId, storeName),
|
|
entry,
|
|
context
|
|
);
|
|
asker.waitForResponse ();
|
|
passphrase = asker.password ();
|
|
if (!asker.accepted ()) {
|
|
goto cleanup1;
|
|
}
|
|
}
|
|
|
|
switch (_entry.keyReferenceType) {
|
|
case keyTypeInvalid:
|
|
break;
|
|
case keyTypePKCS12:
|
|
{
|
|
KeyBundle bundle = KeyBundle::fromFile (
|
|
_entry.keyReference,
|
|
passphrase,
|
|
&cresult
|
|
);
|
|
if (cresult == ConvertGood) {
|
|
_privkey = bundle.privateKey ().toRSA ();
|
|
ret = true;
|
|
}
|
|
}
|
|
break;
|
|
case keyTypePKCS8Inline:
|
|
{
|
|
PrivateKey k = PrivateKey::fromDER (
|
|
Base64 ().stringToArray (_entry.keyReference),
|
|
passphrase,
|
|
&cresult
|
|
);
|
|
if (cresult == ConvertGood) {
|
|
_privkey = k.toRSA ();
|
|
ret = true;
|
|
}
|
|
}
|
|
break;
|
|
case keyTypePKCS8FilePEM:
|
|
{
|
|
PrivateKey k = PrivateKey::fromPEMFile (
|
|
_entry.keyReference,
|
|
passphrase,
|
|
&cresult
|
|
);
|
|
if (cresult == ConvertGood) {
|
|
_privkey = k.toRSA ();
|
|
ret = true;
|
|
}
|
|
}
|
|
break;
|
|
case keyTypePKCS8FileDER:
|
|
{
|
|
QFile file (_entry.keyReference);
|
|
if (file.open (QIODevice::ReadOnly)) {
|
|
QByteArray contents = file.readAll ();
|
|
|
|
PrivateKey k = PrivateKey::fromDER (
|
|
contents,
|
|
passphrase,
|
|
&cresult
|
|
);
|
|
if (cresult == ConvertGood) {
|
|
_privkey = k.toRSA ();
|
|
ret = true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (_entry.unlockTimeout != -1) {
|
|
dueTime = QDateTime::currentDateTime ().addSecs (_entry.unlockTimeout);
|
|
}
|
|
|
|
cleanup1:
|
|
;
|
|
|
|
}
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreRSAContext::_ensureAccess - return ret=%d",
|
|
ret ? 1 : 0
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
class softstorePKeyContext : public PKeyContext
|
|
{
|
|
|
|
private:
|
|
PKeyBase *_k;
|
|
|
|
public:
|
|
softstorePKeyContext (Provider *p) : PKeyContext (p) {
|
|
_k = NULL;
|
|
}
|
|
|
|
~softstorePKeyContext () {
|
|
delete _k;
|
|
_k = NULL;
|
|
}
|
|
|
|
virtual
|
|
Provider::Context *
|
|
clone () const {
|
|
softstorePKeyContext *c = new softstorePKeyContext (*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<softstoreRSAContext *>(_k)->_publicKey ().toDER ();
|
|
}
|
|
|
|
virtual
|
|
QString
|
|
publicToPEM () const {
|
|
return static_cast<softstoreRSAContext *>(_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;
|
|
}
|
|
};
|
|
|
|
class softstoreKeyStoreEntryContext : public KeyStoreEntryContext
|
|
{
|
|
private:
|
|
KeyStoreEntry::Type _item_type;
|
|
KeyBundle _key;
|
|
SoftStoreEntry _entry;
|
|
QString _serialized;
|
|
|
|
public:
|
|
softstoreKeyStoreEntryContext (
|
|
const KeyBundle &key,
|
|
const SoftStoreEntry &entry,
|
|
const QString &serialized,
|
|
Provider *p
|
|
) : KeyStoreEntryContext(p) {
|
|
_item_type = KeyStoreEntry::TypeKeyBundle;
|
|
_key = key;
|
|
_entry = entry;
|
|
_serialized = serialized;
|
|
}
|
|
|
|
softstoreKeyStoreEntryContext (
|
|
const softstoreKeyStoreEntryContext &from
|
|
) : KeyStoreEntryContext(from) {
|
|
_item_type = from._item_type;
|
|
_key = from._key;
|
|
_entry = from._entry;
|
|
_serialized = from._serialized;
|
|
}
|
|
|
|
virtual
|
|
Provider::Context *
|
|
clone () const {
|
|
return new softstoreKeyStoreEntryContext (*this);
|
|
}
|
|
|
|
public:
|
|
virtual
|
|
KeyStoreEntry::Type
|
|
type () const {
|
|
return KeyStoreEntry::TypeKeyBundle;
|
|
}
|
|
|
|
virtual
|
|
QString
|
|
name () const {
|
|
return _entry.name;
|
|
}
|
|
|
|
virtual
|
|
QString
|
|
id () const {
|
|
return _entry.name;
|
|
}
|
|
|
|
virtual
|
|
KeyBundle
|
|
keyBundle () const {
|
|
return _key;
|
|
}
|
|
|
|
virtual
|
|
Certificate
|
|
certificate () const {
|
|
return _entry.chain.primary ();
|
|
}
|
|
|
|
virtual
|
|
QString
|
|
storeId () const {
|
|
return QString ().sprintf ("%s/%s", "qca-softstore", myPrintable (_entry.name));
|
|
}
|
|
|
|
virtual
|
|
QString
|
|
storeName () const {
|
|
return _entry.name;
|
|
}
|
|
|
|
virtual
|
|
bool
|
|
ensureAccess () {
|
|
return static_cast<softstoreRSAContext *>(static_cast<PKeyContext *>(_key.privateKey ().context ())->key ())->_ensureAccess ();
|
|
}
|
|
|
|
virtual
|
|
QString
|
|
serialize () const {
|
|
return _serialized;
|
|
}
|
|
};
|
|
|
|
class softstoreKeyStoreListContext : public KeyStoreListContext
|
|
{
|
|
Q_OBJECT
|
|
|
|
private:
|
|
int _last_id;
|
|
QList<SoftStoreEntry> _entries;
|
|
|
|
public:
|
|
softstoreKeyStoreListContext (Provider *p) : KeyStoreListContext (p) {
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::softstoreKeyStoreListContext - entry Provider=%p",
|
|
(void *)p
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
_last_id = 0;
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::softstoreKeyStoreListContext - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
~softstoreKeyStoreListContext () {
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::~softstoreKeyStoreListContext - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
s_keyStoreList = NULL;
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::~softstoreKeyStoreListContext - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
virtual
|
|
Provider::Context *
|
|
clone () const {
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::clone - entry/return",
|
|
Logger::Debug
|
|
);
|
|
return NULL;
|
|
}
|
|
|
|
public:
|
|
virtual
|
|
void
|
|
start () {
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::start - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
QMetaObject::invokeMethod(this, "doReady", Qt::QueuedConnection);
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::start - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
virtual
|
|
void
|
|
setUpdatesEnabled (bool enabled) {
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::setUpdatesEnabled - entry/return enabled=%d",
|
|
enabled ? 1 : 0
|
|
),
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
virtual
|
|
KeyStoreEntryContext *
|
|
entry (
|
|
int id,
|
|
const QString &entryId
|
|
) {
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::entry - entry/return id=%d entryId='%s'",
|
|
id,
|
|
myPrintable (entryId)
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
Q_UNUSED(id);
|
|
Q_UNUSED(entryId);
|
|
return NULL;
|
|
}
|
|
|
|
virtual
|
|
KeyStoreEntryContext *
|
|
entryPassive (
|
|
const QString &serialized
|
|
) {
|
|
KeyStoreEntryContext *entry = NULL;
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::entryPassive - entry serialized='%s'",
|
|
myPrintable (serialized)
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
if (serialized.startsWith ("qca-softstore/")) {
|
|
SoftStoreEntry sentry;
|
|
|
|
if (_deserializeSoftStoreEntry (serialized, sentry)) {
|
|
entry = _keyStoreEntryBySoftStoreEntry (sentry);
|
|
}
|
|
}
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::entryPassive - return entry=%p",
|
|
(void *)entry
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return entry;
|
|
}
|
|
|
|
virtual
|
|
KeyStore::Type
|
|
type (int id) const {
|
|
Q_UNUSED(id);
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::type - entry/return id=%d",
|
|
id
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return KeyStore::User;
|
|
}
|
|
|
|
virtual
|
|
QString
|
|
storeId (int id) const {
|
|
QString ret;
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::storeId - entry id=%d",
|
|
id
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
ret = "qca-softstore";
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::storeId - return ret=%s",
|
|
myPrintable (ret)
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return ret;
|
|
}
|
|
|
|
virtual
|
|
QString
|
|
name (int id) const {
|
|
QString ret;
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::name - entry id=%d",
|
|
id
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
ret = "User Software Store";
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::name - return ret=%s",
|
|
myPrintable (ret)
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return ret;
|
|
}
|
|
|
|
virtual
|
|
QList<KeyStoreEntry::Type>
|
|
entryTypes (int id) const {
|
|
Q_UNUSED(id);
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::entryTypes - entry/return id=%d",
|
|
id
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
QList<KeyStoreEntry::Type> list;
|
|
list += KeyStoreEntry::TypeKeyBundle;
|
|
list += KeyStoreEntry::TypeCertificate;
|
|
return list;
|
|
}
|
|
|
|
virtual
|
|
QList<int>
|
|
keyStores () {
|
|
QList<int> list;
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::keyStores - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
list += _last_id;
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::keyStores - return out.size()=%d",
|
|
list.size ()
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return list;
|
|
}
|
|
|
|
virtual
|
|
QList<KeyStoreEntryContext *>
|
|
entryList (int id) {
|
|
QList<KeyStoreEntryContext*> list;
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::entryList - entry id=%d",
|
|
id
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
foreach (SoftStoreEntry e, _entries) {
|
|
list += _keyStoreEntryBySoftStoreEntry (e);
|
|
}
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::entryList - return out.size()=%d",
|
|
list.size ()
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return list;
|
|
}
|
|
|
|
void
|
|
_emit_diagnosticText (
|
|
const QString &t
|
|
) {
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::_emit_diagnosticText - entry t='%s'",
|
|
myPrintable (t)
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
QCA_logTextMessage (t, Logger::Warning);
|
|
|
|
emit diagnosticText (t);
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::_emit_diagnosticText - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
private slots:
|
|
void
|
|
doReady () {
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::doReady - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
emit busyEnd ();
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::doReady - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
void
|
|
doUpdated () {
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::doUpdated - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
emit updated ();
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::doUpdated - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
public:
|
|
void
|
|
_updateConfig (const QVariantMap &config, const int maxEntries) {
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::_updateConfig - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
QMap<QString, KeyType> keyTypeMap;
|
|
keyTypeMap["pkcs12"] = keyTypePKCS12;
|
|
keyTypeMap["pkcs8"] = keyTypePKCS8Inline;
|
|
keyTypeMap["pkcs8-file-pem"] = keyTypePKCS8FilePEM;
|
|
keyTypeMap["pkcs8-file-der"] = keyTypePKCS8FileDER;
|
|
|
|
QMap<QString, PublicType> publicTypeMap;
|
|
publicTypeMap["x509chain"] = publicTypeX509Chain;
|
|
|
|
_last_id++;
|
|
_entries.clear ();
|
|
|
|
for (int i=0;i<maxEntries;i++) {
|
|
if (config[QString ().sprintf ("entry_%02d_enabled", i)].toBool ()) {
|
|
ConvertResult cresult;
|
|
SoftStoreEntry entry;
|
|
PublicType publicType = publicTypeInvalid;
|
|
|
|
entry.name = config[QString ().sprintf ("entry_%02d_name", i)].toString ();
|
|
QString stringReferenceType = config[QString ().sprintf ("entry_%02d_private_type", i)].toString ();
|
|
QString stringPublicType = config[QString ().sprintf ("entry_%02d_public_type", i)].toString ();
|
|
entry.noPassphrase = config[QString ().sprintf ("entry_%02d_no_passphrase", i)].toBool ();
|
|
entry.unlockTimeout = config[QString ().sprintf ("entry_%02d_unlock_timeout", i)].toInt ();
|
|
|
|
if (publicTypeMap.contains (stringPublicType)) {
|
|
publicType = publicTypeMap[stringPublicType];
|
|
}
|
|
else {
|
|
_emit_diagnosticText (
|
|
QString ().sprintf (
|
|
"Software Store: Bad public key type of '%s' entry.\n",
|
|
myPrintable (entry.name)
|
|
)
|
|
);
|
|
goto cleanup1;
|
|
}
|
|
|
|
if (keyTypeMap.contains (stringReferenceType)) {
|
|
entry.keyReferenceType = keyTypeMap[stringReferenceType];
|
|
}
|
|
else {
|
|
_emit_diagnosticText (
|
|
QString ().sprintf (
|
|
"Software Store: Bad private key type of '%s' entry.\n",
|
|
myPrintable (entry.name)
|
|
)
|
|
);
|
|
goto cleanup1;
|
|
}
|
|
|
|
entry.keyReference = config[QString ().sprintf ("entry_%02d_private", i)].toString ();
|
|
|
|
switch (publicType) {
|
|
case publicTypeInvalid:
|
|
goto cleanup1;
|
|
break;
|
|
case publicTypeX509Chain:
|
|
QStringList base64certs = config[QString ().sprintf ("entry_%02d_public", i)].toString ().split ("!");
|
|
|
|
foreach (QString s, base64certs) {
|
|
entry.chain += Certificate::fromDER (
|
|
Base64 ().stringToArray (s).toByteArray (),
|
|
&cresult
|
|
);
|
|
}
|
|
|
|
if (cresult != ConvertGood) {
|
|
_emit_diagnosticText (
|
|
QString ().sprintf (
|
|
"Software Store: Cannot load certificate of '%s' entry.\n",
|
|
myPrintable (entry.name)
|
|
)
|
|
);
|
|
goto cleanup1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
_entries += entry;
|
|
|
|
cleanup1:
|
|
; //nothing to do for this entry.
|
|
}
|
|
}
|
|
|
|
QMetaObject::invokeMethod(s_keyStoreList, "doUpdated", Qt::QueuedConnection);
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreKeyStoreListContext::_updateConfig - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
|
|
private:
|
|
QString
|
|
_serializeSoftStoreEntry (
|
|
const SoftStoreEntry &entry
|
|
) const {
|
|
QString serialized;
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::_serializeSoftStoreEntry - entry name=%s",
|
|
myPrintable (entry.name)
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
serialized = QString ().sprintf (
|
|
"qca-softstore/0/%s/%d/%s/%d/%d/x509chain/",
|
|
myPrintable (_escapeString (entry.name)),
|
|
entry.keyReferenceType,
|
|
myPrintable (_escapeString (entry.keyReference)),
|
|
entry.noPassphrase ? 1 : 0,
|
|
entry.unlockTimeout
|
|
);
|
|
|
|
QStringList list;
|
|
foreach (Certificate i, entry.chain) {
|
|
list += _escapeString (Base64 ().arrayToString (i.toDER ()));
|
|
}
|
|
|
|
serialized.append (list.join ("/"));
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::_serializeSoftStoreEntry - return serialized='%s'",
|
|
myPrintable (serialized)
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return serialized;
|
|
}
|
|
|
|
bool
|
|
_deserializeSoftStoreEntry (
|
|
const QString &serialized,
|
|
SoftStoreEntry &entry
|
|
) const {
|
|
bool ret = false;
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::_deserializeSoftStoreEntry - entry from='%s'",
|
|
myPrintable (serialized)
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
entry = SoftStoreEntry ();
|
|
|
|
QStringList list = serialized.split ("/");
|
|
int n=0;
|
|
|
|
if (list.size () < 8) {
|
|
goto cleanup;
|
|
}
|
|
|
|
if (list[n++] != "qca-softstore") {
|
|
goto cleanup;
|
|
}
|
|
|
|
if (list[n++].toInt () != 0) {
|
|
goto cleanup;
|
|
}
|
|
|
|
entry.name = _unescapeString (list[n++]);
|
|
entry.keyReferenceType = (KeyType)list[n++].toInt ();
|
|
entry.keyReference = _unescapeString (list[n++]);
|
|
entry.noPassphrase = list[n++].toInt () != 0;
|
|
entry.unlockTimeout = list[n++].toInt ();
|
|
n++; // skip public key for now.
|
|
|
|
while (n < list.size ()) {
|
|
Certificate cert = Certificate::fromDER (
|
|
Base64 ().stringToArray (_unescapeString (list[n++])).toByteArray ()
|
|
);
|
|
if (cert.isNull ()) {
|
|
goto cleanup;
|
|
}
|
|
entry.chain += cert;
|
|
}
|
|
|
|
ret = true;
|
|
|
|
cleanup:
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::_deserializeSoftStoreEntry - return ret=%d chain.size()=%d",
|
|
ret ? 1 : 0,
|
|
entry.chain.size ()
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return ret;
|
|
}
|
|
|
|
softstoreKeyStoreEntryContext *
|
|
_keyStoreEntryBySoftStoreEntry (
|
|
const SoftStoreEntry &sentry
|
|
) const {
|
|
softstoreKeyStoreEntryContext *entry = NULL;
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::_keyStoreEntryBySoftStoreEntry - entry name=%s",
|
|
myPrintable (sentry.name)
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
QString serialized = _serializeSoftStoreEntry (sentry);
|
|
|
|
softstoreRSAContext *rsakey = new softstoreRSAContext (
|
|
sentry,
|
|
serialized,
|
|
provider()
|
|
);
|
|
|
|
softstorePKeyContext *pkc = new softstorePKeyContext (provider ());
|
|
pkc->setKey (rsakey);
|
|
PrivateKey privkey;
|
|
privkey.change (pkc);
|
|
KeyBundle key;
|
|
key.setCertificateChainAndKey (
|
|
sentry.chain,
|
|
privkey
|
|
);
|
|
|
|
entry = new softstoreKeyStoreEntryContext (
|
|
key,
|
|
sentry,
|
|
serialized,
|
|
provider ()
|
|
);
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreKeyStoreListContext::_keyStoreEntryBySoftStoreEntry - return entry=%p",
|
|
(void *)entry
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return entry;
|
|
}
|
|
|
|
QString
|
|
_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
|
|
_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 softstoreQCAPlugin;
|
|
|
|
class softstoreProvider : public Provider
|
|
{
|
|
private:
|
|
static const int _CONFIG_MAX_ENTRIES;
|
|
|
|
QVariantMap _config;
|
|
|
|
public:
|
|
softstoreProvider () {
|
|
}
|
|
|
|
~softstoreProvider () {
|
|
}
|
|
|
|
public:
|
|
virtual
|
|
int
|
|
qcaVersion() const {
|
|
return QCA_VERSION;
|
|
}
|
|
|
|
virtual
|
|
void
|
|
init () {
|
|
}
|
|
|
|
virtual
|
|
QString
|
|
name () const {
|
|
return "qca-softstore";
|
|
}
|
|
|
|
virtual
|
|
QStringList
|
|
features () const {
|
|
QCA_logTextMessage (
|
|
"softstoreProvider::features - entry/return",
|
|
Logger::Debug
|
|
);
|
|
|
|
QStringList list;
|
|
list += "pkey";
|
|
list += "keystorelist";
|
|
return list;
|
|
}
|
|
|
|
virtual
|
|
Context *
|
|
createContext (
|
|
const QString &type
|
|
) {
|
|
Provider::Context *context = NULL;
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreProvider::createContext - entry type='%s'",
|
|
myPrintable (type)
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
if (type == "keystorelist") {
|
|
if (s_keyStoreList == NULL) {
|
|
s_keyStoreList = new softstoreKeyStoreListContext (this);
|
|
s_keyStoreList->_updateConfig (_config, _CONFIG_MAX_ENTRIES);
|
|
}
|
|
context = s_keyStoreList;
|
|
}
|
|
|
|
QCA_logTextMessage (
|
|
QString ().sprintf (
|
|
"softstoreProvider::createContext - return context=%p",
|
|
(void *)context
|
|
),
|
|
Logger::Debug
|
|
);
|
|
|
|
return context;
|
|
}
|
|
|
|
virtual
|
|
QVariantMap
|
|
defaultConfig () const {
|
|
QVariantMap mytemplate;
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreProvider::defaultConfig - entry/return",
|
|
Logger::Debug
|
|
);
|
|
|
|
mytemplate["formtype"] = "http://affinix.com/qca/forms/qca-softstore#1.0";
|
|
for (int i=0;i<_CONFIG_MAX_ENTRIES;i++) {
|
|
mytemplate[QString ().sprintf ("entry_%02d_enabled", i)] = false;
|
|
mytemplate[QString ().sprintf ("entry_%02d_name", i)] = "";
|
|
mytemplate[QString ().sprintf ("entry_%02d_public_type", i)] = "";
|
|
mytemplate[QString ().sprintf ("entry_%02d_private_type", i)] = "";
|
|
mytemplate[QString ().sprintf ("entry_%02d_public", i)] = "";
|
|
mytemplate[QString ().sprintf ("entry_%02d_private", i)] = "";
|
|
mytemplate[QString ().sprintf ("entry_%02d_unlock_timeout", i)] = -1;
|
|
mytemplate[QString ().sprintf ("entry_%02d_no_passphrase", i)] = false;
|
|
}
|
|
|
|
return mytemplate;
|
|
}
|
|
|
|
virtual
|
|
void
|
|
configChanged (const QVariantMap &config) {
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreProvider::configChanged - entry",
|
|
Logger::Debug
|
|
);
|
|
|
|
_config = config;
|
|
|
|
if (s_keyStoreList != NULL) {
|
|
s_keyStoreList->_updateConfig (_config, _CONFIG_MAX_ENTRIES);
|
|
}
|
|
|
|
QCA_logTextMessage (
|
|
"softstoreProvider::configChanged - return",
|
|
Logger::Debug
|
|
);
|
|
}
|
|
};
|
|
|
|
const int softstoreProvider::_CONFIG_MAX_ENTRIES = 50;
|
|
|
|
class softstorePlugin : public QObject, public QCAPlugin
|
|
{
|
|
Q_OBJECT
|
|
Q_INTERFACES(QCAPlugin)
|
|
|
|
public:
|
|
virtual Provider *createProvider() { return new softstoreProvider; }
|
|
};
|
|
|
|
#include "qca-softstore.moc"
|
|
|
|
Q_EXPORT_PLUGIN2(qca_softstore, softstorePlugin)
|