tizen 2.4 release
[framework/security/key-manager.git] / src / manager / common / key-impl.cpp
1 /* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
2  *
3  *  Licensed under the Apache License, Version 2.0 (the "License");
4  *  you may not use this file except in compliance with the License.
5  *  You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  *  Unless required by applicable law or agreed to in writing, software
10  *  distributed under the License is distributed on an "AS IS" BASIS,
11  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  *  See the License for the specific language governing permissions and
13  *  limitations under the License
14  *
15  *
16  * @file        key-impl.cpp
17  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
18  * @version     1.0
19  * @brief       Key implementation.
20  */
21 #include <string.h>
22
23 #include <functional>
24 #include <memory>
25 #include <sstream>
26 #include <ios>
27
28 #include <openssl/bio.h>
29 #include <openssl/evp.h>
30 #include <openssl/pem.h>
31 #include <openssl/x509.h>
32
33 #include <dpl/log/log.h>
34
35 #include <ckm/ckm-type.h>
36 #include <key-impl.h>
37
38 namespace CKM {
39 namespace {
40
41 typedef std::unique_ptr<BIO, std::function<void(BIO*)>> BioUniquePtr;
42
43 int passcb(char *buff, int size, int rwflag, void *userdata) {
44     (void) rwflag;
45     Password *ptr = static_cast<Password*>(userdata);
46     if (ptr == NULL)
47         return 0;
48     if (ptr->empty())
49         return 0;
50     if (static_cast<int>(ptr->size()) > size)
51         return 0;
52     memcpy(buff, ptr->c_str(), ptr->size());
53     return ptr->size();
54 }
55
56 typedef int(*I2D_CONV)(BIO*, EVP_PKEY*);
57
58 CKM::RawBuffer i2d(I2D_CONV fun, EVP_PKEY* pkey) {
59     BioUniquePtr bio(BIO_new(BIO_s_mem()), BIO_free_all);
60
61     if (NULL == pkey) {
62         LogDebug("You are trying to read empty key!");
63         return RawBuffer();
64     }
65
66     if (NULL == bio.get()) {
67         LogError("Error in memory allocation! Function: BIO_new.");
68         return RawBuffer();
69     }
70
71     if (1 != fun(bio.get(), pkey)) {
72         LogError("Error in conversion EVP_PKEY to der");
73         return RawBuffer();
74     }
75
76     CKM::RawBuffer output(8196);
77
78     int size = BIO_read(bio.get(), output.data(), output.size());
79
80     if (size <= 0) {
81         LogError("Error in BIO_read: " << size);
82         return RawBuffer();
83     }
84
85     output.resize(size);
86     return output;
87 }
88
89 } // anonymous namespace
90
91 KeyImpl::KeyImpl()
92   : m_pkey(NULL, EVP_PKEY_free)
93   , m_type(KeyType::KEY_NONE)
94 {}
95
96 KeyImpl::KeyImpl(const KeyImpl &second) {
97     m_pkey = second.m_pkey;
98     m_type = second.m_type;
99 }
100
101 KeyImpl &KeyImpl::operator=(const KeyImpl &second) {
102     if (this == &second)
103         return *this;
104
105     m_pkey = second.m_pkey;
106     m_type = second.m_type;
107
108     return *this;
109 }
110
111 KeyImpl::KeyImpl(const RawBuffer &buf, const Password &password)
112   : m_pkey(NULL, EVP_PKEY_free)
113   , m_type(KeyType::KEY_NONE)
114 {
115     bool isPrivate = false;
116     EVP_PKEY *pkey = NULL;
117     BioUniquePtr bio(BIO_new(BIO_s_mem()), BIO_free_all);
118
119     LogDebug("Start to parse key:");
120 //    printDER(buf);
121
122     if (buf[0] != '-') {
123         BIO_write(bio.get(), buf.data(), buf.size());
124         pkey = d2i_PUBKEY_bio(bio.get(), NULL);
125         isPrivate = false;
126         LogDebug("Trying d2i_PUBKEY_bio Status: " << (void*)pkey);
127     }
128
129     if (!pkey && buf[0] != '-') {
130         (void)BIO_reset(bio.get());
131         BIO_write(bio.get(), buf.data(), buf.size());
132         pkey = d2i_PrivateKey_bio(bio.get(), NULL);
133         isPrivate = true;
134         LogDebug("Trying d2i_PrivateKey_bio Status: " << (void*)pkey);
135     }
136
137     if (!pkey && buf[0] == '-') {
138         (void)BIO_reset(bio.get());
139         BIO_write(bio.get(), buf.data(), buf.size());
140         pkey = PEM_read_bio_PUBKEY(bio.get(), NULL, passcb, const_cast<Password*>(&password));
141         isPrivate = false;
142         LogDebug("PEM_read_bio_PUBKEY Status: " << (void*)pkey);
143     }
144
145     if (!pkey && buf[0] == '-') {
146         (void)BIO_reset(bio.get());
147         BIO_write(bio.get(), buf.data(), buf.size());
148         pkey = PEM_read_bio_PrivateKey(bio.get(), NULL, passcb, const_cast<Password*>(&password));
149         isPrivate = true;
150         LogDebug("PEM_read_bio_PrivateKey Status: " << (void*)pkey);
151     }
152
153     if (!pkey) {
154         LogError("Failed to parse key");
155         return;
156     }
157
158     m_pkey.reset(pkey, EVP_PKEY_free);
159
160     switch(EVP_PKEY_type(pkey->type))
161     {
162         case EVP_PKEY_RSA:
163             m_type = isPrivate ? KeyType::KEY_RSA_PRIVATE : KeyType::KEY_RSA_PUBLIC;
164             break;
165
166         case EVP_PKEY_DSA:
167             m_type = isPrivate ? KeyType::KEY_DSA_PRIVATE : KeyType::KEY_DSA_PUBLIC;
168             break;
169
170         case EVP_PKEY_EC:
171             m_type = isPrivate ? KeyType::KEY_ECDSA_PRIVATE : KeyType::KEY_ECDSA_PUBLIC;
172             break;
173     }
174     LogDebug("KeyType is: " << (int)m_type << " isPrivate: " << isPrivate);
175 }
176
177 KeyImpl::KeyImpl(EvpShPtr pkey, KeyType type) : m_pkey(pkey), m_type(type)
178 {
179     int expected_type = EVP_PKEY_NONE;
180     switch(type)
181     {
182         case KeyType::KEY_RSA_PRIVATE:
183         case KeyType::KEY_RSA_PUBLIC:
184             expected_type = EVP_PKEY_RSA;
185             break;
186
187         case KeyType::KEY_DSA_PRIVATE:
188         case KeyType::KEY_DSA_PUBLIC:
189             expected_type = EVP_PKEY_DSA;
190             break;
191
192         case KeyType::KEY_AES:
193             LogError("Error, AES keys are not supported yet.");
194             break;
195
196         case KeyType::KEY_ECDSA_PRIVATE:
197         case KeyType::KEY_ECDSA_PUBLIC:
198             expected_type = EVP_PKEY_EC;
199             break;
200
201         default:
202             LogError("Unknown key type provided.");
203             break;
204     }
205
206     // verify if actual key type matches the expected tpe
207     int given_key_type = EVP_PKEY_type(pkey->type);
208     if(given_key_type==EVP_PKEY_NONE || expected_type!=given_key_type)
209     {
210         m_pkey.reset();
211         m_type = KeyType::KEY_NONE;
212     }
213 }
214
215 bool KeyImpl::empty() const {
216     return m_pkey.get() == NULL;
217 }
218
219 KeyImpl::EvpShPtr KeyImpl::getEvpShPtr() const {
220     return m_pkey;
221 }
222
223 KeyType KeyImpl::getType() const {
224     return m_type;
225 }
226
227 RawBuffer KeyImpl::getDERPRV() const {
228     return i2d(i2d_PrivateKey_bio, m_pkey.get());
229 }
230
231 RawBuffer KeyImpl::getDERPUB() const {
232     return i2d(i2d_PUBKEY_bio, m_pkey.get());
233 }
234
235 RawBuffer KeyImpl::getDER() const {
236     switch(m_type)
237     {
238         case KeyType::KEY_RSA_PRIVATE:
239         case KeyType::KEY_DSA_PRIVATE:
240         case KeyType::KEY_ECDSA_PRIVATE:
241             return getDERPRV();
242
243         case KeyType::KEY_RSA_PUBLIC:
244         case KeyType::KEY_DSA_PUBLIC:
245         case KeyType::KEY_ECDSA_PUBLIC:
246             return getDERPUB();
247
248         default:
249             break;
250     }
251     return RawBuffer();
252 }
253
254 KeyShPtr Key::create(const RawBuffer &raw, const Password &password) {
255     try {
256         KeyShPtr output = std::make_shared<KeyImpl>(raw, password);
257         if (output->empty())
258             output.reset();
259         return output;
260     } catch (const std::bad_alloc &) {
261         LogDebug("Bad alloc was catch during KeyImpl creation");
262     } catch (...) {
263         LogError("Critical error: Unknown exception was caught during KeyImpl creation");
264     }
265     return KeyShPtr();
266 }
267
268 } // namespace CKM
269