ocsp.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,187 行 · 第 1/5 页

C
2,187
字号
	case SEC_OID_PKIX_OCSP_BASIC_RESPONSE:	    {		ocspBasicOCSPResponse *basicResponse;		basicResponse = ocsp_DecodeBasicOCSPResponse(arena,							     &rbytes->response);		if (basicResponse == NULL)		    return SECFailure;		rbytes->decodedResponse.basic = basicResponse;	    }	    break;	/*	 * Add new/future response types here.	 */	default:	    PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE);	    return SECFailure;    }    return SECSuccess;}/* * FUNCTION: CERT_DecodeOCSPResponse *   Decode a DER encoded OCSP Response. * INPUTS: *   SECItem *src *     Pointer to a SECItem holding DER encoded OCSP Response. * RETURN: *   Returns a pointer to a CERTOCSPResponse (the decoded OCSP Response); *   the caller is responsible for destroying it.  Or NULL if error (either *   response could not be decoded (SEC_ERROR_OCSP_MALFORMED_RESPONSE), *   it was of an unexpected type (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE), *   or a low-level or internal error occurred). */CERTOCSPResponse *CERT_DecodeOCSPResponse(SECItem *src){    PRArenaPool *arena = NULL;    CERTOCSPResponse *response = NULL;    SECStatus rv = SECFailure;    ocspResponseStatus sv;    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);    if (arena == NULL) {	goto loser;    }    response = (CERTOCSPResponse *) PORT_ArenaZAlloc(arena,						     sizeof(CERTOCSPResponse));    if (response == NULL) {	goto loser;    }    response->arena = arena;    rv = SEC_ASN1DecodeItem(arena, response, ocsp_OCSPResponseTemplate, src);    if (rv != SECSuccess) {	if (PORT_GetError() == SEC_ERROR_BAD_DER)	    PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);	goto loser;    }    sv = (ocspResponseStatus) DER_GetInteger(&response->responseStatus);    response->statusValue = sv;    if (sv != ocspResponse_successful) {	/*	 * If the response status is anything but successful, then we	 * are all done with decoding; the status is all there is.	 */	return response;    }    /*     * A successful response contains much more information, still encoded.     * Now we need to decode that.     */    rv = ocsp_DecodeResponseBytes(arena, response->responseBytes);    if (rv != SECSuccess) {	goto loser;    }    return response;loser:    if (arena != NULL) {	PORT_FreeArena(arena, PR_FALSE);    }    return NULL;}/* * The way an OCSPResponse is defined, there are many levels to descend * before getting to the actual response information.  And along the way * we need to check that the response *type* is recognizable, which for * now means that it is a BasicOCSPResponse, because that is the only * type currently defined.  Rather than force all routines to perform * a bunch of sanity checking every time they want to work on a response, * this function isolates that and gives back the interesting part. * Note that no copying is done, this just returns a pointer into the * substructure of the response which is passed in. * * XXX This routine only works when a valid response structure is passed * into it; this is checked with many assertions.  Assuming the response * was creating by decoding, it wouldn't make it this far without being * okay.  That is a sufficient assumption since the entire OCSP interface * is only used internally.  When this interface is officially exported, * each assertion below will need to be followed-up with setting an error * and returning (null). */static ocspResponseData *ocsp_GetResponseData(CERTOCSPResponse *response){    ocspBasicOCSPResponse *basic;    ocspResponseData *responseData;    PORT_Assert(response != NULL);    PORT_Assert(response->responseBytes != NULL);    PORT_Assert(response->responseBytes->responseTypeTag		== SEC_OID_PKIX_OCSP_BASIC_RESPONSE);    basic = response->responseBytes->decodedResponse.basic;    PORT_Assert(basic != NULL);    responseData = basic->tbsResponseData;    PORT_Assert(responseData != NULL);    return responseData;}/* * Much like the routine above, except it returns the response signature. * Again, no copy is done. */static ocspSignature *ocsp_GetResponseSignature(CERTOCSPResponse *response){    ocspBasicOCSPResponse *basic;    PORT_Assert(response != NULL);    PORT_Assert(response->responseBytes != NULL);    PORT_Assert(response->responseBytes->responseTypeTag		== SEC_OID_PKIX_OCSP_BASIC_RESPONSE);    basic = response->responseBytes->decodedResponse.basic;    PORT_Assert(basic != NULL);    return &(basic->responseSignature);}/* * FUNCTION: CERT_DestroyOCSPResponse *   Frees an OCSP Response structure. * INPUTS: *   CERTOCSPResponse *request *     Pointer to CERTOCSPResponse to be freed. * RETURN: *   No return value; no errors. */voidCERT_DestroyOCSPResponse(CERTOCSPResponse *response){    if (response != NULL) {	ocspSignature *signature = ocsp_GetResponseSignature(response);	if (signature->cert != NULL)	    CERT_DestroyCertificate(signature->cert);	/*	 * We should actually never have a response without an arena,	 * but check just in case.  (If there isn't one, there is not	 * much we can do about it...)	 */	PORT_Assert(response->arena != NULL);	if (response->arena != NULL) {	    PORT_FreeArena(response->arena, PR_FALSE);	}    }}/* * OVERALL OCSP CLIENT SUPPORT (make and send a request, verify a response): *//* * Pick apart a URL, saving the important things in the passed-in pointers. * * We expect to find "http://<hostname>[:<port>]/[path]", though we will * tolerate that final slash character missing, as well as beginning and * trailing whitespace, and any-case-characters for "http".  All of that * tolerance is what complicates this routine.  What we want is just to * pick out the hostname, the port, and the path. * * On a successful return, the caller will need to free the output pieces * of hostname and path, which are copies of the values found in the url. */static SECStatusocsp_ParseURL(char *url, char **pHostname, PRUint16 *pPort, char **pPath){    unsigned short port = 80;		/* default, in case not in url */    char *hostname = NULL;    char *path = NULL;    char *save;    char c;    int len;    if (url == NULL)	goto loser;    /*     * Skip beginning whitespace.     */    c = *url;    while ((c == ' ' || c == '\t') && c != '\0') {	url++;	c = *url;    }    if (c == '\0')	goto loser;    /*     * Confirm, then skip, protocol.  (Since we only know how to do http,     * that is all we will accept).     */    if (PORT_Strncasecmp(url, "http://", 7) != 0)	goto loser;    url += 7;    /*     * Whatever comes next is the hostname (or host IP address).  We just     * save it aside and then search for its end so we can determine its     * length and copy it.     *     * XXX Note that because we treat a ':' as a terminator character     * (and below, we expect that to mean there is a port specification     * immediately following), we will not handle IPv6 addresses.  That is     * apparently an acceptable limitation, for the time being.  Some day,     * when there is a clear way to specify a URL with an IPv6 address that     * can be parsed unambiguously, this code should be made to do that.     */    save = url;    c = *url;    while (c != '/' && c != ':' && c != '\0' && c != ' ' && c != '\t') {	url++;	c = *url;    }    len = url - save;    hostname = PORT_Alloc(len + 1);    if (hostname == NULL)	goto loser;    PORT_Memcpy(hostname, save, len);    hostname[len] = '\0';    /*     * Now we figure out if there was a port specified or not.     * If so, we need to parse it (as a number) and skip it.     */    if (c == ':') {	url++;	port = (unsigned short) PORT_Atoi(url);	c = *url;	while (c != '/' && c != '\0' && c != ' ' && c != '\t') {	    if (c < '0' || c > '9')		goto loser;	    url++;	    c = *url;	}    }    /*     * Last thing to find is a path.  There *should* be a slash,     * if nothing else -- but if there is not we provide one.     */    if (c == '/') {	save = url;	while (c != '\0' && c != ' ' && c != '\t') {	    url++;	    c = *url;	}	len = url - save;	path = PORT_Alloc(len + 1);	if (path == NULL)	    goto loser;	PORT_Memcpy(path, save, len);	path[len] = '\0';    } else {	path = PORT_Strdup("/");    }    *pHostname = hostname;    *pPort = port;    *pPath = path;    return SECSuccess;loser:    if (hostname != NULL)	PORT_Free(hostname);    if (path != NULL)	PORT_Free(path);    PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);    return SECFailure;}/* * Open a socket to the specified host on the specified port, and return it. * The host is either a hostname or an IP address. */static PRFileDesc *ocsp_ConnectToHost(const char *host, PRUint16 port){    PRFileDesc *sock = NULL;    PRIntervalTime timeout;    PRNetAddr addr;    char *netdbbuf = NULL;    sock = PR_NewTCPSocket();    if (sock == NULL)	goto loser;    /* XXX Some day need a way to set (and get?) the following value */    timeout = PR_SecondsToInterval(30);    /*     * If the following converts an IP address string in "dot notation"     * into a PRNetAddr.  If it fails, we assume that is because we do not     * have such an address, but instead a host *name*.  In that case we     * then lookup the host by name.  Using the NSPR function this way     * means we do not have to have our own logic for distinguishing a     * valid numerical IP address from a hostname.     */    if (PR_StringToNetAddr(host, &addr) != PR_SUCCESS) {	PRIntn hostIndex;	PRHostEnt hostEntry;	netdbbuf = PORT_Alloc(PR_NETDB_BUF_SIZE);	if (netdbbuf == NULL)	    goto loser;	if (PR_GetHostByName(host, netdbbuf, PR_NETDB_BUF_SIZE,			     &hostEntry) != PR_SUCCESS)	    goto loser;	hostIndex = 0;	do {	    hostIndex = PR_EnumerateHostEnt(hostIndex, &hostEntry, port, &addr);	    if (hostIndex < 0)		goto loser;	} while (PR_Connect(sock, &addr, timeout) != PR_SUCCESS		 && hostIndex > 0);        if (hostIndex == 0)	    goto loser;	PORT_Free(netdbbuf);    } else {	/*	 * First put the port into the address, then connect.	 */	if (PR_InitializeNetAddr(PR_IpAddrNull, port, &addr) != PR_SUCCESS)	    goto loser;	if (PR_Connect(sock, &addr, timeout) != PR_SUCCESS)	    goto loser;    }    return sock;loser:    if (sock != NULL)	PR_Close(sock);    if (netdbbuf != NULL)	PORT_Free(netdbbuf);    return NULL;}/* * Sends an encoded OCSP request to the server identified by "location", * and returns the socket on which it was sent (so can listen for the reply). * "location" is expected to be a valid URL -- an error parsing it produces * SEC_ERROR_CERT_BAD_ACCESS_LOCATION.  Other errors are likely problems * connecting to it, or writing to it, or allocating memory, and the low-level * errors appropriate to the problem will be set. */static PRFileDesc *ocsp_SendEncodedRequest(char *location, SECItem *encodedRequest){    char *hostname = NULL;    char *path = NULL;    PRUint16 port;    SECStatus rv;    PRFileDesc *sock = NULL;    PRFileDesc *returnSock = NULL;    char *header = NULL;    /*     * Take apart the location, getting the hostname, port, and path.     */    rv = ocsp_ParseURL(location, &hostname, &port, &path);    if (rv != SECSuccess)	goto loser;    PORT_Assert(hostname != NULL);    PORT_Assert(path != NULL);    sock = ocsp_ConnectToHost(hostname, port);    if (sock == NULL)	goto loser;    header = PR_smprintf("POST %s HTTP/1.0\r\n"			 "Host: %s:%d\r\n"			 "Content-Type: application/ocsp-request\r\n"			 "Content-Length: %u\r\n\r\n",			 path, hostname, port, encodedRequest->len);    if (header == NULL)	goto loser;    /*     * The NSPR documentation promises that if it can, it will write the full     * amount; this will not return a partial value expecting us to loop.     */    if (PR_Write(sock, header, (PRInt32) PORT_Strlen(header)) < 0)	goto loser;    if (PR_Write(sock, encodedRequest->data,		 (PRInt32) encodedRequest->len) < 0)	goto loser;    returnSock = sock;    sock = NULL;loser:    if (header != NULL)	PORT_Free(header);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?