merge with master
[framework/osp/net.git] / src / http / FNetHttp_HttpTransactionImpl.cpp
index 6e1bf75..27b16b2 100644 (file)
@@ -38,6 +38,7 @@
 #include <FNetHttpIHttpEntity.h>
 #include <FNetHttpIHttpProgressEventListener.h>
 #include <FBaseSysLog.h>
+#include <FSecurity.h>
 #include <FBase_StringConverter.h>
 #include <FBaseRt_EventDispatcher.h>
 #include <FSecCert_CertService.h>
@@ -97,6 +98,7 @@ _HttpTransactionImpl::_HttpTransactionImpl(HttpTransaction* pHttpTransaction)
        , __isAlreadyResumed(false)
        , __isAlreadyPaused(false)
        , __isCertRequiredEventFired(false)
+       , __certificateFlag(HTTP_CV_FLAG_AUTOMATIC)
        , __pHttpProgressListener(null)
        , __pHttpTransactionUserData(null)
        , __pHttpCurl(null)
@@ -345,6 +347,80 @@ _HttpTransactionImpl::Abort(void)
        return r;
 }
 
+result
+_HttpTransactionImpl::Set(_HttpTransactionImpl* pHttpTransactionImpl)
+{
+       result r = E_SUCCESS;
+
+       HttpRequest* pHttpRequest = null;
+       _HttpRequestImpl* pHttpRequestImpl = null;
+       _HttpRequestImpl* pSrcHttpRequestImpl = null;
+
+       ByteBuffer* pRequestBuffer = null;
+       ArrayListT< IHttpTransactionEventListener* > listenerList;
+       Object* pUserObject = null;
+
+       //Sets user object.
+       pUserObject = pHttpTransactionImpl->GetUserObject();
+       __pUserData = pUserObject;
+
+       //Sets event listener.
+       r = listenerList.Construct(*(pHttpTransactionImpl->GetEventListenerList()));
+       SysTryReturn(NID_NET_HTTP, r == E_SUCCESS, null, E_OUT_OF_MEMORY,
+                                "[E_OUT_OF_MEMORY] Memory allocation failed.");
+
+       for (int i = 0; i < listenerList.GetCount(); i++)
+       {
+               IHttpTransactionEventListener* pListener = null;
+               r = listenerList.GetAt(i, pListener);
+               SysTryReturn(NID_NET_HTTP, r == E_SUCCESS && pListener != null, null, E_SYSTEM,
+                                       "[E_SYSTEM] A system error has occurred.");
+
+               r = this->AddHttpTransactionListener(*pListener);
+               SysTryReturn(NID_NET_HTTP, r == E_SUCCESS, null, r,
+                                       "[%s] Failed to add the HttpTransactionEventListener.", GetErrorMessage(r));
+       }
+
+       __pHttpProgressListener = pHttpTransactionImpl->GetHttpProgressEventListener();
+
+       __enableTransactionReadyToWrite = pHttpTransactionImpl->IsTransactionReadyToWriteEanbled();
+       __timeout = pHttpTransactionImpl->GetTimeout();
+       __certificateId = pHttpTransactionImpl->GetClientCertificate();
+       __isAlreadyResumed = pHttpTransactionImpl->IsAlreadyResumed();
+       __certificateFlag = pHttpTransactionImpl->GetServerCertificateVerification();
+
+       pHttpRequest = pHttpTransactionImpl->GetRequest();
+       SysTryReturn(NID_NET_HTTP, pHttpRequest != null, null, E_SYSTEM,
+                                "[E_SYSTEM] An internal error has occurred.");
+
+       pHttpRequestImpl = _HttpRequestImpl::GetInstance(*pHttpRequest);
+       SysTryReturn(NID_NET_HTTP, pHttpRequestImpl != null, null, E_SYSTEM,
+                                "[E_SYSTEM] An internal error has occurred.");
+
+       pSrcHttpRequestImpl = _HttpRequestImpl::GetInstance(*__pHttpRequest);
+       SysTryReturn(NID_NET_HTTP, pSrcHttpRequestImpl != null, null, E_SYSTEM,
+                                "[E_SYSTEM] An internal error has occurred.");
+
+       //Sets HttpRequest.
+       r = pSrcHttpRequestImpl->Set(pHttpRequestImpl);
+       SysTryReturn(NID_NET_HTTP, r == E_SUCCESS, null, E_SYSTEM,
+                                "[E_SYSTEM] An internal error has occurred.");
+
+       pRequestBuffer = pHttpTransactionImpl->GetRequestBuffer();
+       if (pRequestBuffer != null)
+       {
+               //Clear the flag of _HttpRequestImpl
+               pSrcHttpRequestImpl->SetReceivedTransactionReadyToWriteEvent(false);
+
+               r = pSrcHttpRequestImpl->WriteBody(*pRequestBuffer);
+               SysTryReturn(NID_NET_HTTP, r == E_SUCCESS, null, r, "[%s] Failed to write the body.", GetErrorMessage(r));
+
+               SysLog(NID_NET_HTTP, "The __pRequestBuffer is added to the Body.");
+       }
+
+       return r;
+}
+
 String
 _HttpTransactionImpl::GetDefaultUserAgent(void)
 {
@@ -577,11 +653,17 @@ _HttpTransactionImpl::Submit(void)
                SysTryReturnResult(NID_NET_HTTP, r == E_SUCCESS,
                                                   E_INVALID_ARG, "Failed to parse the content-length.");
                //Set Content-Length
-               if (contentLen >= 0)
+               if (contentLen > 0)
                {
                        curl_easy_setopt(pCurl, CURLOPT_POSTFIELDSIZE_LARGE, static_cast< curl_off_t >(contentLen));
                        SysLog(NID_NET_HTTP, "Set the Content-Length(%lld).", contentLen);
                }
+               else if (contentLen == 0)
+               {
+                       curl_easy_setopt(pCurl, CURLOPT_POSTFIELDSIZE_LARGE, static_cast< curl_off_t >(contentLen));
+                       curl_easy_setopt(pCurl, CURLOPT_COPYPOSTFIELDS, NULL);
+                       SysLog(NID_NET_HTTP, "Set the Content-Length(%lld).", contentLen);
+               }
 
                SysLog(NID_NET_HTTP, "The Content-Length is %lld.", contentLen);
        }
@@ -646,20 +728,29 @@ _HttpTransactionImpl::Submit(void)
                curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_TIME, 30L);
        }
 
-       //Set default CA path.
-       String caPath = _CertService::GetCertificateCrtFilePath();
-       SysLog(NID_NET_HTTP, "The CA Path is %ls.", caPath.GetPointer());
+       if (__certificateFlag == HTTP_CV_FLAG_IGNORED)
+       {
+               curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0);
+               curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0);
+               SysLog(NID_NET_HTTP, "The server certificate verification is ignored.");
 
-       char* pCaPath = _StringConverter::CopyToCharArrayN(caPath);
-       SysTryReturnResult(NID_NET_HTTP, pCaPath != null,
-                                          E_OUT_OF_MEMORY, "Memory allocation failed.");
+       } else
+       {
+               //Set default CA path.
+               String caPath = _CertService::GetCertificateCrtFilePath();
+               SysLog(NID_NET_HTTP, "The CA Path is %ls.", caPath.GetPointer());
 
-       curl_easy_setopt(pCurl, CURLOPT_CAINFO, pCaPath);
-       curl_easy_setopt(pCurl, CURLOPT_CAPATH, null);
-       delete[] pCaPath;
+               char* pCaPath = _StringConverter::CopyToCharArrayN(caPath);
+               SysTryReturnResult(NID_NET_HTTP, pCaPath != null,
+                                                  E_OUT_OF_MEMORY, "Memory allocation failed.");
+
+               curl_easy_setopt(pCurl, CURLOPT_CAINFO, pCaPath);
+               curl_easy_setopt(pCurl, CURLOPT_CAPATH, null);
+               delete[] pCaPath;
 
-       curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0);
-       curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 2);
+               curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0);
+               curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 2);
+       }
 
        if (__certificateId >= 0)
        {
@@ -1104,6 +1195,12 @@ _HttpTransactionImpl::SetTimeout(int timeout)
        return r;
 }
 
+int
+_HttpTransactionImpl::GetTimeout(void) const
+{
+       return __timeout;
+}
+
 result
 _HttpTransactionImpl::SetClientCertificate(int certificateId)
 {
@@ -1122,6 +1219,36 @@ _HttpTransactionImpl::SetClientCertificate(int certificateId)
        return r;
 }
 
+int
+_HttpTransactionImpl::GetClientCertificate(void) const
+{
+       return __certificateId;
+}
+
+result
+_HttpTransactionImpl::SetServerCertificateVerification(NetHttpCertificateVerificationFlag flag)
+{
+       result r = E_SUCCESS;
+
+       SysTryReturnResult(NID_NET_HTTP, __isClosed == false,
+                                          E_INVALID_STATE, "HttpTransaction[%d] is already closed.", __transactionId);
+
+       SysTryReturnResult(NID_NET_HTTP, __isSubmitted == false,
+                                          E_INVALID_STATE, "HttpTransaction[%d] is already submitted.", __transactionId);
+
+       __certificateFlag = flag;
+
+       SysLog(NID_NET_HTTP, "Set the flag for certificate verification.[%s].", _HttpUtility::ConvertNetHttpCertificateVerificationFlagToString(flag));
+
+       return r;
+}
+
+NetHttpCertificateVerificationFlag
+_HttpTransactionImpl::GetServerCertificateVerification(void) const
+{
+       return __certificateFlag;
+}
+
 _HttpTransactionImpl*
 _HttpTransactionImpl::GetInstance(HttpTransaction& httpTransaction)
 {
@@ -1724,15 +1851,32 @@ _HttpTransactionImpl::OnHttpSslHandshake(CURL* pCurl, SSL_CTX* pSslctx, void* pU
        result r = E_SUCCESS;
        CURLcode curlCode = CURLE_OK;
 
+       SysLog(NID_NET_HTTP, "Received OnHttpSslHandshake()");
+
        _HttpTransactionUserData* pHttpTransactionUserData = static_cast< _HttpTransactionUserData* >(pUserData);
        _HttpTransactionImpl* pHttpTransactionImpl = pHttpTransactionUserData->GetHttpTransactionImpl();
 
-       if (pHttpTransactionImpl->__isAlreadyResumed)
+       if (pHttpTransactionImpl->__isAlreadyResumed || pHttpTransactionImpl->__certificateFlag == HTTP_CV_FLAG_IGNORED)
        {
                SysLog(NID_NET_HTTP, "Resume the HttpTransaction. Ignore to verify the server cert.");
        }
        else
        {
+               if (pHttpTransactionImpl->__certificateFlag == HTTP_CV_FLAG_MANUAL)
+               {
+                       unique_ptr<_HttpSslInfo> pSSLInfo;
+
+                       SysLog(NID_NET_HTTP, "The certificate mode is HTTP_CV_FLAG_MANUAL");
+
+                       pSSLInfo.reset(new (std::nothrow) _HttpSslInfo(pHttpTransactionUserData->GetSocketFd(), pHttpTransactionImpl->__pHttpTransactionEvent));
+                       SysTryReturn(NID_NET_HTTP, pSSLInfo != null, CURLE_SSL_CERTPROBLEM, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
+
+                       r = _HttpUtility::SetSslCertInfo(*pSSLInfo);
+                       SysTryReturn(NID_NET_HTTP, r == E_SUCCESS, CURLE_SSL_CERTPROBLEM, r, "[%s] Memory allocation failed.", GetErrorMessage(r));
+
+                       pSSLInfo.release();
+               }
+
                SSL_CTX_set_verify_depth(pSslctx, _HTTP_CERT_VERIFICATION_DEPTH_LIMIT);
                SSL_CTX_set_verify(pSslctx, SSL_VERIFY_PEER, _HttpTransactionImpl::OnHttpSslVerify);
        }
@@ -1789,6 +1933,7 @@ _HttpTransactionImpl::OnHttpSslVerify(int preverify_ok, X509_STORE_CTX* pX509ctx
        result r = E_SUCCESS;
        int socketFd = -1;
        unique_ptr<_HttpSslInfo> pSSLInfo;
+       _HttpSslInfo* pExistSslInfo = null;
        int sslIndex = SSL_get_ex_data_X509_STORE_CTX_idx();
        SSL* pSsl = (SSL*) X509_STORE_CTX_get_ex_data(pX509ctx, sslIndex);
 
@@ -1797,54 +1942,151 @@ _HttpTransactionImpl::OnHttpSslVerify(int preverify_ok, X509_STORE_CTX* pX509ctx
        socketFd = SSL_get_fd(pSsl);
        SysLog(NID_NET_HTTP, "The ssl socket is %d.", socketFd);
 
-       X509* pServerCert = null;
+       X509* pSrcServerCert = null;
+       unique_ptr<X509, _X509Deleter> pServerCert;
        int depth = X509_STORE_CTX_get_error_depth(pX509ctx);
        int error = X509_STORE_CTX_get_error(pX509ctx);
 
-       if (error != X509_V_OK)
+       pExistSslInfo = _HttpUtility::GetSslCertInfo(socketFd);
+
+       if (pExistSslInfo != null)
        {
-               STACK_OF(X509)* pServerCertChain = null;
+               bool certVerificationResult = false;
+
+               _HttpTransactionEvent* pHttpTransactionEvent = pExistSslInfo->GetHttpTransactionEvent();
+               SysTryReturn(NID_NET_HTTP, pHttpTransactionEvent != null, 0, E_SYSTEM, "[E_SYSTEM] pHttpTransactionEvent must not be null.");
+
+               if (pHttpTransactionEvent->GetCertRequestedResult())
+               {
+                       SysLog(NID_NET_HTTP, "The certificate verification is already resumed.");
+                       return 1;
+               }
+
+               //The certificateFlag is HTTP_CV_FLAG_MANUAL.
                String serverCertString;
-               pServerCertChain = X509_STORE_CTX_get1_chain(pX509ctx);
+               STACK_OF(X509)* pSrcServerCertChain = X509_STORE_CTX_get1_chain(pX509ctx);
+               unique_ptr<STACK_OF(X509), _X509ChainDeleter> pServerCertChain(pSrcServerCertChain);
                if (pServerCertChain != null)
                {
+                       unique_ptr<IList, _CollectionDeleter> pCertList(new (nothrow) LinkedList(SingleObjectDeleter));
+                       SysTryReturn(NID_NET_HTTP, pCertList != null, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
+
                        int numberOfCerts = pServerCertChain->stack.num;
                        for (int i = numberOfCerts; i > 0; i--)
                        {
-                               pServerCert = sk_X509_pop(pServerCertChain);
+                               pSrcServerCert = sk_X509_pop(pSrcServerCertChain);
+                               pServerCert.reset(pSrcServerCert);
                                if (pServerCert != null)
                                {
                                        char tempSubjectName[_HTTP_CERT_SUBJECT_SIZE];
-                                       X509_NAME_oneline(X509_get_subject_name(pServerCert), tempSubjectName, _HTTP_CERT_SUBJECT_SIZE);
+                                       X509_NAME_oneline(X509_get_subject_name(pSrcServerCert), tempSubjectName, _HTTP_CERT_SUBJECT_SIZE);
                                        serverCertString = String(tempSubjectName);
 
-                                       SysLog(NID_NET_HTTP, "The subject of certificate is %ls[depth: %d].", serverCertString.GetPointer(), i -1);
-                                       depth = i -1;
-                                       X509_free(pServerCert);
+                                       SysLog(NID_NET_HTTP, "Count of Certs(%d), The subject of certificate is %ls[depth: %d].", numberOfCerts, serverCertString.GetPointer(), i -1);
+
+                                       // Converter X509 to ByteBuffer.
+                                       int bufferSize = -1;
+                                       int len = -1;
+                                       ByteBuffer buffer;
+                                       unique_ptr<X509Certificate> pX509Certificate;
+                                       char* pSrcCertBytes = null;
+                                       unique_ptr<char, _CharDeleter> pCertBytes;
+
+                                       BIO* pNewBIoCert = BIO_new(BIO_s_mem());
+                                       unique_ptr<BIO, _BIoDeleter> pBIoCert(pNewBIoCert);
+                                       SysTryReturn(NID_NET_HTTP, pBIoCert != null, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
+
+                                       PEM_write_bio_X509(pNewBIoCert, pSrcServerCert);
+                                       bufferSize = BIO_number_written(pNewBIoCert);
+
+                                       pSrcCertBytes = (char*) calloc(bufferSize, sizeof(char));
+                                       pCertBytes.reset(pSrcCertBytes);
+                                       SysTryReturn(NID_NET_HTTP, pCertBytes != null, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
+
+                                       len = BIO_read(pNewBIoCert, pSrcCertBytes, bufferSize);
+                                       SysLog(NID_NET_HTTP, "The buffer size is %d.", len);
+
+                                       r = buffer.Construct((byte*)pSrcCertBytes, 0, len, len);
+                                       SysTryReturn(NID_NET_HTTP, r == E_SUCCESS, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
 
+                                       pX509Certificate.reset(new (nothrow) X509Certificate());
+                                       SysTryReturn(NID_NET_HTTP, pX509Certificate != null, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
+
+                                       r = pX509Certificate->Construct(buffer);
+                                       SysTryReturn(NID_NET_HTTP, r == E_SUCCESS, 0, E_SYSTEM, "[E_SYSTEM] Failed to construct X509Certificate.");
+
+                                       SysLog(NID_NET_HTTP, "Subject: %ls, Issuer: %ls", pX509Certificate->GetSubject().GetPointer(), pX509Certificate->GetIssuer().GetPointer());
+
+                                       r = pCertList->Add(*pX509Certificate);
+                                       SysTryReturn(NID_NET_HTTP, r == E_SUCCESS, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
+
+                                       pX509Certificate.release();
                                }
                        }
-                       sk_X509_free(pServerCertChain);
-               }
-
-               const char* pErrorMsg = X509_verify_cert_error_string(error);
-               SysLog(NID_NET_HTTP, "Failed to verify the cert. depth(%d) - error(%s)", depth, pErrorMsg);
-               SysLog(NID_NET_HTTP, "The subject of last certificate is %ls.", serverCertString.GetPointer());
 
-               pSSLInfo.reset(new (std::nothrow) _HttpSslInfo(socketFd, depth, serverCertString, pErrorMsg));
-               SysTryReturn(NID_NET_HTTP, pSSLInfo != null, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
+                       //Fire the event(_HTTP_TRANSACTION_EVENT_TYPE_CERT_VERIFICATION_REQUESTED)
+                       pHttpTransactionEvent->FireTransactionCertVerificationRequestedNEvent(pCertList.release());
 
-               r = _HttpUtility::AddSslCertInfo(*pSSLInfo);
-               SysTryReturn(NID_NET_HTTP, r == E_SUCCESS, 0, r, "[%s] Memory allocation failed.", GetErrorMessage(r));
+                       certVerificationResult = pHttpTransactionEvent->GetCertRequestedResult();
+                       if (certVerificationResult)
+                       {
+                               _HttpSessionImpl* pHttpSessionImpl = pHttpTransactionEvent->GetHttpSessionImpl();
+                               pHttpSessionImpl->IgnoreSslVerification();
+                       }
 
-               pSSLInfo.release();
+                       //Check the result
+                       return pHttpTransactionEvent->GetCertRequestedResult();
+               }
 
                return 0;
 
-       }
-       else
+       } else
        {
-               return 1;
+               // The certificateFlag is HTTP_CV_FLAG_AUTOMATIC.
+               if (error != X509_V_OK)
+               {
+                       String serverCertString;
+                       STACK_OF(X509)* pSrcServerCertChain = X509_STORE_CTX_get1_chain(pX509ctx);
+                       unique_ptr<STACK_OF(X509), _X509ChainDeleter> pServerCertChain(pSrcServerCertChain);
+                       if (pServerCertChain != null)
+                       {
+                               int numberOfCerts = pServerCertChain->stack.num;
+                               for (int i = numberOfCerts; i > 0; i--)
+                               {
+                                       pSrcServerCert = sk_X509_pop(pSrcServerCertChain);
+                                       pServerCert.reset(pSrcServerCert);
+                                       if (pServerCert != null)
+                                       {
+                                               char tempSubjectName[_HTTP_CERT_SUBJECT_SIZE];
+                                               X509_NAME_oneline(X509_get_subject_name(pSrcServerCert), tempSubjectName, _HTTP_CERT_SUBJECT_SIZE);
+                                               serverCertString = String(tempSubjectName);
+
+                                               SysLog(NID_NET_HTTP, "The subject of certificate is %ls[depth: %d].", serverCertString.GetPointer(), i -1);
+                                               depth = i -1;
+                                       }
+                               }
+                       }
+
+                       const char* pErrorMsg = X509_verify_cert_error_string(error);
+                       SysLog(NID_NET_HTTP, "Failed to verify the cert. depth(%d) - error(%s)", depth, pErrorMsg);
+                       SysLog(NID_NET_HTTP, "The subject of last certificate is %ls.", serverCertString.GetPointer());
+
+                       pSSLInfo.reset(new (std::nothrow) _HttpSslInfo(socketFd, depth, serverCertString, pErrorMsg));
+                       SysTryReturn(NID_NET_HTTP, pSSLInfo != null, 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
+
+                       r = _HttpUtility::SetSslCertInfo(*pSSLInfo);
+                       SysTryReturn(NID_NET_HTTP, r == E_SUCCESS, 0, r, "[%s] Memory allocation failed.", GetErrorMessage(r));
+
+                       pSSLInfo.release();
+
+                       return 0;
+
+               }
+               else
+               {
+                       return 1;
+               }
+
        }
 }