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