99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * CDDL HEADER START
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * The contents of this file are subject to the terms of the
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Common Development and Distribution License (the "License").
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * You may not use this file except in compliance with the License.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * See the License for the specific language governing permissions
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * and limitations under the License.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * When distributing Covered Code, include this CDDL HEADER in each
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * If applicable, add the following below this CDDL HEADER, with the
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * fields enclosed by brackets "[]" replaced with your own identifying
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * information: Portions Copyright [yyyy] [name of copyright owner]
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * CDDL HEADER END
30a5e8fa1253cb33980ee4514743cf683f584b4ewyllys * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Use is subject to license terms.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * File: CLIENT.C
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys#pragma ident "%Z%%M% %I% %E% SMI"
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllystypedef enum {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * This function will establish a socket to the host on the specified port.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * If succeed, it return a socket descriptor; otherwise, return -1.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys return (-1);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys return (-1);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys sizeof (opt)) < 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys return (-1);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if (connect(sockfd, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys return (-1);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * This function will connect to host on the port.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * If succeed, return a socket descriptor; otherwise, return 0.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllyssend_ocsp_request(int sock, char *reqfile, char *hostname)
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys"POST %s HTTP/1.0\r\n\
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllysContent-Type: application/ocsp-request\r\n\
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllysContent-Length: %d\r\n\r\n";
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* open the request file */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Send http header */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys (void) snprintf(req_header, 256, req_format, hostname,
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys (void) snprintf(req_header, 256, req_format, "/", s.st_size);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Send the request content */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys while ((bytes = read(filefd, buf, OCSP_BUFSIZE)) > 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Perform a write that can handle EINTR.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys return (0);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if (cc < 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys } else if (cc == 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys } while (len > 0);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * This function will get the response from the server, check the http status
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * line, and write the response content to a file. If this is a OCSP response,
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * it will check the content type also.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllysget_encoded_response(int sock, KMF_RESPONSE_TYPE resptype, int filefd,
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys unsigned int maxsecs)
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys const int buf_incre = OCSP_BUFSIZE; /* 1 KB at a time */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* set O_NONBLOCK flag on socket */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* set up poll */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * First read HTTP status line and headers. We will read up to at
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * least the end of the HTTP headers
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys } else if (poll_ret < 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys } else { /* bytes > 0 */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys headerEnd = strstr((const char *)buf + search_offset,
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys } while ((!headerEnd) && (EOS == B_FALSE) && (buflen < maxBufSize));
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* could not find the end of headers */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Parse the HTTP status line, which will look like this:
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * "HTTP/1.1 200 OK".
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys (strncasecmp((const char *)buf, httpprotocol, httplen) != 0)) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Check the HTTP status code. If it is not 200, the HTTP response
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * is not good.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Parse the HTTP headers in the buffer. Save content-type and
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * content-length only.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys } else if (strcasecmp(nextHeader, "content-length") == 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys } while (nextHeader && (nextHeader < (headerEnd + CRLFlen)));
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Check the contenttype if this is an OCSP response */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Now we are ready to read the body of the response */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys offset = offset - (int)(headerEnd - (const char *)buf) - marklen;
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* move all data to the beginning of the buffer */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* resize buffer to only what's needed to hold the current response */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys ((contentlength == 0) || (offset < contentlength)) &&
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* we still need to receive more content data */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys } else if (poll_ret < 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys } else if (((contentlength != 0) && (offset < contentlength)) ||
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* write to the file */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys int port, char *proxy, int proxy_port, char *respfile,
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys unsigned int maxsecs)
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if (hostname == NULL || reqfile == NULL || respfile == NULL) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys final_proxy_port = (proxy_port == 0 || proxy_port == -1) ?
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Connect to server */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Send the OCSP request */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys (void) snprintf(http_hostname, sizeof (http_hostname),
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys ret = send_ocsp_request(sock, reqfile, http_hostname);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Retrieve the OCSP response */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys maxsecs = 30; /* default poll time limit is 30 seconds */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if ((respfd = open(respfile, O_CREAT |O_RDWR | O_EXCL, 0600)) == -1) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllyssend_download_request(int sock, char *hostname, int port, boolean_t is_proxy,
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys"GET %s HTTP/1.0\r\n\
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllysHost: %s:%d\r\n\
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllysAccept: */*\r\n\r\n";
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys (void) snprintf(url, sizeof (url), "http://%s:%d/%s",
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys (void) snprintf(req_header, sizeof (req_header), req_format, url,
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if (write(sock, req_header, strlen(req_header)) < 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Parse URI */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* get the host name */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* get the port number */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if (port == 0) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Get the path */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Connect to server */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys final_proxy_port = (proxy_port == 0 || proxy_port == -1) ?
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Send the request */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys ret = send_download_request(sock, hostname, port, is_proxy, path);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Retrieve the response */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys ret = get_encoded_response(sock, KMF_RESPONSE_FILE, filefd,
30a5e8fa1253cb33980ee4514743cf683f584b4ewyllyskmf_download_crl(KMF_HANDLE_T handle, char *uri, char *proxy, int proxy_port,
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys unsigned int maxsecs, char *crlfile, KMF_ENCODE_FORMAT *pformat)
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if (uri == NULL || crlfile == NULL || pformat == NULL)
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if ((fd = open(crlfile, O_CREAT |O_RDWR | O_EXCL, 0644)) == -1)
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Download the file and save it to a temp file. To make rename()
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * happy, the temp file needs to be created in the same directory as
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * the target file.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys (void) snprintf(tempfn, MAXPATHLEN, "%s/%s", dirname(filename),
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys ret = download_file(uri, proxy, proxy_port, maxsecs, tmpfd);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Check if it is a CRL file and get its format */
30a5e8fa1253cb33980ee4514743cf683f584b4ewyllys if (kmf_is_crl_file(handle, tempfn, pformat) != KMF_OK) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Finally, change the temp filename to the target crlfile */
30a5e8fa1253cb33980ee4514743cf683f584b4ewyllyskmf_download_cert(KMF_HANDLE_T handle, char *uri, char *proxy, int proxy_port,
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys unsigned int maxsecs, char *certfile, KMF_ENCODE_FORMAT *pformat)
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if (uri == NULL || certfile == NULL || pformat == NULL)
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys if ((fd = open(certfile, O_CREAT |O_RDWR | O_EXCL, 0644)) == -1)
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Download the file and save it to a temp file. To make rename()
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * happy, the temp file needs to be created in the same directory as
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * the target file.
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys (void) snprintf(tempfn, MAXPATHLEN, "%s/%s", dirname(filename),
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys ret = download_file(uri, proxy, proxy_port, maxsecs, tmpfd);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Check if it is a Cert file and get its format */
30a5e8fa1253cb33980ee4514743cf683f584b4ewyllys if (kmf_is_cert_file(handle, tempfn, pformat) != KMF_OK) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Finally, change the temp filename to the target filename */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys char *hostname = NULL, *host_uri = NULL, *proxyname = NULL;
30a5e8fa1253cb33980ee4514743cf683f584b4ewyllys if (user_cert == NULL || ta_cert == NULL || response == NULL)
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Create an OCSP request */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Create temporary files to hold the OCSP request & response data.
30a5e8fa1253cb33980ee4514743cf683f584b4ewyllys ret = kmf_create_ocsp_request(handle, numattr, attrlist);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Get the responder URI from certificate
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Authority Information Access
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * thru OID_PKIX_AD_OCSP
30a5e8fa1253cb33980ee4514743cf683f584b4ewyllys ret = kmf_get_cert_auth_info_access(user_cert, &aia);
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys for (i = 0; i < aia.numberOfAccessDescription; i++) {
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* Parse the URI string; get the hostname and port */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys /* get the proxy info */
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * Send the request to an OCSP responder and receive an
99ebb4ca412cb0a19d77a3899a87c055b9c30fa8wyllys * OCSP response.
30a5e8fa1253cb33980ee4514743cf683f584b4ewyllys ret = kmf_get_encoded_ocsp_response(handle, ocsp_reqname,