*/
#pragma once
#include <memory>
+#include <vector>
#include <ckm/ckm-raw-buffer.h>
#include <ckm/ckm-type.h>
typedef std::unique_ptr<GObj> GObjUPtr;
typedef std::shared_ptr<GObj> GObjShPtr;
+typedef std::vector<GObjUPtr> GObjUPtrVector;
} // namespace Crypto
} // namespace CKM
class GStore {
public:
- virtual GObjUPtr getObject(const Token &) { ThrowErr(Exc::Crypto::OperationNotSupported); }
- virtual TokenPair generateAKey(const CryptoAlgorithm &) { ThrowErr(Exc::Crypto::OperationNotSupported); }
- virtual Token generateSKey(const CryptoAlgorithm &) { ThrowErr(Exc::Crypto::OperationNotSupported); }
- virtual Token import(DataType, const RawBuffer &) { ThrowErr(Exc::Crypto::OperationNotSupported); }
- virtual void destroy(const Token &) { ThrowErr(Exc::Crypto::OperationNotSupported); }
+ virtual GObjUPtr getObject(const Token &, const Password &) {
+ ThrowErr(Exc::Crypto::OperationNotSupported);
+ }
+ virtual TokenPair generateAKey(const CryptoAlgorithm &, const Password &, const Password &) {
+ ThrowErr(Exc::Crypto::OperationNotSupported);
+ }
+ virtual Token generateSKey(const CryptoAlgorithm &, const Password &) {
+ ThrowErr(Exc::Crypto::OperationNotSupported);
+ }
+ virtual Token import(DataType, const RawBuffer &, const Password &) {
+ ThrowErr(Exc::Crypto::OperationNotSupported);
+ }
+ virtual void destroy(const Token &) {
+ ThrowErr(Exc::Crypto::OperationNotSupported);
+ }
virtual ~GStore() {}
protected:
return rsa_padding;
}
-TokenPair createKeyPairRSA(CryptoBackend backendId, const int size)
+DataPair createKeyPairRSA(const int size)
{
EvpPkeyUPtr pkey;
}
pkey = EvpPkeyUPtr(pkeyTmp, EVP_PKEY_free);
- return std::make_pair<Token, Token>(Token(backendId, DataType(KeyType::KEY_RSA_PRIVATE), i2d(i2d_PrivateKey_bio, pkey.get())),
- Token(backendId, DataType(KeyType::KEY_RSA_PUBLIC), i2d(i2d_PUBKEY_bio, pkey.get())));
+ return std::make_pair<Data, Data>(
+ {DataType(KeyType::KEY_RSA_PRIVATE), i2d(i2d_PrivateKey_bio, pkey.get())},
+ {DataType(KeyType::KEY_RSA_PUBLIC), i2d(i2d_PUBKEY_bio, pkey.get())});
}
-TokenPair createKeyPairDSA(CryptoBackend backendId, const int size)
+DataPair createKeyPairDSA(const int size)
{
EvpPkeyUPtr pkey;
EvpPkeyUPtr pparam;
}
pkey = EvpPkeyUPtr(pkeyTmp, EVP_PKEY_free);
- return std::make_pair<Token, Token>(Token(backendId, DataType(KeyType::KEY_DSA_PRIVATE), i2d(i2d_PrivateKey_bio, pkey.get())),
- Token(backendId, DataType(KeyType::KEY_DSA_PUBLIC), i2d(i2d_PUBKEY_bio, pkey.get())));
+ return std::make_pair<Data, Data>(
+ {DataType(KeyType::KEY_DSA_PRIVATE), i2d(i2d_PrivateKey_bio, pkey.get())},
+ {DataType(KeyType::KEY_DSA_PUBLIC), i2d(i2d_PUBKEY_bio, pkey.get())});
}
-TokenPair createKeyPairECDSA(CryptoBackend backendId, ElipticCurve type)
+DataPair createKeyPairECDSA(ElipticCurve type)
{
int ecCurve = NOT_DEFINED;
EvpPkeyUPtr pkey;
}
pkey = EvpPkeyUPtr(pkeyTmp, EVP_PKEY_free);
- return std::make_pair<Token, Token>(Token(backendId, DataType(KeyType::KEY_ECDSA_PRIVATE), i2d(i2d_PrivateKey_bio, pkey.get())),
- Token(backendId, DataType(KeyType::KEY_ECDSA_PUBLIC), i2d(i2d_PUBKEY_bio, pkey.get())));
+ return std::make_pair<Data, Data>(
+ {DataType(KeyType::KEY_ECDSA_PRIVATE), i2d(i2d_PrivateKey_bio, pkey.get())},
+ {DataType(KeyType::KEY_ECDSA_PUBLIC), i2d(i2d_PUBKEY_bio, pkey.get())});
}
-Token createKeyAES(CryptoBackend backendId, const int sizeBits)
+Data createKeyAES(const int sizeBits)
{
// check the parameters of functions
if(sizeBits!=128 && sizeBits!=192 && sizeBits!=256) {
ThrowMsg(Exc::Crypto::InternalError, "Error in AES key generation");
}
- return Token(backendId, DataType(KeyType::KEY_AES), CKM::RawBuffer(key, key+sizeBytes));
+ return { DataType(KeyType::KEY_AES), CKM::RawBuffer(key, key+sizeBytes)};
}
-TokenPair generateAKey(CryptoBackend backendId, const CryptoAlgorithm &algorithm)
+DataPair generateAKey(const CryptoAlgorithm &algorithm)
{
validateParams<IsAsymGeneration>(algorithm);
{
int keyLength = unpack<int>(algorithm, ParamName::GEN_KEY_LEN);
if(keyType == AlgoType::RSA_GEN)
- return createKeyPairRSA(backendId, keyLength);
+ return createKeyPairRSA(keyLength);
else
- return createKeyPairDSA(backendId, keyLength);
+ return createKeyPairDSA(keyLength);
}
else // AlgoType::ECDSA_GEN
{
ElipticCurve ecType = unpack<ElipticCurve>(algorithm, ParamName::GEN_EC);
- return createKeyPairECDSA(backendId, ecType);
+ return createKeyPairECDSA(ecType);
}
}
-Token generateSKey(CryptoBackend backendId, const CryptoAlgorithm &algorithm)
+Data generateSKey(const CryptoAlgorithm &algorithm)
{
validateParams<IsSymGeneration>(algorithm);
int keySizeBits = unpack<int>(algorithm, ParamName::GEN_KEY_LEN);
- return createKeyAES(backendId, keySizeBits);
+ return createKeyAES(keySizeBits);
}
RawBuffer encryptDataAes(
#include <certificate-impl.h>
#include <ckm/ckm-type.h>
#include <openssl/evp.h>
-#include <token.h>
#include <sw-backend/obj.h>
#define EVP_SUCCESS 1 // DO NOTCHANGE THIS VALUE
namespace SW {
namespace Internals {
-TokenPair createKeyPairRSA(CryptoBackend backendId, const int size);
-TokenPair createKeyPairDSA(CryptoBackend backendId, const int size);
-TokenPair createKeyPairECDSA(CryptoBackend backendId, ElipticCurve type1);
-Token createKeyAES(CryptoBackend backendId, const int sizeBits);
+// TODO replace it with DataContainer
+struct Data {
+ DataType type;
+ RawBuffer buffer;
+};
-TokenPair generateAKey(CryptoBackend backendId, const CryptoAlgorithm &algorithm);
-Token generateSKey(CryptoBackend backendId, const CryptoAlgorithm &algorithm);
+typedef std::pair<Data,Data> DataPair;
+
+DataPair createKeyPairRSA(const int size);
+DataPair createKeyPairDSA(const int size);
+DataPair createKeyPairECDSA(ElipticCurve type1);
+Data createKeyAES(const int sizeBits);
+
+DataPair generateAKey(const CryptoAlgorithm &algorithm);
+Data generateSKey(const CryptoAlgorithm &algorithm);
RawBuffer symmetricEncrypt(const RawBuffer &key,
const CryptoAlgorithm &alg,
typedef std::unique_ptr<BIO, std::function<void(BIO*)>> BioUniquePtr;
-RawBuffer BData::getBinary() const {
- return m_raw;
-}
-
RawBuffer SKey::encrypt(const CryptoAlgorithm &alg, const RawBuffer &data)
{
return Internals::symmetricEncrypt(getBinary(), alg, data);
, m_type(keyType)
{}
- virtual RawBuffer getBinary() const;
+ virtual RawBuffer getBinary() const { return m_raw; }
protected:
RawBuffer m_raw;
DataType m_type;
*/
#include <memory>
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+
#include <generic-backend/exception.h>
#include <sw-backend/obj.h>
#include <sw-backend/store.h>
#include <sw-backend/internals.h>
+#include <message-buffer.h>
+
+namespace CKM {
+namespace Crypto {
+namespace SW {
+
namespace {
+const int ITERATIONS = 1024;
+const int KEY_LENGTH = 16; // length of AES key derived from password
+const int STORE_AES_GCM_TAG_SIZE = 16; // length of AES GCM tag
+
+// internal SW encryption scheme flags
+enum EncryptionScheme {
+ NONE = 0,
+ PASSWORD = 1 << 0
+};
+
template <typename T, typename ...Args>
std::unique_ptr<T> make_unique(Args&& ...args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
-} // namespace anonymous
+RawBuffer generateRandIV() {
+ RawBuffer civ(EVP_MAX_IV_LENGTH);
-namespace CKM {
-namespace Crypto {
-namespace SW {
+ if (1 != RAND_bytes(civ.data(), civ.size()))
+ ThrowErr(Exc::Crypto::InternalError, "RAND_bytes failed to generate IV.");
+ return civ;
+}
+
+RawBuffer passwordToKey(const Password &password, const RawBuffer &salt, size_t keySize)
+{
+ RawBuffer result(keySize);
+
+ if (1 != PKCS5_PBKDF2_HMAC_SHA1(
+ password.c_str(),
+ password.size(),
+ salt.data(),
+ salt.size(),
+ ITERATIONS,
+ result.size(),
+ result.data()))
+ {
+ ThrowErr(Exc::InternalError, "PCKS5_PKKDF2_HMAC_SHA1 failed.");
+ }
+
+ return result;
+}
+
+RawBuffer unpack(const RawBuffer& packed, const Password& pass)
+{
+ MessageBuffer buffer;
+ buffer.Push(packed);
+ int encryptionScheme = 0;
+ RawBuffer data;
+ buffer.Deserialize(encryptionScheme, data);
+
+ if (encryptionScheme == 0)
+ return data;
+
+ MessageBuffer internalBuffer;
+ internalBuffer.Push(data);
+ RawBuffer encrypted;
+ RawBuffer iv;
+ RawBuffer tag;
+
+ // serialization exceptions will be catched as CKM::Exception and will cause
+ // CKM_API_ERROR_SERVER_ERROR
+ internalBuffer.Deserialize(encrypted, iv, tag);
+
+ /*
+ * AES GCM will check data integrity and handle cases where:
+ * - wrong password is used
+ * - password is empty when it shouldn't be
+ * - password is not empty when it should be
+ */
+ RawBuffer key = passwordToKey(pass, iv, KEY_LENGTH);
+
+ RawBuffer ret;
+ try {
+ ret = Crypto::SW::Internals::decryptDataAesGcm(key, encrypted, iv, tag);
+ } catch( const Exc::Crypto::InternalError& e) {
+ ThrowErr(Exc::AuthenticationFailed, "Decryption with custom password failed");
+ }
+ return ret;
+}
+
+RawBuffer pack(const RawBuffer& data, const Password& pass)
+{
+ int scheme = EncryptionScheme::NONE;
+ RawBuffer packed = data;
+ if (!pass.empty()) {
+ RawBuffer iv = generateRandIV();
+ RawBuffer key = passwordToKey(pass, iv, KEY_LENGTH);
+
+ std::pair<RawBuffer, RawBuffer> ret;
+ try {
+ ret = Crypto::SW::Internals::encryptDataAesGcm(key, data, iv, STORE_AES_GCM_TAG_SIZE);
+ } catch( const Exc::Crypto::InternalError& e) {
+ ThrowErr(Exc::AuthenticationFailed, "Encryption with custom password failed");
+ }
+ scheme |= EncryptionScheme::PASSWORD;
+
+ // serialization exceptions will be catched as CKM::Exception and will cause
+ // CKM_API_ERROR_SERVER_ERROR
+ packed = MessageBuffer::Serialize(ret.first, iv, ret.second).Pop();
+ }
+ // encryption scheme + internal buffer
+ return MessageBuffer::Serialize(scheme, packed).Pop();
+}
+
+} // namespace anonymous
Store::Store(CryptoBackend backendId)
: GStore(backendId)
{
}
-GObjUPtr Store::getObject(const Token &token) {
+GObjUPtr Store::getObject(const Token &token, const Password &pass) {
if (token.backendId != m_backendId) {
ThrowErr(Exc::Crypto::WrongBackend, "Decider choose wrong backend!");
}
+ RawBuffer data = unpack(token.data, pass);
+
if (token.dataType.isKeyPrivate() || token.dataType.isKeyPublic()) {
- return make_unique<AKey>(token.data, token.dataType);
+ return make_unique<AKey>(data, token.dataType);
}
if (token.dataType == DataType(DataType::KEY_AES)) {
- return make_unique<SKey>(token.data, token.dataType);
+ return make_unique<SKey>(data, token.dataType);
}
- if (token.dataType.isCertificate()) {
- return make_unique<Cert>(token.data, token.dataType);
+ if (token.dataType.isCertificate() || token.dataType.isChainCert()) {
+ return make_unique<Cert>(data, token.dataType);
}
if (token.dataType.isBinaryData()) {
- return make_unique<BData>(token.data, token.dataType);
+ return make_unique<BData>(data, token.dataType);
}
ThrowErr(Exc::Crypto::DataTypeNotSupported,
"This type of data is not supported by openssl backend: ", (int)token.dataType);
}
-TokenPair Store::generateAKey(const CryptoAlgorithm &algorithm)
+TokenPair Store::generateAKey(const CryptoAlgorithm &algorithm,
+ const Password &prvPass,
+ const Password &pubPass)
{
- return Internals::generateAKey(m_backendId, algorithm);
+ Internals::DataPair ret = Internals::generateAKey(algorithm);
+ return std::make_pair<Token,Token>(
+ Token(m_backendId, ret.first.type, pack(ret.first.buffer, prvPass)),
+ Token(m_backendId, ret.second.type, pack(ret.second.buffer, pubPass)));
}
-Token Store::generateSKey(const CryptoAlgorithm &algorithm)
+Token Store::generateSKey(const CryptoAlgorithm &algorithm, const Password &pass)
{
- return Internals::generateSKey(m_backendId, algorithm);
+ Internals::Data ret = Internals::generateSKey(algorithm);
+ return Token(m_backendId, ret.type, pack(ret.buffer, pass));
}
-Token Store::import(DataType dataType, const RawBuffer &buffer) {
- return Token(m_backendId, dataType, buffer);
+Token Store::import(DataType dataType, const RawBuffer &input, const Password &pass) {
+
+ RawBuffer data = pack(input, pass);
+ return Token(m_backendId, dataType, std::move(data));
}
} // namespace SW
public:
explicit Store(CryptoBackend backendId);
- virtual GObjUPtr getObject(const Token &token);
- virtual TokenPair generateAKey(const CryptoAlgorithm &);
- virtual Token generateSKey(const CryptoAlgorithm &);
- virtual Token import(DataType dataType, const RawBuffer &buffer);
+ virtual GObjUPtr getObject(const Token &, const Password &);
+ virtual TokenPair generateAKey(const CryptoAlgorithm &, const Password &, const Password &);
+ virtual Token generateSKey(const CryptoAlgorithm &, const Password &);
+ virtual Token import(DataType, const RawBuffer &, const Password &);
virtual void destroy(const Token &){}
};
: GStore(backendId)
{}
-GObjUPtr Store::getObject(const Token &) {
+GObjUPtr Store::getObject(const Token &, const Password &) {
ThrowErr(Exc::Crypto::OperationNotSupported, "Trust zone backend is not implemented!");
}
-TokenPair Store::generateAKey(const CryptoAlgorithm &) {
+TokenPair Store::generateAKey(const CryptoAlgorithm &, const Password &, const Password &) {
ThrowErr(Exc::Crypto::OperationNotSupported, "Trust zone backend is not implemented!");
}
-Token Store::import(DataType, const RawBuffer &) {
+Token Store::import(DataType, const RawBuffer &, const Password &) {
ThrowErr(Exc::Crypto::OperationNotSupported, "Trust zone backend is not implemented!");
}
public:
explicit Store(CryptoBackend backendId);
- virtual GObjUPtr getObject(const Token &token);
- virtual TokenPair generateAKey(const CryptoAlgorithm &);
- virtual Token import(DataType dataType, const RawBuffer &buffer);
+ virtual GObjUPtr getObject(const Token &, const Password &);
+ virtual TokenPair generateAKey(const CryptoAlgorithm &, const Password &, const Password &);
+ virtual Token import(DataType dataType, const RawBuffer &buffer, const Password &);
virtual void destroy(const Token &){}
};
const Policy &policy) const
{
Crypto::GStore& store = m_decider.getStore(dataType, policy.extractable);
- Token token = store.import(dataType, data);
-
- DB::Row row(std::move(token), name, label, static_cast<int>(policy.extractable));
// do not encrypt data with password during cc_mode on
- if(m_accessControl.isCCMode()) {
- crypto.encryptRow("", row);
- } else {
- crypto.encryptRow(policy.password, row);
- }
+ Token token = store.import(dataType, data, m_accessControl.isCCMode() ? "" : policy.password);
+ DB::Row row(std::move(token), name, label, static_cast<int>(policy.extractable));
+ crypto.encryptRow(row);
return row;
}
DB::Row row;
try {
// Key is for internal service use. It won't be exported to the client
- int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, label, pass, row);
+ Crypto::GObjUPtr obj;
+ int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, name, label, pass, obj);
if (retCode == CKM_API_SUCCESS)
- key = m_decider.getStore(row).getObject(row);
+ key = std::move(obj);
return retCode;
} catch (const DB::Crypto::Exception::Base &e) {
LogError("DB::Crypto failed with message: " << e.GetMessage());
// destroy it in store
for(auto& r : rows) {
- /*
- * TODO: If row is encrypted with user password we won't be able to decrypt it (tz id).
- * Encryption/decryption with user password and with app key should both be done inside the
- * store (import, getKey and generateXKey).
- */
try {
handler.crypto.decryptRow(Password(), r);
+ m_decider.getStore(r).destroy(r);
} catch (const Exc::AuthenticationFailed&) {
LogDebug("Authentication failed when removing data. Ignored.");
}
- m_decider.getStore(r.dataType, r.exportable).destroy(r);
}
// delete row in db
return m_accessControl.canRead(cred, PermissionForLabel(accessorLabel, permissionRowOpt));
}
+Crypto::GObjUPtr CKMLogic::rowToObject(
+ UserData& handler,
+ DB::Row row,
+ const Password& password)
+{
+ Crypto::GStore& store = m_decider.getStore(row);
+
+ Password pass = m_accessControl.isCCMode() ? "" : password;
+
+ // decrypt row
+ Crypto::GObjUPtr obj;
+ if(CryptoLogic::getSchemeVersion(row.encryptionScheme) == CryptoLogic::ENCRYPTION_V2) {
+ handler.crypto.decryptRow(Password(), row);
+
+ obj = store.getObject(row, pass);
+ } else {
+ // decrypt entirely with old scheme: b64(pass(appkey(data))) -> data
+ handler.crypto.decryptRow(pass, row);
+ // destroy it in store
+ store.destroy(row);
+
+ // import it to store with new scheme: data -> pass(data)
+ Token token = store.import(row.dataType,row.data, pass);
+
+ // get it from the store (it can be different than the data we imported into store)
+ obj = store.getObject(token, pass);
+
+ // update row with new token
+ *static_cast<Token*>(&row) = std::move(token);
+
+ // encrypt it with app key: pass(data) -> b64(appkey(pass(data))
+ handler.crypto.encryptRow(row);
+
+ // update it in db
+ handler.database.updateRow(row);
+ }
+ return obj;
+}
+
int CKMLogic::readDataHelper(
bool exportFlag,
const Credentials &cred,
const Name &name,
const Label &label,
const Password &password,
- DB::RowVector &rows)
+ Crypto::GObjUPtrVector &objs)
{
auto &handler = selectDatabase(cred, label);
// read rows
DB::Crypto::Transaction transaction(&handler.database);
+ DB::RowVector rows;
int retCode = readMultiRow(name, ownerLabel, dataType, handler.database, rows);
if(CKM_API_SUCCESS != retCode)
return retCode;
// decrypt row
for(auto &row : rows)
- handler.crypto.decryptRow(password, row);
+ objs.push_back(rowToObject(handler, std::move(row), password));
+ // rowToObject may modify db
+ transaction.commit();
return CKM_API_SUCCESS;
}
const Name &name,
const Label &label,
const Password &password,
- DB::Row &row)
+ Crypto::GObjUPtr &obj)
+{
+ DataType objDataType;
+ return readDataHelper(exportFlag, cred, dataType, name, label, password, obj, objDataType);
+}
+
+int CKMLogic::readDataHelper(
+ bool exportFlag,
+ const Credentials &cred,
+ DataType dataType,
+ const Name &name,
+ const Label &label,
+ const Password &password,
+ Crypto::GObjUPtr &obj,
+ DataType& objDataType)
{
auto &handler = selectDatabase(cred, label);
// read row
DB::Crypto::Transaction transaction(&handler.database);
+ DB::Row row;
int retCode = readSingleRow(name, ownerLabel, dataType, handler.database, row);
if(CKM_API_SUCCESS != retCode)
return retCode;
+ objDataType = row.dataType;
+
// check access rights
retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, row, exportFlag, handler.database);
if(CKM_API_SUCCESS != retCode)
if(CKM_API_SUCCESS != retCode)
return retCode;
- // decrypt row
- handler.crypto.decryptRow(password, row);
+ obj = rowToObject(handler, std::move(row), password);
+ // rowToObject may modify db
+ transaction.commit();
return CKM_API_SUCCESS;
}
{
int retCode = CKM_API_SUCCESS;
DB::Row row;
+ DataType objDataType;
try {
- retCode = readDataHelper(true, cred, dataType, name, label, password, row);
+ Crypto::GObjUPtr obj;
+ retCode = readDataHelper(true, cred, dataType, name, label, password, obj, objDataType);
+ if(retCode == CKM_API_SUCCESS)
+ row.data = std::move(obj->getBinary());
} catch (const DB::Crypto::Exception::Base &e) {
LogError("DB::Crypto failed with message: " << e.GetMessage());
retCode = CKM_API_ERROR_DB_ERROR;
auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET),
commandId,
retCode,
- static_cast<int>(row.dataType),
+ static_cast<int>(objDataType),
row.data);
return response.Pop();
}
int retCode;
// read private key (mandatory)
- DB::Row privKeyRow;
- retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, label, keyPassword, privKeyRow);
+ Crypto::GObjUPtr keyObj;
+ retCode = readDataHelper(true, cred, DataType::DB_KEY_FIRST, name, label, keyPassword, keyObj);
if(retCode != CKM_API_SUCCESS)
return retCode;
- privKey = CKM::Key::create(privKeyRow.data);
+ privKey = CKM::Key::create(keyObj->getBinary());
// read certificate (mandatory)
- DB::Row certRow;
- retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, label, certPassword, certRow);
+ Crypto::GObjUPtr certObj;
+ retCode = readDataHelper(true, cred, DataType::CERTIFICATE, name, label, certPassword, certObj);
if(retCode != CKM_API_SUCCESS)
return retCode;
- cert = CKM::Certificate::create(certRow.data, DataFormat::FORM_DER);
+ cert = CKM::Certificate::create(certObj->getBinary(), DataFormat::FORM_DER);
// read CA cert chain (optional)
- DB::RowVector rawCaChain;
- retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, label, certPassword, rawCaChain);
+ Crypto::GObjUPtrVector caChainObjs;
+ retCode = readDataHelper(true, cred, DataType::DB_CHAIN_FIRST, name, label, certPassword, caChainObjs);
if(retCode != CKM_API_SUCCESS &&
retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
return retCode;
- for(auto &rawCaCert : rawCaChain)
- caChain.push_back(CKM::Certificate::create(rawCaCert.data, DataFormat::FORM_DER));
+ for(auto &caCertObj : caChainObjs)
+ caChain.push_back(CKM::Certificate::create(caCertObj->getBinary(), DataFormat::FORM_DER));
// if anything found, return it
if(privKey || cert || caChain.size()>0)
const Label &label,
const PolicySerializable &policy)
{
+ auto &handler = selectDatabase(cred, label);
+
+ // use client label if not explicitly provided
+ const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
+ if( m_accessControl.isSystemService(cred) && ownerLabel.compare(OWNER_ID_SYSTEM)!=0)
+ return CKM_API_ERROR_INPUT_PARAM;
+
+ // check if save is possible
+ DB::Crypto::Transaction transaction(&handler.database);
+ int retCode = checkSaveConditions(cred, handler, name, ownerLabel);
+ if(retCode != CKM_API_SUCCESS)
+ return retCode;
+
+ // create key in store
CryptoAlgorithm keyGenAlgorithm;
keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN);
keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size);
- Token key = m_decider.getStore(DataType::KEY_AES, policy.extractable).generateSKey(keyGenAlgorithm);
-
- return saveDataHelper(cred,
- name,
- label,
- DataType::KEY_AES,
- key.data,
- policy);
+ Token key = m_decider.getStore(DataType::KEY_AES, policy.extractable).generateSKey(keyGenAlgorithm, policy.password);
+
+ // save the data
+ DB::Row row(std::move(key), name, ownerLabel, static_cast<int>(policy.extractable));
+ handler.crypto.encryptRow(row);
+
+ handler.database.saveRow(row);
+
+ transaction.commit();
+ return CKM_API_SUCCESS;
}
if(!dt.isKey())
ThrowErr(Exc::InputParam, "Error, parameter ALGO_TYPE with wrong value.");
+ // use client label if not explicitly provided
+ const Label &ownerLabelPrv = labelPrivate.empty() ? cred.smackLabel : labelPrivate;
+ if( m_accessControl.isSystemService(cred) && ownerLabelPrv.compare(OWNER_ID_SYSTEM)!=0)
+ return CKM_API_ERROR_INPUT_PARAM;
+ const Label &ownerLabelPub = labelPublic.empty() ? cred.smackLabel : labelPublic;
+ if( m_accessControl.isSystemService(cred) && ownerLabelPub.compare(OWNER_ID_SYSTEM)!=0)
+ return CKM_API_ERROR_INPUT_PARAM;
+
bool exportable = policyPrivate.extractable || policyPublic.extractable;
- TokenPair keys = m_decider.getStore(dt, exportable).generateAKey(keyGenParams);
+ TokenPair keys = m_decider.getStore(dt, exportable).generateAKey(keyGenParams,
+ policyPrivate.password,
+ policyPublic.password);
DB::Crypto::Transaction transactionPriv(&handlerPriv.database);
// in case the same database is used for private and public - the second
// transaction will not be executed
DB::Crypto::Transaction transactionPub(&handlerPub.database);
- int retCode = saveDataHelper(cred,
- namePrivate,
- labelPrivate,
- keys.first.dataType,
- keys.first.data,
- policyPrivate);
- if (CKM_API_SUCCESS != retCode)
+ int retCode;
+ retCode = checkSaveConditions(cred, handlerPriv, namePrivate, ownerLabelPrv);
+ if(retCode != CKM_API_SUCCESS)
return retCode;
-
- retCode = saveDataHelper(cred,
- namePublic,
- labelPublic,
- keys.second.dataType,
- keys.second.data,
- policyPublic);
- if (CKM_API_SUCCESS != retCode)
+ retCode = checkSaveConditions(cred, handlerPub, namePrivate, ownerLabelPub);
+ if(retCode != CKM_API_SUCCESS)
return retCode;
+ // save the data
+ DB::Row rowPrv(std::move(keys.first), namePrivate, ownerLabelPrv, static_cast<int>(policyPrivate.extractable));
+ handlerPriv.crypto.encryptRow(rowPrv);
+ handlerPriv.database.saveRow(rowPrv);
+
+ DB::Row rowPub(std::move(keys.second), namePublic, ownerLabelPub, static_cast<int>(policyPublic.extractable));
+ handlerPub.crypto.encryptRow(rowPub);
+ handlerPub.database.saveRow(rowPub);
+
transactionPub.commit();
transactionPriv.commit();
return CKM_API_SUCCESS;
{
DB::Row row;
for (auto &i: labelNameVector) {
- int ec = readDataHelper(false, cred, DataType::CERTIFICATE, i.second, i.first, Password(), row);
+ // certificates can't be protected with custom user password
+ Crypto::GObjUPtr obj;
+ int ec = readDataHelper(false, cred, DataType::CERTIFICATE, i.second, i.first, Password(), obj);
if (ec != CKM_API_SUCCESS)
return ec;
- certVector.push_back(CertificateImpl(row.data, DataFormat::FORM_DER));
+
+ certVector.emplace_back(obj->getBinary(), DataFormat::FORM_DER);
// try to read chain certificates (if present)
- DB::RowVector rawCaChain;
- ec = readDataHelper(false, cred, DataType::DB_CHAIN_FIRST, i.second, i.first, CKM::Password(), rawCaChain);
+ Crypto::GObjUPtrVector caChainObjs;
+ ec = readDataHelper(false, cred, DataType::DB_CHAIN_FIRST, i.second, i.first, CKM::Password(), caChainObjs);
if(ec != CKM_API_SUCCESS && ec != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
return ec;
- for(auto &rawCaCert : rawCaChain)
- certVector.push_back(CertificateImpl(rawCaCert.data, DataFormat::FORM_DER));
+ for(auto &caCertObj : caChainObjs)
+ certVector.emplace_back(caCertObj->getBinary(), DataFormat::FORM_DER);
}
return CKM_API_SUCCESS;
}
int retCode = CKM_API_SUCCESS;
try {
- retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName, ownerLabel, password, row);
+ Crypto::GObjUPtr obj;
+ retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, privateKeyName, ownerLabel, password, obj);
if(retCode == CKM_API_SUCCESS) {
- signature = m_decider.getStore(row).getObject(row)->sign(cryptoAlg, message);
+ signature = obj->sign(cryptoAlg, message);
}
} catch (const DB::Crypto::Exception::Base &e) {
LogError("DB::Crypto failed with message: " << e.GetMessage());
// try certificate first - looking for a public key.
// in case of PKCS, pub key from certificate will be found first
// rather than private key from the same PKCS.
- retCode = readDataHelper(false, cred, DataType::CERTIFICATE, publicKeyOrCertName, ownerLabel, password, row);
+ Crypto::GObjUPtr obj;
+ retCode = readDataHelper(false, cred, DataType::CERTIFICATE, publicKeyOrCertName, ownerLabel, password, obj);
if (retCode == CKM_API_ERROR_DB_ALIAS_UNKNOWN) {
- retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, publicKeyOrCertName, ownerLabel, password, row);
+ retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, publicKeyOrCertName, ownerLabel, password, obj);
}
if (retCode == CKM_API_SUCCESS) {
- retCode = m_decider.getStore(row).getObject(row)->verify(params, message, signature);
+ retCode = obj->verify(params, message, signature);
}
} catch (const Exc::Exception &e) {
retCode = e.error();
bool exportFlag,
DB::Crypto & database);
+ Crypto::GObjUPtr rowToObject(
+ UserData& handler,
+ DB::Row row,
+ const Password& password);
+
int readDataHelper(
bool exportFlag,
const Credentials &cred,
const Name &name,
const Label &label,
const Password &password,
- DB::Row &row);
+ Crypto::GObjUPtr &obj);
+
+ int readDataHelper(
+ bool exportFlag,
+ const Credentials &cred,
+ DataType dataType,
+ const Name &name,
+ const Label &label,
+ const Password &password,
+ Crypto::GObjUPtr &obj,
+ DataType& objDataType);
int readDataHelper(
bool exportFlag,
const Name &name,
const Label &label,
const Password &password,
- DB::RowVector &rows);
+ Crypto::GObjUPtrVector &objs);
int createKeyAESHelper(
const Credentials &cred,
#include <iostream>
#include <fstream>
#include <utility>
+#include <climits>
#include <stdio.h>
#include <string.h>
#include <generic-backend/exception.h>
#include <sw-backend/internals.h>
+namespace CKM {
+
namespace {
const static int AES_CBC_KEY_SIZE = 32;
const static int AES_GCM_TAG_SIZE = 16;
-} // anonymous namespace
+// Encryption scheme flags (enable/disable specific encryption type, multiple choice)
+const int ENCR_BASE64 = 1 << 0;
+const int ENCR_APPKEY = 1 << 1;
+const int ENCR_PASSWORD = 1 << 2;
-namespace CKM {
+// Encryption order flags (single choice)
+const int ENCR_ORDER_OFFSET = 24;
+const int ENCR_ORDER_FILTER = INT_MAX << ENCR_ORDER_OFFSET; // 0xff000000
+const int ENCR_ORDER_CLEAR = ~ENCR_ORDER_FILTER; // 0x00ffffff
+/*
+ * ENCR_ORDER_V1 - v1 encryption order. Token returned from store is encrypted with app key and
+ * optionally by custom user password. In such form it is stored in db.
+ */
+const int ENCR_ORDER_V1 = CryptoLogic::ENCRYPTION_V1 << ENCR_ORDER_OFFSET;
+/*
+ * ENCR_ORDER_V2 - v2 encryption order. Stored data is optionally encrypted by store with
+ * user password. Returned token is encrypted with app key and stored in db.
+ */
+const int ENCR_ORDER_V2 = CryptoLogic::ENCRYPTION_V2 << ENCR_ORDER_OFFSET;
+
+} // anonymous namespace
CryptoLogic::CryptoLogic() {}
return civ;
}
-void CryptoLogic::encryptRow(const Password &password, DB::Row &row)
+void CryptoLogic::encryptRow(DB::Row &row)
{
try {
DB::Row crow = row;
crow.tag = dataPair.second;
- if (!password.empty()) {
- key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
-
- crow.data = Crypto::SW::Internals::encryptDataAes(AlgoType::AES_CBC, key, crow.data, crow.iv);
- crow.encryptionScheme |= ENCR_PASSWORD;
- }
-
encBase64(crow.data);
crow.encryptionScheme |= ENCR_BASE64;
encBase64(crow.iv);
+ crow.encryptionScheme &= ENCR_ORDER_CLEAR;
+ crow.encryptionScheme |= ENCR_ORDER_V2;
+
row = std::move(crow);
} catch(const CKM::Base64Encoder::Exception::Base &e) {
ThrowErr(Exc::InternalError, e.GetMessage());
}
}
+int CryptoLogic::getSchemeVersion(int encryptionScheme)
+{
+ return encryptionScheme >> ENCR_ORDER_OFFSET;
+}
+
void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
{
try {
decBase64(crow.data);
}
- if (crow.encryptionScheme & ENCR_PASSWORD) {
- key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
- crow.data = Crypto::SW::Internals::decryptDataAes(AlgoType::AES_CBC, key, crow.data, crow.iv);
+ if((crow.encryptionScheme >> ENCR_ORDER_OFFSET) == ENCR_ORDER_V2) {
+ if (crow.encryptionScheme & ENCR_APPKEY) {
+ key = m_keyMap[crow.ownerLabel];
+ crow.data = Crypto::SW::Internals::decryptDataAesGcm(key, crow.data, crow.iv, crow.tag);
+ }
+ } else {
+ if (crow.encryptionScheme & ENCR_PASSWORD) {
+ key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
+ crow.data = Crypto::SW::Internals::decryptDataAes(AlgoType::AES_CBC, key, crow.data, crow.iv);
+ }
+
+ if (crow.encryptionScheme & ENCR_APPKEY) {
+ key = m_keyMap[crow.ownerLabel];
+ crow.data = Crypto::SW::Internals::decryptDataAesGcm(key, crow.data, crow.iv, crow.tag);
+ }
}
-
- if (crow.encryptionScheme & ENCR_APPKEY) {
- key = m_keyMap[crow.ownerLabel];
- crow.data = Crypto::SW::Internals::decryptDataAesGcm(key, crow.data, crow.iv, crow.tag);
- }
-
if (static_cast<int>(crow.data.size()) < crow.dataSize) {
ThrowErr(Exc::AuthenticationFailed, "Decrypted row size mismatch");
}
virtual ~CryptoLogic(){}
void decryptRow(const Password &password, DB::Row &row);
- void encryptRow(const Password &password, DB::Row &row);
+ void encryptRow(DB::Row &row);
+
+ static int getSchemeVersion(int encryptionScheme);
bool haveKey(const Label &smackLabel);
void pushKey(const Label &smackLabel,
const RawBuffer &applicationKey);
void removeKey(const Label &smackLabel);
+ static const int ENCRYPTION_V1 = 0;
+ static const int ENCRYPTION_V2 = 1;
+
private:
+ // Encryption scheme flags (enable/disable specific encryption type, multiple choice)
static const int ENCR_BASE64 = 1 << 0;
static const int ENCR_APPKEY = 1 << 1;
static const int ENCR_PASSWORD = 1 << 2;
+ // Encryption order flags (single choice)
+ static const int ENCR_ORDER_CLEAR = 0x00ffffff;
+ static const int ENCR_ORDER_FILTER = ~ENCR_ORDER_CLEAR;
+ /*
+ * ENCR_ORDER_V1 - v1 encryption order. Token returned from store is encrypted with app key and
+ * optionally by custom user password. Is such form it is stored in db.
+ */
+ static const int ENCR_ORDER_V1 = ENCR_ORDER_CLEAR + 0;
+ /*
+ * ENCR_ORDER_V2 - v2 encryption order. Stored data is optionally encrypted by store with
+ * user password. Returned token is encrypted with app key and stored in db.
+ */
+ static const int ENCR_ORDER_V2 = ENCR_ORDER_CLEAR + 1;
+
std::map<Label, RawBuffer> m_keyMap;
RawBuffer generateRandIV() const;
" ?009"
" );";
+ const char *DB_CMD_OBJECT_UPDATE =
+ "UPDATE OR FAIL OBJECTS SET"
+ " algorithmType = ?003,"
+ " encryptionScheme = ?004,"
+ " iv = ?005,"
+ " dataSize = ?006,"
+ " data = ?007,"
+ " tag = ?008"
+ " WHERE idx IN (SELECT idx FROM NAMES WHERE name=?101 and label=?102)"
+ " AND dataType = ?002;";
+
const char *DB_CMD_OBJECT_SELECT_BY_NAME_AND_LABEL =
"SELECT * FROM [join_name_object_tables] "
" WHERE (dataType BETWEEN ?001 AND ?002) "
"Couldn't save Row");
}
+ void Crypto::updateRow(const Row &row) {
+ Try {
+ // transaction is present in the layer above
+ ObjectTable objectTable(this->m_connection);
+ objectTable.updateRow(row);
+ return;
+ } Catch(SqlConnection::Exception::SyntaxError) {
+ LogError("Couldn't prepare update statement");
+ } Catch(SqlConnection::Exception::InternalError) {
+ LogError("Couldn't execute update statement");
+ }
+ ThrowMsg(Crypto::Exception::InternalError,
+ "Couldn't update Row");
+ }
+
bool Crypto::deleteRow(
const Name &name,
const Label &ownerLabel)
insertObjectCommand->Step();
}
+
+ void Crypto::ObjectTable::updateRow(const Row &row)
+ {
+ SqlConnection::DataCommandUniquePtr updateObjectCommand =
+ m_connection->PrepareDataCommand(DB_CMD_OBJECT_UPDATE);
+ updateObjectCommand->BindInteger(2, static_cast<int>(row.dataType));
+ updateObjectCommand->BindInteger(3, static_cast<int>(row.algorithmType));
+ updateObjectCommand->BindInteger(4, row.encryptionScheme);
+ updateObjectCommand->BindBlob (5, row.iv);
+ updateObjectCommand->BindInteger(6, row.dataSize);
+ updateObjectCommand->BindBlob (7, row.data);
+ updateObjectCommand->BindBlob (8, row.tag);
+
+ // name table reference
+ updateObjectCommand->BindString (101, row.name.c_str());
+ updateObjectCommand->BindString (102, row.ownerLabel.c_str());
+
+ updateObjectCommand->Step();
+ }
} // namespace DB
} // namespace CKM
const Label &owner,
const RowVector &rows);
+ void updateRow(
+ const Row &row);
+
bool isNameLabelPresent(
const Name &name,
const Label &owner) const;
void addRow(
const Row &row);
+ void updateRow(
+ const Row &row);
private:
SqlConnection* m_connection;