Add type parameter to "get" commands
[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                         alg.getParam(ParamName::ED_TAG_LEN, ctrLenOrTagSizeBits);
222                         alg.getParam(ParamName::ED_AAD, aad);
223                         break;
224                 case AlgoType::RSA_OAEP:
225                         break;
226                 default:
227                         ThrowErr(Exc::Crypto::InputParam, "Invalid decryption algorithm");
228                         break;
229         }
230 }
231
232 } // namespace
233
234 RawBuffer generateIV()
235 {
236         RawBuffer result;
237         TrustZoneContext::Instance().generateIV(result);
238         return result;
239 }
240
241 void generateSKey(const CryptoAlgorithm &alg,
242                                 const Password &pwd,
243                                 const RawBuffer &iv,
244                                 RawBuffer &tag,
245                                 const RawBuffer &hash)
246 {
247         AlgoType keyType = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
248         int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
249
250         if (!pwd.empty()) {
251                 if (iv.empty()) {
252                         ThrowErr(Exc::InputParam, "Key generation with password encryption requires an IV");
253                 }
254
255                 RawBuffer pwdBuf(pwd.begin(), pwd.end());
256                 TrustZoneContext::Instance().generateSKeyPwd(getGenSKeyType(keyType),
257                                                                                                         pwdBuf, iv, keyBits,
258                                                                                                         tag, hash);
259         } else {
260                 TrustZoneContext::Instance().generateSKey(getGenSKeyType(keyType), keyBits,
261                                                                                                 hash);
262         }
263
264 }
265
266 AlgoType generateAKey(const CryptoAlgorithm &alg,
267                                         const Password &pubPwd,
268                                         const Password &privPwd,
269                                         const RawBuffer &pubPwdIv,
270                                         const RawBuffer &privPwdIv,
271                                         RawBuffer &pubTag,
272                                         RawBuffer &privTag,
273                                         const RawBuffer &hashPriv,
274                                         const RawBuffer &hashPub)
275 {
276         AlgoType keyType = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
277
278         RawBuffer pubPwdBuf;
279         if (!pubPwd.empty())
280                 pubPwdBuf.assign(pubPwd.begin(), pubPwd.end());
281
282         RawBuffer privPwdBuf;
283         if (!privPwd.empty())
284                 privPwdBuf.assign(privPwd.begin(), privPwd.end());
285
286         switch (keyType) {
287         case AlgoType::RSA_GEN: {
288                 int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
289                 TrustZoneContext::Instance().generateRSAKey(keyBits,
290                                                                                                         pubPwdBuf,
291                                                                                                         pubPwdIv,
292                                                                                                         privPwdBuf,
293                                                                                                         privPwdIv,
294                                                                                                         pubTag,
295                                                                                                         privTag,
296                                                                                                         hashPriv,
297                                                                                                         hashPub);
298                 break;
299         }
300         case AlgoType::DSA_GEN: {
301                 int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
302                 RawBuffer prime;
303                 RawBuffer subprime;
304                 RawBuffer base;
305                 generateDSAParams(keyBits, prime, subprime, base);
306                 TrustZoneContext::Instance().generateDSAKey(keyBits,
307                                                                                                         prime,
308                                                                                                         subprime,
309                                                                                                         base,
310                                                                                                         pubPwdBuf,
311                                                                                                         pubPwdIv,
312                                                                                                         privPwdBuf,
313                                                                                                         privPwdIv,
314                                                                                                         pubTag,
315                                                                                                         privTag,
316                                                                                                         hashPriv,
317                                                                                                         hashPub);
318                 break;
319         }
320         case AlgoType::ECDSA_GEN: {
321                 CKM::ElipticCurve ec = unpack<CKM::ElipticCurve>(alg, ParamName::GEN_EC);
322                 TrustZoneContext::Instance().generateECKey(toTzEc(ec),
323                                                                                                    pubPwdBuf,
324                                                                                                    pubPwdIv,
325                                                                                                    privPwdBuf,
326                                                                                                    privPwdIv,
327                                                                                                    pubTag,
328                                                                                                    privTag,
329                                                                                                    hashPriv,
330                                                                                                    hashPub);
331                 break;
332         }
333         default: {
334                 ThrowErr(Exc::Crypto::InputParam,
335                         "Invalid algo type provided for generateAKey function");
336         }
337         }
338
339         return keyType;
340 }
341
342 void destroyKey(const RawBuffer &keyId)
343 {
344         TrustZoneContext::Instance().executeDestroy(keyId);
345 }
346
347 void importData(const Data &data,
348                                          const EncryptionParams &encData,
349                                          const Password &pwd,
350                                          const RawBuffer &pwdIV,
351                                          RawBuffer &tag,
352                                          const RawBuffer &hash)
353 {
354
355         const auto dataType = toTzDataType(data.type);
356
357         RawBuffer pwdBuf(pwd.begin(), pwd.end());
358         uint32_t keySizeBits = data.data.size() * 8;
359         TrustZoneContext::Instance().importData(dataType,
360                                                                                 data.data,
361                                                                                 encData,
362                                                                                 pwdBuf,
363                                                                                 pwdIV,
364                                                                                 keySizeBits,
365                                                                                 tag,
366                                                                                 hash);
367 }
368
369 void importWrappedKey(const RawBuffer &wrappingKeyId,
370                                           const Pwd &wrappingKeyPwd,
371                                           const CryptoAlgorithm &alg,
372                                           const Data &encryptedKey,
373                                           const Password &encryptedKeyPassword,
374                                           const RawBuffer &encryptedKeyIV,
375                                           RawBuffer &encryptedKeyTag,
376                                           const RawBuffer &encryptedKeyId)
377 {
378         RawBuffer encryptedKeyPwdBuf(encryptedKeyPassword.begin(), encryptedKeyPassword.end());
379
380         AlgoType algo;
381         uint32_t ctrLenOrTagSizeBits = 0;
382         RawBuffer iv;
383         RawBuffer aad;
384         decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad);
385
386         // TODO it is awful!
387         TrustZoneContext::Instance().importWrappedKey(wrappingKeyId,
388                                                                                                   wrappingKeyPwd,
389                                                                                                   getAlgType(algo),
390                                                                                                   iv,
391                                                                                                   ctrLenOrTagSizeBits,
392                                                                                                   aad,
393                                                                                                   toTzDataType(encryptedKey.type),
394                                                                                                   encryptedKey.data,
395                                                                                                   encryptedKeyPwdBuf,
396                                                                                                   encryptedKeyIV,
397                                                                                                   encryptedKeyTag,
398                                                                                                   encryptedKeyId);
399 }
400
401 RawBuffer exportWrappedKey(const RawBuffer &wrappingKeyId,
402                                                    const Pwd &wrappingKeyPwd,
403                                                    const CryptoAlgorithm &alg,
404                                                    const RawBuffer &keyToWrapId,
405                                                    const Pwd &keyToWrapPwd,
406                                                    const DataType &keyToWrapType)
407 {
408         AlgoType algo;
409         uint32_t ctrLenOrTagSizeBits = 0;
410         RawBuffer iv;
411         RawBuffer aad;
412         decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad);
413
414         // TODO it is awful!
415         return TrustZoneContext::Instance().exportWrappedKey(wrappingKeyId,
416                                                                                                                  wrappingKeyPwd,
417                                                                                                                  getAlgType(algo),
418                                                                                                                  iv,
419                                                                                                                  ctrLenOrTagSizeBits,
420                                                                                                                  aad,
421                                                                                                                  keyToWrapId,
422                                                                                                                  keyToWrapPwd,
423                                                                                                                  toTzDataType(keyToWrapType));
424 }
425
426 RawBuffer getData(const RawBuffer &dataId,
427                                   const Pwd &pwd,
428                                   const DataType &type)
429 {
430         RawBuffer result;
431         TrustZoneContext::Instance().getData(dataId,
432                                  pwd,
433                                  toTzDataType(type),
434                                  result);
435         return result;
436 }
437
438 void destroyData(const RawBuffer &dataId)
439 {
440         TrustZoneContext::Instance().destroyData(dataId);
441 }
442
443 BufferPair encryptDataAesGcm(const RawBuffer &keyId,
444                                                         const Pwd &pwd,
445                                                         const RawBuffer &iv,
446                                                         int tagSize,
447                                                         const RawBuffer &data,
448                                                         const RawBuffer &aad)
449 {
450         RawBuffer result;
451         RawBuffer tag;
452
453         TrustZoneContext::Instance().executeEncryptAE(keyId, pwd, iv, tagSize,
454                                                                                                 aad, data, result, tag);
455
456         return std::make_pair(result, tag);
457 }
458
459 RawBuffer encryptDataAesGcmPacked(const RawBuffer &keyId,
460                                                                 const Pwd &pwd,
461                                                                 const RawBuffer &iv,
462                                                                 int tagSize,
463                                                                 const RawBuffer &data,
464                                                                 const RawBuffer &aad)
465 {
466         auto pair = encryptDataAesGcm(keyId, pwd, iv, tagSize, data, aad);
467         std::copy(pair.second.begin(), pair.second.end(),
468                         std::back_inserter(pair.first));
469         return pair.first;
470 }
471
472 RawBuffer decryptDataAesGcm(const RawBuffer &keyId,
473                                                         const Pwd &pwd,
474                                                         const RawBuffer &iv,
475                                                         int tagSizeBits,
476                                                         const RawBuffer &tag,
477                                                         const RawBuffer &data,
478                                                         const RawBuffer &aad)
479 {
480         RawBuffer result;
481
482         TrustZoneContext::Instance().executeDecryptAE(keyId, pwd, iv, tagSizeBits,
483                                                                                                 tag, aad, data, result);
484
485         return result;
486 }
487
488 RawBuffer decryptDataAesGcmPacked(const RawBuffer &keyId,
489                                                                 const Pwd &pwd,
490                                                                 const RawBuffer &iv,
491                                                                 int tagSizeBits,
492                                                                 const RawBuffer &data,
493                                                                 const RawBuffer &aad)
494 {
495         int tagSizeBytes = tagSizeBits / 8;
496         if (tagSizeBytes > static_cast<int>(data.size()))
497                 ThrowErr(Exc::Crypto::InputParam, "Wrong size of tag");
498
499         auto tagPos = data.data() + data.size() - tagSizeBytes;
500         return decryptDataAesGcm(keyId,
501                                                         pwd,
502                                                         iv,
503                                                         tagSizeBits,
504                                                         RawBuffer(tagPos, data.data() + data.size()),
505                                                         RawBuffer(data.data(), tagPos),
506                                                         aad);
507 }
508
509
510 RawBuffer symmetricEncrypt(const RawBuffer &keyId,
511                                                 const Pwd &pwd,
512                                                 const CryptoAlgorithm &alg,
513                                                 const RawBuffer &data)
514 {
515         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
516         uint64_t ctrLen = 0;
517
518         switch (algo) {
519                 case AlgoType::AES_CTR: {
520                         ctrLen = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
521                         // counter length is in bits
522                         if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) {
523                                 LogError("CTR length invalid: " << std::to_string(ctrLen));
524                                 ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
525                         }
526                         // no break here, we still need to slide down to executeCrypt
527                         fallthru;
528                 }
529                 case AlgoType::AES_CBC:
530                 case AlgoType::AES_CFB: {
531                         RawBuffer result;
532                         TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
533                                                                                                         getAlgType(algo),
534                                                                                                         keyId,
535                                                                                                         pwd,
536                                                                                                         unpack<RawBuffer>(alg, ParamName::ED_IV),
537                                                                                                         data,
538                                                                                                         result);
539                         return result;
540                 }
541                 case AlgoType::AES_GCM: {
542                         int tagLenBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
543                         alg.getParam(ParamName::ED_TAG_LEN, tagLenBits);
544                         RawBuffer aad;
545                         alg.getParam(ParamName::ED_AAD, aad);
546                         return encryptDataAesGcmPacked(keyId,
547                                                                                 pwd,
548                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
549                                                                                 tagLenBits,
550                                                                                 data,
551                                                                                 aad);
552                 }
553                 default:
554                         break;
555         }
556
557         ThrowErr(Exc::Crypto::OperationNotSupported,
558                                 "Incorrect algorithm provided for symmetric crypto operation");
559 }
560
561 RawBuffer symmetricDecrypt(const RawBuffer &keyId,
562                                                 const Pwd &pwd,
563                                                 const CryptoAlgorithm &alg,
564                                                 const RawBuffer &data)
565 {
566         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
567         uint64_t ctrLen = 0;
568
569         switch (algo) {
570                 case AlgoType::AES_CTR: {
571                         ctrLen = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
572                         // counter length is in bits
573                         if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) {
574                                 LogError("CTR length invalid: " << std::to_string(ctrLen));
575                                 ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
576                         }
577                         // no break here, we still need to slide down to executeCrypt
578                         fallthru;
579                 }
580                 case AlgoType::AES_CBC:
581                 case AlgoType::AES_CFB: {
582                         RawBuffer result;
583                         TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
584                                                                                                         getAlgType(algo),
585                                                                                                         keyId,
586                                                                                                         pwd,
587                                                                                                         unpack<RawBuffer>(alg, ParamName::ED_IV),
588                                                                                                         data,
589                                                                                                         result);
590                         return result;
591                 }
592                 case AlgoType::AES_GCM: {
593                         int tagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
594                         alg.getParam(ParamName::ED_TAG_LEN, tagSizeBits);
595                         RawBuffer aad;
596                         alg.getParam(ParamName::ED_AAD, aad);
597                         return decryptDataAesGcmPacked(keyId,
598                                                                                 pwd,
599                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
600                                                                                 tagSizeBits,
601                                                                                 data,
602                                                                                 aad);
603                 }
604                 default:
605                         break;
606         }
607
608         ThrowErr(Exc::Crypto::OperationNotSupported,
609                                 "Incorrect algorithm provided for symmetric crypto operation");
610 }
611
612 RawBuffer asymmetricEncrypt(const RawBuffer &keyId,
613                                                         const Pwd &pwd,
614                                                         const CryptoAlgorithm &alg,
615                                                         const RawBuffer &data)
616 {
617         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
618         RawBuffer result;
619
620         switch (algo)
621         {
622         case AlgoType::RSA_OAEP: {
623                 TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
624                                                                                                 getAlgType(algo),
625                                                                                                 keyId,
626                                                                                                 pwd,
627                                                                                                 result, // unused dummy
628                                                                                                 data,
629                                                                                                 result);
630                 return result;
631         }
632         default:
633                 break;
634         }
635
636         ThrowErr(Exc::Crypto::OperationNotSupported,
637                                 "Incorrect algorithm provided for asymmetric crypto operation");
638 }
639
640 RawBuffer asymmetricDecrypt(const RawBuffer &keyId,
641                                                         const Pwd &pwd,
642                                                         const CryptoAlgorithm &alg,
643                                                         const RawBuffer &cipher)
644 {
645         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
646         RawBuffer result;
647
648         switch (algo)
649         {
650         case AlgoType::RSA_OAEP: {
651                 TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
652                                                                                                 getAlgType(algo),
653                                                                                                 keyId,
654                                                                                                 pwd,
655                                                                                                 result, // unused dummy
656                                                                                                 cipher,
657                                                                                                 result);
658                 return result;
659         }
660         default:
661                 break;
662         }
663
664         ThrowErr(Exc::Crypto::OperationNotSupported,
665                                 "Incorrect algorithm provided for asymmetric crypto operation");
666 }
667
668 uint32_t initCipher(const RawBuffer &keyId,
669                                         const Pwd &pwd,
670                                         const CryptoAlgorithm &alg,
671                                         bool encrypt)
672 {
673         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
674
675         switch (algo)
676         {
677         case AlgoType::AES_GCM: {
678                 int tagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
679                 alg.getParam(ParamName::ED_TAG_LEN, tagSizeBits);
680                 RawBuffer aad;
681                 alg.getParam(ParamName::ED_AAD, aad);
682                 return TrustZoneContext::Instance().initGcmCipher(encrypt ? CIPHER_ENCRYPT : CIPHER_DECRYPT,
683                                                                                                                   keyId,
684                                                                                                                   pwd,
685                                                                                                                   unpack<RawBuffer>(alg, ParamName::ED_IV),
686                                                                                                                   tagSizeBits,
687                                                                                                                   aad);
688         }
689         case AlgoType::AES_CBC:
690         case AlgoType::AES_CTR:
691         case AlgoType::AES_CFB:
692                 // TODO optionally implement above modes as well
693         default:
694                 break;
695         };
696
697         ThrowErr(Exc::Crypto::OperationNotSupported,
698                          "Incorrect algorithm provided for symmetric crypto operation");
699 }
700
701 void addAAD(uint32_t opId,
702                         const RawBuffer &aad)
703 {
704         TrustZoneContext::Instance().addGcmAAD(opId, aad);
705 }
706
707 RawBuffer updateCipher(uint32_t opId,
708                                            const RawBuffer &data)
709 {
710         return TrustZoneContext::Instance().updateGcmCipher(opId, data);
711 }
712
713 RawBuffer finalizeCipher(uint32_t opId,
714                                                  const RawBuffer &data)
715 {
716         return TrustZoneContext::Instance().finalizeGcmCipher(opId, data);
717 }
718
719 RawBuffer sign(const RawBuffer &pkeyId,
720                         const Pwd &pwd,
721                         const CryptoAlgorithm &alg,
722                         const RawBuffer &message)
723 {
724         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
725         HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
726         if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE)
727                 ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option");
728
729         RawBuffer signature;
730         TrustZoneContext::Instance().executeSign(getAlgType(algo),
731                                                                                         getHashType(hash),
732                                                                                         pkeyId,
733                                                                                         pwd,
734                                                                                         message,
735                                                                                         signature);
736         return signature;
737 }
738
739 int verify(const RawBuffer &pkeyId,
740                 const Pwd &pwd,
741                 const CryptoAlgorithm &alg,
742                 const RawBuffer &message,
743                 const RawBuffer &signature)
744 {
745         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
746         HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
747         if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE)
748                 ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option");
749
750         return TrustZoneContext::Instance().executeVerify(getAlgType(algo),
751                                                                                                         getHashType(hash),
752                                                                                                         pkeyId,
753                                                                                                         pwd,
754                                                                                                         message,
755                                                                                                         signature);
756 }
757
758 void deriveECDH(const RawBuffer &prvKeyId,
759                                 const Pwd &prvKeyPwd,
760                                 const RawBuffer &pubKey,
761                                 const Password &secretPwd,
762                                 const RawBuffer &secretPwdIV,
763                                 RawBuffer &secretTag,
764                                 const RawBuffer &secretHash)
765 {
766         auto peerKey = std::make_shared<KeyImpl>(pubKey);
767         if (peerKey->getType() != KeyType::KEY_ECDSA_PUBLIC)
768                 ThrowErr(Exc::Crypto::InputParam, "ECDH requires peer's public EC key");
769         auto peerEvp = peerKey->getEvpShPtr().get();
770         assert(peerEvp);
771
772         int subType = EVP_PKEY_type(EVP_PKEY_id(peerEvp));
773         if (subType != EVP_PKEY_EC)
774                 ThrowErr(Exc::Crypto::InputParam, "Invalid key type: ", subType);
775
776         auto ecKey = EVP_PKEY_get0_EC_KEY(peerEvp);
777         if (!ecKey)
778                 ThrowErr(Exc::Crypto::InternalError, "Can't get EC key");
779
780         auto ecPoint = EC_KEY_get0_public_key(ecKey);
781         if (!ecPoint)
782                 ThrowErr(Exc::Crypto::InternalError, "Can't get EC public key");
783
784         auto ecGroup = EC_KEY_get0_group(ecKey);
785         if (!ecGroup)
786                 ThrowErr(Exc::Crypto::InternalError, "Can't get EC group");
787
788         BIGNUM *x = BN_new();
789         BIGNUM *y = BN_new();
790         if (!EC_POINT_get_affine_coordinates(ecGroup, ecPoint, x, y, NULL))
791                 ThrowErr(Exc::Crypto::InternalError, "Failed to get EC pub key coordinates");
792
793         auto xBuf = extractBignumData(x);
794         auto yBuf = extractBignumData(y);
795
796         RawBuffer secretPwdBuf(secretPwd.begin(), secretPwd.end());
797
798         TrustZoneContext::Instance().executeEcdh(prvKeyId,
799                                                                                          prvKeyPwd,
800                                                                                          xBuf,
801                                                                                          yBuf,
802                                                                                          secretPwdBuf,
803                                                                                          secretPwdIV,
804                                                                                          secretTag,
805                                                                                          secretHash);
806 }
807
808 void deriveKBKDF(const RawBuffer &secretId,
809                                  const Pwd &secretPwd,
810                                  const CryptoAlgorithm &alg,
811                                  const Password &keyPwd,
812                                  const RawBuffer &keyPwdIV,
813                                  RawBuffer &keyTag,
814                                  const RawBuffer &keyHash)
815 {
816         RawBuffer label, context, fixed;
817         size_t length;
818         alg.getParam(ParamName::KDF_LEN, length);
819         alg.getParam(ParamName::KBKDF_LABEL, label);
820         alg.getParam(ParamName::KBKDF_CONTEXT, context);
821         alg.getParam(ParamName::KBKDF_FIXED_INPUT, fixed);
822         auto prf = unpack<KdfPrf>(alg, ParamName::KDF_PRF);
823         auto mode = unpack<KbkdfMode>(alg, ParamName::KBKDF_MODE);
824         auto location = unpack<KbkdfCounterLocation>(alg, ParamName::KBKDF_COUNTER_LOCATION);
825
826         size_t rlen = 32, llen = 32, dummy;
827         alg.getParam(ParamName::KBKDF_RLEN, rlen);
828         alg.getParam(ParamName::KBKDF_LLEN, llen);
829         bool noSeparator = alg.getParam(ParamName::KBKDF_NO_SEPARATOR, dummy);
830
831         RawBuffer keyPwdBuf(keyPwd.begin(), keyPwd.end());
832
833         TrustZoneContext::Instance().executeKbkdf(secretId,
834                                                                                           secretPwd,
835                                                                                           length,
836                                                                                           label,
837                                                                                           context,
838                                                                                           fixed,
839                                                                                           toTzPrf(prf),
840                                                                                           toTzKbkdfMode(mode),
841                                                                                           toTzCtrLoc(location),
842                                                                                           rlen,
843                                                                                           llen,
844                                                                                           noSeparator,
845                                                                                           keyPwdBuf,
846                                                                                           keyPwdIV,
847                                                                                           keyTag,
848                                                                                           keyHash);
849 }
850
851 size_t maxChunkSize()
852 {
853         return TrustZoneContext::Instance().getMaxChunkSize();
854 }
855
856 } // namespace Internals
857 } // namespace TZ
858 } // namespace Crypto
859 } // namespace CKM