From 64fdd666ffad209bf51b73530b80e6868507e67c Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Mon, 14 Sep 2015 20:33:12 -0500 Subject: Add ability to decrypt multiple data objects in the same session using a cryptographic card Add LUKS key verification routine --- tdecore/tdehw/tdecryptographiccarddevice.cpp | 164 ++++++++++++++++++++++----- 1 file changed, 133 insertions(+), 31 deletions(-) (limited to 'tdecore/tdehw/tdecryptographiccarddevice.cpp') diff --git a/tdecore/tdehw/tdecryptographiccarddevice.cpp b/tdecore/tdehw/tdecryptographiccarddevice.cpp index 99c00b9e5..37aa6cac5 100644 --- a/tdecore/tdehw/tdecryptographiccarddevice.cpp +++ b/tdecore/tdehw/tdecryptographiccarddevice.cpp @@ -40,6 +40,8 @@ // 1 second #define PCSC_POLL_TIMEOUT_S 1000 +#define CARD_MAX_LOGIN_RETRY_COUNT 3 + /* FIXME * This is incomplete */ @@ -63,6 +65,7 @@ CryptoCardDeviceWatcher::CryptoCardDeviceWatcher() { #endif m_cardPINPromptDone = true; m_pinCallbacksEnabled = false; + m_cardReusePIN = false; } CryptoCardDeviceWatcher::~CryptoCardDeviceWatcher() { @@ -196,6 +199,14 @@ void CryptoCardDeviceWatcher::setProvidedPin(TQString pin) { m_cardPINPromptDone = true; } +void CryptoCardDeviceWatcher::retrySamePin(bool enable) { + m_cardReusePIN = enable; + if (!enable) { + m_cardPIN = "SHREDDINGTHEPINISMOSTSECURE"; + m_cardPIN = TQString::null; + } +} + TQString CryptoCardDeviceWatcher::getCardATR(TQString readerName) { #ifdef WITH_PCSC unsigned int i; @@ -247,6 +258,10 @@ TQString CryptoCardDeviceWatcher::doPinRequest(TQString prompt) { return TQString::null; } + if (m_cardReusePIN) { + return m_cardPIN; + } + m_cardPINPromptDone = false; emit(pinRequested(prompt)); while (!m_cardPINPromptDone) { @@ -269,6 +284,7 @@ static void pkcs_log_hook(IN void * const global_data, IN unsigned flags, IN con 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()); @@ -307,6 +323,11 @@ int CryptoCardDeviceWatcher::initializePkcs() { } #endif + if ((rv = pkcs11h_setMaxLoginRetries(CARD_MAX_LOGIN_RETRY_COUNT)) != CKR_OK) { + printf("pkcs11h_setMaxLoginRetries failed: %s\n", pkcs11h_getMessage(rv)); + return -1; + } + if ((rv = pkcs11h_setPINPromptHook(pkcs_pin_hook, this)) != CKR_OK) { printf("pkcs11h_setPINPromptHook failed: %s\n", pkcs11h_getMessage(rv)); return -1; @@ -337,7 +358,7 @@ int CryptoCardDeviceWatcher::retrieveCardCertificates(TQString readerName) { return -1; } - rv = pkcs11h_certificate_enumCertificateIds(PKCS11H_ENUM_METHOD_CACHE, NULL, PKCS11H_PROMPT_MASK_ALLOW_ALL, &issuers, &certs); + rv = pkcs11h_certificate_enumCertificateIds(PKCS11H_ENUM_METHOD_CACHE, NULL, PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT, &issuers, &certs); if ((rv != CKR_OK) || (certs == NULL)) { printf("Cannot enumerate certificates: %s\n", pkcs11h_getMessage(rv)); return -1; @@ -350,7 +371,7 @@ int CryptoCardDeviceWatcher::retrieveCardCertificates(TQString readerName) { printf("Certificate %d name: '%s'\n", i, label.ascii()); pkcs11h_certificate_t certificate; - rv = pkcs11h_certificate_create(certs->certificate_id, NULL, PKCS11H_PROMPT_MASK_ALLOW_ALL, PKCS11H_PIN_CACHE_INFINITE, &certificate); + rv = pkcs11h_certificate_create(certs->certificate_id, NULL, PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT, PKCS11H_PIN_CACHE_INFINITE, &certificate); if (rv != CKR_OK) { printf("Cannot read certificate: %s\n", pkcs11h_getMessage(rv)); pkcs11h_certificate_freeCertificateId(certs->certificate_id); @@ -542,6 +563,19 @@ void TDECryptographicCardDevice::workerRequestedPin(TQString prompt) { } int TDECryptographicCardDevice::decryptDataEncryptedWithCertPublicKey(TQByteArray &ciphertext, TQByteArray &plaintext, TQString *errstr) { + TQValueList cipherTextList; + TQValueList plainTextList; + TQValueList retCodeList; + + cipherTextList.append(ciphertext); + + this->decryptDataEncryptedWithCertPublicKey(cipherTextList, plainTextList, retCodeList, errstr); + + plaintext = plainTextList[0]; + return retCodeList[0]; +} + +int TDECryptographicCardDevice::decryptDataEncryptedWithCertPublicKey(TQValueList &cipherTextList, TQValueList &plainTextList, TQValueList &retcodes, TQString *errstr) { #if WITH_PKCS int ret = -1; @@ -559,7 +593,7 @@ int TDECryptographicCardDevice::decryptDataEncryptedWithCertPublicKey(TQByteArra return -1; } - rv = pkcs11h_certificate_enumCertificateIds(PKCS11H_ENUM_METHOD_CACHE, NULL, PKCS11H_PROMPT_MASK_ALLOW_ALL, &issuers, &certs); + rv = pkcs11h_certificate_enumCertificateIds(PKCS11H_ENUM_METHOD_CACHE, NULL, PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT, &issuers, &certs); if ((rv != CKR_OK) || (certs == NULL)) { if (errstr) *errstr = i18n("Cannot enumerate certificates: %1").arg(pkcs11h_getMessage(rv)); return -1; @@ -570,7 +604,7 @@ int TDECryptographicCardDevice::decryptDataEncryptedWithCertPublicKey(TQByteArra 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); + rv = pkcs11h_certificate_create(certs->certificate_id, NULL, PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT, 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); @@ -588,17 +622,11 @@ int TDECryptographicCardDevice::decryptDataEncryptedWithCertPublicKey(TQByteArra 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"); + if (errstr) *errstr = i18n("Cannot get X509 object"); ret = -1; } @@ -610,34 +638,105 @@ int TDECryptographicCardDevice::decryptDataEncryptedWithCertPublicKey(TQByteArra 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")); + // Check PIN + rv = pkcs11h_certificate_ensureKeyAccess(certificate); + if (rv != CKR_OK) { + if (rv == CKR_CANCEL) { + ret = -3; + break; + } + else if ((rv == CKR_PIN_INCORRECT) || (rv == CKR_USER_NOT_LOGGED_IN)) { ret = -2; - continue; + break; + } + else { + ret = -2; + break; } } - 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; + // We know the cached PIN is correct; disable any further login prompts + m_watcherObject->retrySamePin(true); + + TQValueList::iterator it; + TQValueList::iterator it2; + TQValueList::iterator it3; + plainTextList.clear(); + retcodes.clear(); + for (it = cipherTextList.begin(); it != cipherTextList.end(); ++it) { + plainTextList.append(TQByteArray()); + retcodes.append(-1); } - 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)); + for (it = cipherTextList.begin(), it2 = plainTextList.begin(), it3 = retcodes.begin(); it != cipherTextList.end(); ++it, ++it2, ++it3) { + TQByteArray& ciphertext = *it; + TQByteArray& plaintext = *it2; + int& retcode = *it3; + + // Verify minimum size + if (ciphertext.size() < 16) { + if (errstr) *errstr = i18n("Cannot decrypt: %1").arg(i18n("Ciphertext too small")); ret = -2; + retcode = -2; + continue; + } + + // Try to get RSA parameters and verify maximum size + 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; + retcode = -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 (%2)").arg(pkcs11h_getMessage(rv)).arg(rv); + if (rv == CKR_CANCEL) { + ret = -3; + retcode = -3; + break; + } + else if ((rv == CKR_PIN_INCORRECT) || (rv == CKR_USER_NOT_LOGGED_IN)) { + ret = -2; + retcode = -2; + break; + } + else { + ret = -2; + retcode = -2; + } } else { - if (errstr) *errstr = TQString::null; - ret = 0; + // 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 (%2)").arg(pkcs11h_getMessage(rv)).arg(rv); + if (rv == CKR_CANCEL) { + ret = -3; + retcode = -3; + break; + } + else if ((rv == CKR_PIN_INCORRECT) || (rv == CKR_USER_NOT_LOGGED_IN)) { + ret = -2; + retcode = -2; + break; + } + else { + ret = -2; + retcode = -2; + } + } + else { + if (errstr) *errstr = TQString::null; + ret = 0; + retcode = 0; + } } } @@ -653,6 +752,9 @@ int TDECryptographicCardDevice::decryptDataEncryptedWithCertPublicKey(TQByteArra } pkcs11h_certificate_freeCertificateIdList(issuers); + // Restore normal login attempt method + m_watcherObject->retrySamePin(false); + return ret; #else return -1; -- cgit v1.2.1