namespace CKM {
namespace Crypto {
-namespace {
-
-#ifdef TZ_BACKEND_ENABLED
-CryptoBackend tryGetTzBackend()
-{
- try {
- LogDebug("Trying to open TA session...");
- TZ::Internals::TrustZoneContext::Instance();
- } catch (const Exc::Crypto::InternalError& e) {
- LogDebug("...failed. Selecting SW backend.");
- return CryptoBackend::OpenSSL;
- }
-
- LogDebug("...succeeded. Selecting TZ backend.");
- return CryptoBackend::TrustZone;
-}
-#endif
-
-template <class ForceOpenSSL>
-CryptoBackend chooseBackend(const Policy &policy, const ForceOpenSSL &forceOpenSSL)
-{
-#ifdef TZ_BACKEND_ENABLED
- switch (policy.backend) {
- case CKM::PolicyBackend::FORCE_SOFTWARE: return CryptoBackend::OpenSSL;
- case CKM::PolicyBackend::FORCE_HARDWARE: return CryptoBackend::TrustZone;
- case CKM::PolicyBackend::DEFAULT: break;
- }
- return forceOpenSSL() ? CryptoBackend::OpenSSL : tryGetTzBackend();
-#else // TZ_BACKEND_ENABLED
- (void)policy;
- (void)forceOpenSSL;
- return CryptoBackend::OpenSSL;
-#endif // TZ_BACKEND_ENABLED
-}
-
-} // namespace
-
Decider::Decider()
: m_swStore(CryptoBackend::OpenSSL)
#ifdef TZ_BACKEND_ENABLED
GStore &Decider::getStore(const Token &token)
{
- return getStore(token.backendId);
-};
-
-GStore &Decider::getStore(CryptoBackend cryptoBackend)
-{
GStore *gStore = NULL;
- if (cryptoBackend == CryptoBackend::OpenSSL)
+ if (token.backendId == CryptoBackend::OpenSSL)
gStore = &m_swStore;
#ifdef TZ_BACKEND_ENABLED
- if (cryptoBackend == CryptoBackend::TrustZone)
+ if (token.backendId == CryptoBackend::TrustZone)
gStore = &m_tzStore;
#endif
if (gStore)
return *gStore;
ThrowErr(Exc::Crypto::InternalError,
- "Backend not available. BackendId: ", (int)cryptoBackend);
+ "Backend not available. BackendId: ",
+ static_cast<int>(token.backendId));
+};
+
+GStore* Decider::tryBackend(CryptoBackend backend)
+{
+ switch(backend) {
+ case CryptoBackend::OpenSSL:
+ return &m_swStore;
+ case CryptoBackend::TrustZone:
+#ifdef TZ_BACKEND_ENABLED
+ try {
+ LogDebug("Trying to open TA session...");
+ TZ::Internals::TrustZoneContext::Instance();
+ LogDebug("...succeeded. Selecting TZ backend.");
+ return &m_tzStore;
+ } catch (const Exc::Crypto::InternalError& e) {
+ LogDebug("...failed.");
+ }
+#endif
+ default:
+ break;
+ }
+ return nullptr;
+}
+
+/*
+ * operation encrypted type extractable backend
+ * ----------------------------------------------
+ * import FALSE binary - TZ/SW
+ * skey FALSE TZ/SW
+ * skey TRUE SW
+ * akey - SW
+ * cert - SW
+ * TRUE binary - TZ
+ * skey FALSE TZ
+ * skey TRUE NONE
+ * akey - NONE
+ * cert - NONE
+ * generate - binary FALSE TZ/SW
+ * - binary TRUE SW
+ * - cert - NONE
+ * - skey FALSE TZ/SW
+ * - skey TRUE SW
+ * - akey FALSE TZ/SW
+ * - akey TRUE SW
+ */
+std::deque<CryptoBackend> Decider::getCompatibleBackends(DataType data,
+ const Policy &policy,
+ bool import,
+ bool encrypted)
+{
+ std::deque<CryptoBackend> backends;
+
+ auto addSW = [&]{
+ if (policy.backend != CKM::PolicyBackend::FORCE_HARDWARE)
+ backends.push_back(CryptoBackend::OpenSSL);
+ };
+
+ auto addTZ = [&]{
+#ifdef TZ_BACKEND_ENABLED
+ if (policy.backend != CKM::PolicyBackend::FORCE_SOFTWARE)
+ backends.push_front(CryptoBackend::TrustZone);
+#endif
+ };
+
+ if (import) {
+ if (!encrypted)
+ addSW();
+
+ if (data.isBinaryData() || (data.isSKey() && !policy.extractable))
+ addTZ();
+ } else { // generate/derive
+ assert(!encrypted);
+
+ if (!data.isCertificate() && !data.isChainCert()) {
+ addSW();
+
+ if (!policy.extractable)
+ addTZ();
+ }
+ }
+ return backends;
}
-GStore &Decider::getStore(DataType data, const Policy &policy, bool encrypted)
+GStore &Decider::getStore(DataType data, const Policy &policy, bool import, bool encrypted)
{
- return getStore(chooseBackend(policy, [&]{
- return !encrypted && !data.isBinaryData() && (
- // tz-backend allows only for data binary export
- policy.extractable ||
- // Use TrustZone only with symmetric keys or unencrypted binary
- // data until asymmetric cryptography is implemented
- !data.isSKey()
- );
- }));
+ auto backends = getCompatibleBackends(data, policy, import, encrypted);
+ if (backends.empty())
+ ThrowErr(Exc::Crypto::InputParam, "No backend supports this operation.");
+
+ for (auto id : backends) {
+ auto backend = tryBackend(id);
+ if (backend != nullptr)
+ return *backend;
+ }
+ ThrowErr(Exc::Crypto::InternalError, "Failed to connect to a compatible backend.");
}
-GStore &Decider::getStore(const Policy &policyPrv)
+bool Decider::checkStore(CryptoBackend requestedBackend, DataType data, const Policy &policy, bool import)
{
- // extractable private key can only be handled by OpenSSL
- return getStore(chooseBackend(policyPrv, [&]{ return policyPrv.extractable; }));
+ auto backends = getCompatibleBackends(data, policy, import);
+ for (auto id : backends) {
+ if (id == requestedBackend)
+ return true;
+ }
+ return false;
}
} // namespace Crypto
if (retCode != CKM_API_SUCCESS)
return retCode;
- Crypto::GStore &store = m_decider.getStore(data.type, policy, !encParams.iv.empty());
+ Crypto::GStore &store = m_decider.getStore(data.type, policy, true, !encParams.iv.empty());
Token token;
if (encParams.iv.empty()) {
bool exportable = policyPrv.extractable || policyPub.extractable;
Policy lessRestricted(Password(), exportable, policyPrv.backend);
- TokenPair keys = m_decider.getStore(policyPrv).generateAKey(
+ // For now any asymmetric key will do. If necessary we can extract it from keyGenParams.
+ TokenPair keys = m_decider.getStore(DataType::DB_KEY_FIRST, policyPrv, false).generateAKey(
keyGenParams,
policyPrv.password,
policyPub.password,
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).generateSKey(keyGenAlgorithm,
- policy.password,
- digest);
+
+ auto& store = m_decider.getStore(DataType::KEY_AES, policy, false);
+ Token key = store.generateSKey(keyGenAlgorithm, policy.password, digest);
dbOp.finalize(std::move(key), policy);
return CKM_API_SUCCESS;
return SerializeMessage(msgID, tryRet([&] {
// Get key/secret for internal service use. It won't be exported to the client
Crypto::GObjUPtr obj;
+ DataType objType;
int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST,
- secretName, secretOwner, secretPassword, obj);
+ secretName, secretOwner, secretPassword, obj, objType);
if (retCode != CKM_API_SUCCESS) {
if (retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN)
return retCode;
retCode = readDataHelper(false, cred, DataType::BINARY_DATA,
- secretName, secretOwner, secretPassword, obj);
+ secretName, secretOwner, secretPassword, obj, objType);
if (retCode != CKM_API_SUCCESS)
return retCode;
}
if (ret != CKM_API_SUCCESS)
return ret;
+ // ECDH (private key) -> binary secret, KBKDF -> symmetric key
+ DataType newKeyType = objType.isKeyPrivate() ? DataType::BINARY_DATA : DataType::KEY_AES;
+ if (!m_decider.checkStore(obj->backendId(), newKeyType, newKeyPolicy, false)) {
+ LogDebug("Can't import the derived key to backend " <<
+ static_cast<int>(obj->backendId()) << " with given policy");
+ return CKM_API_ERROR_INPUT_PARAM;
+ }
+
// derive
Token derived = obj->derive(params, newKeyPolicy.password, digest);
if (retCode != CKM_API_SUCCESS)
return retCode;
+ if (!m_decider.checkStore(wrappingKey->backendId(), keyType, policy, true)) {
+ LogDebug("Can't import the wrapped key to backend " <<
+ static_cast<int>(wrappingKey->backendId()) << " with given policy");
+ return CKM_API_ERROR_INPUT_PARAM;
+ }
+
Token token = wrappingKey->unwrap(params,
Crypto::Data(keyType, std::move(wrappedKey)),
policy.password,