Add additional error logs in ocsp module.
[platform/core/security/key-manager.git] / src / manager / service / ocsp.cpp
index 125a337..a917dd1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2014 Samsung Electronics Co.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 #include <unistd.h>
 #include <key-manager-util.h>
 #include <dpl/log/log.h>
+#include <certificate-impl.h>
+
+#include <ckm/ckm-error.h>
 
 /* Maximum leeway in validity period: default 5 minutes */
 #define MAX_VALIDITY_PERIOD     (5 * 60)
 
-#define CKM_OCSP_OPER_SUCCESS  1
-#define CKM_OCSP_OPER_FAIL             0
-
-#define CKM_DEF_STRING_LEN             256
-
 namespace CKM {
 
 OCSPModule::OCSPModule() {
-       // Do nothing.
+    // Do nothing.
 }
 
 OCSPModule::~OCSPModule(){
-       // Do nothing.
+    // Do nothing.
 }
 
 int OCSPModule::verify(const CertificateImplVector &certificateChain) {
-       X509 *cert = NULL;
-       X509 *issuer = NULL;
-       char url[CKM_DEF_STRING_LEN];
-       int ocspStatus = -1;
-       int result = -1;
-
-       if(&certificateChain == NULL) {
-               LogError("Error in certificateChain value");
-               ThrowMsg(OCSPModule::Exception::OCSP_Internal, "Error in certificateChain value");
-       }
-
-       if((systemCerts = loadSystemCerts(CKM_SYSTEM_CERTS_PATH)) == NULL) {
-               LogError("Error in loadSystemCerts function");
-               ThrowMsg(OCSPModule::Exception::Openssl_Error, "Error in loadSystemCerts function");
-       }
-
-       Try {
-               if((cert = X509_new()) == NULL) {
-                       LogError("Error in X509_new function");
-                       ThrowMsg(OCSPModule::Exception::Openssl_Error, "Error in X509_new function");
-               }
-
-               if((issuer = X509_new()) ==NULL) {
-                       LogError("Error in X509_new function");
-                       ThrowMsg(OCSPModule::Exception::Openssl_Error, "Error in X509_new function");
-               }
-
-               for(unsigned int i=0; i < certificateChain.size() -1; i++) {// except root certificate
-                       rawBufferToX509(&cert, certificateChain[i].getDER());
-                       rawBufferToX509(&issuer, certificateChain[i+1].getDER());
-                       extractAIAUrl(cert, url);
-                       result = ocsp_verify(cert, issuer, systemCerts, url, &ocspStatus);
-                       if(result != OCSP_STATUS_GOOD) {
-                               LogError("Fail to OCSP certification checking");
-                               ThrowMsg(OCSPModule::Exception::OCSP_Internal, "Fail to OCSP certification checking");
-                       }
-               }
-       } Catch(OCSPModule::Exception::Openssl_Error) {
-               if(cert != NULL) {
-                       X509_free(cert);
-               }
-
-               if(issuer != NULL) {
-                       X509_free(issuer);
-               }
-               ReThrowMsg(OCSPModule::Exception::Openssl_Error,"Error in openssl function !!");
-       }
-       Catch(OCSPModule::Exception::OCSP_Internal) {
-                       if(cert != NULL) {
-                               X509_free(cert);
-                       }
-
-                       if(issuer != NULL) {
-                               X509_free(issuer);
-                       }
-                       ReThrowMsg(OCSPModule::Exception::OCSP_Internal,"Fail to OCSP certification checking !!");
-       }
-
-       if(cert != NULL) {
-               X509_free(cert);
-       }
-
-       if(issuer != NULL) {
-               X509_free(issuer);
-       }
-
-       return OCSP_STATUS_GOOD;
-}
+    bool unsupported = false; // ocsp is unsupported in certificate in chain (except root CA)
 
+    if((systemCerts = loadSystemCerts(CKM_SYSTEM_CERTS_PATH)) == NULL) {
+        LogDebug("Error in loadSystemCerts function");
+        return CKM_API_OCSP_STATUS_INTERNAL_ERROR;
+    }
 
-int OCSPModule::ocsp_verify(X509 *cert, X509 *issuer, STACK_OF(X509) *systemCerts, char *url, int *ocspStatus) {
-       OCSP_REQUEST *req = NULL;
-       OCSP_RESPONSE *resp = NULL;
-       OCSP_BASICRESP *bs = NULL;
-       OCSP_CERTID *certid = NULL;
-       BIO *cbio = NULL;
-       SSL_CTX *use_ssl_ctx = NULL;
-       char *host = NULL, *port = NULL, *path = NULL;
-       ASN1_GENERALIZEDTIME *rev = NULL;
-       ASN1_GENERALIZEDTIME *thisupd = NULL;
-       ASN1_GENERALIZEDTIME *nextupd = NULL;
-       int use_ssl = 0;
-       int i = 0 ,tmpIdx = 0;
-       long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
-       int ret = 0;
-       char subj_buf[256];
-       int reason = 0;
-       //    const char *reason_str = NULL;0
-       X509_STORE *trustedStore=NULL;
-
-       if (!OCSP_parse_url(url, &host, &port, &path, &use_ssl)) {
-               /* report error */
-               return OCSP_STATUS_INVALID_URL;
-       }
-
-       cbio = BIO_new_connect(host);
-       if (cbio == NULL) {
-               /*BIO_printf(bio_err, "Error creating connect BIO\n");*/
-               /* report error */
-               return OCSP_STATUS_INTERNAL_ERROR;
-       }
+    for(unsigned int i=0; i < certificateChain.size() -1; i++) {// except root certificate
+        if (certificateChain[i].empty() || certificateChain[i+1].empty()) {
+            LogDebug("Error. Broken certificate chain.");
+            return CKM_API_OCSP_STATUS_INTERNAL_ERROR;
+        }
 
-       if (port != NULL) {
-               BIO_set_conn_port(cbio, port);
-       }
-
-       if (use_ssl == 1) {
-               BIO *sbio = NULL;
-               use_ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-               if (use_ssl_ctx == NULL) {
-                       /* report error */
-                       return OCSP_STATUS_INTERNAL_ERROR;
-               }
-
-               SSL_CTX_set_mode(use_ssl_ctx, SSL_MODE_AUTO_RETRY);
-               sbio = BIO_new_ssl(use_ssl_ctx, 1);
-               if (sbio == NULL) {
-                       /* report error */
-                       return OCSP_STATUS_INTERNAL_ERROR;
-               }
-
-               cbio = BIO_push(sbio, cbio);
-               if (cbio == NULL) {
-                       /* report error */
-                       return OCSP_STATUS_INTERNAL_ERROR;
-               }
-       }
-
-       if (BIO_do_connect(cbio) <= 0) {
-               /*BIO_printf(bio_err, "Error connecting BIO\n");*/
-               /* report error */
-
-               /* free stuff */
-               if (host != NULL) {
-                       OPENSSL_free(host);
-               }
-
-               if (port != NULL) {
-                       OPENSSL_free(port);
-               }
-
-               if (path != NULL) {
-                       OPENSSL_free(path);
-               }
-               host = port = path = NULL;
-
-               if (use_ssl && use_ssl_ctx) {
-                       SSL_CTX_free(use_ssl_ctx);
-               }
-               use_ssl_ctx = NULL;
-
-               if (cbio != NULL) {
-                       BIO_free_all(cbio);
-               }
-               cbio = NULL;
-
-               return OCSP_STATUS_NET_ERROR;
-       }
-
-       req = OCSP_REQUEST_new();
-
-       if(req == NULL) {
-               return OCSP_STATUS_INTERNAL_ERROR;
-       }
-       certid = OCSP_cert_to_id(NULL, cert, issuer);
-       if(certid == NULL)  {
-               return OCSP_STATUS_INTERNAL_ERROR;
-       }
-
-       if(OCSP_request_add0_id(req, certid) == NULL) {
-               return OCSP_STATUS_INTERNAL_ERROR;
-       }
-
-       resp = OCSP_sendreq_bio(cbio, path, req);
-
-       /* free some stuff we no longer need */
-       if (host != NULL) {
-               OPENSSL_free(host);
-       }
+        X509 *cert   = certificateChain[i].getX509();
+        X509 *issuer = certificateChain[i+1].getX509();
+        std::string url = certificateChain[i].getOCSPURL();
 
-       if (port != NULL) {
-               OPENSSL_free(port);
-       }
-
-       if (path != NULL) {
-               OPENSSL_free(path);
-       }
-       host = port = path = NULL;
-
-       if (use_ssl && use_ssl_ctx) {
-               SSL_CTX_free(use_ssl_ctx);
-       }
-       use_ssl_ctx = NULL;
-
-       if (cbio != NULL) {
-               BIO_free_all(cbio);
-       }
-       cbio = NULL;
-
-       if (!resp) {
-               /*BIO_printf(bio_err, "Error querying OCSP responsder\n");*/
-               /* report error */
-               /* free stuff */
-               OCSP_REQUEST_free(req);
-               return OCSP_STATUS_NET_ERROR;
-       }
-
-       i = OCSP_response_status(resp);
-
-       if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
-               /*BIO_printf(out, "Responder Error: %s (%ld)\n",
-                   OCSP_response_status_str(i), i); */
-               /* report error */
-               /* free stuff */
-               OCSP_REQUEST_free(req);
-               OCSP_RESPONSE_free(resp);
-               return OCSP_STATUS_REMOTE_ERROR;
-       }
-
-       bs = OCSP_response_get1_basic(resp);
-       if (!bs) {
-               /* BIO_printf(bio_err, "Error parsing response\n");*/
-               /* report error */
-               /* free stuff */
-               OCSP_REQUEST_free(req);
-               OCSP_RESPONSE_free(resp);
-               return OCSP_STATUS_INVALID_RESPONSE;
-       }
-
-       if(systemCerts != NULL) {
-               trustedStore = X509_STORE_new();
-               for(tmpIdx=0; tmpIdx<sk_X509_num(systemCerts); tmpIdx++) {
-                       X509_STORE_add_cert(trustedStore, sk_X509_value(systemCerts, tmpIdx));
-               }
-               X509_STORE_add_cert(trustedStore, issuer);
-       }
-
-       int response = OCSP_basic_verify(bs, NULL, trustedStore, 0);
-       if (response <= 0) {
-               OCSP_REQUEST_free(req);
-               OCSP_RESPONSE_free(resp);
-               OCSP_BASICRESP_free(bs);
-               X509_STORE_free(trustedStore);
-               // find the reason of error
-               int err = ERR_get_error();
-               char errStr[100];
-               ERR_error_string(err,errStr);
-               // printf("OCSP_basic_verify fail.error = %s\n", errStr);
-               return OCSP_STATUS_INVALID_RESPONSE;
-       }
-
-       if ((i = OCSP_check_nonce(req, bs)) <= 0) {
-               if (i == -1) {
-                       /*BIO_printf(bio_err, "WARNING: no nonce in response\n");*/
-               } else {
-                       /*BIO_printf(bio_err, "Nonce Verify error\n");*/
-                       /* report error */
-                       /* free stuff */
-                       OCSP_REQUEST_free(req);
-                       OCSP_RESPONSE_free(resp);
-                       OCSP_BASICRESP_free(bs);
-                       X509_STORE_free(trustedStore);
-                       return OCSP_STATUS_INVALID_RESPONSE;
-               }
-       }
-
-       (void)X509_NAME_oneline(X509_get_subject_name(cert), subj_buf, 255);
-       if(!OCSP_resp_find_status(bs, certid, ocspStatus, &reason,
-                       &rev, &thisupd, &nextupd)) {
-               /* report error */
-
-               /* free stuff */
-               OCSP_RESPONSE_free(resp);
-               OCSP_REQUEST_free(req);
-               OCSP_BASICRESP_free(bs);
-               X509_STORE_free(trustedStore);
-
-               return OCSP_STATUS_INVALID_RESPONSE;
-       }
-
-
-       /* Check validity: if invalid write to output BIO so we
-        * know which response this refers to.
-        */
-       if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) {
-               /* ERR_print_errors(out); */
-               /* report error */
-
-               /* free stuff */
-               OCSP_REQUEST_free(req);
-               OCSP_RESPONSE_free(resp);
-               OCSP_BASICRESP_free(bs);
-               X509_STORE_free(trustedStore);
-
-               return OCSP_STATUS_INVALID_RESPONSE;
-       }
-
-       if (req != NULL) {
-               OCSP_REQUEST_free(req);
-               req = NULL;
-       }
-
-       if (resp != NULL) {
-               OCSP_RESPONSE_free(resp);
-               resp = NULL;
-       }
-
-       if (bs != NULL) {
-               OCSP_BASICRESP_free(bs);
-               bs = NULL;
-       }
-
-       if(trustedStore != NULL) {
-               X509_STORE_free(trustedStore);
-               trustedStore = NULL;
-       }
-
-       switch(*ocspStatus) {
-       case V_OCSP_CERTSTATUS_GOOD :
-               ret = OCSP_STATUS_GOOD; break;
-       case V_OCSP_CERTSTATUS_REVOKED :
-               ret = OCSP_STATUS_REVOKED; break;
-       case V_OCSP_CERTSTATUS_UNKNOWN :
-               ret = OCSP_STATUS_UNKNOWN; break;
-       }
-
-       return ret;
-}
+        if (url.empty()) {
+            LogDebug("Certificate does not provide OCSP extension.");
+            unsupported = true;
+            continue;
+        }
 
-void OCSPModule::extractAIAUrl(X509 *cert, char *url) {
-       STACK_OF(OPENSSL_STRING) *aia = NULL;
-       aia = X509_get1_ocsp(cert);
-       if(aia == NULL) {
-               return;
-       }
-       strcpy(url, sk_OPENSSL_STRING_value(aia, 0));
-       X509_email_free(aia);
-       return;
+        int result = ocsp_verify(cert, issuer, systemCerts, url);
+
+        if(result != CKM_API_OCSP_STATUS_GOOD) {
+            LogDebug("Fail to OCSP certification checking: " << result);
+            return result;
+        }
+    }
+
+    if (unsupported)
+        return CKM_API_OCSP_STATUS_UNSUPPORTED;
+
+    return CKM_API_OCSP_STATUS_GOOD;
 }
 
+int OCSPModule::ocsp_verify(X509 *cert, X509 *issuer, STACK_OF(X509) *systemCerts, const std::string &constUrl) {
+    OCSP_REQUEST *req = NULL;
+    OCSP_RESPONSE *resp = NULL;
+    OCSP_BASICRESP *bs = NULL;
+    OCSP_CERTID *certid = NULL;
+    BIO *cbio = NULL;
+    SSL_CTX *use_ssl_ctx = NULL;
+    char *host = NULL, *port = NULL, *path = NULL;
+    ASN1_GENERALIZEDTIME *rev = NULL;
+    ASN1_GENERALIZEDTIME *thisupd = NULL;
+    ASN1_GENERALIZEDTIME *nextupd = NULL;
+    int use_ssl = 0;
+    int ocspStatus = -1;
+    int i = 0 ,tmpIdx = 0;
+    long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
+    char subj_buf[256];
+    int reason = 0;
+    //    const char *reason_str = NULL;0
+    X509_STORE *trustedStore=NULL;
+
+    std::vector<char> url(constUrl.begin(), constUrl.end());
+
+    if (!OCSP_parse_url(url.data(), &host, &port, &path, &use_ssl)) {
+        /* report error */
+        return CKM_API_OCSP_STATUS_INVALID_URL;
+    }
+
+    LogDebug("Host: " << host);
+    LogDebug("Port: " << port);
+    LogDebug("Path: " << path);
+    LogDebug("Use_ssl: " << use_ssl);
+
+    cbio = BIO_new_connect(host);
+    if (cbio == NULL) {
+        /*BIO_printf(bio_err, "Error creating connect BIO\n");*/
+        /* report error */
+        return CKM_API_OCSP_STATUS_INTERNAL_ERROR;
+    }
+
+       if (port != NULL) {
+               BIO_set_conn_port(cbio, port);
+    }
+
+    if (use_ssl == 1) {
+        BIO *sbio = NULL;
+        use_ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+        if (use_ssl_ctx == NULL) {
+            /* report error */
+            return CKM_API_OCSP_STATUS_INTERNAL_ERROR;
+        }
+
+        SSL_CTX_set_mode(use_ssl_ctx, SSL_MODE_AUTO_RETRY);
+        sbio = BIO_new_ssl(use_ssl_ctx, 1);
+        if (sbio == NULL) {
+            /* report error */
+            return CKM_API_OCSP_STATUS_INTERNAL_ERROR;
+        }
+
+        cbio = BIO_push(sbio, cbio);
+        if (cbio == NULL) {
+            /* report error */
+            return CKM_API_OCSP_STATUS_INTERNAL_ERROR;
+        }
+    }
+
+    if (BIO_do_connect(cbio) <= 0) {
+        LogDebug("Error in BIO_do_connect.");
+        ERR_print_errors_fp(stderr);
+        /*BIO_printf(bio_err, "Error connecting BIO\n");*/
+        /* report error */
+
+        /* free stuff */
+        if (host != NULL) {
+            OPENSSL_free(host);
+        }
+
+        if (port != NULL) {
+            OPENSSL_free(port);
+        }
+
+        if (path != NULL) {
+            OPENSSL_free(path);
+        }
+        host = port = path = NULL;
+
+        if (use_ssl && use_ssl_ctx) {
+            SSL_CTX_free(use_ssl_ctx);
+        }
+        use_ssl_ctx = NULL;
+
+        if (cbio != NULL) {
+            BIO_free_all(cbio);
+        }
+        cbio = NULL;
+
+        return CKM_API_OCSP_STATUS_NET_ERROR;
+    }
+
+    req = OCSP_REQUEST_new();
+
+    if(req == NULL) {
+        LogDebug("Error in OCPS_REQUEST_new");
+        return CKM_API_OCSP_STATUS_INTERNAL_ERROR;
+    }
+    certid = OCSP_cert_to_id(NULL, cert, issuer);
+    if(certid == NULL)  {
+        LogDebug("Error in OCSP_cert_to_id");
+        return CKM_API_OCSP_STATUS_INTERNAL_ERROR;
+    }
+
+    if(OCSP_request_add0_id(req, certid) == NULL) {
+        LogDebug("Error in OCSP_request_add0_id");
+        return CKM_API_OCSP_STATUS_INTERNAL_ERROR;
+    }
+
+    resp = OCSP_sendreq_bio(cbio, path, req);
+
+    /* free some stuff we no longer need */
+    if (host != NULL) {
+        OPENSSL_free(host);
+    }
+
+    if (port != NULL) {
+        OPENSSL_free(port);
+    }
+
+    if (path != NULL) {
+        OPENSSL_free(path);
+    }
+    host = port = path = NULL;
+
+    if (use_ssl && use_ssl_ctx) {
+        SSL_CTX_free(use_ssl_ctx);
+    }
+    use_ssl_ctx = NULL;
+
+    if (cbio != NULL) {
+        BIO_free_all(cbio);
+    }
+    cbio = NULL;
+
+    if (!resp) {
+        /*BIO_printf(bio_err, "Error querying OCSP responsder\n");*/
+        /* report error */
+        /* free stuff */
+        OCSP_REQUEST_free(req);
+        return CKM_API_OCSP_STATUS_NET_ERROR;
+    }
+
+    i = OCSP_response_status(resp);
+
+    if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+        /*BIO_printf(out, "Responder Error: %s (%ld)\n",
+          OCSP_response_status_str(i), i); */
+        /* report error */
+        /* free stuff */
+        OCSP_REQUEST_free(req);
+        OCSP_RESPONSE_free(resp);
+        return CKM_API_OCSP_STATUS_REMOTE_ERROR;
+    }
+
+    bs = OCSP_response_get1_basic(resp);
+    if (!bs) {
+        /* BIO_printf(bio_err, "Error parsing response\n");*/
+        /* report error */
+        /* free stuff */
+        OCSP_REQUEST_free(req);
+        OCSP_RESPONSE_free(resp);
+
+        LogDebug("Error in OCSP_response_get1_basic");
+        return CKM_API_OCSP_STATUS_INVALID_RESPONSE;
+    }
+
+    if(systemCerts != NULL) {
+        trustedStore = X509_STORE_new();
+        for(tmpIdx=0; tmpIdx<sk_X509_num(systemCerts); tmpIdx++) {
+            X509_STORE_add_cert(trustedStore, sk_X509_value(systemCerts, tmpIdx));
+        }
+        X509_STORE_add_cert(trustedStore, issuer);
+    }
+
+    int response = OCSP_basic_verify(bs, NULL, trustedStore, 0);
+    if (response <= 0) {
+        OCSP_REQUEST_free(req);
+        OCSP_RESPONSE_free(resp);
+        OCSP_BASICRESP_free(bs);
+        X509_STORE_free(trustedStore);
+        // find the reason of error
+        int err = ERR_get_error();
+        char errStr[100];
+        ERR_error_string(err,errStr);
+        // printf("OCSP_basic_verify fail.error = %s\n", errStr);
+        LogDebug("Error in OCSP_basic_verify.");
+        return CKM_API_OCSP_STATUS_INVALID_RESPONSE;
+    }
+
+    if ((i = OCSP_check_nonce(req, bs)) <= 0) {
+        if (i == -1) {
+            /*BIO_printf(bio_err, "WARNING: no nonce in response\n");*/
+        } else {
+            /*BIO_printf(bio_err, "Nonce Verify error\n");*/
+            /* report error */
+            /* free stuff */
+            OCSP_REQUEST_free(req);
+            OCSP_RESPONSE_free(resp);
+            OCSP_BASICRESP_free(bs);
+            X509_STORE_free(trustedStore);
+            LogDebug("Error in OCSP_check_nonce");
+            return CKM_API_OCSP_STATUS_INVALID_RESPONSE;
+        }
+    }
+
+    (void)X509_NAME_oneline(X509_get_subject_name(cert), subj_buf, 255);
+    if(!OCSP_resp_find_status(bs, certid, &ocspStatus, &reason,
+          &rev, &thisupd, &nextupd)) {
+        /* report error */
+
+        /* free stuff */
+        OCSP_RESPONSE_free(resp);
+        OCSP_REQUEST_free(req);
+        OCSP_BASICRESP_free(bs);
+        X509_STORE_free(trustedStore);
+
+        LogDebug("Error in OCSP_resp_find_status");
+        return CKM_API_OCSP_STATUS_INVALID_RESPONSE;
+    }
+
+
+    /* Check validity: if invalid write to output BIO so we
+     * know which response this refers to.
+     */
+    if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) {
+        /* ERR_print_errors(out); */
+        /* report error */
+
+        /* free stuff */
+        OCSP_REQUEST_free(req);
+        OCSP_RESPONSE_free(resp);
+        OCSP_BASICRESP_free(bs);
+        X509_STORE_free(trustedStore);
+
+        LogDebug("Error in OCSP_check_validity");
+        return CKM_API_OCSP_STATUS_INVALID_RESPONSE;
+    }
+
+    if (req != NULL) {
+        OCSP_REQUEST_free(req);
+        req = NULL;
+    }
+
+    if (resp != NULL) {
+        OCSP_RESPONSE_free(resp);
+        resp = NULL;
+    }
+
+    if (bs != NULL) {
+        OCSP_BASICRESP_free(bs);
+        bs = NULL;
+    }
+
+    if(trustedStore != NULL) {
+        X509_STORE_free(trustedStore);
+        trustedStore = NULL;
+    }
+
+    switch(ocspStatus) {
+    case V_OCSP_CERTSTATUS_GOOD:
+        return CKM_API_OCSP_STATUS_GOOD;
+    case V_OCSP_CERTSTATUS_REVOKED:
+        return CKM_API_OCSP_STATUS_REVOKED;
+    case V_OCSP_CERTSTATUS_UNKNOWN:
+        return CKM_API_OCSP_STATUS_UNKNOWN;
+    default:
+        LogError("Internal openssl error: Certificate status have value is out of bound.");
+        return CKM_API_OCSP_STATUS_INTERNAL_ERROR;
+    }
 }
+
+} // namespace CKM
+