Add context cleanup command for TZ
[platform/core/security/key-manager.git] / src / manager / crypto / tz-backend / internals.cpp
1 /*
2  *  Copyright (c) 2017-2020 Samsung Electronics Co., Ltd. All rights reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  */
16 /*
17  * @file       internals.h
18  * @author     Krzysztof Dynowski (k.dynowski@samsung.com)
19  * @author     Lukasz Kostyra (l.kostyra@samsung.com)
20  * @version    1.0
21  */
22
23 #include <generic-backend/exception.h>
24 #include <generic-backend/algo-validation.h>
25 #include <generic-backend/crypto-params.h>
26 #include <dpl/log/log.h>
27 #include <utils.h>
28 #include <openssl/evp.h>
29 #include <openssl/dsa.h>
30 #include <openssl/ec.h>
31 #include <openssl/bio.h>
32 #include <openssl/bn.h>
33
34 #include <tz-backend/internals.h>
35 #include <tz-backend/tz-context.h>
36 #include <openssl-error-handler.h>
37 #include <km_ta_defines.h>
38 #include <key-impl.h>
39
40 #include <functional>
41
42 #ifndef __has_cpp_attribute
43 #define __has_cpp_attribute(_) 0
44 #endif
45
46 #if __has_cpp_attribute(fallthrough)
47 #define fallthru [[fallthrough]]
48 #else
49 #define fallthru ((void)0)
50 #endif
51
52 namespace {
53
54 CKM::RawBuffer extractBignumData(const BIGNUM* bn)
55 {
56         size_t size = static_cast<size_t>(BN_num_bytes(bn));
57
58         CKM::RawBuffer result(size);
59         int ret = BN_bn2bin(bn, result.data());
60         if (ret != static_cast<int>(size)) {
61                 ThrowErr(CKM::Exc::Crypto::InternalError,
62                         "Error while converting bignums - expected "
63                         + std::to_string(size) + " bytes of data, got " + std::to_string(ret));
64         }
65
66         return result;
67 }
68
69 void generateDSAParams(const int sizeBits, CKM::RawBuffer &prime,
70                                         CKM::RawBuffer &subprime, CKM::RawBuffer &base)
71 {
72         auto dsa = uptr<DSA_free>(DSA_new());
73         if (!dsa) {
74                 ThrowErr(CKM::Exc::Crypto::InternalError,
75                         "Failed to create DSA context for parameter gen");
76         }
77
78         if (DSA_generate_parameters_ex(dsa.get(), sizeBits, NULL, 0, NULL, NULL, NULL) == 0) {
79                 ThrowErr(CKM::Exc::Crypto::InternalError,
80                         "Failed to generate DSA params, err = " + std::to_string(ERR_get_error()));
81         }
82
83         // at this stage dsa->p, dsa->q & dsa->r should contain our params
84         // extract them into buffers
85         const BIGNUM *p, *q, *g;
86         DSA_get0_pqg(dsa.get(), &p, &q, &g);
87         prime = extractBignumData(p);
88         subprime = extractBignumData(q);
89         base = extractBignumData(g);
90 }
91
92 tz_data_type toTzDataType(const CKM::DataType dataType) {
93         switch (dataType) {
94         case CKM::DataType::BINARY_DATA:       return TYPE_GENERIC_SECRET;
95         case CKM::DataType::KEY_AES:           return TYPE_SKEY;
96         case CKM::DataType::KEY_DSA_PRIVATE:   return TYPE_AKEY_PRIVATE_DSA;
97         case CKM::DataType::KEY_RSA_PRIVATE:   return TYPE_AKEY_PRIVATE_RSA;
98         case CKM::DataType::KEY_ECDSA_PRIVATE: return TYPE_AKEY_PRIVATE_EC;
99         case CKM::DataType::KEY_DSA_PUBLIC:    return TYPE_AKEY_PUBLIC_DSA;
100         case CKM::DataType::KEY_RSA_PUBLIC:    return TYPE_AKEY_PUBLIC_RSA;
101         case CKM::DataType::KEY_ECDSA_PUBLIC:  return TYPE_AKEY_PUBLIC_EC;
102         default:
103                 ThrowErr(CKM::Exc::Crypto::DataTypeNotSupported,
104                         "Data type could not be imported by tz-backend");
105         }
106 }
107
108 tz_ec toTzEc(CKM::ElipticCurve ec)
109 {
110         switch(ec) {
111         case CKM::ElipticCurve::prime192v1: return EC_NIST_P192;
112         case CKM::ElipticCurve::prime256v1: return EC_NIST_P256;
113         case CKM::ElipticCurve::secp384r1: return EC_NIST_P384;
114         default: ThrowErr(CKM::Exc::Crypto::DataTypeNotSupported, "EC not supported by tz-backend");
115         }
116 }
117
118 tz_prf toTzPrf(CKM::KdfPrf prf)
119 {
120         switch(prf) {
121         case CKM::KdfPrf::HMAC_SHA256: return PRF_HMAC_SHA256;
122         case CKM::KdfPrf::HMAC_SHA384: return PRF_HMAC_SHA384;
123         case CKM::KdfPrf::HMAC_SHA512: return PRF_HMAC_SHA512;
124         default: ThrowErr(CKM::Exc::Crypto::DataTypeNotSupported, "PRF not supported by tz-backend");
125         }
126 }
127
128 tz_kbkdf_mode toTzKbkdfMode(CKM::KbkdfMode mode)
129 {
130         switch(mode) {
131         case CKM::KbkdfMode::COUNTER: return KBKDF_MODE_COUNTER;
132         default:
133                 ThrowErr(CKM::Exc::Crypto::DataTypeNotSupported, "KBKDF mode not supported by tz-backend");
134         }
135 }
136
137 tz_kbkdf_ctr_loc toTzCtrLoc(CKM::KbkdfCounterLocation loc)
138 {
139         switch(loc) {
140         case CKM::KbkdfCounterLocation::BEFORE_FIXED: return KBKDF_LOC_BEFORE_FIXED;
141         case CKM::KbkdfCounterLocation::AFTER_FIXED: return KBKDF_LOC_AFTER_FIXED;
142         case CKM::KbkdfCounterLocation::MIDDLE_FIXED: return KBKDF_LOC_MIDDLE_FIXED;
143         default:
144                 ThrowErr(CKM::Exc::Crypto::DataTypeNotSupported,
145                         "KBKDF counter location not supported by tz-backend");
146         }
147 }
148
149 } // namespace
150
151 namespace CKM {
152 namespace Crypto {
153 namespace TZ {
154 namespace Internals {
155
156 namespace {
157
158 tz_algo_type getGenSKeyType(AlgoType type)
159 {
160         switch (type)
161         {
162         case AlgoType::AES_GEN: return ALGO_AES_GEN;
163         default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported");
164         }
165 }
166
167 tz_algo_type getAlgType(AlgoType type)
168 {
169         switch (type)
170         {
171         case AlgoType::AES_CBC: return ALGO_AES_CBC;
172         case AlgoType::AES_CTR: return ALGO_AES_CTR;
173         case AlgoType::AES_CFB: return ALGO_AES_CFB;
174         case AlgoType::AES_GCM: return ALGO_AES_GCM;
175         case AlgoType::RSA_OAEP: return ALGO_RSA;
176         case AlgoType::RSA_SV: return ALGO_RSA_SV;
177         case AlgoType::DSA_SV: return ALGO_DSA_SV;
178         case AlgoType::ECDSA_SV: return ALGO_ECDSA_SV;
179         default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported");
180         };
181 }
182
183 tz_hash_type getHashType(HashAlgorithm hash)
184 {
185         switch (hash)
186         {
187         case HashAlgorithm::SHA1: return HASH_SHA1;
188         case HashAlgorithm::SHA256: return HASH_SHA256;
189         case HashAlgorithm::SHA384: return HASH_SHA384;
190         case HashAlgorithm::SHA512: return HASH_SHA512;
191         default:
192                 ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported");
193         }
194 }
195
196 void decompose(const CryptoAlgorithm &alg,
197                            AlgoType &algo,
198                            uint32_t &ctrLenOrTagSizeBits,
199                            RawBuffer &iv,
200                            RawBuffer &aad)
201 {
202         algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
203         switch (algo) {
204                 case AlgoType::AES_CTR:
205                         iv = unpack<RawBuffer>(alg, ParamName::ED_IV);
206                         ctrLenOrTagSizeBits = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
207                         // counter length is in bits
208                         if (ctrLenOrTagSizeBits != Params::DEFAULT_AES_IV_LEN * 8) {
209                                 LogError("CTR length invalid: " << std::to_string(ctrLenOrTagSizeBits));
210                                 ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
211                         }
212                         break;
213                 case AlgoType::AES_CBC:
214                         iv = unpack<RawBuffer>(alg, ParamName::ED_IV);
215                         break;
216                 case AlgoType::AES_CFB:
217                         iv = unpack<RawBuffer>(alg, ParamName::ED_IV);
218                         break;
219                 case AlgoType::AES_GCM:
220                         iv = unpack<RawBuffer>(alg, ParamName::ED_IV);
221                         ctrLenOrTagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
222                         alg.getParam(ParamName::ED_TAG_LEN, ctrLenOrTagSizeBits);
223                         alg.getParam(ParamName::ED_AAD, aad);
224                         break;
225                 case AlgoType::RSA_OAEP:
226                         break;
227                 default:
228                         ThrowErr(Exc::Crypto::InputParam, "Invalid decryption algorithm");
229                         break;
230         }
231 }
232
233 } // namespace
234
235 RawBuffer generateIV()
236 {
237         RawBuffer result;
238         TrustZoneContext::Instance().generateIV(result);
239         return result;
240 }
241
242 void generateSKey(const CryptoAlgorithm &alg,
243                                 const Password &pwd,
244                                 const RawBuffer &iv,
245                                 RawBuffer &tag,
246                                 const RawBuffer &hash)
247 {
248         AlgoType keyType = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
249         int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
250
251         if (!pwd.empty()) {
252                 if (iv.empty()) {
253                         ThrowErr(Exc::InputParam, "Key generation with password encryption requires an IV");
254                 }
255
256                 RawBuffer pwdBuf(pwd.begin(), pwd.end());
257                 TrustZoneContext::Instance().generateSKeyPwd(getGenSKeyType(keyType),
258                                                                                                         pwdBuf, iv, keyBits,
259                                                                                                         tag, hash);
260         } else {
261                 TrustZoneContext::Instance().generateSKey(getGenSKeyType(keyType), keyBits,
262                                                                                                 hash);
263         }
264
265 }
266
267 AlgoType generateAKey(const CryptoAlgorithm &alg,
268                                         const Password &pubPwd,
269                                         const Password &privPwd,
270                                         const RawBuffer &pubPwdIv,
271                                         const RawBuffer &privPwdIv,
272                                         RawBuffer &pubTag,
273                                         RawBuffer &privTag,
274                                         const RawBuffer &hashPriv,
275                                         const RawBuffer &hashPub)
276 {
277         AlgoType keyType = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
278
279         RawBuffer pubPwdBuf;
280         if (!pubPwd.empty())
281                 pubPwdBuf.assign(pubPwd.begin(), pubPwd.end());
282
283         RawBuffer privPwdBuf;
284         if (!privPwd.empty())
285                 privPwdBuf.assign(privPwd.begin(), privPwd.end());
286
287         switch (keyType) {
288         case AlgoType::RSA_GEN: {
289                 int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
290                 TrustZoneContext::Instance().generateRSAKey(keyBits,
291                                                                                                         pubPwdBuf,
292                                                                                                         pubPwdIv,
293                                                                                                         privPwdBuf,
294                                                                                                         privPwdIv,
295                                                                                                         pubTag,
296                                                                                                         privTag,
297                                                                                                         hashPriv,
298                                                                                                         hashPub);
299                 break;
300         }
301         case AlgoType::DSA_GEN: {
302                 int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
303                 RawBuffer prime;
304                 RawBuffer subprime;
305                 RawBuffer base;
306                 generateDSAParams(keyBits, prime, subprime, base);
307                 TrustZoneContext::Instance().generateDSAKey(keyBits,
308                                                                                                         prime,
309                                                                                                         subprime,
310                                                                                                         base,
311                                                                                                         pubPwdBuf,
312                                                                                                         pubPwdIv,
313                                                                                                         privPwdBuf,
314                                                                                                         privPwdIv,
315                                                                                                         pubTag,
316                                                                                                         privTag,
317                                                                                                         hashPriv,
318                                                                                                         hashPub);
319                 break;
320         }
321         case AlgoType::ECDSA_GEN: {
322                 CKM::ElipticCurve ec = unpack<CKM::ElipticCurve>(alg, ParamName::GEN_EC);
323                 TrustZoneContext::Instance().generateECKey(toTzEc(ec),
324                                                                                                    pubPwdBuf,
325                                                                                                    pubPwdIv,
326                                                                                                    privPwdBuf,
327                                                                                                    privPwdIv,
328                                                                                                    pubTag,
329                                                                                                    privTag,
330                                                                                                    hashPriv,
331                                                                                                    hashPub);
332                 break;
333         }
334         default: {
335                 ThrowErr(Exc::Crypto::InputParam,
336                         "Invalid algo type provided for generateAKey function");
337         }
338         }
339
340         return keyType;
341 }
342
343 void destroyKey(const RawBuffer &keyId)
344 {
345         TrustZoneContext::Instance().executeDestroy(keyId);
346 }
347
348 void importData(const Data &data,
349                                          const EncryptionParams &encData,
350                                          const Password &pwd,
351                                          const RawBuffer &pwdIV,
352                                          RawBuffer &tag,
353                                          const RawBuffer &hash)
354 {
355
356         const auto dataType = toTzDataType(data.type);
357
358         RawBuffer pwdBuf(pwd.begin(), pwd.end());
359         uint32_t keySizeBits = data.data.size() * 8;
360         TrustZoneContext::Instance().importData(dataType,
361                                                                                 data.data,
362                                                                                 encData,
363                                                                                 pwdBuf,
364                                                                                 pwdIV,
365                                                                                 keySizeBits,
366                                                                                 tag,
367                                                                                 hash);
368 }
369
370 void importWrappedKey(const RawBuffer &wrappingKeyId,
371                                           const Pwd &wrappingKeyPwd,
372                                           const CryptoAlgorithm &alg,
373                                           const Data &encryptedKey,
374                                           const Password &encryptedKeyPassword,
375                                           const RawBuffer &encryptedKeyIV,
376                                           RawBuffer &encryptedKeyTag,
377                                           const RawBuffer &encryptedKeyId)
378 {
379         RawBuffer encryptedKeyPwdBuf(encryptedKeyPassword.begin(), encryptedKeyPassword.end());
380
381         AlgoType algo;
382         uint32_t ctrLenOrTagSizeBits = 0;
383         RawBuffer iv;
384         RawBuffer aad;
385         decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad);
386
387         // TODO it is awful!
388         TrustZoneContext::Instance().importWrappedKey(wrappingKeyId,
389                                                                                                   wrappingKeyPwd,
390                                                                                                   getAlgType(algo),
391                                                                                                   iv,
392                                                                                                   ctrLenOrTagSizeBits,
393                                                                                                   aad,
394                                                                                                   toTzDataType(encryptedKey.type),
395                                                                                                   encryptedKey.data,
396                                                                                                   encryptedKeyPwdBuf,
397                                                                                                   encryptedKeyIV,
398                                                                                                   encryptedKeyTag,
399                                                                                                   encryptedKeyId);
400 }
401
402 RawBuffer exportWrappedKey(const RawBuffer &wrappingKeyId,
403                                                    const Pwd &wrappingKeyPwd,
404                                                    const CryptoAlgorithm &alg,
405                                                    const RawBuffer &keyToWrapId,
406                                                    const Pwd &keyToWrapPwd,
407                                                    const DataType &keyToWrapType)
408 {
409         AlgoType algo;
410         uint32_t ctrLenOrTagSizeBits = 0;
411         RawBuffer iv;
412         RawBuffer aad;
413         decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad);
414
415         // TODO it is awful!
416         return TrustZoneContext::Instance().exportWrappedKey(wrappingKeyId,
417                                                                                                                  wrappingKeyPwd,
418                                                                                                                  getAlgType(algo),
419                                                                                                                  iv,
420                                                                                                                  ctrLenOrTagSizeBits,
421                                                                                                                  aad,
422                                                                                                                  keyToWrapId,
423                                                                                                                  keyToWrapPwd,
424                                                                                                                  toTzDataType(keyToWrapType));
425 }
426
427 RawBuffer getData(const RawBuffer &dataId,
428                                   const Pwd &pwd,
429                                   const DataType &type)
430 {
431         RawBuffer result;
432         TrustZoneContext::Instance().getData(dataId,
433                                  pwd,
434                                  toTzDataType(type),
435                                  result);
436         return result;
437 }
438
439 void destroyData(const RawBuffer &dataId)
440 {
441         TrustZoneContext::Instance().destroyData(dataId);
442 }
443
444 BufferPair encryptDataAesGcm(const RawBuffer &keyId,
445                                                         const Pwd &pwd,
446                                                         const RawBuffer &iv,
447                                                         int tagSize,
448                                                         const RawBuffer &data,
449                                                         const RawBuffer &aad)
450 {
451         RawBuffer result;
452         RawBuffer tag;
453
454         TrustZoneContext::Instance().executeEncryptAE(keyId, pwd, iv, tagSize,
455                                                                                                 aad, data, result, tag);
456
457         return std::make_pair(result, tag);
458 }
459
460 RawBuffer encryptDataAesGcmPacked(const RawBuffer &keyId,
461                                                                 const Pwd &pwd,
462                                                                 const RawBuffer &iv,
463                                                                 int tagSize,
464                                                                 const RawBuffer &data,
465                                                                 const RawBuffer &aad)
466 {
467         auto pair = encryptDataAesGcm(keyId, pwd, iv, tagSize, data, aad);
468         std::copy(pair.second.begin(), pair.second.end(),
469                         std::back_inserter(pair.first));
470         return pair.first;
471 }
472
473 RawBuffer decryptDataAesGcm(const RawBuffer &keyId,
474                                                         const Pwd &pwd,
475                                                         const RawBuffer &iv,
476                                                         int tagSizeBits,
477                                                         const RawBuffer &tag,
478                                                         const RawBuffer &data,
479                                                         const RawBuffer &aad)
480 {
481         RawBuffer result;
482
483         TrustZoneContext::Instance().executeDecryptAE(keyId, pwd, iv, tagSizeBits,
484                                                                                                 tag, aad, data, result);
485
486         return result;
487 }
488
489 RawBuffer decryptDataAesGcmPacked(const RawBuffer &keyId,
490                                                                 const Pwd &pwd,
491                                                                 const RawBuffer &iv,
492                                                                 int tagSizeBits,
493                                                                 const RawBuffer &data,
494                                                                 const RawBuffer &aad)
495 {
496         int tagSizeBytes = tagSizeBits / 8;
497         if (tagSizeBytes > static_cast<int>(data.size()))
498                 ThrowErr(Exc::Crypto::InputParam, "Wrong size of tag");
499
500         auto tagPos = data.data() + data.size() - tagSizeBytes;
501         return decryptDataAesGcm(keyId,
502                                                         pwd,
503                                                         iv,
504                                                         tagSizeBits,
505                                                         RawBuffer(tagPos, data.data() + data.size()),
506                                                         RawBuffer(data.data(), tagPos),
507                                                         aad);
508 }
509
510
511 RawBuffer symmetricEncrypt(const RawBuffer &keyId,
512                                                 const Pwd &pwd,
513                                                 const CryptoAlgorithm &alg,
514                                                 const RawBuffer &data)
515 {
516         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
517         uint64_t ctrLen = 0;
518
519         switch (algo) {
520                 case AlgoType::AES_CTR: {
521                         ctrLen = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
522                         // counter length is in bits
523                         if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) {
524                                 LogError("CTR length invalid: " << std::to_string(ctrLen));
525                                 ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
526                         }
527                         // no break here, we still need to slide down to executeCrypt
528                         fallthru;
529                 }
530                 case AlgoType::AES_CBC:
531                 case AlgoType::AES_CFB: {
532                         RawBuffer result;
533                         TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
534                                                                                                         getAlgType(algo),
535                                                                                                         keyId,
536                                                                                                         pwd,
537                                                                                                         unpack<RawBuffer>(alg, ParamName::ED_IV),
538                                                                                                         data,
539                                                                                                         result);
540                         return result;
541                 }
542                 case AlgoType::AES_GCM: {
543                         int tagLenBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
544                         alg.getParam(ParamName::ED_TAG_LEN, tagLenBits);
545                         RawBuffer aad;
546                         alg.getParam(ParamName::ED_AAD, aad);
547                         return encryptDataAesGcmPacked(keyId,
548                                                                                 pwd,
549                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
550                                                                                 tagLenBits,
551                                                                                 data,
552                                                                                 aad);
553                 }
554                 default:
555                         break;
556         }
557
558         ThrowErr(Exc::Crypto::OperationNotSupported,
559                                 "Incorrect algorithm provided for symmetric crypto operation");
560 }
561
562 RawBuffer symmetricDecrypt(const RawBuffer &keyId,
563                                                 const Pwd &pwd,
564                                                 const CryptoAlgorithm &alg,
565                                                 const RawBuffer &data)
566 {
567         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
568         uint64_t ctrLen = 0;
569
570         switch (algo) {
571                 case AlgoType::AES_CTR: {
572                         ctrLen = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
573                         // counter length is in bits
574                         if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) {
575                                 LogError("CTR length invalid: " << std::to_string(ctrLen));
576                                 ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
577                         }
578                         // no break here, we still need to slide down to executeCrypt
579                         fallthru;
580                 }
581                 case AlgoType::AES_CBC:
582                 case AlgoType::AES_CFB: {
583                         RawBuffer result;
584                         TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
585                                                                                                         getAlgType(algo),
586                                                                                                         keyId,
587                                                                                                         pwd,
588                                                                                                         unpack<RawBuffer>(alg, ParamName::ED_IV),
589                                                                                                         data,
590                                                                                                         result);
591                         return result;
592                 }
593                 case AlgoType::AES_GCM: {
594                         int tagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
595                         alg.getParam(ParamName::ED_TAG_LEN, tagSizeBits);
596                         RawBuffer aad;
597                         alg.getParam(ParamName::ED_AAD, aad);
598                         return decryptDataAesGcmPacked(keyId,
599                                                                                 pwd,
600                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
601                                                                                 tagSizeBits,
602                                                                                 data,
603                                                                                 aad);
604                 }
605                 default:
606                         break;
607         }
608
609         ThrowErr(Exc::Crypto::OperationNotSupported,
610                                 "Incorrect algorithm provided for symmetric crypto operation");
611 }
612
613 RawBuffer asymmetricEncrypt(const RawBuffer &keyId,
614                                                         const Pwd &pwd,
615                                                         const CryptoAlgorithm &alg,
616                                                         const RawBuffer &data)
617 {
618         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
619         RawBuffer result;
620
621         switch (algo)
622         {
623         case AlgoType::RSA_OAEP: {
624                 TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
625                                                                                                 getAlgType(algo),
626                                                                                                 keyId,
627                                                                                                 pwd,
628                                                                                                 result, // unused dummy
629                                                                                                 data,
630                                                                                                 result);
631                 return result;
632         }
633         default:
634                 break;
635         }
636
637         ThrowErr(Exc::Crypto::OperationNotSupported,
638                                 "Incorrect algorithm provided for asymmetric crypto operation");
639 }
640
641 RawBuffer asymmetricDecrypt(const RawBuffer &keyId,
642                                                         const Pwd &pwd,
643                                                         const CryptoAlgorithm &alg,
644                                                         const RawBuffer &cipher)
645 {
646         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
647         RawBuffer result;
648
649         switch (algo)
650         {
651         case AlgoType::RSA_OAEP: {
652                 TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
653                                                                                                 getAlgType(algo),
654                                                                                                 keyId,
655                                                                                                 pwd,
656                                                                                                 result, // unused dummy
657                                                                                                 cipher,
658                                                                                                 result);
659                 return result;
660         }
661         default:
662                 break;
663         }
664
665         ThrowErr(Exc::Crypto::OperationNotSupported,
666                                 "Incorrect algorithm provided for asymmetric crypto operation");
667 }
668
669 uint32_t initCipher(const RawBuffer &keyId,
670                                         const Pwd &pwd,
671                                         const CryptoAlgorithm &alg,
672                                         bool encrypt)
673 {
674         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
675
676         switch (algo)
677         {
678         case AlgoType::AES_GCM: {
679                 int tagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
680                 alg.getParam(ParamName::ED_TAG_LEN, tagSizeBits);
681                 RawBuffer aad;
682                 alg.getParam(ParamName::ED_AAD, aad);
683                 return TrustZoneContext::Instance().initGcmCipher(encrypt ? CIPHER_ENCRYPT : CIPHER_DECRYPT,
684                                                                                                                   keyId,
685                                                                                                                   pwd,
686                                                                                                                   unpack<RawBuffer>(alg, ParamName::ED_IV),
687                                                                                                                   tagSizeBits,
688                                                                                                                   aad);
689         }
690         case AlgoType::AES_CBC:
691         case AlgoType::AES_CTR:
692         case AlgoType::AES_CFB:
693                 // TODO optionally implement above modes as well
694         default:
695                 break;
696         };
697
698         ThrowErr(Exc::Crypto::OperationNotSupported,
699                          "Incorrect algorithm provided for symmetric crypto operation");
700 }
701
702 void addAAD(uint32_t opId,
703                         const RawBuffer &aad)
704 {
705         TrustZoneContext::Instance().addGcmAAD(opId, aad);
706 }
707
708 RawBuffer updateCipher(uint32_t opId,
709                                            const RawBuffer &data)
710 {
711         return TrustZoneContext::Instance().updateGcmCipher(opId, data);
712 }
713
714 RawBuffer finalizeCipher(uint32_t opId,
715                                                  const RawBuffer &data)
716 {
717         return TrustZoneContext::Instance().finalizeGcmCipher(opId, data);
718 }
719
720 void cleanupCipher(uint32_t opId)
721 {
722         return TrustZoneContext::Instance().cleanupCipher(opId);
723 }
724
725 RawBuffer sign(const RawBuffer &pkeyId,
726                         const Pwd &pwd,
727                         const CryptoAlgorithm &alg,
728                         const RawBuffer &message)
729 {
730         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
731         HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
732         if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE)
733                 ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option");
734
735         RawBuffer signature;
736         TrustZoneContext::Instance().executeSign(getAlgType(algo),
737                                                                                         getHashType(hash),
738                                                                                         pkeyId,
739                                                                                         pwd,
740                                                                                         message,
741                                                                                         signature);
742         return signature;
743 }
744
745 int verify(const RawBuffer &pkeyId,
746                 const Pwd &pwd,
747                 const CryptoAlgorithm &alg,
748                 const RawBuffer &message,
749                 const RawBuffer &signature)
750 {
751         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
752         HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
753         if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE)
754                 ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option");
755
756         return TrustZoneContext::Instance().executeVerify(getAlgType(algo),
757                                                                                                         getHashType(hash),
758                                                                                                         pkeyId,
759                                                                                                         pwd,
760                                                                                                         message,
761                                                                                                         signature);
762 }
763
764 void deriveECDH(const RawBuffer &prvKeyId,
765                                 const Pwd &prvKeyPwd,
766                                 const RawBuffer &pubKey,
767                                 const Password &secretPwd,
768                                 const RawBuffer &secretPwdIV,
769                                 RawBuffer &secretTag,
770                                 const RawBuffer &secretHash)
771 {
772         auto peerKey = std::make_shared<KeyImpl>(pubKey);
773         if (peerKey->getType() != KeyType::KEY_ECDSA_PUBLIC)
774                 ThrowErr(Exc::Crypto::InputParam, "ECDH requires peer's public EC key");
775         auto peerEvp = peerKey->getEvpShPtr().get();
776         assert(peerEvp);
777
778         int subType = EVP_PKEY_type(EVP_PKEY_id(peerEvp));
779         if (subType != EVP_PKEY_EC)
780                 ThrowErr(Exc::Crypto::InputParam, "Invalid key type: ", subType);
781
782         auto ecKey = EVP_PKEY_get0_EC_KEY(peerEvp);
783         if (!ecKey)
784                 ThrowErr(Exc::Crypto::InternalError, "Can't get EC key");
785
786         auto ecPoint = EC_KEY_get0_public_key(ecKey);
787         if (!ecPoint)
788                 ThrowErr(Exc::Crypto::InternalError, "Can't get EC public key");
789
790         auto ecGroup = EC_KEY_get0_group(ecKey);
791         if (!ecGroup)
792                 ThrowErr(Exc::Crypto::InternalError, "Can't get EC group");
793
794         BIGNUM *x = BN_new();
795         BIGNUM *y = BN_new();
796         if (!EC_POINT_get_affine_coordinates(ecGroup, ecPoint, x, y, NULL))
797                 ThrowErr(Exc::Crypto::InternalError, "Failed to get EC pub key coordinates");
798
799         auto xBuf = extractBignumData(x);
800         auto yBuf = extractBignumData(y);
801
802         RawBuffer secretPwdBuf(secretPwd.begin(), secretPwd.end());
803
804         TrustZoneContext::Instance().executeEcdh(prvKeyId,
805                                                                                          prvKeyPwd,
806                                                                                          xBuf,
807                                                                                          yBuf,
808                                                                                          secretPwdBuf,
809                                                                                          secretPwdIV,
810                                                                                          secretTag,
811                                                                                          secretHash);
812 }
813
814 void deriveKBKDF(const RawBuffer &secretId,
815                                  const Pwd &secretPwd,
816                                  const CryptoAlgorithm &alg,
817                                  const Password &keyPwd,
818                                  const RawBuffer &keyPwdIV,
819                                  RawBuffer &keyTag,
820                                  const RawBuffer &keyHash)
821 {
822         RawBuffer label, context, fixed;
823         size_t length;
824         alg.getParam(ParamName::KDF_LEN, length);
825         alg.getParam(ParamName::KBKDF_LABEL, label);
826         alg.getParam(ParamName::KBKDF_CONTEXT, context);
827         alg.getParam(ParamName::KBKDF_FIXED_INPUT, fixed);
828         auto prf = unpack<KdfPrf>(alg, ParamName::KDF_PRF);
829         auto mode = unpack<KbkdfMode>(alg, ParamName::KBKDF_MODE);
830         auto location = unpack<KbkdfCounterLocation>(alg, ParamName::KBKDF_COUNTER_LOCATION);
831
832         size_t rlen = 32, llen = 32, dummy;
833         alg.getParam(ParamName::KBKDF_RLEN, rlen);
834         alg.getParam(ParamName::KBKDF_LLEN, llen);
835         bool noSeparator = alg.getParam(ParamName::KBKDF_NO_SEPARATOR, dummy);
836
837         RawBuffer keyPwdBuf(keyPwd.begin(), keyPwd.end());
838
839         TrustZoneContext::Instance().executeKbkdf(secretId,
840                                                                                           secretPwd,
841                                                                                           length,
842                                                                                           label,
843                                                                                           context,
844                                                                                           fixed,
845                                                                                           toTzPrf(prf),
846                                                                                           toTzKbkdfMode(mode),
847                                                                                           toTzCtrLoc(location),
848                                                                                           rlen,
849                                                                                           llen,
850                                                                                           noSeparator,
851                                                                                           keyPwdBuf,
852                                                                                           keyPwdIV,
853                                                                                           keyTag,
854                                                                                           keyHash);
855 }
856
857 size_t maxChunkSize()
858 {
859         return TrustZoneContext::Instance().getMaxChunkSize();
860 }
861
862 } // namespace Internals
863 } // namespace TZ
864 } // namespace Crypto
865 } // namespace CKM