7b7b9be1826a706ee0397f681dc9c484b8098922
[platform/core/security/key-manager.git] / src / manager / crypto / tz-backend / internals.cpp
1 /*
2  *  Copyright (c) 2017 - 2019 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 <openssl/evp.h>
28 #include <openssl/dsa.h>
29 #include <openssl/bio.h>
30 #include <openssl/bn.h>
31
32 #include <tz-backend/internals.h>
33 #include <tz-backend/tz-context.h>
34 #include <openssl-error-handler.h>
35 #include <km_ta_defines.h>
36
37 #include <functional>
38
39 namespace {
40
41 using DSAPtr = std::unique_ptr<DSA, std::function<void(DSA*)>>;
42
43 CKM::RawBuffer extractBignumData(BIGNUM* bn)
44 {
45         size_t size = static_cast<size_t>(BN_num_bytes(bn));
46
47         CKM::RawBuffer result(size);
48         int ret = BN_bn2bin(bn, result.data());
49         if (ret != static_cast<int>(size)) {
50                 ThrowErr(CKM::Exc::Crypto::InternalError,
51                         "Error while converting bignums - expected "
52                         + std::to_string(size) + " bytes of data, got " + std::to_string(ret));
53         }
54
55         return result;
56 }
57
58 void generateDSAParams(const int sizeBits, CKM::RawBuffer &prime,
59                                         CKM::RawBuffer &subprime, CKM::RawBuffer &base)
60 {
61         DSAPtr dsa(DSA_new(), DSA_free);
62         if (!dsa) {
63                 ThrowErr(CKM::Exc::Crypto::InternalError,
64                         "Failed to create DSA context for parameter gen");
65         }
66
67         if (DSA_generate_parameters_ex(dsa.get(), sizeBits, NULL, 0, NULL, NULL, NULL) == 0) {
68                 ThrowErr(CKM::Exc::Crypto::InternalError,
69                         "Failed to generate DSA params, err = " + std::to_string(ERR_get_error()));
70         }
71
72         // at this stage dsa->p, dsa->q & dsa->r should contain our params
73         // extract them into buffers
74         prime = extractBignumData(dsa->p);
75         subprime = extractBignumData(dsa->q);
76         base = extractBignumData(dsa->g);
77 }
78
79 } // namespace
80
81 namespace CKM {
82 namespace Crypto {
83 namespace TZ {
84 namespace Internals {
85
86 tz_algo_type getGenSKeyType(AlgoType type)
87 {
88         switch (type)
89         {
90         case AlgoType::AES_GEN: return ALGO_AES_GEN;
91         default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported");
92         }
93 }
94
95 tz_algo_type getAlgType(AlgoType type)
96 {
97         switch (type)
98         {
99         case AlgoType::AES_CBC: return ALGO_AES_CBC;
100         case AlgoType::AES_CTR: return ALGO_AES_CTR;
101         case AlgoType::AES_CFB: return ALGO_AES_CFB;
102         case AlgoType::AES_GCM: return ALGO_AES_GCM;
103         case AlgoType::RSA_OAEP: return ALGO_RSA;
104         case AlgoType::RSA_SV: return ALGO_RSA_SV;
105         case AlgoType::DSA_SV: return ALGO_DSA_SV;
106         case AlgoType::ECDSA_SV: return ALGO_ECDSA_SV;
107         default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported");
108         };
109 }
110
111 tz_algo_type getAlgType(KeyType keyType)
112 {
113         switch (keyType)
114         {
115         case KeyType::KEY_AES:
116                 return ALGO_AES_GEN;
117         case KeyType::KEY_RSA_PUBLIC:
118         case KeyType::KEY_RSA_PRIVATE:
119                 return ALGO_RSA_GEN;
120         case KeyType::KEY_DSA_PUBLIC:
121         case KeyType::KEY_DSA_PRIVATE:
122                 return ALGO_DSA_GEN;
123         case KeyType::KEY_ECDSA_PUBLIC:
124         case KeyType::KEY_ECDSA_PRIVATE:
125                 return ALGO_ECDSA_GEN;
126         default:
127                 ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported");
128         };
129 }
130
131 tz_hash_type getHashType(HashAlgorithm hash)
132 {
133         switch (hash)
134         {
135         case HashAlgorithm::SHA1: return HASH_SHA1;
136         case HashAlgorithm::SHA256: return HASH_SHA256;
137         case HashAlgorithm::SHA384: return HASH_SHA384;
138         case HashAlgorithm::SHA512: return HASH_SHA512;
139         default:
140                 ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported");
141         }
142 }
143
144 RawBuffer generateIV()
145 {
146         RawBuffer result;
147         TrustZoneContext::Instance().generateIV(result);
148         return result;
149 }
150
151 Data generateSKey(const CryptoAlgorithm &alg,
152                                 const Password &pwd,
153                                 const RawBuffer &iv,
154                                 RawBuffer &tag)
155 {
156         AlgoType keyType = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
157         int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
158
159         Data keyData;
160         keyData.type = DataType(KeyType::KEY_AES);
161
162         if (!pwd.empty()) {
163                 if (iv.empty()) {
164                         ThrowErr(Exc::InputParam, "Key generation with password encryption requires an IV");
165                 }
166
167                 RawBuffer pwdBuf(pwd.begin(), pwd.end());
168                 TrustZoneContext::Instance().generateSKeyPwd(getGenSKeyType(keyType),
169                                                                                                         pwdBuf, iv, keyBits,
170                                                                                                         keyData.data, tag);
171         } else {
172                 TrustZoneContext::Instance().generateSKey(getGenSKeyType(keyType), keyBits,
173                                                                                                 keyData.data);
174         }
175
176         return keyData;
177 }
178
179 DataPair generateAKey(const CryptoAlgorithm &alg,
180                                         const Password &pubPwd,
181                                         const Password &privPwd,
182                                         const RawBuffer &pubPwdIv,
183                                         const RawBuffer &privPwdIv,
184                                         RawBuffer &pubTag,
185                                         RawBuffer &privTag)
186 {
187         AlgoType keyType = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
188         int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
189
190         Data pubKeyData;
191         Data privKeyData;
192
193         RawBuffer pubPwdBuf;
194         if (!pubPwd.empty())
195                 pubPwdBuf.assign(pubPwd.begin(), pubPwd.end());
196
197         RawBuffer privPwdBuf;
198         if (!privPwd.empty())
199                 privPwdBuf.assign(privPwd.begin(), privPwd.end());
200
201         switch (keyType) {
202         case AlgoType::RSA_GEN: {
203                 pubKeyData.type = DataType(KeyType::KEY_RSA_PUBLIC);
204                 privKeyData.type = DataType(KeyType::KEY_RSA_PRIVATE);
205
206                 TrustZoneContext::Instance().generateRSAKey(keyBits,
207                                                                                                         pubPwdBuf,
208                                                                                                         pubPwdIv,
209                                                                                                         privPwdBuf,
210                                                                                                         privPwdIv,
211                                                                                                         pubKeyData.data,
212                                                                                                         pubTag,
213                                                                                                         privKeyData.data,
214                                                                                                         privTag);
215                 break;
216         }
217         case AlgoType::DSA_GEN: {
218                 pubKeyData.type = DataType(KeyType::KEY_DSA_PUBLIC);
219                 privKeyData.type = DataType(KeyType::KEY_DSA_PRIVATE);
220
221                 RawBuffer prime;
222                 RawBuffer subprime;
223                 RawBuffer base;
224                 generateDSAParams(keyBits, prime, subprime, base);
225                 TrustZoneContext::Instance().generateDSAKey(keyBits,
226                                                                                                         prime,
227                                                                                                         subprime,
228                                                                                                         base,
229                                                                                                         pubPwdBuf,
230                                                                                                         pubPwdIv,
231                                                                                                         privPwdBuf,
232                                                                                                         privPwdIv,
233                                                                                                         pubKeyData.data,
234                                                                                                         pubTag,
235                                                                                                         privKeyData.data,
236                                                                                                         privTag);
237                 break;
238         }
239         default: {
240                 ThrowErr(Exc::Crypto::InputParam,
241                         "Invalid algo type provided for generateAKey function");
242         }
243         }
244
245         return DataPair(pubKeyData, privKeyData);
246 }
247
248 void destroyKey(const RawBuffer &key)
249 {
250         TrustZoneContext::Instance().executeDestroy(key);
251 }
252
253 RawBuffer importData(const Data &data,
254                                          const EncryptionParams &encData,
255                                          const Password &pwd,
256                                          const RawBuffer &pwdIV,
257                                          RawBuffer &tag)
258 {
259
260         uint32_t dataType;
261
262         if (data.type.isSKey()) {
263                 dataType = TYPE_SKEY;
264         } else if (data.type.isBinaryData()) {
265                 dataType = TYPE_GENERIC_SECRET;
266         } else if (data.type.isKeyPrivate()) {
267                 dataType = TYPE_AKEY_PRIVATE;
268         } else if (data.type.isKeyPublic()) {
269                 dataType = TYPE_AKEY_PUBLIC;
270         } else {
271                 ThrowErr(Exc::Crypto::DataTypeNotSupported,
272                         "Data type could not be impoted by tz-backend");
273         }
274
275         RawBuffer result;
276
277         RawBuffer pwdBuf(pwd.begin(), pwd.end());
278         uint32_t keySizeBits = data.data.size() * 8;
279         TrustZoneContext::Instance().importData(dataType,
280                                                                                 data.data,
281                                                                                 encData,
282                                                                                 pwdBuf,
283                                                                                 pwdIV,
284                                                                                 keySizeBits,
285                                                                                 Params::DERIVED_KEY_LENGTH_BITS,
286                                                                                 result,
287                                                                                 tag);
288         return result;
289 }
290
291 RawBuffer getData(const RawBuffer &dataId,
292                                   const Pwd &pwd)
293 {
294         RawBuffer result;
295         TrustZoneContext::Instance().getData(dataId,
296                                  pwd,
297                                  result);
298         return result;
299 }
300
301 void destroyData(const RawBuffer &dataId)
302 {
303         TrustZoneContext::Instance().destroyData(dataId);
304 }
305
306 BufferPair encryptDataAesGcm(const RawBuffer &key,
307                                                         const Pwd &pwd,
308                                                         const RawBuffer &iv,
309                                                         int tagSize,
310                                                         const RawBuffer &data,
311                                                         const RawBuffer &aad)
312 {
313         RawBuffer result;
314         RawBuffer tag;
315
316         TrustZoneContext::Instance().executeEncryptAE(key, pwd, iv, tagSize,
317                                                                                                 aad, data, result, tag);
318
319         return std::make_pair(result, tag);
320 }
321
322 RawBuffer encryptDataAesGcmPacked(const RawBuffer &key,
323                                                                 const Pwd &pwd,
324                                                                 const RawBuffer &iv,
325                                                                 int tagSize,
326                                                                 const RawBuffer &data,
327                                                                 const RawBuffer &aad)
328 {
329         auto pair = encryptDataAesGcm(key, pwd, iv, tagSize, data, aad);
330         std::copy(pair.second.begin(), pair.second.end(),
331                         std::back_inserter(pair.first));
332         return pair.first;
333 }
334
335 RawBuffer decryptDataAesGcm(const RawBuffer &key,
336                                                         const Pwd &pwd,
337                                                         const RawBuffer &iv,
338                                                         int tagSizeBits,
339                                                         const RawBuffer &tag,
340                                                         const RawBuffer &data,
341                                                         const RawBuffer &aad)
342 {
343         RawBuffer result;
344
345         TrustZoneContext::Instance().executeDecryptAE(key, pwd, iv, tagSizeBits,
346                                                                                                 tag, aad, data, result);
347
348         return result;
349 }
350
351 RawBuffer decryptDataAesGcmPacked(const RawBuffer &key,
352                                                                 const Pwd &pwd,
353                                                                 const RawBuffer &iv,
354                                                                 int tagSizeBits,
355                                                                 const RawBuffer &data,
356                                                                 const RawBuffer &aad)
357 {
358         int tagSizeBytes = tagSizeBits / 8;
359         if (tagSizeBytes > static_cast<int>(data.size()))
360                 ThrowErr(Exc::Crypto::InputParam, "Wrong size of tag");
361
362         auto tagPos = data.data() + data.size() - tagSizeBytes;
363         return decryptDataAesGcm(key,
364                                                         pwd,
365                                                         iv,
366                                                         tagSizeBits,
367                                                         RawBuffer(tagPos, data.data() + data.size()),
368                                                         RawBuffer(data.data(), tagPos),
369                                                         aad);
370 }
371
372
373 RawBuffer symmetricEncrypt(const RawBuffer &key,
374                                                 const Pwd &pwd,
375                                                 const CryptoAlgorithm &alg,
376                                                 const RawBuffer &data)
377 {
378         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
379         uint64_t ctrLen = 0;
380
381         switch (algo) {
382                 case AlgoType::AES_CTR: {
383                         ctrLen = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
384                         // counter length is in bits
385                         if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) {
386                                 LogError("CTR length invalid: " << std::to_string(ctrLen));
387                                 ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
388                         }
389                         // no break here, we still need to slide down to executeCrypt
390                 }
391                 case AlgoType::AES_CBC:
392                 case AlgoType::AES_CFB: {
393                         RawBuffer result;
394                         TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
395                                                                                                         getAlgType(algo),
396                                                                                                         key,
397                                                                                                         pwd,
398                                                                                                         unpack<RawBuffer>(alg, ParamName::ED_IV),
399                                                                                                         data,
400                                                                                                         result);
401                         return result;
402                 }
403                 case AlgoType::AES_GCM: {
404                         int tagLenBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
405                         alg.getParam(ParamName::ED_TAG_LEN, tagLenBits);
406                         RawBuffer aad;
407                         alg.getParam(ParamName::ED_AAD, aad);
408                         return encryptDataAesGcmPacked(key,
409                                                                                 pwd,
410                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
411                                                                                 tagLenBits,
412                                                                                 data,
413                                                                                 aad);
414                 }
415                 default:
416                         break;
417         }
418
419         ThrowErr(Exc::Crypto::OperationNotSupported,
420                                 "Incorrect algorithm provided for symmetric crypto operation");
421 }
422
423 RawBuffer symmetricDecrypt(const RawBuffer &key,
424                                                 const Pwd &pwd,
425                                                 const CryptoAlgorithm &alg,
426                                                 const RawBuffer &data)
427 {
428         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
429         uint64_t ctrLen = 0;
430
431         switch (algo) {
432                 case AlgoType::AES_CTR: {
433                         ctrLen = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
434                         // counter length is in bits
435                         if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) {
436                                 LogError("CTR length invalid: " << std::to_string(ctrLen));
437                                 ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
438                         }
439                         // no break here, we still need to slide down to executeCrypt
440                 }
441                 case AlgoType::AES_CBC:
442                 case AlgoType::AES_CFB: {
443                         RawBuffer result;
444                         TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
445                                                                                                         getAlgType(algo),
446                                                                                                         key,
447                                                                                                         pwd,
448                                                                                                         unpack<RawBuffer>(alg, ParamName::ED_IV),
449                                                                                                         data,
450                                                                                                         result);
451                         return result;
452                 }
453                 case AlgoType::AES_GCM: {
454                         int tagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
455                         alg.getParam(ParamName::ED_TAG_LEN, tagSizeBits);
456                         RawBuffer aad;
457                         alg.getParam(ParamName::ED_AAD, aad);
458                         return decryptDataAesGcmPacked(key,
459                                                                                 pwd,
460                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
461                                                                                 tagSizeBits,
462                                                                                 data,
463                                                                                 aad);
464                 }
465                 default:
466                         break;
467         }
468
469         ThrowErr(Exc::Crypto::OperationNotSupported,
470                                 "Incorrect algorithm provided for symmetric crypto operation");
471 }
472
473 RawBuffer asymmetricEncrypt(const RawBuffer &key,
474                                                         const Pwd &pwd,
475                                                         const CryptoAlgorithm &alg,
476                                                         const RawBuffer &data)
477 {
478         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
479         RawBuffer result;
480
481         switch (algo)
482         {
483         case AlgoType::RSA_OAEP: {
484                 TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
485                                                                                                 getAlgType(algo),
486                                                                                                 key,
487                                                                                                 pwd,
488                                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
489                                                                                                 data,
490                                                                                                 result);
491                 return result;
492         }
493         default:
494                 break;
495         }
496
497         ThrowErr(Exc::Crypto::OperationNotSupported,
498                                 "Incorrect algorithm provided for asymmetric crypto operation");
499 }
500
501 RawBuffer asymmetricDecrypt(const RawBuffer &key,
502                                                         const Pwd &pwd,
503                                                         const CryptoAlgorithm &alg,
504                                                         const RawBuffer &cipher)
505 {
506         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
507         RawBuffer result;
508
509         switch (algo)
510         {
511         case AlgoType::RSA_OAEP: {
512                 TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
513                                                                                                 getAlgType(algo),
514                                                                                                 key,
515                                                                                                 pwd,
516                                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
517                                                                                                 cipher,
518                                                                                                 result);
519                 return result;
520         }
521         default:
522                 break;
523         }
524
525         ThrowErr(Exc::Crypto::OperationNotSupported,
526                                 "Incorrect algorithm provided for asymmetric crypto operation");
527 }
528
529 RawBuffer sign(const RawBuffer &pkey,
530                         const Pwd &pwd,
531                         const CryptoAlgorithm &alg,
532                         const RawBuffer &message)
533 {
534         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
535         HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
536         RawBuffer signature;
537         TrustZoneContext::Instance().executeSign(getAlgType(algo),
538                                                                                         getHashType(hash),
539                                                                                         pkey,
540                                                                                         pwd,
541                                                                                         message,
542                                                                                         signature);
543         return signature;
544 }
545
546 int verify(const RawBuffer &pkey,
547                 const Pwd &pwd,
548                 const CryptoAlgorithm &alg,
549                 const RawBuffer &message,
550                 const RawBuffer &signature)
551 {
552         AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
553         HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
554         return TrustZoneContext::Instance().executeVerify(getAlgType(algo),
555                                                                                                         getHashType(hash),
556                                                                                                         pkey,
557                                                                                                         pwd,
558                                                                                                         message,
559                                                                                                         signature);
560 }
561
562 } // namespace Internals
563 } // namespace TZ
564 } // namespace Crypto
565 } // namespace CKM