Add ability to decrypt multiple data objects in the same session using a cryptographic card

Add LUKS key verification routine
pull/1/head
Timothy Pearson 9 years ago
parent 402781f094
commit 64fdd666ff

@ -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;

@ -110,13 +110,28 @@ 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.

@ -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;

@ -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;

@ -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);

Loading…
Cancel
Save