Allow EC keys to be imported to 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_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 {
407         AlgoType algo;
408         uint32_t ctrLenOrTagSizeBits = 0;
409         RawBuffer iv;
410         RawBuffer aad;
411         decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad);
412
413         // TODO it is awful!
414         return TrustZoneContext::Instance().exportWrappedKey(wrappingKeyId,
415                                                                                                                  wrappingKeyPwd,
416                                                                                                                  getAlgType(algo),
417                                                                                                                  iv,
418                                                                                                                  ctrLenOrTagSizeBits,
419                                                                                                                  aad,
420                                                                                                                  keyToWrapId,
421                                                                                                                  keyToWrapPwd);
422 }
423
424 RawBuffer getData(const RawBuffer &dataId,
425                                   const Pwd &pwd)
426 {
427         RawBuffer result;
428         TrustZoneContext::Instance().getData(dataId,
429                                  pwd,
430                                  result);
431         return result;
432 }
433
434 void destroyData(const RawBuffer &dataId)
435 {
436         TrustZoneContext::Instance().destroyData(dataId);
437 }
438
439 BufferPair encryptDataAesGcm(const RawBuffer &keyId,
440                                                         const Pwd &pwd,
441                                                         const RawBuffer &iv,
442                                                         int tagSize,
443                                                         const RawBuffer &data,
444                                                         const RawBuffer &aad)
445 {
446         RawBuffer result;
447         RawBuffer tag;
448
449         TrustZoneContext::Instance().executeEncryptAE(keyId, pwd, iv, tagSize,
450                                                                                                 aad, data, result, tag);
451
452         return std::make_pair(result, tag);
453 }
454
455 RawBuffer encryptDataAesGcmPacked(const RawBuffer &keyId,
456                                                                 const Pwd &pwd,
457                                                                 const RawBuffer &iv,
458                                                                 int tagSize,
459                                                                 const RawBuffer &data,
460                                                                 const RawBuffer &aad)
461 {
462         auto pair = encryptDataAesGcm(keyId, pwd, iv, tagSize, data, aad);
463         std::copy(pair.second.begin(), pair.second.end(),
464                         std::back_inserter(pair.first));
465         return pair.first;
466 }
467
468 RawBuffer decryptDataAesGcm(const RawBuffer &keyId,
469                                                         const Pwd &pwd,
470                                                         const RawBuffer &iv,
471                                                         int tagSizeBits,
472                                                         const RawBuffer &tag,
473                                                         const RawBuffer &data,
474                                                         const RawBuffer &aad)
475 {
476         RawBuffer result;
477
478         TrustZoneContext::Instance().executeDecryptAE(keyId, pwd, iv, tagSizeBits,
479                                                                                                 tag, aad, data, result);
480
481         return result;
482 }
483
484 RawBuffer decryptDataAesGcmPacked(const RawBuffer &keyId,
485                                                                 const Pwd &pwd,
486                                                                 const RawBuffer &iv,
487                                                                 int tagSizeBits,
488                                                                 const RawBuffer &data,
489                                                                 const RawBuffer &aad)
490 {
491         int tagSizeBytes = tagSizeBits / 8;
492         if (tagSizeBytes > static_cast<int>(data.size()))
493                 ThrowErr(Exc::Crypto::InputParam, "Wrong size of tag");
494
495         auto tagPos = data.data() + data.size() - tagSizeBytes;
496         return decryptDataAesGcm(keyId,
497                                                         pwd,
498                                                         iv,
499                                                         tagSizeBits,
500                                                         RawBuffer(tagPos, data.data() + data.size()),
501                                                         RawBuffer(data.data(), tagPos),
502                                                         aad);
503 }
504
505
506 RawBuffer symmetricEncrypt(const RawBuffer &keyId,
507                                                 const Pwd &pwd,
508                                                 const CryptoAlgorithm &alg,
509                                                 const RawBuffer &data)
510 {
511         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
512         uint64_t ctrLen = 0;
513
514         switch (algo) {
515                 case AlgoType::AES_CTR: {
516                         ctrLen = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
517                         // counter length is in bits
518                         if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) {
519                                 LogError("CTR length invalid: " << std::to_string(ctrLen));
520                                 ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
521                         }
522                         // no break here, we still need to slide down to executeCrypt
523                         fallthru;
524                 }
525                 case AlgoType::AES_CBC:
526                 case AlgoType::AES_CFB: {
527                         RawBuffer result;
528                         TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
529                                                                                                         getAlgType(algo),
530                                                                                                         keyId,
531                                                                                                         pwd,
532                                                                                                         unpack<RawBuffer>(alg, ParamName::ED_IV),
533                                                                                                         data,
534                                                                                                         result);
535                         return result;
536                 }
537                 case AlgoType::AES_GCM: {
538                         int tagLenBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
539                         alg.getParam(ParamName::ED_TAG_LEN, tagLenBits);
540                         RawBuffer aad;
541                         alg.getParam(ParamName::ED_AAD, aad);
542                         return encryptDataAesGcmPacked(keyId,
543                                                                                 pwd,
544                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
545                                                                                 tagLenBits,
546                                                                                 data,
547                                                                                 aad);
548                 }
549                 default:
550                         break;
551         }
552
553         ThrowErr(Exc::Crypto::OperationNotSupported,
554                                 "Incorrect algorithm provided for symmetric crypto operation");
555 }
556
557 RawBuffer symmetricDecrypt(const RawBuffer &keyId,
558                                                 const Pwd &pwd,
559                                                 const CryptoAlgorithm &alg,
560                                                 const RawBuffer &data)
561 {
562         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
563         uint64_t ctrLen = 0;
564
565         switch (algo) {
566                 case AlgoType::AES_CTR: {
567                         ctrLen = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
568                         // counter length is in bits
569                         if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) {
570                                 LogError("CTR length invalid: " << std::to_string(ctrLen));
571                                 ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
572                         }
573                         // no break here, we still need to slide down to executeCrypt
574                         fallthru;
575                 }
576                 case AlgoType::AES_CBC:
577                 case AlgoType::AES_CFB: {
578                         RawBuffer result;
579                         TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
580                                                                                                         getAlgType(algo),
581                                                                                                         keyId,
582                                                                                                         pwd,
583                                                                                                         unpack<RawBuffer>(alg, ParamName::ED_IV),
584                                                                                                         data,
585                                                                                                         result);
586                         return result;
587                 }
588                 case AlgoType::AES_GCM: {
589                         int tagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
590                         alg.getParam(ParamName::ED_TAG_LEN, tagSizeBits);
591                         RawBuffer aad;
592                         alg.getParam(ParamName::ED_AAD, aad);
593                         return decryptDataAesGcmPacked(keyId,
594                                                                                 pwd,
595                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
596                                                                                 tagSizeBits,
597                                                                                 data,
598                                                                                 aad);
599                 }
600                 default:
601                         break;
602         }
603
604         ThrowErr(Exc::Crypto::OperationNotSupported,
605                                 "Incorrect algorithm provided for symmetric crypto operation");
606 }
607
608 RawBuffer asymmetricEncrypt(const RawBuffer &keyId,
609                                                         const Pwd &pwd,
610                                                         const CryptoAlgorithm &alg,
611                                                         const RawBuffer &data)
612 {
613         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
614         RawBuffer result;
615
616         switch (algo)
617         {
618         case AlgoType::RSA_OAEP: {
619                 TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
620                                                                                                 getAlgType(algo),
621                                                                                                 keyId,
622                                                                                                 pwd,
623                                                                                                 result, // unused dummy
624                                                                                                 data,
625                                                                                                 result);
626                 return result;
627         }
628         default:
629                 break;
630         }
631
632         ThrowErr(Exc::Crypto::OperationNotSupported,
633                                 "Incorrect algorithm provided for asymmetric crypto operation");
634 }
635
636 RawBuffer asymmetricDecrypt(const RawBuffer &keyId,
637                                                         const Pwd &pwd,
638                                                         const CryptoAlgorithm &alg,
639                                                         const RawBuffer &cipher)
640 {
641         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
642         RawBuffer result;
643
644         switch (algo)
645         {
646         case AlgoType::RSA_OAEP: {
647                 TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
648                                                                                                 getAlgType(algo),
649                                                                                                 keyId,
650                                                                                                 pwd,
651                                                                                                 result, // unused dummy
652                                                                                                 cipher,
653                                                                                                 result);
654                 return result;
655         }
656         default:
657                 break;
658         }
659
660         ThrowErr(Exc::Crypto::OperationNotSupported,
661                                 "Incorrect algorithm provided for asymmetric crypto operation");
662 }
663
664 uint32_t initCipher(const RawBuffer &keyId,
665                                         const Pwd &pwd,
666                                         const CryptoAlgorithm &alg,
667                                         bool encrypt)
668 {
669         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
670
671         switch (algo)
672         {
673         case AlgoType::AES_GCM: {
674                 int tagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
675                 alg.getParam(ParamName::ED_TAG_LEN, tagSizeBits);
676                 RawBuffer aad;
677                 alg.getParam(ParamName::ED_AAD, aad);
678                 return TrustZoneContext::Instance().initGcmCipher(encrypt ? CIPHER_ENCRYPT : CIPHER_DECRYPT,
679                                                                                                                   keyId,
680                                                                                                                   pwd,
681                                                                                                                   unpack<RawBuffer>(alg, ParamName::ED_IV),
682                                                                                                                   tagSizeBits,
683                                                                                                                   aad);
684         }
685         case AlgoType::AES_CBC:
686         case AlgoType::AES_CTR:
687         case AlgoType::AES_CFB:
688                 // TODO optionally implement above modes as well
689         default:
690                 break;
691         };
692
693         ThrowErr(Exc::Crypto::OperationNotSupported,
694                          "Incorrect algorithm provided for symmetric crypto operation");
695 }
696
697 void addAAD(uint32_t opId,
698                         const RawBuffer &aad)
699 {
700         TrustZoneContext::Instance().addGcmAAD(opId, aad);
701 }
702
703 RawBuffer updateCipher(uint32_t opId,
704                                            const RawBuffer &data)
705 {
706         return TrustZoneContext::Instance().updateGcmCipher(opId, data);
707 }
708
709 RawBuffer finalizeCipher(uint32_t opId,
710                                                  const RawBuffer &data)
711 {
712         return TrustZoneContext::Instance().finalizeGcmCipher(opId, data);
713 }
714
715 RawBuffer sign(const RawBuffer &pkeyId,
716                         const Pwd &pwd,
717                         const CryptoAlgorithm &alg,
718                         const RawBuffer &message)
719 {
720         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
721         HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
722         if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE)
723                 ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option");
724
725         RawBuffer signature;
726         TrustZoneContext::Instance().executeSign(getAlgType(algo),
727                                                                                         getHashType(hash),
728                                                                                         pkeyId,
729                                                                                         pwd,
730                                                                                         message,
731                                                                                         signature);
732         return signature;
733 }
734
735 int verify(const RawBuffer &pkeyId,
736                 const Pwd &pwd,
737                 const CryptoAlgorithm &alg,
738                 const RawBuffer &message,
739                 const RawBuffer &signature)
740 {
741         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
742         HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
743         if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE)
744                 ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option");
745
746         return TrustZoneContext::Instance().executeVerify(getAlgType(algo),
747                                                                                                         getHashType(hash),
748                                                                                                         pkeyId,
749                                                                                                         pwd,
750                                                                                                         message,
751                                                                                                         signature);
752 }
753
754 void deriveECDH(const RawBuffer &prvKeyId,
755                                 const Pwd &prvKeyPwd,
756                                 const RawBuffer &pubKey,
757                                 const Password &secretPwd,
758                                 const RawBuffer &secretPwdIV,
759                                 RawBuffer &secretTag,
760                                 const RawBuffer &secretHash)
761 {
762         auto peerKey = std::make_shared<KeyImpl>(pubKey);
763         if (peerKey->getType() != KeyType::KEY_ECDSA_PUBLIC)
764                 ThrowErr(Exc::Crypto::InputParam, "ECDH requires peer's public EC key");
765         auto peerEvp = peerKey->getEvpShPtr().get();
766         assert(peerEvp);
767
768         int subType = EVP_PKEY_type(EVP_PKEY_id(peerEvp));
769         if (subType != EVP_PKEY_EC)
770                 ThrowErr(Exc::Crypto::InputParam, "Invalid key type: ", subType);
771
772         auto ecKey = EVP_PKEY_get0_EC_KEY(peerEvp);
773         if (!ecKey)
774                 ThrowErr(Exc::Crypto::InternalError, "Can't get EC key");
775
776         auto ecPoint = EC_KEY_get0_public_key(ecKey);
777         if (!ecPoint)
778                 ThrowErr(Exc::Crypto::InternalError, "Can't get EC public key");
779
780         auto ecGroup = EC_KEY_get0_group(ecKey);
781         if (!ecGroup)
782                 ThrowErr(Exc::Crypto::InternalError, "Can't get EC group");
783
784         BIGNUM *x = BN_new();
785         BIGNUM *y = BN_new();
786         if (!EC_POINT_get_affine_coordinates(ecGroup, ecPoint, x, y, NULL))
787                 ThrowErr(Exc::Crypto::InternalError, "Failed to get EC pub key coordinates");
788
789         auto xBuf = extractBignumData(x);
790         auto yBuf = extractBignumData(y);
791
792         RawBuffer secretPwdBuf(secretPwd.begin(), secretPwd.end());
793
794         TrustZoneContext::Instance().executeEcdh(prvKeyId,
795                                                                                          prvKeyPwd,
796                                                                                          xBuf,
797                                                                                          yBuf,
798                                                                                          secretPwdBuf,
799                                                                                          secretPwdIV,
800                                                                                          secretTag,
801                                                                                          secretHash);
802 }
803
804 void deriveKBKDF(const RawBuffer &secretId,
805                                  const CryptoAlgorithm &alg,
806                                  const Password &keyPwd,
807                                  const RawBuffer &keyPwdIV,
808                                  RawBuffer &keyTag,
809                                  const RawBuffer &keyHash)
810 {
811         RawBuffer label, context, fixed;
812         alg.getParam(ParamName::KBKDF_LABEL, label);
813         alg.getParam(ParamName::KBKDF_CONTEXT, context);
814         alg.getParam(ParamName::KBKDF_FIXED_INPUT, fixed);
815         auto prf = unpack<KdfPrf>(alg, ParamName::KDF_PRF);
816         auto mode = unpack<KbkdfMode>(alg, ParamName::KBKDF_MODE);
817         auto location = unpack<KbkdfCounterLocation>(alg, ParamName::KBKDF_COUNTER_LOCATION);
818
819         size_t rlen = 32, llen = 32, dummy;
820         alg.getParam(ParamName::KBKDF_RLEN, rlen);
821         alg.getParam(ParamName::KBKDF_LLEN, llen);
822         bool noSeparator = alg.getParam(ParamName::KBKDF_NO_SEPARATOR, dummy);
823
824         RawBuffer keyPwdBuf(keyPwd.begin(), keyPwd.end());
825
826         TrustZoneContext::Instance().executeKbkdf(secretId,
827                                                                                           label,
828                                                                                           context,
829                                                                                           fixed,
830                                                                                           toTzPrf(prf),
831                                                                                           toTzKbkdfMode(mode),
832                                                                                           toTzCtrLoc(location),
833                                                                                           rlen,
834                                                                                           llen,
835                                                                                           noSeparator,
836                                                                                           keyPwdBuf,
837                                                                                           keyPwdIV,
838                                                                                           keyTag,
839                                                                                           keyHash);
840 }
841
842
843 } // namespace Internals
844 } // namespace TZ
845 } // namespace Crypto
846 } // namespace CKM