summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2015-09-14 20:33:12 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2015-09-14 20:33:12 -0500
commit64fdd666ffad209bf51b73530b80e6868507e67c (patch)
tree93641f2c532c02909a4285e33f3c30e7fbc2bb9c
parent402781f094e9a2450942f9d58215da281ba080c2 (diff)
downloadtdelibs-64fdd666.tar.gz
tdelibs-64fdd666.zip
Add ability to decrypt multiple data objects in the same session using a cryptographic card
Add LUKS key verification routine
-rw-r--r--tdecore/tdehw/tdecryptographiccarddevice.cpp164
-rw-r--r--tdecore/tdehw/tdecryptographiccarddevice.h17
-rw-r--r--tdecore/tdehw/tdecryptographiccarddevice_private.h2
-rw-r--r--tdecore/tdehw/tdestoragedevice.cpp31
-rw-r--r--tdecore/tdehw/tdestoragedevice.h16
5 files changed, 197 insertions, 33 deletions
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<TQByteArray> cipherTextList;
+ TQValueList<TQByteArray> plainTextList;
+ TQValueList<int> retCodeList;
+
+ cipherTextList.append(ciphertext);
+
+ this->decryptDataEncryptedWithCertPublicKey(cipherTextList, plainTextList, retCodeList, errstr);
+
+ plaintext = plainTextList[0];
+ return retCodeList[0];
+}
+
+int TDECryptographicCardDevice::decryptDataEncryptedWithCertPublicKey(TQValueList<TQByteArray> &cipherTextList, TQValueList<TQByteArray> &plainTextList, TQValueList<int> &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<TQByteArray>::iterator it;
+ TQValueList<TQByteArray>::iterator it2;
+ TQValueList<int>::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;
diff --git a/tdecore/tdehw/tdecryptographiccarddevice.h b/tdecore/tdehw/tdecryptographiccarddevice.h
index fd5256d23..db0f08289 100644
--- a/tdecore/tdehw/tdecryptographiccarddevice.h
+++ b/tdecore/tdehw/tdecryptographiccarddevice.h
@@ -110,14 +110,29 @@ class TDECORE_EXPORT TDECryptographicCardDevice : public TDEGenericDevice
* 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.
+ * This method decrypts one data object only
* @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
+ * @return 0 on success, -1 on general failure, -2 on encryption failure, -3 on user cancel
*/
int decryptDataEncryptedWithCertPublicKey(TQByteArray &ciphertext, TQByteArray &plaintext, TQString *errstr=NULL);
/**
+ * 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.
+ * This method is used to decrypt multiple data objects in one pass.
+ * @param cipherTextList Encrypted data object list
+ * @param plainTextList Decrypted data object list
+ * @param retcodes Return code for each data object
+ * @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, -3 on user cancel
+ */
+ int decryptDataEncryptedWithCertPublicKey(TQValueList<TQByteArray> &cipherTextList, TQValueList<TQByteArray> &plainTextList, TQValueList<int> &retcodes, TQString *errstr);
+
+ /**
* Create a new random key and encrypt with the public key
* contained in the given certificate.
* @param plaintext Generated (decrypted) random key
diff --git a/tdecore/tdehw/tdecryptographiccarddevice_private.h b/tdecore/tdehw/tdecryptographiccarddevice_private.h
index 3371098f2..b7d38fe52 100644
--- a/tdecore/tdehw/tdecryptographiccarddevice_private.h
+++ b/tdecore/tdehw/tdecryptographiccarddevice_private.h
@@ -59,6 +59,7 @@ class CryptoCardDeviceWatcher : public TQObject
int initializePkcs();
TQString doPinRequest(TQString prompt);
void setProvidedPin(TQString pin);
+ void retrySamePin(bool enable);
void enablePINEntryCallbacks(bool enable);
public:
@@ -72,6 +73,7 @@ class CryptoCardDeviceWatcher : public TQObject
bool m_pinCallbacksEnabled;
TQString m_cardPIN;
bool m_cardPINPromptDone;
+ bool m_cardReusePIN;
#ifdef WITH_PCSC
SCARDCONTEXT m_cardContext;
SCARD_READERSTATE *m_readerStates;
diff --git a/tdecore/tdehw/tdestoragedevice.cpp b/tdecore/tdehw/tdestoragedevice.cpp
index 1b4be9283..ff309f0f5 100644
--- a/tdecore/tdehw/tdestoragedevice.cpp
+++ b/tdecore/tdehw/tdestoragedevice.cpp
@@ -179,11 +179,16 @@ void TDEStorageDevice::internalInitializeLUKSIfNeeded() {
}
void TDEStorageDevice::cryptSetOperationsUnlockPassword(TQByteArray password) {
+#if defined(WITH_CRYPTSETUP)
+ crypt_memory_lock(NULL, 1);
m_cryptDevicePassword = password;
+#endif
}
void TDEStorageDevice::cryptClearOperationsUnlockPassword() {
+ m_cryptDevicePassword.fill(0);
m_cryptDevicePassword.resize(0);
+ crypt_memory_lock(NULL, 0);
}
bool TDEStorageDevice::cryptOperationsUnlockPasswordSet() {
@@ -195,6 +200,32 @@ bool TDEStorageDevice::cryptOperationsUnlockPasswordSet() {
}
}
+TDELUKSResult::TDELUKSResult TDEStorageDevice::cryptCheckKey(unsigned int keyslot) {
+#if defined(WITH_CRYPTSETUP)
+ int ret;
+
+ if (m_cryptDevice) {
+ if (keyslot < m_cryptKeySlotCount) {
+ ret = crypt_activate_by_passphrase(m_cryptDevice, NULL, keyslot, m_cryptDevicePassword.data(), m_cryptDevicePassword.size(), 0);
+ if (ret < 0) {
+ return TDELUKSResult::KeyslotOpFailed;
+ }
+ else {
+ return TDELUKSResult::Success;
+ }
+ }
+ else {
+ return TDELUKSResult::InvalidKeyslot;
+ }
+ }
+ else {
+ return TDELUKSResult::LUKSNotFound;
+ }
+#else
+ return TDELUKSResult::LUKSNotSupported;
+#endif
+}
+
TDELUKSResult::TDELUKSResult TDEStorageDevice::cryptAddKey(unsigned int keyslot, TQByteArray password) {
#if defined(WITH_CRYPTSETUP)
int ret;
diff --git a/tdecore/tdehw/tdestoragedevice.h b/tdecore/tdehw/tdestoragedevice.h
index d3d797686..b5922eec9 100644
--- a/tdecore/tdehw/tdestoragedevice.h
+++ b/tdecore/tdehw/tdestoragedevice.h
@@ -368,13 +368,27 @@ class TDECORE_EXPORT TDEStorageDevice : public TDEGenericDevice
bool cryptOperationsUnlockPasswordSet();
/**
- * Adds a new key to the specific keyslot, overwriting the existing key if present
+ * Checks the preloaded unlock password against the specified keyslot
+ *
+ * @param keyslot Keyslot number
+ * @return TDELUKSResult::TDELUKSResult containing the status code returned
+ * from the operation, or TDELUKSResult::LUKSNotSupported if LUKS support unavailable
+ * @return TDELUKSResult::Success on success
+ *
+ * @see cryptSetOperationsUnlockPassword
+ */
+ TDELUKSResult::TDELUKSResult cryptCheckKey(unsigned int keyslot);
+
+ /**
+ * Adds a new key to the specified keyslot, overwriting the existing key if present
*
* @param keyslot New keyslot number
* @param password New keyslot password
* @return TDELUKSResult::TDELUKSResult containing the status code returned
* from the operation, or TDELUKSResult::LUKSNotSupported if LUKS support unavailable
* @return TDELUKSResult::Success on success
+ *
+ * @see cryptSetOperationsUnlockPassword
*/
TDELUKSResult::TDELUKSResult cryptAddKey(unsigned int keyslot, TQByteArray password);