Openssl: add thread support and fix initialization
[platform/core/security/key-manager.git] / src / manager / common / pkcs12-impl.cpp
1 /* Copyright (c) 2014 Samsung Electronics Co.
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        pkcs12-impl.cpp
17  * @author      Barlomiej Grzelewski (b.grzelewski@samsung.com)
18  * @version     1.0
19  * @brief       Certificate Implmentation.
20  */
21 #include <openssl/bio.h>
22 #include <openssl/evp.h>
23 #include <openssl/pkcs12.h>
24 #include <openssl/x509.h>
25
26 #include <dpl/log/log.h>
27
28 #include <crypto-init.h>
29 #include <pkcs12-impl.h>
30
31 #include <certificate-impl.h>
32 #include <key-impl.h>
33
34 namespace CKM {
35 namespace {
36
37 typedef std::unique_ptr<BIO, std::function<void(BIO*)>> BioUniquePtr;
38
39 } // anonymous namespace
40
41 PKCS12Impl::PKCS12Impl(const KeyShPtr &key, const CertificateShPtr &cert, const CertificateShPtrVector &caChain)
42     : m_pkey(key),
43       m_cert(cert),
44       m_ca(caChain)
45 {
46 }
47
48 PKCS12Impl::PKCS12Impl(const RawBuffer &buffer, const Password &password)
49 {
50     EVP_PKEY *pkey = NULL;
51     X509 *cert = NULL;
52     STACK_OF(X509) *ca = NULL;
53     ::PKCS12 *pkcs12 = NULL;
54
55     BioUniquePtr bio(BIO_new(BIO_s_mem()), BIO_free_all);
56     LogDebug("Start to parse PKCS12");
57
58     int result = BIO_write(bio.get(), buffer.data(), buffer.size());
59     if (result != static_cast<int>(buffer.size())) {
60         LogError("BIO_write failed. result = " << result << " Expected: " << buffer.size());
61         return;
62     }
63
64     pkcs12 = d2i_PKCS12_bio(bio.get(), NULL);
65
66     if (pkcs12 == NULL) {
67         LogDebug("d2i_PKCS12_bio failed.");
68         return;
69     }
70
71     // needed if parsing is done before manager initialization
72     initOpenSslOnce();
73
74     if (!PKCS12_verify_mac(pkcs12, password.c_str(), password.size())) {
75         LogDebug("Pkcs12 verify failed. Wrong password");
76         return;
77     }
78
79     if (!PKCS12_parse(pkcs12, password.c_str(), &pkey, &cert, &ca)) {
80         LogError("PKCS12_parse failed");
81         return;
82     }
83
84     if (pkey) {
85         KeyImpl::EvpShPtr ptr(pkey, EVP_PKEY_free);
86         switch(EVP_PKEY_type(pkey->type))
87         {
88             case EVP_PKEY_RSA:
89                 m_pkey = std::make_shared<KeyImpl>(ptr, KeyType::KEY_RSA_PRIVATE);
90                 break;
91
92             case EVP_PKEY_DSA:
93                 m_pkey = std::make_shared<KeyImpl>(ptr, KeyType::KEY_DSA_PRIVATE);
94                 break;
95
96             case EVP_PKEY_EC:
97                 m_pkey = std::make_shared<KeyImpl>(ptr, KeyType::KEY_ECDSA_PRIVATE);
98                 break;
99
100             default:
101                 LogError("Unsupported private key type.");
102                 EVP_PKEY_free(pkey);
103                 break;
104         }
105     }
106
107     if (cert) {
108         m_cert = std::make_shared<CertificateImpl>(cert, false);
109     }
110
111     if (ca) {
112         while (sk_X509_num(ca) > 0) {
113             X509 *top = sk_X509_pop(ca);
114             m_ca.push_back(std::make_shared<CertificateImpl>(top, false));
115         }
116
117         sk_X509_pop_free(ca, X509_free);
118     }
119 }
120
121 PKCS12Impl::PKCS12Impl(const PKCS12 &other)
122     : m_pkey(other.getKey()),
123       m_cert(other.getCertificate()),
124       m_ca(other.getCaCertificateShPtrVector())
125 {
126 }
127
128 PKCS12Impl::PKCS12Impl(PKCS12Impl &&other)
129     : m_pkey(std::move(other.m_pkey)),
130       m_cert(std::move(other.m_cert)),
131       m_ca(std::move(other.m_ca))
132 {
133 }
134
135 PKCS12Impl::PKCS12Impl(const PKCS12Impl &other)
136     : m_pkey(other.getKey()),
137       m_cert(other.getCertificate()),
138       m_ca(other.getCaCertificateShPtrVector())
139 {
140 }
141
142 PKCS12Impl& PKCS12Impl::operator=(const PKCS12Impl &other)
143 {
144     if(this != &other)
145     {
146         m_pkey = other.getKey();
147         m_cert = other.getCertificate();
148         m_ca = other.getCaCertificateShPtrVector();
149     }
150     return *this;
151 }
152
153 KeyShPtr PKCS12Impl::getKey() const {
154     return m_pkey;
155 }
156
157 CertificateShPtr PKCS12Impl::getCertificate() const {
158     return m_cert;
159 }
160
161 CertificateShPtrVector PKCS12Impl::getCaCertificateShPtrVector() const {
162     return m_ca;
163 }
164
165 bool PKCS12Impl::empty() const {
166     return m_pkey.get() == NULL && m_cert.get() == NULL && m_ca.empty();
167 }
168
169 PKCS12Impl::~PKCS12Impl()
170 {}
171
172 PKCS12ShPtr PKCS12::create(const RawBuffer &rawBuffer, const Password &password) {
173     try {
174         auto output = std::make_shared<PKCS12Impl>(rawBuffer, password);
175         if (output->empty())
176             output.reset();
177         return output;
178     } catch (const std::bad_alloc &e) {
179         LogDebug("Bad alloc was caught during PKCS12 creation");
180     } catch (...) {
181         LogError("Critical error: Unknown exception was caught during PCKS12Impl creation!");
182     }
183     return PKCS12ShPtr();
184 }
185
186 } // namespace CKM
187