2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @author Tomasz Morawski(t.morawski@samsung.com)
18 * @author Michal Ciepielski(m.ciepielski@samsung.com)
19 * @author Piotr Marcinkiewicz(p.marcinkiew@samsung.com)
22 * @brief Routines for certificate validation over OCSP
25 #include <vcore/OCSPImpl.h>
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>
36 #include <dpl/log/log.h>
37 #include <dpl/assert.h>
38 #include <dpl/foreach.h>
39 #include <dpl/scoped_free.h>
41 #include <libsoup/soup.h>
43 #include <vcore/Certificate.h>
44 #include <vcore/SoupMessageSendSync.h>
45 #include <vcore/ValidatorFactories.h>
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,
57 const int ConnectionTimeoutInSeconds = 6;
58 const int ConnectionRetryCount = 3;
60 //! Maximum leeway in validity period in seconds: default 1 day
61 //! (@see checkRevocationStatus function code)
63 //! Maximum validity time for revocation status (1 day)
64 const int MaxValidatyPeriodInSeconds = 24 * 60 * 60;
66 //! Max age (@see checkRevocationStatus function code)
67 const int MaxAge = -1;
68 } // anonymous namespace
70 namespace ValidationCore {
72 const char* OCSPImpl::DEFAULT_RESPONDER_URI_ENV = "OCSP_DEFAULT_RESPONDER_URI";
74 static const EVP_MD* getDigestAlg(OCSP::DigestAlgorithm alg)
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()),
99 m_bUseDefResponder(false),
100 m_bSignRequest(false),
104 SoupWrapper::SoupMessageSendBase::RequestStatus OCSPImpl::sendOcspRequest(
105 OCSP_REQUEST* argRequest,
106 const std::string& argUri)
108 using namespace SoupWrapper;
109 // convert OCSP_REQUEST to memory buffer
112 if (!convertToBuffer(argRequest, &requestBuffer, &requestSizeInt)) {
113 VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
114 "OCSP: failed to convert OCSP_REQUEST to mem buffer");
117 Assert(requestSizeInt >= 0);
119 SoupMessageSendBase::MessageBuffer buffer;
120 buffer.resize(requestSizeInt);
121 memcpy(&buffer[0], requestBuffer, requestSizeInt);
124 char *cport = 0,*chost = 0,*cpath = 0;
127 if (!OCSP_parse_url(const_cast<char*>(argUri.c_str()),
133 LogWarning("Error in OCSP_parse_url");
134 return SoupMessageSendBase::REQUEST_STATUS_CONNECTION_ERROR;
137 std::string host = chost;
148 m_soupMessage.setHost(argUri);
149 m_soupMessage.setHeader("Host", host);
150 m_soupMessage.setRequest(std::string("application/ocsp-request"),
153 return m_soupMessage.sendSync();
156 ValidationCore::VerificationStatusSet OCSPImpl::validateCertificateList(
157 const CertificateList &certs)
159 VerificationStatusSet statusSet;
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);
169 CertificatePtr root = certs.back();
170 CertStoreId::Set storedSetId = createCertificateIdentifier().find(root);
171 char* ocspUrl = storedSetId.getOcspUrl();
175 setUseDefaultResponder(true);
176 setDefaultResponder(ocspUrl);
179 CertificateList::const_iterator iter = certs.begin();
180 CertificateList::const_iterator parent = iter;
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)
190 minValidity = m_responseValidity;
193 m_responseValidity = minValidity;
198 VerificationStatus OCSPImpl::checkEndEntity(
199 const CertificateCollection &chain)
201 // this is temporary fix. it must be rewriten
202 VerificationStatusSet verSet;
204 CertificateList clst;
205 if (chain.isChain() && chain.size() >= 2) {
206 CertificateList::const_iterator icert = chain.begin();
207 clst.push_back(*icert);
209 clst.push_back(*icert);
211 verSet += validateCertificateList(clst);
213 return verSet.convertToStatus();
216 VerificationStatus OCSPImpl::validateCertificate(CertificatePtr argCert,
217 CertificatePtr argIssuer)
219 using namespace SoupWrapper;
227 if (!m_bUseDefResponder) {
228 uri = argCert->getOCSPURL();
230 return VERIFICATION_STATUS_NOT_SUPPORT;
233 if (m_strResponderURI.empty()) {
234 VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
235 "Default responder is not set");
237 LogWarning("Default responder will be used");
239 uri = m_strResponderURI;
243 CreateRequestResult newRequest = createRequest(argCert, argIssuer);
244 if (!newRequest.success) {
245 VcoreThrowMsg(OCSPImpl::Exception::VerificationError, "Request creation failed");
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);
253 SoupMessageSendBase::RequestStatus requestStatus;
254 requestStatus = sendOcspRequest(requestCont, uri);
256 if (requestStatus != SoupMessageSendBase::REQUEST_STATUS_OK) {
257 return VERIFICATION_STATUS_CONNECTION_FAILED;
260 // Response is m_soupMessage, convert it to OCSP_RESPONSE
261 OcspResponse response = convertToResponse();
263 if (!response.first) {
264 VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
265 "OCSP: failed to convert mem buffer to OCSP_RESPONSE");
268 SSLSmartContainer <OCSP_RESPONSE> responseCont(response.second);
269 // verify response eg. check response status,
270 // validate responder certificate
271 validateResponse(requestCont,
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;
290 LogWarning("OCSP: Good");
291 return VERIFICATION_STATUS_GOOD;
294 void OCSPImpl::setDefaultResponder(const char *uri)
297 m_strResponderURI = std::string(uri);
300 void OCSPImpl::setUseDefaultResponder(bool value)
302 m_bUseDefResponder = value;
305 time_t OCSPImpl::getResponseValidity()
307 return m_responseValidity;
310 OCSPImpl::CreateRequestResult OCSPImpl::createRequest(CertificatePtr argCert,
311 CertificatePtr argIssuer)
313 OCSP_REQUEST* newRequest = OCSP_REQUEST_new();
316 LogWarning("OCSP: Failed to create a request");
317 return CreateRequestResult();
320 SSLSmartContainer <OCSP_REQUEST> requestCont(newRequest);
322 OCSP_CERTID* certId = addSerial(argCert, argIssuer);
325 LogWarning("OCSP: Unable to create a serial id");
326 return CreateRequestResult();
328 SSLSmartContainer <OCSP_CERTID> certIdCont(certId);
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();
337 OCSP_request_add1_nonce(requestCont, 0, -1);
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();
347 if (!OCSP_request_sign(requestCont,
348 m_pSignCert->getX509(),
354 LogWarning("OCSP: Unable to sign request");
355 return CreateRequestResult();
358 return CreateRequestResult(true,
359 requestCont.DetachPtr(),
360 certIdCont.DetachPtr());
363 OCSP_CERTID* OCSPImpl::addSerial(CertificatePtr argCert,
364 CertificatePtr argIssuer)
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());
370 return OCSP_cert_id_new(m_pCertIdDigestAlg, iname, ikey, serial);
373 void OCSPImpl::setDigestAlgorithmForCertId(OCSP::DigestAlgorithm alg)
375 const EVP_MD* foundAlg = getDigestAlg(alg);
377 if (NULL != foundAlg) {
378 m_pCertIdDigestAlg = foundAlg;
380 LogDebug("Request for unsupported CertId digest algorithm ignored!");
384 void OCSPImpl::setDigestAlgorithmForRequest(OCSP::DigestAlgorithm alg)
386 const EVP_MD* foundAlg = getDigestAlg(alg);
388 if (NULL != foundAlg) {
389 m_pRequestDigestAlg = foundAlg;
391 LogDebug("Request for unsupported OCSP request digest algorithm ignored!");
395 void OCSPImpl::setTrustedStore(const CertificateList& certs)
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());
405 void OCSPImpl::validateResponse(OCSP_REQUEST* argRequest,
406 OCSP_RESPONSE* argResponse,
407 OCSP_CERTID* argCertId)
409 int result = OCSP_response_status(argResponse);
411 if (result != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
412 handleInvalidResponse(result);
413 VcoreThrowMsg(OCSPImpl::Exception::VerificationError, "OCSP_response_status failed");
416 // get response object
417 OCSP_BASICRESP* basic = OCSP_response_get1_basic(argResponse);
419 VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
420 "OCSP: Unable to get a BASICRESP object.");
423 SSLSmartContainer <OCSP_BASICRESP> basicRespCont(basic);
424 if (m_bUseNonce && OCSP_check_nonce(argRequest, basicRespCont) <= 0) {
425 VcoreThrowMsg(OCSPImpl::Exception::VerificationError, "OCSP: Invalid nonce");
428 if (!verifyResponse(basic)) {
429 VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
430 "Unable to verify the OCSP responder's certificate");
433 checkRevocationStatus(basicRespCont, argCertId);
436 bool OCSPImpl::verifyResponse(OCSP_BASICRESP* basic)
438 Assert(m_pTrustedStore);
439 // verify ocsp response
440 int response = OCSP_basic_verify(basic, NULL, m_pTrustedStore, 0);
442 LogWarning("OCSP verification failed");
448 void OCSPImpl::checkRevocationStatus(OCSP_BASICRESP* basic,
451 ASN1_GENERALIZEDTIME* producedAt;
452 ASN1_GENERALIZEDTIME* thisUpdate;
453 ASN1_GENERALIZEDTIME* nextUpdate;
457 m_responseValidity = 0;
459 if (!OCSP_resp_find_status(basic,
467 VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
468 "OCSP: Failed to find certificate status.");
471 if (!OCSP_check_validity(thisUpdate,
473 MaxValidatyPeriodInSeconds,
476 VcoreThrowMsg(OCSPImpl::Exception::VerificationError,
477 "OCSP: Failed to check certificate validate.");
481 asn1GeneralizedTimeToTimeT(nextUpdate,&m_responseValidity);
484 LogDebug("Time of next OCSP update got from server: " << m_responseValidity);
485 LogDebug("Expires in: " << (m_responseValidity - now));
486 LogDebug("Original: " << nextUpdate->data);
490 case V_OCSP_CERTSTATUS_GOOD:
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");
497 Assert(false && "Invalid status");
501 OCSPImpl::OcspResponse OCSPImpl::convertToResponse()
503 using namespace SoupWrapper;
505 // convert memory buffer to ocsp response object
507 OCSP_RESPONSE* response;
509 SoupMessageSendBase::MessageBuffer buffer = m_soupMessage.getResponse();
511 res_bmem.length = buffer.size();
512 res_bmem.data = &buffer[0];
513 res_bmem.max = buffer.size();
515 BIO* res_mem_bio = BIO_new(BIO_s_mem());
516 BIO_set_mem_buf(res_mem_bio, &res_bmem, BIO_NOCLOSE);
518 response = d2i_OCSP_RESPONSE_bio(res_mem_bio, NULL);
519 BIO_free_all(res_mem_bio);
522 LogWarning("OCSP: Failed to convert OCSP Response to DER format");
523 return std::make_pair(false, static_cast<OCSP_RESPONSE*>(NULL));
526 return std::make_pair(true, response);
529 void OCSPImpl::handleInvalidResponse(int result)
532 case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
533 LogWarning("OCSP: Server returns "
534 "OCSP_RESPONSE_STATUS_MALFORMEDREQUEST status");
536 case OCSP_RESPONSE_STATUS_INTERNALERROR:
537 LogWarning("OCSP: Server returns "
538 "OCSP_RESPONSE_STATUS_INTERNALERROR status");
540 case OCSP_RESPONSE_STATUS_TRYLATER:
541 LogWarning("OCSP: Server returns "
542 "OCSP_RESPONSE_STATUS_TRYLATER status");
544 case OCSP_RESPONSE_STATUS_SIGREQUIRED:
545 LogWarning("OCSP: Server returns "
546 "OCSP_RESPONSE_STATUS_SIGREQUIRED status");
548 case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
549 LogWarning("OCSP: Server returns "
550 "OCSP_RESPONSE_STATUS_UNAUTHORIZED status");
553 Assert(false && "Invalid result value");
556 } // namespace ValidationCore