Add cryptographic card decryption method to tdehwlib

pull/1/head
Timothy Pearson 9 years ago
parent ffa54887ce
commit 402781f094

@ -61,6 +61,8 @@ CryptoCardDeviceWatcher::CryptoCardDeviceWatcher() {
#ifdef WITH_PCSC #ifdef WITH_PCSC
m_readerStates = NULL; m_readerStates = NULL;
#endif #endif
m_cardPINPromptDone = true;
m_pinCallbacksEnabled = false;
} }
CryptoCardDeviceWatcher::~CryptoCardDeviceWatcher() { CryptoCardDeviceWatcher::~CryptoCardDeviceWatcher() {
@ -189,6 +191,11 @@ void CryptoCardDeviceWatcher::requestTermination() {
m_terminationRequested = true; m_terminationRequested = true;
} }
void CryptoCardDeviceWatcher::setProvidedPin(TQString pin) {
m_cardPIN = pin;
m_cardPINPromptDone = true;
}
TQString CryptoCardDeviceWatcher::getCardATR(TQString readerName) { TQString CryptoCardDeviceWatcher::getCardATR(TQString readerName) {
#ifdef WITH_PCSC #ifdef WITH_PCSC
unsigned int i; unsigned int i;
@ -231,21 +238,54 @@ TQString CryptoCardDeviceWatcher::getCardATR(TQString readerName) {
#endif #endif
} }
void CryptoCardDeviceWatcher::enablePINEntryCallbacks(bool enable) {
m_pinCallbacksEnabled = enable;
}
TQString CryptoCardDeviceWatcher::doPinRequest(TQString prompt) {
if (!m_pinCallbacksEnabled) {
return TQString::null;
}
m_cardPINPromptDone = false;
emit(pinRequested(prompt));
while (!m_cardPINPromptDone) {
usleep(100);
}
if (m_cardPIN.length() > 0) {
return m_cardPIN;
}
else {
return TQString::null;
}
}
#ifdef WITH_PKCS #ifdef WITH_PKCS
static void pkcs_log_hook(IN void * const global_data, IN unsigned flags, IN const char * const format, IN va_list args) { static void pkcs_log_hook(IN void * const global_data, IN unsigned flags, IN const char * const format, IN va_list args) {
vprintf(format, args); vprintf(format, args);
printf("\n"); printf("\n");
} }
static PKCS11H_BOOL pkcs_pin_hook(IN void * const global_data, IN void * const user_data, IN const pkcs11h_token_id_t token, IN const unsigned retry, OUT char * const pin, IN const size_t pin_max) {
CryptoCardDeviceWatcher* watcher = (CryptoCardDeviceWatcher*)global_data;
TQString providedPin = watcher->doPinRequest(i18n("Please enter the PIN for '%1'").arg(token->display));
if (providedPin.length() > 0) {
snprintf(pin, pin_max, "%s", providedPin.ascii());
// Success
return 1;
}
else {
// Abort
return 0;
}
}
#endif #endif
int CryptoCardDeviceWatcher::retrieveCardCertificates(TQString readerName) { int CryptoCardDeviceWatcher::initializePkcs() {
#if WITH_PKCS #if WITH_PKCS
int ret = -1;
CK_RV rv; CK_RV rv;
pkcs11h_certificate_id_list_t issuers;
pkcs11h_certificate_id_list_t certs;
printf("Initializing pkcs11-helper\n"); printf("Initializing pkcs11-helper\n");
if ((rv = pkcs11h_initialize()) != CKR_OK) { if ((rv = pkcs11h_initialize()) != CKR_OK) {
printf("pkcs11h_initialize failed: %s\n", pkcs11h_getMessage(rv)); printf("pkcs11h_initialize failed: %s\n", pkcs11h_getMessage(rv));
@ -253,29 +293,51 @@ int CryptoCardDeviceWatcher::retrieveCardCertificates(TQString readerName) {
} }
printf("Registering pkcs11-helper hooks\n"); printf("Registering pkcs11-helper hooks\n");
if ((rv = pkcs11h_setLogHook(pkcs_log_hook, NULL)) != CKR_OK) { if ((rv = pkcs11h_setLogHook(pkcs_log_hook, this)) != CKR_OK) {
printf("pkcs11h_setLogHook failed: %s\n", pkcs11h_getMessage(rv)); printf("pkcs11h_setLogHook failed: %s\n", pkcs11h_getMessage(rv));
return -1; return -1;
} }
pkcs11h_setLogLevel(PKCS11H_LOG_WARN); pkcs11h_setLogLevel(PKCS11H_LOG_WARN);
// pkcs11h_setLogLevel(PKCS11H_LOG_DEBUG2);
#if 0 #if 0
if ((rv = pkcs11h_setTokenPromptHook(_pkcs11h_hooks_token_prompt, NULL)) != CKR_OK) { if ((rv = pkcs11h_setTokenPromptHook(_pkcs11h_hooks_token_prompt, NULL)) != CKR_OK) {
printf("pkcs11h_setTokenPromptHook failed: %s\n", pkcs11h_getMessage(rv)); printf("pkcs11h_setTokenPromptHook failed: %s\n", pkcs11h_getMessage(rv));
return -1; return -1;
} }
if ((rv = pkcs11h_setPINPromptHook(_pkcs11h_hooks_pin_prompt, NULL)) != CKR_OK) { #endif
if ((rv = pkcs11h_setPINPromptHook(pkcs_pin_hook, this)) != CKR_OK) {
printf("pkcs11h_setPINPromptHook failed: %s\n", pkcs11h_getMessage(rv)); printf("pkcs11h_setPINPromptHook failed: %s\n", pkcs11h_getMessage(rv));
return -1; return -1;
} }
#endif
printf("Adding provider '%s'\n", OPENSC_PKCS11_PROVIDER_LIBRARY); printf("Adding provider '%s'\n", OPENSC_PKCS11_PROVIDER_LIBRARY);
if ((rv = pkcs11h_addProvider(OPENSC_PKCS11_PROVIDER_LIBRARY, OPENSC_PKCS11_PROVIDER_LIBRARY, FALSE, PKCS11H_PRIVATEMODE_MASK_AUTO, PKCS11H_SLOTEVENT_METHOD_AUTO, 0, FALSE)) != CKR_OK) { if ((rv = pkcs11h_addProvider(OPENSC_PKCS11_PROVIDER_LIBRARY, OPENSC_PKCS11_PROVIDER_LIBRARY, FALSE, PKCS11H_PRIVATEMODE_MASK_AUTO, PKCS11H_SLOTEVENT_METHOD_AUTO, 0, FALSE)) != CKR_OK) {
printf("pkcs11h_addProvider failed: %s\n", pkcs11h_getMessage(rv)); printf("pkcs11h_addProvider failed: %s\n", pkcs11h_getMessage(rv));
return -1; return -1;
} }
rv = pkcs11h_certificate_enumCertificateIds(PKCS11H_ENUM_METHOD_CACHE, NULL, PKCS11H_PROMPT_MASK_ALLOW_NONE, &issuers, &certs); return 0;
#else
return -1;
#endif
}
int CryptoCardDeviceWatcher::retrieveCardCertificates(TQString readerName) {
#if WITH_PKCS
int ret = -1;
CK_RV rv;
pkcs11h_certificate_id_list_t issuers;
pkcs11h_certificate_id_list_t certs;
if (initializePkcs() < 0) {
printf("Unable to initialize PKCS\n");
return -1;
}
rv = pkcs11h_certificate_enumCertificateIds(PKCS11H_ENUM_METHOD_CACHE, NULL, PKCS11H_PROMPT_MASK_ALLOW_ALL, &issuers, &certs);
if ((rv != CKR_OK) || (certs == NULL)) { if ((rv != CKR_OK) || (certs == NULL)) {
printf("Cannot enumerate certificates: %s\n", pkcs11h_getMessage(rv)); printf("Cannot enumerate certificates: %s\n", pkcs11h_getMessage(rv));
return -1; return -1;
@ -288,13 +350,14 @@ int CryptoCardDeviceWatcher::retrieveCardCertificates(TQString readerName) {
printf("Certificate %d name: '%s'\n", i, label.ascii()); printf("Certificate %d name: '%s'\n", i, label.ascii());
pkcs11h_certificate_t certificate; pkcs11h_certificate_t certificate;
rv = pkcs11h_certificate_create(certs->certificate_id, NULL, PKCS11H_PROMPT_MASK_ALLOW_NONE, PKCS11H_PIN_CACHE_INFINITE, &certificate); rv = pkcs11h_certificate_create(certs->certificate_id, NULL, PKCS11H_PROMPT_MASK_ALLOW_ALL, PKCS11H_PIN_CACHE_INFINITE, &certificate);
if (rv != CKR_OK) { if (rv != CKR_OK) {
printf("Can not read certificate: %s\n", pkcs11h_getMessage(rv)); printf("Cannot read certificate: %s\n", pkcs11h_getMessage(rv));
pkcs11h_certificate_freeCertificateId(certs->certificate_id); pkcs11h_certificate_freeCertificateId(certs->certificate_id);
ret = -1; ret = -1;
break; break;
} }
pkcs11h_certificate_freeCertificateId(certs->certificate_id); pkcs11h_certificate_freeCertificateId(certs->certificate_id);
pkcs11h_openssl_session_t openssl_session = NULL; pkcs11h_openssl_session_t openssl_session = NULL;
@ -335,13 +398,12 @@ int CryptoCardDeviceWatcher::retrieveCardCertificates(TQString readerName) {
printf("Unable to copy X509 certificate\n"); printf("Unable to copy X509 certificate\n");
} }
pkcs11h_certificate_freeCertificateIdList(issuers);
pkcs11h_openssl_freeSession(openssl_session); pkcs11h_openssl_freeSession(openssl_session);
i++; i++;
} }
pkcs11h_certificate_freeCertificateIdList(issuers);
return ret; return ret;
#else #else
return -1; return -1;
@ -386,6 +448,7 @@ void TDECryptographicCardDevice::enableCardMonitoring(bool enable) {
m_watcherObject->cardDevice = this; m_watcherObject->cardDevice = this;
m_watcherObject->moveToThread(m_watcherThread); m_watcherObject->moveToThread(m_watcherThread);
TQObject::connect(m_watcherObject, SIGNAL(statusChanged(TQString,TQString)), this, SLOT(cardStatusChanged(TQString,TQString))); TQObject::connect(m_watcherObject, SIGNAL(statusChanged(TQString,TQString)), this, SLOT(cardStatusChanged(TQString,TQString)));
TQObject::connect(m_watcherObject, SIGNAL(pinRequested(TQString)), this, SLOT(workerRequestedPin(TQString)));
TQTimer::singleShot(0, m_watcherObject, SLOT(run())); TQTimer::singleShot(0, m_watcherObject, SLOT(run()));
m_watcherThread->start(); m_watcherThread->start();
@ -407,6 +470,12 @@ void TDECryptographicCardDevice::enableCardMonitoring(bool enable) {
#endif #endif
} }
void TDECryptographicCardDevice::enablePINEntryCallbacks(bool enable) {
if (m_watcherObject) {
m_watcherObject->enablePINEntryCallbacks(enable);
}
}
int TDECryptographicCardDevice::cardPresent() { int TDECryptographicCardDevice::cardPresent() {
if (m_watcherObject && m_watcherThread) { if (m_watcherObject && m_watcherThread) {
if (m_cardPresent) if (m_cardPresent)
@ -462,6 +531,134 @@ void TDECryptographicCardDevice::cardStatusChanged(TQString status, TQString atr
} }
} }
void TDECryptographicCardDevice::setProvidedPin(TQString pin) {
if (m_watcherObject) {
m_watcherObject->setProvidedPin(pin);
}
}
void TDECryptographicCardDevice::workerRequestedPin(TQString prompt) {
emit(pinRequested(prompt, this));
}
int TDECryptographicCardDevice::decryptDataEncryptedWithCertPublicKey(TQByteArray &ciphertext, TQByteArray &plaintext, TQString *errstr) {
#if WITH_PKCS
int ret = -1;
if (!m_watcherObject) {
if (errstr) *errstr = i18n("Card watcher object not available");
return -1;
}
CK_RV rv;
pkcs11h_certificate_id_list_t issuers;
pkcs11h_certificate_id_list_t certs;
if (m_watcherObject->initializePkcs() < 0) {
if (errstr) *errstr = i18n("Unable to initialize PKCS");
return -1;
}
rv = pkcs11h_certificate_enumCertificateIds(PKCS11H_ENUM_METHOD_CACHE, NULL, PKCS11H_PROMPT_MASK_ALLOW_ALL, &issuers, &certs);
if ((rv != CKR_OK) || (certs == NULL)) {
if (errstr) *errstr = i18n("Cannot enumerate certificates: %1").arg(pkcs11h_getMessage(rv));
return -1;
}
int i = 0;
for (pkcs11h_certificate_id_list_t cert = certs; cert != NULL; cert = cert->next) {
TQString label = cert->certificate_id->displayName;
pkcs11h_certificate_t certificate;
rv = pkcs11h_certificate_create(certs->certificate_id, NULL, PKCS11H_PROMPT_MASK_ALLOW_ALL, PKCS11H_PIN_CACHE_INFINITE, &certificate);
if (rv != CKR_OK) {
if (errstr) *errstr = i18n("Cannot read certificate: %1").arg(pkcs11h_getMessage(rv));
pkcs11h_certificate_freeCertificateId(certs->certificate_id);
ret = -1;
break;
}
pkcs11h_certificate_freeCertificateId(certs->certificate_id);
pkcs11h_openssl_session_t openssl_session = NULL;
if ((openssl_session = pkcs11h_openssl_createSession(certificate)) == NULL) {
if (errstr) *errstr = i18n("Cannot initialize openssl session to retrieve cryptographic objects");
pkcs11h_certificate_freeCertificate(certificate);
ret = -1;
break;
}
if (ciphertext.size() < 16) {
if (errstr) *errstr = i18n("Cannot decrypt: %1").arg(i18n("Ciphertext too small"));
ret = -2;
continue;
}
// Get certificate data
X509* x509_local;
x509_local = pkcs11h_openssl_session_getX509(openssl_session);
if (!x509_local) {
if (errstr) *errstr = i18n("Cannot get X509 object\n");
ret = -1;
}
// Extract public key from X509 certificate
EVP_PKEY* x509_pubkey = NULL;
RSA* rsa_pubkey = NULL;
x509_pubkey = X509_get_pubkey(x509_local);
if (x509_pubkey) {
rsa_pubkey = EVP_PKEY_get1_RSA(x509_pubkey);
}
// Try to get RSA parameters
if (rsa_pubkey) {
unsigned int rsa_length = RSA_size(rsa_pubkey);
if (ciphertext.size() > rsa_length) {
if (errstr) *errstr = i18n("Cannot decrypt: %1").arg(i18n("Ciphertext too large"));
ret = -2;
continue;
}
}
size_t size = 0;
// Determine output buffer size
rv = pkcs11h_certificate_decryptAny(certificate, CKM_RSA_PKCS, (unsigned char*)ciphertext.data(), ciphertext.size(), NULL, &size);
if (rv != CKR_OK) {
if (errstr) *errstr = i18n("Cannot determine decrypted message length: %1").arg(pkcs11h_getMessage(rv));
ret = -2;
}
else {
// Decrypt data
plaintext.resize(size);
rv = pkcs11h_certificate_decryptAny(certificate, CKM_RSA_PKCS, (unsigned char*)ciphertext.data(), ciphertext.size(), (unsigned char*)plaintext.data(), &size);
if (rv != CKR_OK) {
if (errstr) *errstr = i18n("Cannot decrypt: %1").arg(pkcs11h_getMessage(rv));
ret = -2;
}
else {
if (errstr) *errstr = TQString::null;
ret = 0;
}
}
pkcs11h_openssl_freeSession(openssl_session);
// Only interested in first certificate for now
// FIXME
// If cards with multiple certificates are used this should be modified to try decryption
// using each certificate in turn...
break;
i++;
}
pkcs11h_certificate_freeCertificateIdList(issuers);
return ret;
#else
return -1;
#endif
}
int TDECryptographicCardDevice::createNewSecretRSAKeyFromCertificate(TQByteArray &plaintext, TQByteArray &ciphertext, X509* certificate) { int TDECryptographicCardDevice::createNewSecretRSAKeyFromCertificate(TQByteArray &plaintext, TQByteArray &ciphertext, X509* certificate) {
unsigned int i; unsigned int i;
int retcode = -1; int retcode = -1;

@ -57,6 +57,20 @@ class TDECORE_EXPORT TDECryptographicCardDevice : public TDEGenericDevice
*/ */
void enableCardMonitoring(bool enable); void enableCardMonitoring(bool enable);
/**
* Enable / disable PIN entry.
*
* @note You must connect to pinRequested and call setProvidedPin with
* the provided PIN, otherwise the TDECryptographicCardDevice object
* will hang waiting for input.
*
* @param enable true to enable, false to disable.
*
* @see setProvidedPin(TQString pin)
* @see pinRequested
*/
void enablePINEntryCallbacks(bool enable);
/** /**
* If monitoring of insert / remove events is enabled, * If monitoring of insert / remove events is enabled,
* return whether or not a card is present. * return whether or not a card is present.
@ -82,6 +96,27 @@ class TDECORE_EXPORT TDECryptographicCardDevice : public TDEGenericDevice
*/ */
X509CertificatePtrList cardX509Certificates(); X509CertificatePtrList cardX509Certificates();
/**
* Sets the user-provided PIN from within the pinRequested callback.
* This method must not be called from anywhere else in user code.
* @param pin the user-provided PIN, TQString::null to abort
*
* @see pinRequested(TQString prompt)
*/
void setProvidedPin(TQString pin);
/**
* If monitoring of insert / remove events is enabled, and a card has been inserted,
* decrypt data originally encrypted using a public key from one of the certificates
* stored on the card.
* This operation takes place on the card, and in most cases will require PIN entry.
* @param ciphertext Encrypted data
* @param plaintext Decrypted data
* @param errstr Pointer to TQString to be loaded with error description on failure
* @return 0 on success, -1 on general failure, -2 on encryption failure
*/
int decryptDataEncryptedWithCertPublicKey(TQByteArray &ciphertext, TQByteArray &plaintext, TQString *errstr=NULL);
/** /**
* Create a new random key and encrypt with the public key * Create a new random key and encrypt with the public key
* contained in the given certificate. * contained in the given certificate.
@ -94,10 +129,12 @@ class TDECORE_EXPORT TDECryptographicCardDevice : public TDEGenericDevice
public slots: public slots:
void cardStatusChanged(TQString status, TQString atr); void cardStatusChanged(TQString status, TQString atr);
void workerRequestedPin(TQString prompt);
signals: signals:
void cardInserted(); void cardInserted();
void cardRemoved(); void cardRemoved();
void pinRequested(TQString prompt, TDECryptographicCardDevice* cdevice);
private: private:
TQEventLoopThread *m_watcherThread; TQEventLoopThread *m_watcherThread;

@ -53,6 +53,13 @@ class CryptoCardDeviceWatcher : public TQObject
signals: signals:
void statusChanged(TQString, TQString); void statusChanged(TQString, TQString);
void pinRequested(TQString);
public:
int initializePkcs();
TQString doPinRequest(TQString prompt);
void setProvidedPin(TQString pin);
void enablePINEntryCallbacks(bool enable);
public: public:
TDECryptographicCardDevice *cardDevice; TDECryptographicCardDevice *cardDevice;
@ -62,6 +69,9 @@ class CryptoCardDeviceWatcher : public TQObject
private: private:
bool m_terminationRequested; bool m_terminationRequested;
bool m_pinCallbacksEnabled;
TQString m_cardPIN;
bool m_cardPINPromptDone;
#ifdef WITH_PCSC #ifdef WITH_PCSC
SCARDCONTEXT m_cardContext; SCARDCONTEXT m_cardContext;
SCARD_READERSTATE *m_readerStates; SCARD_READERSTATE *m_readerStates;

Loading…
Cancel
Save