michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "OCSPRequestor.h" michael@0: michael@0: #include "nsIURLParser.h" michael@0: #include "nsNSSCallbacks.h" michael@0: #include "nsNetCID.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "pkix/ScopedPtr.h" michael@0: #include "secerr.h" michael@0: michael@0: namespace mozilla { namespace psm { michael@0: michael@0: using mozilla::pkix::ScopedPtr; michael@0: michael@0: void michael@0: ReleaseHttpServerSession(nsNSSHttpServerSession* httpServerSession) michael@0: { michael@0: delete httpServerSession; michael@0: } michael@0: typedef ScopedPtr michael@0: ScopedHTTPServerSession; michael@0: michael@0: void michael@0: ReleaseHttpRequestSession(nsNSSHttpRequestSession* httpRequestSession) michael@0: { michael@0: httpRequestSession->Release(); michael@0: } michael@0: typedef ScopedPtr michael@0: ScopedHTTPRequestSession; michael@0: michael@0: SECItem* DoOCSPRequest(PLArenaPool* arena, const char* url, michael@0: const SECItem* encodedRequest, PRIntervalTime timeout) michael@0: { michael@0: nsCOMPtr urlParser = do_GetService(NS_STDURLPARSER_CONTRACTID); michael@0: if (!urlParser) { michael@0: PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); michael@0: return nullptr; michael@0: } michael@0: michael@0: uint32_t schemePos; michael@0: int32_t schemeLen; michael@0: uint32_t authorityPos; michael@0: int32_t authorityLen; michael@0: uint32_t pathPos; michael@0: int32_t pathLen; michael@0: nsresult rv = urlParser->ParseURL(url, PL_strlen(url), michael@0: &schemePos, &schemeLen, michael@0: &authorityPos, &authorityLen, michael@0: &pathPos, &pathLen); michael@0: if (NS_FAILED(rv)) { michael@0: PR_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, 0); michael@0: return nullptr; michael@0: } michael@0: if (schemeLen < 0 || authorityLen < 0) { michael@0: PR_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, 0); michael@0: return nullptr; michael@0: } michael@0: nsAutoCString scheme(url + schemePos, schemeLen); michael@0: if (!scheme.LowerCaseEqualsLiteral("http")) { michael@0: // We dont support https:// to avoid loops see Bug 92923 michael@0: PR_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, 0); michael@0: return nullptr; michael@0: } michael@0: michael@0: uint32_t hostnamePos; michael@0: int32_t hostnameLen; michael@0: int32_t port; michael@0: // We do not support urls with user@pass sections in the URL, michael@0: // In cas we find them we will ignore and try to connect with michael@0: rv = urlParser->ParseAuthority(url + authorityPos, authorityLen, michael@0: nullptr, nullptr, nullptr, nullptr, michael@0: &hostnamePos, &hostnameLen, &port); michael@0: if (NS_FAILED(rv)) { michael@0: PR_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, 0); michael@0: return nullptr; michael@0: } michael@0: if (hostnameLen < 0) { michael@0: PR_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, 0); michael@0: return nullptr; michael@0: } michael@0: if (port == -1) { michael@0: port = 80; michael@0: } michael@0: michael@0: nsAutoCString hostname(url + authorityPos + hostnamePos, hostnameLen); michael@0: SEC_HTTP_SERVER_SESSION serverSessionPtr = nullptr; michael@0: if (nsNSSHttpInterface::createSessionFcn(hostname.BeginReading(), port, michael@0: &serverSessionPtr) != SECSuccess) { michael@0: PR_SetError(SEC_ERROR_NO_MEMORY, 0); michael@0: return nullptr; michael@0: } michael@0: michael@0: ScopedHTTPServerSession serverSession( michael@0: reinterpret_cast(serverSessionPtr)); michael@0: nsAutoCString path; michael@0: if (pathLen > 0) { michael@0: path.Assign(url + pathPos, pathLen); michael@0: } else { michael@0: path.Assign("/"); michael@0: } michael@0: SEC_HTTP_REQUEST_SESSION requestSessionPtr; michael@0: if (nsNSSHttpInterface::createFcn(serverSession.get(), "http", michael@0: path.BeginReading(), "POST", michael@0: timeout, &requestSessionPtr) michael@0: != SECSuccess) { michael@0: PR_SetError(SEC_ERROR_NO_MEMORY, 0); michael@0: return nullptr; michael@0: } michael@0: michael@0: ScopedHTTPRequestSession requestSession( michael@0: reinterpret_cast(requestSessionPtr)); michael@0: if (nsNSSHttpInterface::setPostDataFcn(requestSession.get(), michael@0: reinterpret_cast(encodedRequest->data), encodedRequest->len, michael@0: "application/ocsp-request") != SECSuccess) { michael@0: PR_SetError(SEC_ERROR_NO_MEMORY, 0); michael@0: return nullptr; michael@0: } michael@0: michael@0: uint16_t httpResponseCode; michael@0: const char* httpResponseData; michael@0: uint32_t httpResponseDataLen = 0; // 0 means any response size is acceptable michael@0: if (nsNSSHttpInterface::trySendAndReceiveFcn(requestSession.get(), nullptr, michael@0: &httpResponseCode, nullptr, michael@0: nullptr, &httpResponseData, michael@0: &httpResponseDataLen) michael@0: != SECSuccess) { michael@0: PR_SetError(SEC_ERROR_OCSP_SERVER_ERROR, 0); michael@0: return nullptr; michael@0: } michael@0: michael@0: if (httpResponseCode != 200) { michael@0: PR_SetError(SEC_ERROR_OCSP_SERVER_ERROR, 0); michael@0: return nullptr; michael@0: } michael@0: michael@0: SECItem* encodedResponse = SECITEM_AllocItem(arena, nullptr, michael@0: httpResponseDataLen); michael@0: if (!encodedResponse) { michael@0: PR_SetError(SEC_ERROR_NO_MEMORY, 0); michael@0: return nullptr; michael@0: } michael@0: michael@0: memcpy(encodedResponse->data, httpResponseData, httpResponseDataLen); michael@0: return encodedResponse; michael@0: } michael@0: michael@0: } } // namespace mozilla::psm