Key derivation in TZ backend 25/290125/8
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Thu, 16 Mar 2023 11:45:45 +0000 (12:45 +0100)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 27 Mar 2023 08:50:30 +0000 (10:50 +0200)
Change-Id: I76a9b93d0e2deb82724ba941b97dcc4c995b08d7

src/manager/crypto/tz-backend/internals.cpp
src/manager/crypto/tz-backend/internals.h
src/manager/crypto/tz-backend/obj.cpp
src/manager/crypto/tz-backend/obj.h
src/manager/crypto/tz-backend/store.cpp
src/manager/crypto/tz-backend/store.h
src/manager/crypto/tz-backend/tz-context.cpp
src/manager/crypto/tz-backend/tz-context.h

index 0c8d537..b8abe24 100644 (file)
@@ -27,6 +27,7 @@
 #include <utils.h>
 #include <openssl/evp.h>
 #include <openssl/dsa.h>
+#include <openssl/ec.h>
 #include <openssl/bio.h>
 #include <openssl/bn.h>
 
@@ -34,6 +35,7 @@
 #include <tz-backend/tz-context.h>
 #include <openssl-error-handler.h>
 #include <km_ta_defines.h>
+#include <key-impl.h>
 
 #include <functional>
 
@@ -570,6 +572,88 @@ int verify(const RawBuffer &pkey,
                                                                                                        signature);
 }
 
+void deriveECDH(const RawBuffer &prvKey,
+                               const Pwd &prvKeyPwd,
+                               const RawBuffer &pubKey,
+                               const Password &secretPwd,
+                               const RawBuffer &secretPwdIV,
+                               RawBuffer &secretTag,
+                               const RawBuffer &secretHash)
+{
+       auto peerKey = std::make_shared<KeyImpl>(pubKey);
+       if (peerKey->getType() != KeyType::KEY_ECDSA_PUBLIC)
+               ThrowErr(Exc::Crypto::InputParam, "ECDH requires peer's public EC key");
+       auto peerEvp = peerKey->getEvpShPtr().get();
+       assert(peerEvp);
+
+       int subType = EVP_PKEY_type(EVP_PKEY_id(peerEvp));
+       if (subType != EVP_PKEY_EC)
+               ThrowErr(Exc::Crypto::InputParam, "Invalid key type: ", subType);
+
+       auto ecKey = EVP_PKEY_get0_EC_KEY(peerEvp);
+       if (!ecKey)
+               ThrowErr(Exc::Crypto::InternalError, "Can't get EC key");
+
+       auto ecPoint = EC_KEY_get0_public_key(ecKey);
+       if (!ecPoint)
+               ThrowErr(Exc::Crypto::InternalError, "Can't get EC public key");
+
+       auto ecGroup = EC_KEY_get0_group(ecKey);
+       if (!ecGroup)
+               ThrowErr(Exc::Crypto::InternalError, "Can't get EC group");
+
+       BIGNUM *x = BN_new();
+       BIGNUM *y = BN_new();
+       if (!EC_POINT_get_affine_coordinates(ecGroup, ecPoint, x, y, NULL))
+               ThrowErr(Exc::Crypto::InternalError, "Failed to get EC pub key coordinates");
+
+       auto xBuf = extractBignumData(x);
+       auto yBuf = extractBignumData(y);
+
+       RawBuffer secretPwdBuf(secretPwd.begin(), secretPwd.end());
+
+       TrustZoneContext::Instance().executeEcdh(prvKey,
+                                                                                        prvKeyPwd,
+                                                                                        xBuf,
+                                                                                        yBuf,
+                                                                                        secretPwdBuf,
+                                                                                        secretPwdIV,
+                                                                                        secretTag,
+                                                                                        secretHash);
+}
+
+void deriveKBKDF(const RawBuffer &secret,
+                                const CryptoAlgorithm &alg,
+                                const Password &keyPwd,
+                                const RawBuffer &keyPwdIV,
+                                RawBuffer &keyTag,
+                                const RawBuffer &keyHash)
+{
+       auto prf = unpack<KdfPrf>(alg, ParamName::KDF_PRF);
+       auto mode = unpack<KbkdfMode>(alg, ParamName::KBKDF_MODE);
+       auto location = unpack<KbkdfCounterLocation>(alg, ParamName::KBKDF_COUNTER_LOCATION);
+
+       size_t rlen = 32, llen = 32, dummy;
+       alg.getParam(ParamName::KBKDF_RLEN, rlen);
+       alg.getParam(ParamName::KBKDF_LLEN, llen);
+       bool noSeparator = alg.getParam(ParamName::KBKDF_NO_SEPARATOR, dummy);
+
+       RawBuffer keyPwdBuf(keyPwd.begin(), keyPwd.end());
+
+       TrustZoneContext::Instance().executeKbkdf(secret,
+                                                                                         prf,
+                                                                                         mode,
+                                                                                         location,
+                                                                                         rlen,
+                                                                                         llen,
+                                                                                         noSeparator,
+                                                                                         keyPwdBuf,
+                                                                                         keyPwdIV,
+                                                                                         keyTag,
+                                                                                         keyHash);
+}
+
+
 } // namespace Internals
 } // namespace TZ
 } // namespace Crypto
index 3322eee..bdfcc03 100644 (file)
@@ -118,6 +118,20 @@ int verify(const RawBuffer &pkey,
                const RawBuffer &message,
                const RawBuffer &signature);
 
+void deriveECDH(const RawBuffer &prvKey,
+                               const Pwd &prvKeyPwd,
+                               const RawBuffer &pubKey,
+                               const Password &secretPwd,
+                               const RawBuffer &secretPwdIV,
+                               RawBuffer &secretTag,
+                               const RawBuffer &secretHash);
+
+void deriveKBKDF(const RawBuffer &secret,
+                                const CryptoAlgorithm &alg,
+                                const Password &keyPwd,
+                                const RawBuffer &keyPwdIV,
+                                RawBuffer &keyTag,
+                                const RawBuffer &keyHash);
 } // namespace Internals
 } // namespace TZ
 } // namespace Crypto
index e6a91ee..86ac7a6 100644 (file)
@@ -19,7 +19,9 @@
  * @version    1.0
  */
 #include <generic-backend/exception.h>
+#include <generic-backend/algo-validation.h>
 #include <tz-backend/obj.h>
+#include <tz-backend/store.h>
 #include <tz-backend/internals.h>
 
 namespace CKM {
@@ -48,6 +50,24 @@ AlgoType key2algo(DataType type)
 }
 } // namespace anonymous
 
+Token BData::derive(const CryptoAlgorithm &alg, const Password &pass, const RawBuffer &hash)
+{
+       auto algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+       if (algo != AlgoType::KBKDF)
+               ThrowErr(Exc::Crypto::InputParam, "Wrong algorithm");
+
+       RawBuffer iv;
+       RawBuffer tag;
+       if (!pass.empty()) {
+               // IV is needed for key encryption
+               iv = Internals::generateIV();
+       }
+
+       Internals::deriveKBKDF(getBinary(), alg, pass, iv, tag, hash);
+
+       return Token(backendId(), DataType(KeyType::KEY_AES), Store::pack(hash, pass, iv, tag));
+}
+
 RawBuffer SKey::encrypt(const CryptoAlgorithm &alg, const RawBuffer &data)
 {
     return Internals::symmetricEncrypt(getBinary(), getPassword(), alg, data);
@@ -68,6 +88,29 @@ RawBuffer AKey::decrypt(const CryptoAlgorithm &alg, const RawBuffer &cipher)
        return Internals::asymmetricDecrypt(getBinary(), getPassword(), alg, cipher);
 }
 
+Token AKey::derive(const CryptoAlgorithm &alg, const Password &pass, const RawBuffer &hash)
+{
+       if (m_type != DataType::KEY_ECDSA_PRIVATE)
+               ThrowErr(Exc::Crypto::InputParam, "ECDH requires EC private key");
+
+       auto algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+       if (algo != AlgoType::ECDH)
+               ThrowErr(Exc::Crypto::InputParam, "Wrong algorithm");
+
+       auto pubKey = unpack<RawBuffer>(alg, ParamName::ECDH_PUBKEY);
+
+       RawBuffer iv;
+       RawBuffer tag;
+       if (!pass.empty()) {
+               // IV is needed for key encryption
+               iv = Internals::generateIV();
+       }
+
+       Internals::deriveECDH(getBinary(), getPassword(), pubKey, pass, iv, tag, hash);
+
+       return Token(backendId(), DataType::BINARY_DATA, Store::pack(hash, pass, iv, tag));
+}
+
 RawBuffer AKey::sign(
        const CryptoAlgorithm &alg,
        const RawBuffer &message)
index b4d77d8..77b3be8 100644 (file)
@@ -66,6 +66,7 @@ public:
        {
                return m_raw;
        }
+       Token derive(const CryptoAlgorithm &, const Password &, const RawBuffer &) override;
 
 protected:
        RawBuffer m_raw;
@@ -114,6 +115,7 @@ public:
                           const RawBuffer &sign) override;
        RawBuffer encrypt(const CryptoAlgorithm &, const RawBuffer &) override;
        RawBuffer decrypt(const CryptoAlgorithm &, const RawBuffer &) override;
+       Token derive(const CryptoAlgorithm &, const Password &, const RawBuffer &) override;
 };
 
 class Cert : public AKey {
index e7e58fb..0847166 100644 (file)
@@ -71,20 +71,6 @@ RawBuffer unpackData(const RawBuffer &packed)
        return data;
 }
 
-RawBuffer pack(const RawBuffer &keyId, const Password &pwd,
-                       const RawBuffer &iv, const RawBuffer &tag)
-{
-       // determine whether the key is password protected and store schema info
-       // we don't need to additionally encrypt key ID
-       int scheme = pwd.empty() ? EncryptionScheme::NONE : EncryptionScheme::PASSWORD;
-
-       if (scheme == EncryptionScheme::PASSWORD) {
-               return SerializeMessage(scheme, keyId, iv, tag);
-       } else {
-               return SerializeMessage(scheme, keyId);
-       }
-}
-
 } // namespace
 
 Store::Store(CryptoBackend backendId) :
@@ -204,6 +190,22 @@ void Store::destroy(const Token &token)
        Internals::destroyKey(id);
 }
 
+RawBuffer Store::pack(const RawBuffer &keyId,
+                                         const Password &pwd,
+                                         const RawBuffer &iv,
+                                         const RawBuffer &tag)
+{
+       // determine whether the key is password protected and store schema info
+       // we don't need to additionally encrypt key ID
+       int scheme = pwd.empty() ? EncryptionScheme::NONE : EncryptionScheme::PASSWORD;
+
+       if (scheme == EncryptionScheme::PASSWORD) {
+               return SerializeMessage(scheme, keyId, iv, tag);
+       } else {
+               return SerializeMessage(scheme, keyId);
+       }
+}
+
 } // namespace TZ
 } // namespace Crypto
 } // namespace CKM
index 21e3519..145c76b 100644 (file)
@@ -44,6 +44,11 @@ public:
                                                                   const RawBuffer &);
        virtual void destroy(const Token &);
 
+       static RawBuffer pack(const RawBuffer &keyId,
+                                                 const Password &pwd,
+                                                 const RawBuffer &iv,
+                                                 const RawBuffer &tag);
+
        // TODO device key ID is needed here to support importEncrypted
 };
 
index 8a054bf..efeb4a9 100644 (file)
@@ -657,6 +657,93 @@ void TrustZoneContext::destroyData(const RawBuffer &dataId)
        Execute(CMD_DESTROY_DATA, &op);
 }
 
+TZSerializablePwdData* makeSerializablePwd(const Pwd &pwd)
+{
+       auto &tag = pwd.getTag();
+       return new TZSerializablePwdData(pwd.getPassword(), pwd.getIV(), tag.size() * 8, tag);
+}
+
+void TrustZoneContext::executeEcdh(const RawBuffer &prvKeyId,
+                                                                  const Pwd &prvKeyPwd,
+                                                                  const RawBuffer &pubX,
+                                                                  const RawBuffer &pubY,
+                                                                  const RawBuffer &secretPwdBuf,
+                                                                  const RawBuffer &secretPwdIV,
+                                                                  RawBuffer &secretTag,
+                                                                  const RawBuffer &secretHash)
+{
+       // command ID = CMD_DERIVE
+       LogDebug("TrustZoneContext::executeEcdh");
+
+       auto sIn = makeSerializer(
+               prvKeyId, prvKeyPwd, pubX, pubY, EncPwd{secretPwdBuf, secretPwdIV}, secretHash);
+       TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
+       sIn.Serialize(inMemory);
+
+       TZSerializer sOut;
+       if (!secretPwdBuf.empty()) {
+               sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+       }
+
+       TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
+       if (!secretPwdBuf.empty())
+               op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
+       op.params[0].value.a = ALGO_ECDH_DRV;
+
+       Execute(CMD_DERIVE, &op);
+
+       if (!secretPwdBuf.empty()) {
+               sOut.Deserialize(outMemory);
+               sOut.Pull(secretTag);
+       }
+
+       LogDebug("Derived object ID is (hex): " << rawToHexString(secretHash));
+}
+
+void TrustZoneContext::executeKbkdf(const RawBuffer& secret,
+                                                                       KdfPrf prf,
+                                                                       KbkdfMode mode,
+                                                                       KbkdfCounterLocation location,
+                                                                       size_t rlen,
+                                                                       size_t llen,
+                                                                       bool noSeparator,
+                                                                       const RawBuffer &keyPwdBuf,
+                                                                       const RawBuffer &keyPwdIV,
+                                                                       RawBuffer &keyTag,
+                                                                       const RawBuffer &keyHash)
+{
+       // command ID = CMD_DERIVE
+       LogDebug("TrustZoneContext::executeKbkdf");
+
+       auto sIn = makeSerializer(
+               secret, prf, mode, location, rlen, llen, noSeparator, EncPwd{keyPwdBuf, keyPwdIV}, keyHash);
+       TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
+       sIn.Serialize(inMemory);
+
+       TZSerializer sOut;
+       if (!keyPwdBuf.empty()) {
+               sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+       }
+
+       TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
+       if (!keyPwdBuf.empty())
+               op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
+       op.params[0].value.a = ALGO_KBKDF_DRV;
+
+       Execute(CMD_DERIVE, &op);
+
+       if (!keyPwdBuf.empty()) {
+               sOut.Deserialize(outMemory);
+               sOut.Pull(keyTag);
+       }
+
+       LogDebug("Derived object ID is (hex): " << rawToHexString(keyHash));
+}
+
 void TrustZoneContext::Initialize()
 {
        TEEC_Operation op;
index b85186e..9f7ed02 100644 (file)
@@ -135,6 +135,27 @@ public:
 
        void destroyData(const RawBuffer &dataId);
 
+       void executeEcdh(const RawBuffer &prvKeyId,
+                                        const Pwd &prvKeyPwd,
+                                        const RawBuffer &pubX,
+                                        const RawBuffer &pubY,
+                                        const RawBuffer &secretPwdBuf,
+                                        const RawBuffer &secretPwdIV,
+                                        RawBuffer &secretTag,
+                                        const RawBuffer &secretHash);
+
+       void executeKbkdf(const RawBuffer& secret,
+                                         KdfPrf prf,
+                                         KbkdfMode mode,
+                                         KbkdfCounterLocation location,
+                                         size_t rlen,
+                                         size_t llen,
+                                         bool noSeparator,
+                                         const RawBuffer &keyPwdBuf,
+                                         const RawBuffer &keyPwdIV,
+                                         RawBuffer &keyTag,
+                                         const RawBuffer &keyHash);
+
 private:
        TrustZoneContext();
        ~TrustZoneContext();