bug 152426, delegation of HTTP download for OCSP

r=julien.pierre, r=rrelyea
This commit is contained in:
kaie%kuix.de 2006-02-03 18:14:49 +00:00
Родитель e4bb03723d
Коммит 3aa755acfa
7 изменённых файлов: 484 добавлений и 8 удалений

Просмотреть файл

@ -43,6 +43,7 @@ EXPORTS = \
PRIVATE_EXPORTS = \
ocspti.h \
ocspi.h \
$(NULL)
MODULE = nss

Просмотреть файл

@ -38,7 +38,7 @@
* Implementation of OCSP services, for both client and server.
* (XXX, really, mostly just for client right now, but intended to do both.)
*
* $Id: ocsp.c,v 1.21 2005/06/30 20:53:57 wtchang%redhat.com Exp $
* $Id: ocsp.c,v 1.22 2006/02/03 18:13:04 kaie%kuix.de Exp $
*/
#include "prerror.h"
@ -68,6 +68,59 @@
#include <stdarg.h>
static struct OCSPGlobalStruct {
PRLock *lock;
const SEC_HttpClientFcn *defaultHttpClientFcn;
} OCSP_Global = { NULL, NULL };
SECStatus
SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable)
{
if (!OCSP_Global.lock) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
PR_Lock(OCSP_Global.lock);
OCSP_Global.defaultHttpClientFcn = fcnTable;
PR_Unlock(OCSP_Global.lock);
return SECSuccess;
}
/* this function is called at NSS initialization time */
SECStatus InitOCSPGlobal(void)
{
if (OCSP_Global.lock != NULL) {
/* already initialized */
return SECSuccess;
}
OCSP_Global.lock = PR_NewLock();
return (OCSP_Global.lock) ? SECSuccess : SECFailure;
}
/*
* A return value of NULL means:
* The application did not register it's own HTTP client.
*/
static const SEC_HttpClientFcn *GetRegisteredHttpClient()
{
const SEC_HttpClientFcn *retval;
if (!OCSP_Global.lock) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return NULL;
}
PR_Lock(OCSP_Global.lock);
retval = OCSP_Global.defaultHttpClientFcn;
PR_Unlock(OCSP_Global.lock);
return retval;
}
/*
* The following structure is only used internally. It is allocated when
* someone turns on OCSP checking, and hangs off of the status-configuration
@ -2133,6 +2186,110 @@ ocsp_GetEncodedResponse(PRArenaPool *arena, PRFileDesc *sock)
return result;
}
/*
* Limit the size of http responses we are willing to accept.
*/
#define MAX_WANTED_OCSP_RESPONSE_LEN 64*1024
static SECItem *
fetchOcspHttpClientV1(PRArenaPool *arena,
const SEC_HttpClientFcnV1 *hcv1,
char *location,
SECItem *encodedRequest)
{
char *hostname = NULL;
char *path = NULL;
PRUint16 port;
SECItem *encodedResponse = NULL;
SEC_HTTP_SERVER_SESSION pServerSession = NULL;
SEC_HTTP_REQUEST_SESSION pRequestSession = NULL;
PRUint16 myHttpResponseCode;
const char *myHttpResponseData;
PRUint32 myHttpResponseDataLen;
if (ocsp_ParseURL(location, &hostname, &port, &path) == SECFailure) {
PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
goto loser;
}
PORT_Assert(hostname != NULL);
PORT_Assert(path != NULL);
if ((*hcv1->createSessionFcn)(
hostname,
port,
&pServerSession) != SECSuccess) {
PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
goto loser;
}
/* We use a non-zero timeout, which means:
- the client will use blocking I/O
- TryFcn will not return WOULD_BLOCK nor a poll descriptor
- it's sufficient to call TryFcn once
*/
if ((*hcv1->createFcn)(
pServerSession,
"http",
path,
"POST",
PR_TicksPerSecond() * 60,
&pRequestSession) != SECSuccess) {
PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
goto loser;
}
if ((*hcv1->setPostDataFcn)(
pRequestSession,
(char*)encodedRequest->data,
encodedRequest->len,
"application/ocsp-request") != SECSuccess) {
PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
goto loser;
}
/* we don't want result objects larger than this: */
myHttpResponseDataLen = MAX_WANTED_OCSP_RESPONSE_LEN;
if ((*hcv1->trySendAndReceiveFcn)(
pRequestSession,
NULL,
&myHttpResponseCode,
NULL,
NULL,
&myHttpResponseData,
&myHttpResponseDataLen) != SECSuccess) {
PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
goto loser;
}
if (myHttpResponseCode != 200) {
PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
goto loser;
}
encodedResponse = SECITEM_AllocItem(arena, NULL, myHttpResponseDataLen);
if (!encodedResponse) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
goto loser;
}
PORT_Memcpy(encodedResponse->data, myHttpResponseData, myHttpResponseDataLen);
loser:
if (pRequestSession != NULL)
(*hcv1->freeFcn)(pRequestSession);
if (pServerSession != NULL)
(*hcv1->freeSessionFcn)(pServerSession);
if (path != NULL)
PORT_Free(path);
if (hostname != NULL)
PORT_Free(hostname);
return encodedResponse;
}
/*
* FUNCTION: CERT_GetEncodedOCSPResponse
@ -2192,6 +2349,7 @@ CERT_GetEncodedOCSPResponse(PRArenaPool *arena, CERTCertList *certList,
SECItem *encodedResponse = NULL;
PRFileDesc *sock = NULL;
SECStatus rv;
const SEC_HttpClientFcn *registeredHttpClient = NULL;
request = CERT_CreateOCSPRequest(certList, time, addServiceLocator,
signerCert);
@ -2207,11 +2365,27 @@ CERT_GetEncodedOCSPResponse(PRArenaPool *arena, CERTCertList *certList,
if (encodedRequest == NULL)
goto loser;
sock = ocsp_SendEncodedRequest(location, encodedRequest);
if (sock == NULL)
goto loser;
registeredHttpClient = GetRegisteredHttpClient();
if (registeredHttpClient
&&
registeredHttpClient->version == 1) {
encodedResponse = fetchOcspHttpClientV1(
arena,
&registeredHttpClient->fcnTable.ftable1,
location,
encodedRequest);
}
else {
/* use internal http client */
sock = ocsp_SendEncodedRequest(location, encodedRequest);
if (sock == NULL)
goto loser;
encodedResponse = ocsp_GetEncodedResponse(arena, sock);
}
encodedResponse = ocsp_GetEncodedResponse(arena, sock);
if (encodedResponse != NULL && pRequest != NULL) {
*pRequest = request;
request = NULL; /* avoid destroying below */

Просмотреть файл

@ -37,7 +37,7 @@
/*
* Interface to the OCSP implementation.
*
* $Id: ocsp.h,v 1.6 2004/04/25 15:03:03 gerv%gerv.net Exp $
* $Id: ocsp.h,v 1.7 2006/02/03 18:13:04 kaie%kuix.de Exp $
*/
#ifndef _OCSP_H_
@ -55,6 +55,18 @@
/************************************************************************/
SEC_BEGIN_PROTOS
/*
* This function registers the HttpClient with whose functions the
* HttpClientFcn structure have been populated as the default Http
* client.
*
* The function table must be a global object.
* The caller must ensure that NSS will be able to call
* the registered functions for the lifetime of the process.
*/
extern SECStatus
SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable);
/*
* FUNCTION: CERT_EnableOCSPChecking
* Turns on OCSP checking for the given certificate database.

Просмотреть файл

@ -0,0 +1,47 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape security libraries.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1994-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* ocspi.h - NSS internal interfaces to OCSP code
*
* $Id: ocspi.h,v 1.2 2006/02/03 18:14:49 kaie%kuix.de Exp $
*/
#ifndef _OCSPI_H_
#define _OCSPI_H_
SECStatus InitOCSPGlobal(void);
#endif /* _OCSPI_H_ */

Просмотреть файл

@ -37,7 +37,7 @@
/*
* Public header for exported OCSP types.
*
* $Id: ocspt.h,v 1.4 2004/04/25 15:03:03 gerv%gerv.net Exp $
* $Id: ocspt.h,v 1.5 2006/02/03 18:13:04 kaie%kuix.de Exp $
*/
#ifndef _OCSPT_H_
@ -59,4 +59,235 @@ typedef struct CERTOCSPCertIDStr CERTOCSPCertID;
typedef struct CERTOCSPCertStatusStr CERTOCSPCertStatus;
typedef struct CERTOCSPSingleResponseStr CERTOCSPSingleResponse;
/*
* This interface is described in terms of an HttpClient which
* supports at least a specified set of functions. (An implementer may
* provide HttpClients with additional functionality accessible only to
* users with a particular implementation in mind.) The basic behavior
* is provided by defining a set of functions, listed in an
* SEC_HttpServerFcnStruct. If the implementor of a SpecificHttpClient
* registers his SpecificHttpClient as the default HttpClient, then his
* functions will be called by the user of an HttpClient, such as an
* OCSPChecker.
*
* The implementer of a specific HttpClient (e.g., the NSS-provided
* DefaultHttpClient), populates an SEC_HttpClientFcnStruct, uses it to
* register his client, and waits for his functions to be called.
*
* For future expandability, the SEC_HttpClientFcnStruct is defined as a
* union, with the version field acting as a selector. The proposed
* initial version of the structure is given following the definition
* of the union. The HttpClientState structure is implementation-
* dependent, and should be opaque to the user.
*/
typedef void * SEC_HTTP_SERVER_SESSION;
typedef void * SEC_HTTP_REQUEST_SESSION;
/*
* This function creates a SEC_HTTP_SERVER_SESSION object. The implementer of a
* specific HttpClient will allocate the necessary space, when this
* function is called, and will free it when the corresponding FreeFcn
* is called. The SEC_HTTP_SERVER_SESSION object is passed, as an opaque object,
* to subsequent calls.
*
* If the function returns SECSuccess, the returned SEC_HTTP_SERVER_SESSION
* must be cleaned up with a call to SEC_HttpServer_FreeSession,
* after processing is finished.
*/
typedef SECStatus (*SEC_HttpServer_CreateSessionFcn)(
const char *host,
PRUint16 portnum,
SEC_HTTP_SERVER_SESSION *pSession);
/*
* This function is called to allow the implementation to attempt to keep
* the connection alive. Depending on the underlying platform, it might
* immediately return SECSuccess without having performed any operations.
* (If a connection has not been kept alive, a subsequent call to
* SEC_HttpRequest_TrySendAndReceiveFcn should reopen the connection
* automatically.)
*
* If the connection uses nonblocking I/O, this function may return
* SECWouldBlock and store a nonzero value at "pPollDesc". In that case
* the caller may wait on the poll descriptor, and should call this function
* again until SECSuccess (and a zero value at "pPollDesc") is obtained.
*/
typedef SECStatus (*SEC_HttpServer_KeepAliveSessionFcn)(
SEC_HTTP_SERVER_SESSION session,
PRPollDesc **pPollDesc);
/*
* This function frees the client SEC_HTTP_SERVER_SESSION object, closes all
* SEC_HTTP_REQUEST_SESSIONs created for that server, discards all partial results,
* frees any memory that was allocated by the client, and invalidates any
* response pointers that might have been returned by prior server or request
* functions.
*/
typedef SECStatus (*SEC_HttpServer_FreeSessionFcn)(
SEC_HTTP_SERVER_SESSION session);
/*
* This function creates a SEC_HTTP_REQUEST_SESSION object. The implementer of a
* specific HttpClient will allocate the necessary space, when this
* function is called, and will free it when the corresponding FreeFcn
* is called. The SEC_HTTP_REQUEST_SESSION object is passed, as an opaque object,
* to subsequent calls.
*
* An implementation that does not support the requested protocol variant
* (usually "http", but could eventually allow "https") or request method
* should return SECFailure.
*
* Timeout values may include the constants PR_INTERVAL_NO_TIMEOUT (wait
* forever) or PR_INTERVAL_NO_WAIT (nonblocking I/O).
*
* If the function returns SECSuccess, the returned SEC_HTTP_REQUEST_SESSION
* must be cleaned up with a call to SEC_HttpRequest_FreeSession,
* after processing is finished.
*/
typedef SECStatus (*SEC_HttpRequest_CreateFcn)(
SEC_HTTP_SERVER_SESSION session,
const char *http_protocol_variant, // usually "http"
const char *path_and_query_string,
const char *http_request_method,
const PRIntervalTime timeout,
SEC_HTTP_REQUEST_SESSION *pRequest);
/*
* This function sets data to be sent to the server for an HTTP request
* of http_request_method == POST. If a particular implementation
* supports it, the details for the POST request can be set by calling
* this function, prior to activating the request with TrySendAndReceiveFcn.
*
* An implementation that does not support the POST method should
* implement a SetPostDataFcn function that returns immediately.
*
* Setting http_content_type is optional, the parameter may
* by NULL or the empty string.
*/
typedef SECStatus (*SEC_HttpRequest_SetPostDataFcn)(
SEC_HTTP_REQUEST_SESSION request,
const char *http_data,
const PRUint32 http_data_len,
const char *http_content_type);
/*
* This function sets an additional HTTP protocol request header.
* If a particular implementation supports it, one or multiple headers
* can be added to the request by calling this function once or multiple
* times, prior to activating the request with TryFcn.
*
* An implementation that does not support setting additional headers
* should implement an AddRequestHeaderFcn function that returns immediately.
*/
typedef SECStatus (*SEC_HttpRequest_AddHeaderFcn)(
SEC_HTTP_REQUEST_SESSION request,
const char *http_header_name,
const char *http_header_value);
/*
* This function initiates or continues an HTTP request. After
* parameters have been set with the Create function and, optionally,
* modified or enhanced with the AddParams function, this call creates
* the socket connection and initiates the communication.
*
* If a timeout value of zero is specified, indicating non-blocking
* I/O, the client creates a non-blocking socket, and returns a status
* of SECWouldBlock and a non-NULL PRPollDesc if the operation is not
* complete. In that case all other return parameters are undefined.
* The caller is expected to repeat the call, possibly after using
* PRPoll to determine that a completion has occurred, until a return
* value of SECSuccess (and a NULL value for pPollDesc) or a return
* value of SECFailure (indicating failure on the network level)
* is obtained.
*
* http_response_data_len is both input and output parameter.
* If a pointer to a PRUint32 is supplied, the http client is
* expected to check the given integer value and always set an out
* value, even on failure.
* An input value of zero means, the caller will accept any response len.
* A different input value indicates the maximum response value acceptable
* to the caller.
* If data is successfully read and the size is acceptable to the caller,
* the function will return SECSuccess and set http_response_data_len to
* the size of the block returned in http_response_data.
* If the data read from the http server is larger than the acceptable
* size, the function will return SECFailure.
* http_response_data_len will be set to a value different from zero to
* indicate the reason of the failure.
* An out value of "0" means, the failure was unrelated to the
* acceptable size.
* An out value of "1" means, the result data is larger than the
* accpeptable size, but the real size is not yet known to the http client
* implementation and it stopped retrieving it,
* Any other out value combined with a return value of SECFailure
* will indicate the actual size of the server data.
*
* The caller is permitted to provide NULL values for any of the
* http_response arguments, indicating the caller is not interested in
* those values. If the caller does provide an address, the HttpClient
* stores at that address a pointer to the corresponding argument, at
* the completion of the operation.
*
* All returned pointers will be owned by the the HttpClient
* implementation and will remain valid until the call to
* SEC_HttpRequest_FreeFcn.
*/
typedef SECStatus (*SEC_HttpRequest_TrySendAndReceiveFcn)(
SEC_HTTP_REQUEST_SESSION request,
PRPollDesc **pPollDesc,
PRUint16 *http_response_code,
const char **http_response_content_type,
const char **http_response_headers,
const char **http_response_data,
PRUint32 *http_response_data_len);
/*
* Calling CancelFcn asks for premature termination of the request.
*
* Future calls to SEC_HttpRequest_TrySendAndReceive should
* by avoided, but in this case the HttpClient implementation
* is expected to return immediately with SECFailure.
*
* After calling CancelFcn, a separate call to SEC_HttpRequest_FreeFcn
* is still necessary to free resources.
*/
typedef SECStatus (*SEC_HttpRequest_CancelFcn)(
SEC_HTTP_REQUEST_SESSION request);
/*
* Before calling this function, it must be assured the request
* has been completed, i.e. either SEC_HttpRequest_TrySendAndReceiveFcn has
* returned SECSuccess, or the request has been canceled with
* a call to SEC_HttpRequest_CancelFcn.
*
* This function frees the client state object, closes all sockets,
* discards all partial results, frees any memory that was allocated
* by the client, and invalidates all response pointers that might
* have been returned by SEC_HttpRequest_TrySendAndReceiveFcn
*/
typedef SECStatus (*SEC_HttpRequest_FreeFcn)(
SEC_HTTP_REQUEST_SESSION request);
typedef struct SEC_HttpClientFcnV1Struct {
SEC_HttpServer_CreateSessionFcn createSessionFcn;
SEC_HttpServer_KeepAliveSessionFcn keepAliveSessionFcn;
SEC_HttpServer_FreeSessionFcn freeSessionFcn;
SEC_HttpRequest_CreateFcn createFcn;
SEC_HttpRequest_SetPostDataFcn setPostDataFcn;
SEC_HttpRequest_AddHeaderFcn addHeaderFcn;
SEC_HttpRequest_TrySendAndReceiveFcn trySendAndReceiveFcn;
SEC_HttpRequest_CancelFcn cancelFcn;
SEC_HttpRequest_FreeFcn freeFcn;
} SEC_HttpClientFcnV1;
typedef struct SEC_HttpClientFcnStruct {
PRInt16 version;
union {
SEC_HttpClientFcnV1 ftable1;
/* SEC_HttpClientFcnV2 ftable2; */
/* ... */
} fcnTable;
} SEC_HttpClientFcn;
#endif /* _OCSPT_H_ */

Просмотреть файл

@ -878,3 +878,9 @@ PK11_GetAllSlotsForCert;
;+ local:
;+ *;
;+};
;+NSS_3.11.1 {
;+ global:
SEC_RegisterDefaultHttpClient;
;+ local:
;+ *;
;+};

Просмотреть файл

@ -36,7 +36,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* $Id: nssinit.c,v 1.69 2005/10/12 19:04:13 wtchang%redhat.com Exp $ */
/* $Id: nssinit.c,v 1.70 2006/02/03 18:13:14 kaie%kuix.de Exp $ */
#include <ctype.h>
#include "seccomon.h"
@ -57,6 +57,7 @@
#include "pki3hack.h"
#include "certi.h"
#include "secmodi.h"
#include "ocspi.h"
/*
* On Windows nss3.dll needs to export the symbol 'mktemp' to be
@ -419,6 +420,10 @@ nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix,
if (SECSuccess != InitCRLCache()) {
return SECFailure;
}
if (SECSuccess != InitOCSPGlobal()) {
return SECFailure;
}
flags = nss_makeFlags(readOnly,noCertDB,noModDB,forceOpen,
pk11_password_required, optimizeSpace);