Refactor log system
[platform/core/security/cert-svc.git] / vcore / src / vcore / OCSPImpl.cpp
1 /*
2  * Copyright (c) 2011 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  * @author      Tomasz Morawski(t.morawski@samsung.com)
18  * @author      Michal Ciepielski(m.ciepielski@samsung.com)
19  * @author      Piotr Marcinkiewicz(p.marcinkiew@samsung.com)
20  * @version     0.4
21  * @file        OCSP.cpp
22  * @brief       Routines for certificate validation over OCSP
23  */
24
25 #include <vcore/OCSPImpl.h>
26
27 #include <string.h>
28 #include <algorithm>
29
30 #include <openssl/ssl.h>
31 #include <openssl/crypto.h>
32 #include <openssl/err.h>
33 #include <openssl/x509v3.h>
34 #include <boost/optional.hpp>
35
36 #include <dpl/log/log.h>
37 #include <dpl/assert.h>
38 #include <dpl/foreach.h>
39 #include <dpl/scoped_free.h>
40
41 #include <libsoup/soup.h>
42
43 #include <vcore/Certificate.h>
44 #include <vcore/SoupMessageSendSync.h>
45 #include <vcore/ValidatorFactories.h>
46
47 extern "C" {
48 // This function is needed to fix "Invalid conversion from void*
49 // to unsigned char*" C++ compiler error during calling
50 // i2d_OCSP_REQUEST_bio macro
51 extern bool convertToBuffer(OCSP_REQUEST* req,
52                 char** buf,
53                 int* size);
54 }
55
56 namespace {
57 const int ConnectionTimeoutInSeconds = 6;
58 const int ConnectionRetryCount = 3;
59
60 //! Maximum leeway in validity period in seconds: default 1 day
61 //! (@see checkRevocationStatus function code)
62
63 //! Maximum validity time for revocation status (1 day)
64 const int MaxValidatyPeriodInSeconds = 24 * 60 * 60;
65
66 //! Max age (@see checkRevocationStatus function code)
67 const int MaxAge = -1;
68 } // anonymous namespace
69
70 namespace ValidationCore {
71
72 const char* OCSPImpl::DEFAULT_RESPONDER_URI_ENV = "OCSP_DEFAULT_RESPONDER_URI";
73
74 static const EVP_MD* getDigestAlg(OCSP::DigestAlgorithm alg)
75 {
76     switch (alg) {
77     case OCSP::SHA1:
78            return EVP_sha1();
79     case OCSP::SHA224:
80            return EVP_sha224();
81     case OCSP::SHA256:
82            return EVP_sha256();
83     case OCSP::SHA384:
84            return EVP_sha384();
85     case OCSP::SHA512:
86            return EVP_sha512();
87     default:
88         return NULL;
89     }
90 }
91
92 OCSPImpl::OCSPImpl() :
93     /* Upgrade of openssl is required to support sha256 */
94     //    m_pCertIdDigestAlg(EVP_sha256()),
95     //    m_pRequestDigestAlg(EVP_sha256()),
96     m_pCertIdDigestAlg(EVP_sha1()),
97     m_pRequestDigestAlg(EVP_sha1()),
98     m_bUseNonce(false),
99     m_bUseDefResponder(false),
100     m_bSignRequest(false),
101     m_pSignKey(0)
102 {}
103
104 SoupWrapper::SoupMessageSendBase::RequestStatus OCSPImpl::sendOcspRequest(
105         OCSP_REQUEST* argRequest,
106         const std::string& argUri)
107 {
108     using namespace SoupWrapper;
109     // convert OCSP_REQUEST to memory buffer
110     char* requestBuffer;
111     int requestSizeInt;
112     if (!convertToBuffer(argRequest, &requestBuffer, &requestSizeInt)) {
113         VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
114                       "OCSP: failed to convert OCSP_REQUEST to mem buffer");
115     }
116
117     Assert(requestSizeInt >= 0);
118
119     SoupMessageSendBase::MessageBuffer buffer;
120     buffer.resize(requestSizeInt);
121     memcpy(&buffer[0], requestBuffer, requestSizeInt);
122     free(requestBuffer);
123
124     char *cport = 0,*chost = 0,*cpath = 0;
125     int use_ssl = 0;
126
127     if (!OCSP_parse_url(const_cast<char*>(argUri.c_str()),
128                         &chost,
129                         &cport,
130                         &cpath,
131                         &use_ssl))
132     {
133         LogWarning("Error in OCSP_parse_url");
134         return SoupMessageSendBase::REQUEST_STATUS_CONNECTION_ERROR;
135     }
136
137     std::string host = chost;
138
139     if (cport) {
140         host += ":";
141         host += cport;
142     }
143
144     free(cport);
145     free(chost);
146     free(cpath);
147
148     m_soupMessage.setHost(argUri);
149     m_soupMessage.setHeader("Host", host);
150     m_soupMessage.setRequest(std::string("application/ocsp-request"),
151                              buffer);
152
153     return m_soupMessage.sendSync();
154 }
155
156 ValidationCore::VerificationStatusSet OCSPImpl::validateCertificateList(
157         const CertificateList &certs)
158 {
159         VerificationStatusSet statusSet;
160
161     if (certs.size() < 2) {
162         // no certificates to verify, just return a error
163         LogWarning("No validation will be proceed. OCSP require at"
164                    " least 2 certificates in chain. Found only " << certs.size());
165         statusSet.add(VERIFICATION_STATUS_ERROR);
166         return statusSet;
167     }
168
169         CertificatePtr root = certs.back();
170         CertStoreId::Set storedSetId = createCertificateIdentifier().find(root);
171         char* ocspUrl = storedSetId.getOcspUrl();
172         
173         if (ocspUrl != NULL)
174         {
175                 setUseDefaultResponder(true);
176                 setDefaultResponder(ocspUrl);
177         }
178
179         CertificateList::const_iterator iter = certs.begin();
180     CertificateList::const_iterator parent = iter;
181
182     time_t minValidity = 0;
183     for (++parent; parent != certs.end(); ++iter, ++parent) {
184         LogDebug("Certificate validation (CN:" << (*iter)->getOneLine() << ")");
185         LogDebug("Parent certificate     (CN:" << (*parent)->getOneLine() << ")");
186         statusSet.add(validateCertificate(*iter, *parent));
187         if ((0 == minValidity || minValidity > m_responseValidity) &&
188                 m_responseValidity > 0)
189         {
190             minValidity = m_responseValidity;
191         }
192     }
193     m_responseValidity = minValidity;
194
195         return statusSet;
196 }
197
198 VerificationStatus OCSPImpl::checkEndEntity(
199                 const CertificateCollection &chain)
200 {
201         // this is temporary fix. it must be rewriten
202         VerificationStatusSet verSet;
203
204         CertificateList clst;
205     if (chain.isChain() && chain.size() >= 2) {
206         CertificateList::const_iterator icert = chain.begin();
207         clst.push_back(*icert);
208         ++icert;
209         clst.push_back(*icert);
210     }
211     verSet += validateCertificateList(clst);
212
213         return verSet.convertToStatus();
214 }
215
216 VerificationStatus OCSPImpl::validateCertificate(CertificatePtr argCert,
217                                              CertificatePtr argIssuer)
218 {
219     using namespace SoupWrapper;
220
221     Assert(!!argCert);
222     Assert(!!argIssuer);
223
224     VcoreTry {
225         std::string uri;
226
227         if (!m_bUseDefResponder) {
228             uri = argCert->getOCSPURL();
229             if (uri.empty()) {
230                 return VERIFICATION_STATUS_NOT_SUPPORT;
231             }
232         } else {
233             if (m_strResponderURI.empty()) {
234                 VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
235                               "Default responder is not set");
236             }
237             LogWarning("Default responder will be used");
238
239             uri = m_strResponderURI;
240         }
241
242         // creates a request
243         CreateRequestResult newRequest = createRequest(argCert, argIssuer);
244         if (!newRequest.success) {
245             VcoreThrowMsg(OCSPImpl::Exception::VerificationError, "Request creation failed");
246         }
247
248         // SSLSmartContainer <OCSP_CERTID> certIdCont(certId);
249         // this smart ptr is commented out in purpose. request
250         // manages certIdmemory (which was done in createRequest above)
251         SSLSmartContainer <OCSP_REQUEST> requestCont(newRequest.ocspRequest);
252
253         SoupMessageSendBase::RequestStatus requestStatus;
254         requestStatus = sendOcspRequest(requestCont, uri);
255
256         if (requestStatus != SoupMessageSendBase::REQUEST_STATUS_OK) {
257             return VERIFICATION_STATUS_CONNECTION_FAILED;
258         }
259
260         // Response is m_soupMessage, convert it to OCSP_RESPONSE
261         OcspResponse response  = convertToResponse();
262
263         if (!response.first) {
264             VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
265                           "OCSP: failed to convert mem buffer to OCSP_RESPONSE");
266         }
267
268         SSLSmartContainer <OCSP_RESPONSE> responseCont(response.second);
269         // verify response eg. check response status,
270         // validate responder certificate
271         validateResponse(requestCont,
272                          responseCont,
273                          newRequest.ocspCertId);
274     } VcoreCatch(OCSPImpl::Exception::ConnectionError) {
275         LogWarning("OCSP: ConnectionError");
276         return VERIFICATION_STATUS_CONNECTION_FAILED;
277     } VcoreCatch(OCSPImpl::Exception::CertificateRevoked) {
278         LogWarning("OCSP: Revoked");
279         return VERIFICATION_STATUS_REVOKED;
280     } VcoreCatch(OCSPImpl::Exception::CertificateUnknown) {
281         LogWarning("OCSP: Unknown");
282         return VERIFICATION_STATUS_UNKNOWN;
283     } VcoreCatch(OCSPImpl::Exception::VerificationError) {
284         LogWarning("OCSP: Verification error");
285         return VERIFICATION_STATUS_VERIFICATION_ERROR;
286     } VcoreCatch(OCSPImpl::Exception::Base) {
287         LogWarning("OCSP: Error");
288         return VERIFICATION_STATUS_ERROR;
289     }
290     LogWarning("OCSP: Good");
291     return VERIFICATION_STATUS_GOOD;
292 }
293
294 void OCSPImpl::setDefaultResponder(const char *uri)
295 {
296     Assert(uri);
297     m_strResponderURI = std::string(uri);
298 }
299
300 void OCSPImpl::setUseDefaultResponder(bool value)
301 {
302     m_bUseDefResponder = value;
303 }
304
305 time_t OCSPImpl::getResponseValidity()
306 {
307     return m_responseValidity;
308 }
309
310 OCSPImpl::CreateRequestResult OCSPImpl::createRequest(CertificatePtr argCert,
311                                               CertificatePtr argIssuer)
312 {
313     OCSP_REQUEST* newRequest = OCSP_REQUEST_new();
314
315     if (!newRequest) {
316         LogWarning("OCSP: Failed to create a request");
317         return CreateRequestResult();
318     }
319
320     SSLSmartContainer <OCSP_REQUEST> requestCont(newRequest);
321
322     OCSP_CERTID* certId = addSerial(argCert, argIssuer);
323
324     if (!certId) {
325         LogWarning("OCSP: Unable to create a serial id");
326         return CreateRequestResult();
327     }
328     SSLSmartContainer <OCSP_CERTID> certIdCont(certId);
329
330     // Inserting certificate ID to request
331     if (!OCSP_request_add0_id(requestCont, certIdCont)) {
332         LogWarning("OCSP: Unable to create a certificate id");
333         return CreateRequestResult();
334     }
335
336     if (m_bUseNonce) {
337         OCSP_request_add1_nonce(requestCont, 0, -1);
338     }
339
340     if (m_bSignRequest) {
341         if (!m_pSignCert || !m_pSignKey) {
342             LogWarning("OCSP: Unable to sign request if "
343                        "SignCert or SignKey was not set");
344             return CreateRequestResult();
345         }
346
347         if (!OCSP_request_sign(requestCont,
348                                m_pSignCert->getX509(),
349                                m_pSignKey,
350                                m_pRequestDigestAlg,
351                                0,
352                                0))
353         {
354             LogWarning("OCSP: Unable to sign request");
355             return CreateRequestResult();
356         }
357     }
358     return CreateRequestResult(true,
359                                requestCont.DetachPtr(),
360                                certIdCont.DetachPtr());
361 }
362
363 OCSP_CERTID* OCSPImpl::addSerial(CertificatePtr argCert,
364                              CertificatePtr argIssuer)
365 {
366     X509_NAME* iname = X509_get_subject_name(argIssuer->getX509());
367     ASN1_BIT_STRING* ikey = X509_get0_pubkey_bitstr(argIssuer->getX509());
368     ASN1_INTEGER* serial = X509_get_serialNumber(argCert->getX509());
369
370     return OCSP_cert_id_new(m_pCertIdDigestAlg, iname, ikey, serial);
371 }
372
373 void OCSPImpl::setDigestAlgorithmForCertId(OCSP::DigestAlgorithm alg)
374 {
375     const EVP_MD* foundAlg = getDigestAlg(alg);
376
377     if (NULL != foundAlg) {
378         m_pCertIdDigestAlg = foundAlg;
379     } else {
380         LogDebug("Request for unsupported CertId digest algorithm ignored!");
381     }
382 }
383
384 void OCSPImpl::setDigestAlgorithmForRequest(OCSP::DigestAlgorithm alg)
385 {
386     const EVP_MD* foundAlg = getDigestAlg(alg);
387
388     if (NULL != foundAlg) {
389         m_pRequestDigestAlg = foundAlg;
390     } else {
391         LogDebug("Request for unsupported OCSP request digest algorithm ignored!");
392     }
393 }
394
395 void OCSPImpl::setTrustedStore(const CertificateList& certs)
396 {
397     X509_STORE *store = X509_STORE_new();
398     m_pTrustedStore = store;
399     // create a trusted store basing on certificate chain from a signature
400     FOREACH(iter, certs) {
401         X509_STORE_add_cert(store, (*iter)->getX509());
402     }
403 }
404
405 void OCSPImpl::validateResponse(OCSP_REQUEST* argRequest,
406                             OCSP_RESPONSE* argResponse,
407                             OCSP_CERTID* argCertId)
408 {
409     int result = OCSP_response_status(argResponse);
410
411     if (result != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
412         handleInvalidResponse(result);
413         VcoreThrowMsg(OCSPImpl::Exception::VerificationError, "OCSP_response_status failed");
414     }
415
416     // get response object
417     OCSP_BASICRESP* basic = OCSP_response_get1_basic(argResponse);
418     if (!basic) {
419         VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
420                       "OCSP: Unable to get a BASICRESP object.");
421     }
422
423     SSLSmartContainer <OCSP_BASICRESP> basicRespCont(basic);
424     if (m_bUseNonce && OCSP_check_nonce(argRequest, basicRespCont) <= 0) {
425         VcoreThrowMsg(OCSPImpl::Exception::VerificationError, "OCSP: Invalid nonce");
426     }
427
428     if (!verifyResponse(basic)) {
429         VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
430                       "Unable to verify the OCSP responder's certificate");
431     }
432
433     checkRevocationStatus(basicRespCont, argCertId);
434 }
435
436 bool OCSPImpl::verifyResponse(OCSP_BASICRESP* basic)
437 {
438     Assert(m_pTrustedStore);
439     // verify ocsp response
440     int response = OCSP_basic_verify(basic, NULL, m_pTrustedStore, 0);
441     if (response <= 0) {
442         LogWarning("OCSP verification failed");
443     }
444
445     return response > 0;
446 }
447
448 void OCSPImpl::checkRevocationStatus(OCSP_BASICRESP* basic,
449                                  OCSP_CERTID* id)
450 {
451     ASN1_GENERALIZEDTIME* producedAt;
452     ASN1_GENERALIZEDTIME* thisUpdate;
453     ASN1_GENERALIZEDTIME* nextUpdate;
454     int reason;
455     int status;
456
457     m_responseValidity = 0;
458
459     if (!OCSP_resp_find_status(basic,
460                                id,
461                                &status,
462                                &reason,
463                                &producedAt,
464                                &thisUpdate,
465                                &nextUpdate))
466     {
467         VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
468                       "OCSP: Failed to find certificate status.");
469     }
470
471     if (!OCSP_check_validity(thisUpdate,
472                              nextUpdate,
473                              MaxValidatyPeriodInSeconds,
474                              MaxAge))
475     {
476         VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
477                       "OCSP: Failed to check certificate validate.");
478     }
479
480     if (nextUpdate) {
481         asn1GeneralizedTimeToTimeT(nextUpdate,&m_responseValidity);
482         time_t now;
483         time(&now);
484         LogDebug("Time of next OCSP update got from server: " << m_responseValidity);
485         LogDebug("Expires in: " << (m_responseValidity - now));
486         LogDebug("Original: " << nextUpdate->data);
487     }
488
489     switch (status) {
490     case V_OCSP_CERTSTATUS_GOOD:
491         return;
492     case V_OCSP_CERTSTATUS_REVOKED:
493         VcoreThrowMsg(OCSPImpl::Exception::CertificateRevoked, "Certificate is Revoked");
494     case V_OCSP_CERTSTATUS_UNKNOWN:
495         VcoreThrowMsg(OCSPImpl::Exception::CertificateUnknown, "Certificate is Unknown");
496     default:
497         Assert(false && "Invalid status");
498     }
499 }
500
501 OCSPImpl::OcspResponse OCSPImpl::convertToResponse()
502 {
503     using namespace SoupWrapper;
504
505     // convert memory buffer to ocsp response object
506     BUF_MEM res_bmem;
507     OCSP_RESPONSE* response;
508
509     SoupMessageSendBase::MessageBuffer buffer = m_soupMessage.getResponse();
510
511     res_bmem.length = buffer.size();
512     res_bmem.data = &buffer[0];
513     res_bmem.max = buffer.size();
514
515     BIO* res_mem_bio = BIO_new(BIO_s_mem());
516     BIO_set_mem_buf(res_mem_bio, &res_bmem, BIO_NOCLOSE);
517
518     response = d2i_OCSP_RESPONSE_bio(res_mem_bio, NULL);
519     BIO_free_all(res_mem_bio);
520
521     if (!response) {
522         LogWarning("OCSP: Failed to convert OCSP Response to DER format");
523         return std::make_pair(false, static_cast<OCSP_RESPONSE*>(NULL));
524     }
525
526     return std::make_pair(true, response);
527 }
528
529 void OCSPImpl::handleInvalidResponse(int result)
530 {
531     switch (result) {
532     case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
533         LogWarning("OCSP: Server returns "
534                    "OCSP_RESPONSE_STATUS_MALFORMEDREQUEST status");
535         break;
536     case OCSP_RESPONSE_STATUS_INTERNALERROR:
537         LogWarning("OCSP: Server returns "
538                    "OCSP_RESPONSE_STATUS_INTERNALERROR status");
539         break;
540     case OCSP_RESPONSE_STATUS_TRYLATER:
541         LogWarning("OCSP: Server returns "
542                    "OCSP_RESPONSE_STATUS_TRYLATER status");
543         break;
544     case OCSP_RESPONSE_STATUS_SIGREQUIRED:
545         LogWarning("OCSP: Server returns "
546                    "OCSP_RESPONSE_STATUS_SIGREQUIRED status");
547         break;
548     case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
549         LogWarning("OCSP: Server returns "
550                    "OCSP_RESPONSE_STATUS_UNAUTHORIZED status");
551         break;
552     default:
553         Assert(false && "Invalid result value");
554     }
555 }
556 } // namespace ValidationCore