Fix backend selection logic
[platform/core/security/key-manager.git] / src / manager / crypto / platform / decider.cpp
1 /*
2  *  Copyright (c) 2015-2021 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       decider.cpp
18  * @author     BartÅ‚omiej Grzelewski (b.grzelewski@samsung.com)
19  * @author     Lukasz Kostyra (l.kostyra@samsung.com)
20  * @version    1.0
21  */
22 #include <dpl/log/log.h>
23
24 #include <crypto-backend.h>
25
26 #include <platform/decider.h>
27
28 #include <generic-backend/exception.h>
29
30 #ifdef TZ_BACKEND_ENABLED
31 #include <tz-backend/tz-context.h>
32 #endif // TZ_BACKEND_ENABLED
33
34 namespace CKM {
35 namespace Crypto {
36
37 Decider::Decider()
38         : m_swStore(CryptoBackend::OpenSSL)
39 #ifdef TZ_BACKEND_ENABLED
40         , m_tzStore(CryptoBackend::TrustZone)
41 #endif
42 {
43 }
44
45 GStore &Decider::getStore(const Token &token)
46 {
47         GStore *gStore = NULL;
48
49         if (token.backendId == CryptoBackend::OpenSSL)
50                 gStore = &m_swStore;
51 #ifdef TZ_BACKEND_ENABLED
52         if (token.backendId == CryptoBackend::TrustZone)
53                 gStore = &m_tzStore;
54 #endif
55         if (gStore)
56                 return *gStore;
57
58         ThrowErr(Exc::Crypto::InternalError,
59                  "Backend not available. BackendId: ",
60                  static_cast<int>(token.backendId));
61 };
62
63 GStore* Decider::tryBackend(CryptoBackend backend)
64 {
65         switch(backend) {
66         case CryptoBackend::OpenSSL:
67                 return &m_swStore;
68         case CryptoBackend::TrustZone:
69 #ifdef TZ_BACKEND_ENABLED
70                 try {
71                         LogDebug("Trying to open TA session...");
72                         TZ::Internals::TrustZoneContext::Instance();
73                         LogDebug("...succeeded. Selecting TZ backend.");
74                         return &m_tzStore;
75                 } catch (const Exc::Crypto::InternalError& e) {
76                         LogDebug("...failed.");
77                 }
78 #endif
79         default:
80                 break;
81         }
82         return nullptr;
83 }
84
85 /*
86  * operation encrypted type   extractable backend
87  * ----------------------------------------------
88  * import    FALSE     binary -           TZ/SW
89  *                     skey   FALSE       TZ/SW
90  *                     skey   TRUE        SW
91  *                     akey   -           SW
92  *                     cert   -           SW
93  *           TRUE      binary -           TZ
94  *                     skey   FALSE       TZ
95  *                     skey   TRUE        NONE
96  *                     akey   -           NONE
97  *                     cert   -           NONE
98  * generate  -         binary FALSE       TZ/SW
99  *           -         binary TRUE        SW
100  *           -         cert   -           NONE
101  *           -         skey   FALSE       TZ/SW
102  *           -         skey   TRUE        SW
103  *           -         akey   FALSE       TZ/SW
104  *           -         akey   TRUE        SW
105  */
106 std::deque<CryptoBackend> Decider::getCompatibleBackends(DataType data,
107                                                          const Policy &policy,
108                                                          bool import,
109                                                          bool encrypted)
110 {
111         std::deque<CryptoBackend> backends;
112
113         auto addSW = [&]{
114                 if (policy.backend != CKM::PolicyBackend::FORCE_HARDWARE)
115                         backends.push_back(CryptoBackend::OpenSSL);
116         };
117
118         auto addTZ = [&]{
119 #ifdef TZ_BACKEND_ENABLED
120                 if (policy.backend != CKM::PolicyBackend::FORCE_SOFTWARE)
121                         backends.push_front(CryptoBackend::TrustZone);
122 #endif
123         };
124
125         if (import) {
126                 if (!encrypted)
127                         addSW();
128
129                 if (data.isBinaryData() || (data.isSKey() && !policy.extractable))
130                         addTZ();
131         } else { // generate/derive
132                 assert(!encrypted);
133
134                 if (!data.isCertificate() && !data.isChainCert()) {
135                         addSW();
136
137                         if (!policy.extractable)
138                                 addTZ();
139                 }
140         }
141         return backends;
142 }
143
144 GStore &Decider::getStore(DataType data, const Policy &policy, bool import, bool encrypted)
145 {
146         auto backends = getCompatibleBackends(data, policy, import, encrypted);
147         if (backends.empty())
148                 ThrowErr(Exc::Crypto::InputParam, "No backend supports this operation.");
149
150         for (auto id : backends) {
151                 auto backend = tryBackend(id);
152                 if (backend != nullptr)
153                         return *backend;
154         }
155         ThrowErr(Exc::Crypto::InternalError, "Failed to connect to a compatible backend.");
156 }
157
158 bool Decider::checkStore(CryptoBackend requestedBackend, DataType data, const Policy &policy, bool import)
159 {
160         auto backends = getCompatibleBackends(data, policy, import);
161         for (auto id : backends) {
162                 if (id == requestedBackend)
163                         return true;
164         }
165         return false;
166 }
167
168 } // namespace Crypto
169 } // namespace CKM
170