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