Migrate tz_backend to openssl 1.1
[platform/core/security/key-manager.git] / src / manager / crypto / tz-backend / internals.cpp
index d2753bc..ae67c8c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2017 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.
 #include <generic-backend/algo-validation.h>
 #include <generic-backend/crypto-params.h>
 #include <dpl/log/log.h>
+#include <openssl/evp.h>
+#include <openssl/dsa.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
 
 #include <tz-backend/internals.h>
 #include <tz-backend/tz-context.h>
+#include <openssl-error-handler.h>
 #include <km_ta_defines.h>
 
+#include <functional>
+
+namespace {
+
+using DSAPtr = std::unique_ptr<DSA, std::function<void(DSA*)>>;
+
+CKM::RawBuffer extractBignumData(const BIGNUM* bn)
+{
+       size_t size = static_cast<size_t>(BN_num_bytes(bn));
+
+       CKM::RawBuffer result(size);
+       int ret = BN_bn2bin(bn, result.data());
+       if (ret != static_cast<int>(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
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+       prime = extractBignumData(dsa->p);
+       subprime = extractBignumData(dsa->q);
+       base = extractBignumData(dsa->g);
+#else
+       const BIGNUM *p, *q, *g;
+       DSA_get0_pqg(dsa.get(), &p, &q, &g);
+       prime = extractBignumData(p);
+       subprime = extractBignumData(q);
+       base = extractBignumData(g);
+#endif
+}
+
+} // 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 +108,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 +125,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;
@@ -86,7 +165,7 @@ Data generateSKey(const CryptoAlgorithm &alg,
        int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
 
        Data keyData;
-       keyData.type = DataType(keyType);
+       keyData.type = DataType(KeyType::KEY_AES);
 
        if (!pwd.empty()) {
                if (iv.empty()) {
@@ -94,23 +173,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<AlgoType>(alg, ParamName::ALGO_TYPE);
+       int keyBits = unpack<int>(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)
@@ -118,24 +258,59 @@ void destroyKey(const RawBuffer &key)
        TrustZoneContext::Instance().executeDestroy(key);
 }
 
-RawBuffer importKey(const Data &data,
-                                       const Password &pwd,
-                                       const RawBuffer &iv,
-                                       RawBuffer &tag)
+RawBuffer importData(const Data &data,
+                                        const EncryptionParams &encData,
+                                        const Password &pwd,
+                                        const RawBuffer &pwdIV,
+                                        RawBuffer &tag)
 {
-       tz_algo_type algo = getAlgType(data.type);
+
+       uint32_t dataType;
+
+       if (data.type.isSKey()) {
+               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");
+       }
+
        RawBuffer result;
 
        RawBuffer pwdBuf(pwd.begin(), pwd.end());
-       TrustZoneContext::Instance().importKey(algo,
+       uint32_t keySizeBits = data.data.size() * 8;
+       TrustZoneContext::Instance().importData(dataType,
                                                                                data.data,
+                                                                               encData,
                                                                                pwdBuf,
-                                                                               iv,
+                                                                               pwdIV,
+                                                                               keySizeBits,
+                                                                               Params::DERIVED_KEY_LENGTH_BITS,
                                                                                result,
                                                                                tag);
        return result;
 }
 
+RawBuffer getData(const RawBuffer &dataId,
+                                 const Pwd &pwd)
+{
+       RawBuffer result;
+       TrustZoneContext::Instance().getData(dataId,
+                                pwd,
+                                result);
+       return result;
+}
+
+void destroyData(const RawBuffer &dataId)
+{
+       TrustZoneContext::Instance().destroyData(dataId);
+}
+
 BufferPair encryptDataAesGcm(const RawBuffer &key,
                                                        const Pwd &pwd,
                                                        const RawBuffer &iv,
@@ -303,41 +478,99 @@ 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<AlgoType>(alg, ParamName::ALGO_TYPE);
+       RawBuffer result;
+
+       switch (algo)
+       {
+       case AlgoType::RSA_OAEP: {
+               TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
+                                                                                               getAlgType(algo),
+                                                                                               key,
+                                                                                               pwd,
+                                                                                               unpack<RawBuffer>(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<AlgoType>(alg, ParamName::ALGO_TYPE);
+       RawBuffer result;
+
+       switch (algo)
+       {
+       case AlgoType::RSA_OAEP: {
+               TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
+                                                                                               getAlgType(algo),
+                                                                                               key,
+                                                                                               pwd,
+                                                                                               unpack<RawBuffer>(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<AlgoType>(alg, ParamName::ALGO_TYPE);
+       HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
+       if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE)
+               ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option");
+
+       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<AlgoType>(alg, ParamName::ALGO_TYPE);
+       HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
+       if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE)
+               ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option");
+
+       return TrustZoneContext::Instance().executeVerify(getAlgType(algo),
+                                                                                                       getHashType(hash),
+                                                                                                       pkey,
+                                                                                                       pwd,
+                                                                                                       message,
+                                                                                                       signature);
 }
 
 } // namespace Internals