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 + -
显示快捷键?