From: Lukasz Kostyra Date: Wed, 20 Feb 2019 11:27:33 +0000 (+0100) Subject: tz-backend: Implement asymmetric operations X-Git-Tag: accepted/tizen/unified/20190602.221856~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=72e8c2c638e3631f01907cd361f094b39c47bac6;p=platform%2Fcore%2Fsecurity%2Fkey-manager.git tz-backend: Implement asymmetric operations Change-Id: Ie98b4e72addb257c2a8de1de57097fe077fff380 --- diff --git a/src/manager/common/data-type.cpp b/src/manager/common/data-type.cpp index 0bcf74f..8de9e15 100644 --- a/src/manager/common/data-type.cpp +++ b/src/manager/common/data-type.cpp @@ -181,6 +181,11 @@ bool DataType::isBinaryData() const return m_dataType == BINARY_DATA; } +bool DataType::isEllipticCurve() const +{ + return (m_dataType == KEY_ECDSA_PRIVATE) || (m_dataType == KEY_ECDSA_PUBLIC); +} + bool DataType::isInRange(int data) { if (data < static_cast(DB_FIRST)) diff --git a/src/manager/common/data-type.h b/src/manager/common/data-type.h index 30829e1..014869f 100644 --- a/src/manager/common/data-type.h +++ b/src/manager/common/data-type.h @@ -84,6 +84,7 @@ public: bool isKeyPublic() const; bool isCertificate() const; bool isBinaryData() const; + bool isEllipticCurve() const; static bool isInRange(int data); static DataType getChainDatatype(unsigned int index); diff --git a/src/manager/crypto/platform/decider.cpp b/src/manager/crypto/platform/decider.cpp index e14e9b6..4ffe83a 100644 --- a/src/manager/crypto/platform/decider.cpp +++ b/src/manager/crypto/platform/decider.cpp @@ -76,20 +76,30 @@ CryptoBackend chooseCryptoBackend(const DataParams& params) // TODO tz-backend could support the master key, but it would require // hardcoding a known key ID and querying TA whether the key is // reachable - if (params[0].encrypted) + if (params[0].encrypted) { return CryptoBackend::OpenSSL; + } // tz-backend allows only for data binary export - if (params[0].policy.extractable && !params[0].data.isBinaryData()) + if (params[0].policy.extractable && !params[0].data.isBinaryData()) { return CryptoBackend::OpenSSL; + } // Use TrustZone only with symmetric keys or unencrypted binary // data until asymmetric cryptography is implemented - if (!params[0].data.isSKey() && !params[0].data.isBinaryData()) + if (!params[0].data.isSKey() && !params[0].data.isBinaryData()) { return CryptoBackend::OpenSSL; + } } else if (params.size() == 2) { - LogDebug("2 keys - asymmetric encryption not yet supported, selecting OpenSSL"); - return CryptoBackend::OpenSSL; + // extractable private key can only be handled by OpenSSL + if (params[0].policy.extractable) { + return CryptoBackend::OpenSSL; + } + + // ECDSA algorithm is unsupported by GP API 1.0 + if (params[0].data.isEllipticCurve() || params[1].data.isEllipticCurve()) { + return CryptoBackend::OpenSSL; + } } try { diff --git a/src/manager/crypto/tz-backend/internals.cpp b/src/manager/crypto/tz-backend/internals.cpp index 71038e0..7b7b9be 100644 --- a/src/manager/crypto/tz-backend/internals.cpp +++ b/src/manager/crypto/tz-backend/internals.cpp @@ -24,18 +24,66 @@ #include #include #include +#include +#include +#include +#include #include #include +#include #include +#include + +namespace { + +using DSAPtr = std::unique_ptr>; + +CKM::RawBuffer extractBignumData(BIGNUM* bn) +{ + size_t size = static_cast(BN_num_bytes(bn)); + + CKM::RawBuffer result(size); + int ret = BN_bn2bin(bn, result.data()); + if (ret != static_cast(size)) { + ThrowErr(CKM::Exc::Crypto::InternalError, + "Error while converting bignums - expected " + + std::to_string(size) + " bytes of data, got " + std::to_string(ret)); + } + + return result; +} + +void generateDSAParams(const int sizeBits, CKM::RawBuffer &prime, + CKM::RawBuffer &subprime, CKM::RawBuffer &base) +{ + DSAPtr dsa(DSA_new(), DSA_free); + if (!dsa) { + ThrowErr(CKM::Exc::Crypto::InternalError, + "Failed to create DSA context for parameter gen"); + } + + if (DSA_generate_parameters_ex(dsa.get(), sizeBits, NULL, 0, NULL, NULL, NULL) == 0) { + ThrowErr(CKM::Exc::Crypto::InternalError, + "Failed to generate DSA params, err = " + std::to_string(ERR_get_error())); + } + + // at this stage dsa->p, dsa->q & dsa->r should contain our params + // extract them into buffers + prime = extractBignumData(dsa->p); + subprime = extractBignumData(dsa->q); + base = extractBignumData(dsa->g); +} + +} // namespace namespace CKM { namespace Crypto { namespace TZ { namespace Internals { -tz_algo_type getGenKeyType(AlgoType type) +tz_algo_type getGenSKeyType(AlgoType type) { switch (type) { @@ -52,6 +100,10 @@ tz_algo_type getAlgType(AlgoType type) case AlgoType::AES_CTR: return ALGO_AES_CTR; case AlgoType::AES_CFB: return ALGO_AES_CFB; case AlgoType::AES_GCM: return ALGO_AES_GCM; + case AlgoType::RSA_OAEP: return ALGO_RSA; + case AlgoType::RSA_SV: return ALGO_RSA_SV; + case AlgoType::DSA_SV: return ALGO_DSA_SV; + case AlgoType::ECDSA_SV: return ALGO_ECDSA_SV; default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported"); }; } @@ -65,11 +117,30 @@ tz_algo_type getAlgType(KeyType keyType) case KeyType::KEY_RSA_PUBLIC: case KeyType::KEY_RSA_PRIVATE: return ALGO_RSA_GEN; + case KeyType::KEY_DSA_PUBLIC: + case KeyType::KEY_DSA_PRIVATE: + return ALGO_DSA_GEN; + case KeyType::KEY_ECDSA_PUBLIC: + case KeyType::KEY_ECDSA_PRIVATE: + return ALGO_ECDSA_GEN; default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported"); }; } +tz_hash_type getHashType(HashAlgorithm hash) +{ + switch (hash) + { + case HashAlgorithm::SHA1: return HASH_SHA1; + case HashAlgorithm::SHA256: return HASH_SHA256; + case HashAlgorithm::SHA384: return HASH_SHA384; + case HashAlgorithm::SHA512: return HASH_SHA512; + default: + ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported"); + } +} + RawBuffer generateIV() { RawBuffer result; @@ -94,23 +165,84 @@ Data generateSKey(const CryptoAlgorithm &alg, } RawBuffer pwdBuf(pwd.begin(), pwd.end()); - TrustZoneContext::Instance().generateSKeyPwd(getGenKeyType(keyType), + TrustZoneContext::Instance().generateSKeyPwd(getGenSKeyType(keyType), pwdBuf, iv, keyBits, keyData.data, tag); } else { - TrustZoneContext::Instance().generateSKey(getGenKeyType(keyType), keyBits, + TrustZoneContext::Instance().generateSKey(getGenSKeyType(keyType), keyBits, keyData.data); } return keyData; } -DataPair generateAKey(const CryptoAlgorithm &, - const Password &, - const RawBuffer &) +DataPair generateAKey(const CryptoAlgorithm &alg, + const Password &pubPwd, + const Password &privPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwdIv, + RawBuffer &pubTag, + RawBuffer &privTag) { - ThrowErr(Exc::Crypto::OperationNotSupported, - "AKeys are not yet implemented in TrustZone backend"); + AlgoType keyType = unpack(alg, ParamName::ALGO_TYPE); + int keyBits = unpack(alg, ParamName::GEN_KEY_LEN); + + Data pubKeyData; + Data privKeyData; + + RawBuffer pubPwdBuf; + if (!pubPwd.empty()) + pubPwdBuf.assign(pubPwd.begin(), pubPwd.end()); + + RawBuffer privPwdBuf; + if (!privPwd.empty()) + privPwdBuf.assign(privPwd.begin(), privPwd.end()); + + switch (keyType) { + case AlgoType::RSA_GEN: { + pubKeyData.type = DataType(KeyType::KEY_RSA_PUBLIC); + privKeyData.type = DataType(KeyType::KEY_RSA_PRIVATE); + + TrustZoneContext::Instance().generateRSAKey(keyBits, + pubPwdBuf, + pubPwdIv, + privPwdBuf, + privPwdIv, + pubKeyData.data, + pubTag, + privKeyData.data, + privTag); + break; + } + case AlgoType::DSA_GEN: { + pubKeyData.type = DataType(KeyType::KEY_DSA_PUBLIC); + privKeyData.type = DataType(KeyType::KEY_DSA_PRIVATE); + + RawBuffer prime; + RawBuffer subprime; + RawBuffer base; + generateDSAParams(keyBits, prime, subprime, base); + TrustZoneContext::Instance().generateDSAKey(keyBits, + prime, + subprime, + base, + pubPwdBuf, + pubPwdIv, + privPwdBuf, + privPwdIv, + pubKeyData.data, + pubTag, + privKeyData.data, + privTag); + break; + } + default: { + ThrowErr(Exc::Crypto::InputParam, + "Invalid algo type provided for generateAKey function"); + } + } + + return DataPair(pubKeyData, privKeyData); } void destroyKey(const RawBuffer &key) @@ -131,6 +263,10 @@ RawBuffer importData(const Data &data, dataType = TYPE_SKEY; } else if (data.type.isBinaryData()) { dataType = TYPE_GENERIC_SECRET; + } else if (data.type.isKeyPrivate()) { + dataType = TYPE_AKEY_PRIVATE; + } else if (data.type.isKeyPublic()) { + dataType = TYPE_AKEY_PUBLIC; } else { ThrowErr(Exc::Crypto::DataTypeNotSupported, "Data type could not be impoted by tz-backend"); @@ -334,41 +470,93 @@ RawBuffer symmetricDecrypt(const RawBuffer &key, "Incorrect algorithm provided for symmetric crypto operation"); } -RawBuffer asymmetricEncrypt(const RawBuffer &, - const Pwd &, - const CryptoAlgorithm &, - const RawBuffer &) +RawBuffer asymmetricEncrypt(const RawBuffer &key, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &data) { + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + RawBuffer result; + + switch (algo) + { + case AlgoType::RSA_OAEP: { + TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT, + getAlgType(algo), + key, + pwd, + unpack(alg, ParamName::ED_IV), + data, + result); + return result; + } + default: + break; + } + ThrowErr(Exc::Crypto::OperationNotSupported, - "Asymmetric encryption is not yet supported on TrustZone backend"); + "Incorrect algorithm provided for asymmetric crypto operation"); } -RawBuffer asymmetricDecrypt(const RawBuffer &, - const Pwd &, - const CryptoAlgorithm &, - const RawBuffer &) +RawBuffer asymmetricDecrypt(const RawBuffer &key, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &cipher) { + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + RawBuffer result; + + switch (algo) + { + case AlgoType::RSA_OAEP: { + TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT, + getAlgType(algo), + key, + pwd, + unpack(alg, ParamName::ED_IV), + cipher, + result); + return result; + } + default: + break; + } + ThrowErr(Exc::Crypto::OperationNotSupported, - "Asymmetric encryption is not yet supported on TrustZone backend"); + "Incorrect algorithm provided for asymmetric crypto operation"); } -RawBuffer sign(const RawBuffer &, - const Pwd &, - const CryptoAlgorithm &, - const RawBuffer &) +RawBuffer sign(const RawBuffer &pkey, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &message) { - ThrowErr(Exc::Crypto::OperationNotSupported, - "Certificate signing is not yet supported on TrustZone backend"); + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + HashAlgorithm hash = unpack(alg, ParamName::SV_HASH_ALGO); + RawBuffer signature; + TrustZoneContext::Instance().executeSign(getAlgType(algo), + getHashType(hash), + pkey, + pwd, + message, + signature); + return signature; } -int verify(const RawBuffer &, - const Pwd &, - const CryptoAlgorithm &, - const RawBuffer &, - const RawBuffer &) +int verify(const RawBuffer &pkey, + const Pwd &pwd, + const CryptoAlgorithm &alg, + const RawBuffer &message, + const RawBuffer &signature) { - ThrowErr(Exc::Crypto::OperationNotSupported, - "Certificate signing is not yet supported on TrustZone backend"); + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + HashAlgorithm hash = unpack(alg, ParamName::SV_HASH_ALGO); + return TrustZoneContext::Instance().executeVerify(getAlgType(algo), + getHashType(hash), + pkey, + pwd, + message, + signature); } } // namespace Internals diff --git a/src/manager/crypto/tz-backend/internals.h b/src/manager/crypto/tz-backend/internals.h index 1c76f8d..b66351c 100644 --- a/src/manager/crypto/tz-backend/internals.h +++ b/src/manager/crypto/tz-backend/internals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2019 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,8 +40,12 @@ using KeyIdPair = std::pair; RawBuffer generateIV(); DataPair generateAKey(const CryptoAlgorithm &alg, - const Password &pwd, - const RawBuffer &iv); + const Password &pubPwd, + const Password &privPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwdIv, + RawBuffer &pubTag, + RawBuffer &privTag); Data generateSKey(const CryptoAlgorithm &alg, const Password &pwd, diff --git a/src/manager/crypto/tz-backend/store.cpp b/src/manager/crypto/tz-backend/store.cpp index 9549693..978a155 100644 --- a/src/manager/crypto/tz-backend/store.cpp +++ b/src/manager/crypto/tz-backend/store.cpp @@ -113,12 +113,15 @@ GObjUPtr Store::getObject(const Token &token, const Password &pass) ThrowErr(Exc::Crypto::AuthenticationFailed, "This token is not protected with password but passed one"); } - // TODO AKeys + + if (token.dataType.isKeyPrivate() || token.dataType.isKeyPublic()) + return make_unique(scheme, id, Pwd(pass, iv, tag), token.dataType); if (token.dataType.isSKey()) return make_unique(scheme, id, Pwd(pass, iv, tag), token.dataType); - // TODO certificate/chaincert + if (token.dataType.isCertificate() || token.dataType.isChainCert()) + return make_unique(scheme, id, Pwd(pass, iv, tag), token.dataType); if (token.dataType.isBinaryData()) { RawBuffer exported_data = Internals::getData(id, Pwd(pass, iv, tag)); @@ -129,11 +132,24 @@ GObjUPtr Store::getObject(const Token &token, const Password &pass) "This type of data is not supported by trustzone backend: ", (int)token.dataType); } -TokenPair Store::generateAKey(const CryptoAlgorithm &, const Password &, - const Password &) +TokenPair Store::generateAKey(const CryptoAlgorithm &alg, const Password &privPass, + const Password &pubPass) { - ThrowErr(Exc::Crypto::OperationNotSupported, - "AKey operations are not implemented on TrustZone backend!"); + RawBuffer pubIv, privIv; + RawBuffer pubTag, privTag; + if (!pubPass.empty()) { + pubIv = Internals::generateIV(); + } + if (!privPass.empty()) { + privIv = Internals::generateIV(); + } + + Internals::DataPair ret = Internals::generateAKey(alg, pubPass, privPass, pubIv, privIv, pubTag, privTag); + + return std::make_pair( + Token(m_backendId, ret.second.type, pack(ret.second.data, privPass, privIv, privTag)), + Token(m_backendId, ret.first.type, pack(ret.first.data, pubPass, pubIv, pubTag)) + ); } Token Store::generateSKey(const CryptoAlgorithm &alg, const Password &pass) @@ -151,7 +167,7 @@ Token Store::generateSKey(const CryptoAlgorithm &alg, const Password &pass) Token Store::import(const Data &data, const Password &pass, const EncryptionParams &e) { - if (!data.type.isBinaryData() && !data.type.isSKey()) + if (!data.type.isBinaryData() && !data.type.isKey()) ThrowErr(Exc::Crypto::DataTypeNotSupported, "Invalid data provided for import"); RawBuffer passIV; diff --git a/src/manager/crypto/tz-backend/tz-context.cpp b/src/manager/crypto/tz-backend/tz-context.cpp index f9b2f2b..0b54bb4 100644 --- a/src/manager/crypto/tz-backend/tz-context.cpp +++ b/src/manager/crypto/tz-backend/tz-context.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -32,6 +31,10 @@ #include #include +#include +#include +#include +#include namespace CKM { namespace Crypto { @@ -65,6 +68,41 @@ static std::string rawToHexString(const RawBuffer &raw) return dump; } +/* + * Maximum size for given key type in bytes according to key-manager-ta implementation. + * Note that they are greater than TEE Internal Core API v1.1.2.50 (Table 5-9) values. + */ +const std::unordered_map MAX_KEY_SIZE = { + { ALGO_RSA, 4096 / 8 }, + { ALGO_RSA_SV, 4096 / 8 }, + { ALGO_DSA_SV, 4096 / 8 } +}; + +void DeserializeKeyID(TrustZoneMemory &mem, RawBuffer &id) +{ + LogDebug("Deserializing key ID"); + + KM_SymmetricInput* output = nullptr; + int ret = KM_ParamsDeserializationInit(mem.Get()->buffer, mem.Get()->size, &output); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize key ID data deserialization: ", ret); + } + + KM_OutData* outData = nullptr; + ret = KM_ParamsDeserializeOutData(output, &outData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize key ID data: ", ret); + } + + if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "Deserialized invalid key ID"); + } + + // data_size should contain how much memory we actually took for our cipher operation + id.resize(outData->data_size); + memcpy(id.data(), outData->data, outData->data_size); +} + } // anonymous namespace TrustZoneContext::TrustZoneContext() @@ -144,24 +182,7 @@ void TrustZoneContext::generateSKey(tz_algo_type algo, op.params[1].memref.size = keyMemorySize; Execute(CMD_GENERATE_KEY, &op); - KM_SymmetricInput* output = nullptr; - int ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to initialize deserialization for generated key ID"); - } - - KM_OutData* outData = nullptr; - ret = KM_ParamsDeserializeOutData(output, &outData); - if (ret) { - ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize generated key ID"); - } - - if (outData == nullptr || outData->data_size != KM_KEY_ID_SIZE) { - ThrowErr(Exc::Crypto::InternalError, "Deserialized incorrect key ID"); - } - - keyId.resize(KM_KEY_ID_SIZE); - memcpy(keyId.data(), outData->data, KM_KEY_ID_SIZE); + DeserializeKeyID(keyMemory, keyId); } void TrustZoneContext::generateSKeyPwd(tz_algo_type algo, @@ -223,6 +244,8 @@ void TrustZoneContext::generateSKeyPwd(tz_algo_type algo, op.params[2].memref.size = keyMemory.Get()->size; Execute(CMD_GENERATE_KEY_PWD, &op); + DeserializeKeyID(keyMemory, keyId); + KM_SymmetricInput* output = nullptr; ret = KM_ParamsDeserializationInit(keyMemory.Get()->buffer, keyMemory.Get()->size, &output); if (ret) { @@ -256,9 +279,174 @@ void TrustZoneContext::generateSKeyPwd(tz_algo_type algo, memcpy(pwdTag.data(), tagData->data, Params::DEFAULT_AES_GCM_TAG_LEN_BYTES); } +void TrustZoneContext::GenerateAKey(tz_command commandId, + TZSerializer &sIn, + uint32_t keySizeBits, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag) +{ + uint32_t pubTagSize = 0; + uint32_t privTagSize = 0; + + uint32_t pubPwdExists = pubPwd.empty() ? 0 : 1; + sIn.Push(new TZSerializableFlag(pubPwdExists)); + if (pubPwdExists) { + sIn.Push(new TZSerializablePwdData(pubPwd, pubPwdIv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS)); + pubTagSize = (Params::DEFAULT_AES_GCM_TAG_LEN_BITS + 7) >> 3; + } + uint32_t privPwdExists = privPwd.empty() ? 0 : 1; + sIn.Push(new TZSerializableFlag(privPwdExists)); + if (privPwdExists) { + sIn.Push(new TZSerializablePwdData(privPwd, privPwdIv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS)); + privTagSize = (Params::DEFAULT_AES_GCM_TAG_LEN_BITS + 7) >> 3; + } + + TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT); + sIn.Serialize(inMemory); + + TZSerializer sOut; + sOut.Push(new TZSerializableBinary(KM_KEY_ID_SIZE)); + sOut.Push(new TZSerializableBinary(pubTagSize)); + sOut.Push(new TZSerializableBinary(KM_KEY_ID_SIZE)); + sOut.Push(new TZSerializableBinary(privTagSize)); + + TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_MEMREF_WHOLE, TEEC_NONE); + op.params[0].value.b = keySizeBits; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + op.params[2].memref.parent = outMemory.Get(); + op.params[2].memref.offset = 0; + op.params[2].memref.size = outMemory.Get()->size; + Execute(commandId, &op); + + sOut.Deserialize(outMemory); + + sOut.Pull(pubKeyId); + if (pubKeyId.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize public key ID"); + } + + if (pubPwdExists) { + sOut.Pull(pubKeyTag); + } + + sOut.Pull(privKeyId); + if (privKeyId.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize private key ID"); + } + + if (privPwdExists) { + sOut.Pull(privKeyTag); + } +} + +void TrustZoneContext::generateRSAKey(uint32_t keySizeBits, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag) +{ + // command ID = CMD_GENERATE_RSA_KEYPAIR + // + // TEEC_Operation layout: + // params: + // [0].value.b - key bit size + // [1].memref - reference to serialized buffer: + // flag marking the public key password presence, + // public key password data if the flag above is not 0, + // flag marking the private key password presence, + // public key private data if the flag above is not 0, + // output: + // [0].value.a - return code + // [2].memref + // Public key ID, + // public key tag if password was present, + // Private key ID, + // private key tag if password was present, + + TZSerializer sIn; + + GenerateAKey(CMD_GENERATE_RSA_KEYPAIR, + sIn, + keySizeBits, + pubPwd, + pubPwdIv, + privPwd, + privPwdIv, + pubKeyId, + pubKeyTag, + privKeyId, + privKeyTag); +} + +void TrustZoneContext::generateDSAKey(uint32_t keySizeBits, + const RawBuffer &prime, + const RawBuffer &subprime, + const RawBuffer &base, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag) +{ + // command ID = CMD_GENERATE_DSA_KEYPAIR + // + // TEEC_Operation layout: + // params: + // [0].value.b - key bit size + // [1].memref - reference to serialized buffer: + // prime, subprime, base, + // flag marking the public key password presence, + // public key password data if the flag above is not 0, + // flag marking the private key password presence, + // public key private data if the flag above is not 0, + // output: + // [0].value.a - return code + // [2].memref + // Public key ID, + // public key tag if password was present, + // Private key ID, + // private key tag if password was present, + + TZSerializer sIn; + sIn.Push(new TZSerializableBinary(prime)); + sIn.Push(new TZSerializableBinary(subprime)); + sIn.Push(new TZSerializableBinary(base)); + + GenerateAKey(CMD_GENERATE_DSA_KEYPAIR, + sIn, + keySizeBits, + pubPwd, + pubPwdIv, + privPwd, + privPwdIv, + pubKeyId, + pubKeyTag, + privKeyId, + privKeyTag); +} + void TrustZoneContext::executeCrypt(tz_command cmd, tz_algo_type algo, - const RawBuffer &key, + const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, const RawBuffer &data, @@ -275,9 +463,9 @@ void TrustZoneContext::executeCrypt(tz_command cmd, // [0].value.a - return code // [2].memref - serialized output buffer - if (key.size() != KM_KEY_ID_SIZE) { + if (keyId.size() != KM_KEY_ID_SIZE) { ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = " - + std::to_string(key.size()) + ")"); + + std::to_string(keyId.size()) + ")"); } KM_BufferSizeDesc bufSize; @@ -289,15 +477,22 @@ void TrustZoneContext::executeCrypt(tz_command cmd, bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); bufSize.iv_size = static_cast(iv.size()); - bufSize.key_id_size = static_cast(key.size()); + bufSize.key_id_size = static_cast(keyId.size()); uint32_t inMemorySize = KM_CalcBufferSize(bufSize); TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); - // decrypt operation does not require padding memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); - bufSize.out_size = static_cast((cmd == CMD_ENCRYPT) ? - data.size() + CIPHER_EXTRA_PADDING_SIZE : - data.size()); + + // decrypt operation does not require padding + bufSize.out_size = static_cast(data.size()); + if (cmd == CMD_ENCRYPT) { + if (algo == ALGO_RSA) { + // We don't know the key length + bufSize.out_size = MAX_KEY_SIZE.at(ALGO_RSA); + } else { + bufSize.out_size = static_cast(data.size() + CIPHER_EXTRA_PADDING_SIZE); + } + } uint32_t outMemorySize = KM_CalcBufferSize(bufSize); TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT); @@ -328,7 +523,7 @@ void TrustZoneContext::executeCrypt(tz_command cmd, ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret); } - ret = KM_ParamsSerializeKeyId(input, key.data(), key.size()); + ret = KM_ParamsSerializeKeyId(input, keyId.data(), keyId.size()); if (ret) { ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret); } @@ -362,7 +557,7 @@ void TrustZoneContext::executeCrypt(tz_command cmd, memcpy(out.data(), outData->data, outData->data_size); } -void TrustZoneContext::executeEncryptAE(const RawBuffer &key, +void TrustZoneContext::executeEncryptAE(const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, int tagSizeBits, @@ -382,7 +577,7 @@ void TrustZoneContext::executeEncryptAE(const RawBuffer &key, // [0].value.a - return code // [2].memref - output - if (key.size() != KM_KEY_ID_SIZE) { + if (keyId.size() != KM_KEY_ID_SIZE) { ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer"); } @@ -396,7 +591,7 @@ void TrustZoneContext::executeEncryptAE(const RawBuffer &key, bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); bufSize.iv_size = static_cast(iv.size()); - bufSize.key_id_size = static_cast(key.size()); + bufSize.key_id_size = static_cast(keyId.size()); bufSize.with_ae_data = true; bufSize.aad_size = static_cast(aad.size()); uint32_t inMemorySize = KM_CalcBufferSize(bufSize); @@ -435,7 +630,7 @@ void TrustZoneContext::executeEncryptAE(const RawBuffer &key, ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret); } - ret = KM_ParamsSerializeKeyId(input, key.data(), key.size()); + ret = KM_ParamsSerializeKeyId(input, keyId.data(), keyId.size()); if (ret) { ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret); } @@ -484,7 +679,7 @@ void TrustZoneContext::executeEncryptAE(const RawBuffer &key, } } -void TrustZoneContext::executeDecryptAE(const RawBuffer &key, +void TrustZoneContext::executeDecryptAE(const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, int tagSizeBits, @@ -504,7 +699,7 @@ void TrustZoneContext::executeDecryptAE(const RawBuffer &key, // [0].value.a - output size // [2].memref - output (decrypted data) - if (key.size() != KM_KEY_ID_SIZE) { + if (keyId.size() != KM_KEY_ID_SIZE) { ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer"); } @@ -517,7 +712,7 @@ void TrustZoneContext::executeDecryptAE(const RawBuffer &key, bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); bufSize.iv_size = static_cast(iv.size()); - bufSize.key_id_size = static_cast(key.size()); + bufSize.key_id_size = static_cast(keyId.size()); bufSize.with_ae_data = true; bufSize.aad_size = static_cast(aad.size()); bufSize.tag_size = static_cast(tag.size()); @@ -556,7 +751,7 @@ void TrustZoneContext::executeDecryptAE(const RawBuffer &key, ThrowErr(Exc::Crypto::InternalError, "Failed to serialize IV data for TZ crypto operation: ", ret); } - ret = KM_ParamsSerializeKeyId(input, key.data(), key.size()); + ret = KM_ParamsSerializeKeyId(input, keyId.data(), keyId.size()); if (ret) { ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ crypto operation: ", ret); } @@ -599,6 +794,197 @@ void TrustZoneContext::executeDecryptAE(const RawBuffer &key, memcpy(out.data(), outData->data, outData->data_size); } +void TrustZoneContext::executeSign(tz_algo_type algo, + tz_hash_type hash, + const RawBuffer &keyId, + const Pwd &pwd, + const RawBuffer &message, + RawBuffer &signature) +{ + // command ID = CMD_SIGN (from km_ta_defines.h) + // + // TEEC_Operation layout: + // input params: + // [0].value.a - algorithm type (tz_algo_type) + // [0].value.b - hash type (tz_hash_type) + // [1].memref - reference to serialized buffer: + // KM_ParamsSerializeInputData with data to sign + // KM_ParamsSerializeKeyId with key id + // output params: + // [0].value.a - return code + // [2].memref - reference to serialized buffer: + // KM_ParamsSerializeOutData with signature data + + if (keyId.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = " + + std::to_string(keyId.size()) + ")"); + } + + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.input_size = static_cast(message.size()); + bufSize.with_pwd_data = true; + bufSize.pwd_size = static_cast(pwd.getPassword().size()); + bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); + bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); + bufSize.key_id_size = static_cast(keyId.size()); + uint32_t inMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.out_size = MAX_KEY_SIZE.at(algo); + uint32_t outMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory outMemory(m_Context, outMemorySize, TEEC_MEM_OUTPUT); + + KM_SymmetricInput* input = nullptr; + int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ sign operations"); + } + + ret = KM_ParamsSerializeInputData(input, message.data(), message.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ sign operation: ", ret); + } + + uint32_t pwdTagSizeBits = pwd.getTag().size() * 8; + ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(), + pwd.getIV().data(), pwd.getIV().size(), + pwd.getTag().data(), pwd.getTag().size(), + Params::DERIVED_KEY_LENGTH_BITS, + Params::DERIVED_KEY_ITERATIONS, + pwdTagSizeBits); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ sign operation: ", ret); + } + + ret = KM_ParamsSerializeKeyId(input, keyId.data(), keyId.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ sign operation: ", ret); + } + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_MEMREF_WHOLE, TEEC_NONE); + op.params[0].value.a = algo; + op.params[0].value.b = hash; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + op.params[2].memref.parent = outMemory.Get(); + op.params[2].memref.offset = 0; + op.params[2].memref.size = outMemory.Get()->size; + Execute(CMD_SIGN, &op); + + KM_SymmetricInput* output = nullptr; + ret = KM_ParamsDeserializationInit(outMemory.Get()->buffer, outMemory.Get()->size, &output); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize output data deserialization: ", ret); + } + + KM_OutData* outData = nullptr; + ret = KM_ParamsDeserializeOutData(output, &outData); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to deserialize output data: ", ret); + } + + signature.resize(outData->data_size); + memcpy(signature.data(), outData->data, outData->data_size); +} + +int TrustZoneContext::executeVerify(tz_algo_type algo, + tz_hash_type hash, + const RawBuffer &keyId, + const Pwd &pwd, + const RawBuffer &message, + const RawBuffer &signature) +{ + // command ID = CMD_VERIFY (from km_ta_defines.h) + // + // TEEC_Operation layout: + // input params: + // [0].value.a - algorithm type (tz_algo_type) + // [0].value.b - hash type (tz_hash_type) + // [1].memref - reference to serialized buffer: + // KM_ParamsSerializeInputData with verify data (signature hidden in Tag data) + // KM_ParamsSerializeKeyId with key id + // output params: + // [0].value.a - return code + + if (keyId.size() != KM_KEY_ID_SIZE) { + ThrowErr(Exc::Crypto::InternalError, "TZ Backend received incorrect key buffer (size = " + + std::to_string(keyId.size()) + ")"); + } + + KM_BufferSizeDesc bufSize; + + memset(&bufSize, 0, sizeof(KM_BufferSizeDesc)); + bufSize.input_size = static_cast(message.size()); + bufSize.with_pwd_data = true; + bufSize.pwd_size = static_cast(pwd.getPassword().size()); + bufSize.pwd_iv_size = static_cast(pwd.getIV().size()); + bufSize.pwd_tag_size = static_cast(pwd.getTag().size()); + bufSize.key_id_size = static_cast(keyId.size()); + bufSize.tag_size = static_cast(signature.size()); + uint32_t inMemorySize = KM_CalcBufferSize(bufSize); + TrustZoneMemory inMemory(m_Context, inMemorySize, TEEC_MEM_INPUT); + + KM_SymmetricInput* input = nullptr; + int ret = KM_ParamsSerializationInit(inMemory.Get()->buffer, inMemory.Get()->size, &input); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to initialize data serialization for TZ sign operations"); + } + + ret = KM_ParamsSerializeInputData(input, message.data(), message.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize input data for TZ sign operation: ", ret); + } + + uint32_t pwdTagSizeBits = pwd.getTag().size() * 8; + ret = KM_ParamsSerializePwdData(input, pwd.getPassword().data(), pwd.getPassword().size(), + pwd.getIV().data(), pwd.getIV().size(), + pwd.getTag().data(), pwd.getTag().size(), + Params::DERIVED_KEY_LENGTH_BITS, + Params::DERIVED_KEY_ITERATIONS, + pwdTagSizeBits); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize password data for TZ sign operation: ", ret); + } + + ret = KM_ParamsSerializeKeyId(input, keyId.data(), keyId.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize key id data for TZ sign operation: ", ret); + } + + ret = KM_ParamsSerializeTagData(input, signature.data(), signature.size()); + if (ret) { + ThrowErr(Exc::Crypto::InternalError, "Failed to serialize signature data for TZ sign operation: ", ret); + } + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_WHOLE, + TEEC_NONE, TEEC_NONE); + op.params[0].value.a = algo; + op.params[0].value.b = hash; + op.params[1].memref.parent = inMemory.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = inMemory.Get()->size; + Execute(CMD_VERIFY, &op); + + int opRet = op.params[0].value.a; + switch (opRet) { + case KM_TA_SUCCESS: + return CKM_API_SUCCESS; + case KM_TA_ERROR_SIGNATURE: + LogWarning("Signature verification failed"); + return CKM_API_ERROR_VERIFICATION_FAILED; + default: + assert(false); // This condition should be checked inside Execute() function + ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", opRet); + } +} + void TrustZoneContext::executeDestroy(const RawBuffer &keyId) { // command ID = CMD_DESTROY_KEY (from km_ta_defines.h) @@ -888,14 +1274,15 @@ void TrustZoneContext::Execute(tz_command commandID, TEEC_Operation* op) } int ta_ret = op->params[0].value.a; - if (ta_ret != KM_TA_SUCCESS) { - switch (ta_ret) { - case KM_TA_ERROR_AUTH_FAILED: - // Authentication cipher failed - notify with proper exception - ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed"); - default: - ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret); - } + switch (ta_ret) { + case KM_TA_SUCCESS: + case KM_TA_ERROR_SIGNATURE: + break; + case KM_TA_ERROR_AUTH_FAILED: + // Authentication cipher failed - notify with proper exception + ThrowErr(Exc::AuthenticationFailed, "Crypto operation authentication failed"); + default: + ThrowErr(Exc::Crypto::InternalError, "Unknown TA error during operation: ", ta_ret); } } diff --git a/src/manager/crypto/tz-backend/tz-context.h b/src/manager/crypto/tz-backend/tz-context.h index 123c21e..05c336e 100644 --- a/src/manager/crypto/tz-backend/tz-context.h +++ b/src/manager/crypto/tz-backend/tz-context.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017 - 2019 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ #include #include #include +#include namespace CKM { namespace Crypto { @@ -48,6 +49,28 @@ public: const uint32_t pwdKeySizeBits, RawBuffer &keyId, RawBuffer &pwdTag); + void generateRSAKey(uint32_t keySizeBits, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag); + void generateDSAKey(uint32_t keySizeBits, + const RawBuffer &prime, + const RawBuffer &subprime, + const RawBuffer &base, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag); + void importData(uint32_t dataType, const RawBuffer &data, const Crypto::EncryptionParams &encData, @@ -60,13 +83,13 @@ public: void executeCrypt(tz_command cmd, tz_algo_type algo, - const RawBuffer &key, + const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, const RawBuffer &data, RawBuffer &out); - void executeEncryptAE(const RawBuffer &key, + void executeEncryptAE(const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, int tagSizeBits, @@ -74,7 +97,7 @@ public: const RawBuffer &data, RawBuffer &out, RawBuffer &tag); - void executeDecryptAE(const RawBuffer &key, + void executeDecryptAE(const RawBuffer &keyId, const Pwd &pwd, const RawBuffer &iv, int tagSizeBits, @@ -83,6 +106,19 @@ public: const RawBuffer &data, RawBuffer &out); + void executeSign(tz_algo_type algo, + tz_hash_type hash, + const RawBuffer &keyId, + const Pwd &pwd, + const RawBuffer &message, + RawBuffer &signature); + int executeVerify(tz_algo_type algo, + tz_hash_type hash, + const RawBuffer &keyId, + const Pwd &pwd, + const RawBuffer &message, + const RawBuffer &signature); + void executeDestroy(const RawBuffer &keyId); void getData(const RawBuffer &dataId, @@ -105,6 +141,18 @@ private: void Execute(tz_command commandID, TEEC_Operation* op); + void GenerateAKey(tz_command commandID, + TZSerializer &sIn, + uint32_t keySizeBits, + const RawBuffer &pubPwd, + const RawBuffer &pubPwdIv, + const RawBuffer &privPwd, + const RawBuffer &privPwdIv, + RawBuffer &pubKeyId, + RawBuffer &pubKeyTag, + RawBuffer &privKeyId, + RawBuffer &privKeyTag); + TEEC_Context m_Context; TEEC_Session m_Session;