client.c revision 99ebb4ca412cb0a19d77a3899a87c055b9c30fa8
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* File: CLIENT.C
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <poll.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <kmfapi.h>
#include <kmfapiP.h>
extern int errno;
#define OCSP_BUFSIZE 1024
typedef enum {
KMF_RESPONSE_OCSP = 1,
#define TEMP_TEMPLATE "temp.XXXXXX"
/*
* This function will establish a socket to the host on the specified port.
* If succeed, it return a socket descriptor; otherwise, return -1.
*/
{
struct sockaddr_in sin;
return (-1);
}
}
return (-1);
}
opt = 1;
sizeof (opt)) < 0) {
return (-1);
}
return (-1);
}
return (sockfd);
}
/*
* This function will connect to host on the port.
* If succeed, return a socket descriptor; otherwise, return 0.
*/
static int
{
int retry = 1;
int sd = 0;
while (retry) {
if (errno == ECONNREFUSED) {
retry = 1;
(void) sleep(1);
} else {
retry = 0;
}
} else {
retry = 0;
}
}
return (sd);
}
static KMF_RETURN
{
char buf[OCSP_BUFSIZE];
struct stat s;
char req_header[256];
static char req_format[] =
"POST %s HTTP/1.0\r\n\
Content-Type: application/ocsp-request\r\n\
Content-Length: %d\r\n\r\n";
return (ret);
}
/* open the request file */
return (ret);
}
/* Send http header */
s.st_size);
} else {
}
goto exit;
}
/* Send the request content */
goto exit;
}
total += n;
}
exit:
return (ret);
}
/*
* Perform a write that can handle EINTR.
*/
static int
{
char *p = buf;
if (len == 0)
return (0);
do {
if (cc < 0) {
continue;
return (cc);
} else if (cc == 0) {
return (len2);
} else {
p += cc;
}
} while (len > 0);
return (len2);
}
/*
* This function will get the response from the server, check the http status
* line, and write the response content to a file. If this is a OCSP response,
* it will check the content type also.
*/
static KMF_RETURN
unsigned int maxsecs)
{
int buflen = 0;
int offset = 0;
int search_offset;
const char *CRLF = "\r\n";
const char *headerEndMark = "\r\n\r\n";
const char *httpprotocol = "HTTP/";
const char *contenttype = NULL;
int contentlength = 0;
int bytes = 0;
char *statusLineEnd = NULL;
char *nextHeader = NULL;
int sock_flag;
int poll_ret;
/* set O_NONBLOCK flag on socket */
return (KMF_ERR_RECV_RESPONSE);
}
sock_flag |= O_NONBLOCK;
return (KMF_ERR_RECV_RESPONSE);
}
/* set up poll */
/*
* First read HTTP status line and headers. We will read up to at
* least the end of the HTTP headers
*/
do {
goto out;
}
}
if (poll_ret == 0) {
break;
} else if (poll_ret < 0) {
goto out;
} else {
goto out;
}
}
if (bytes < 0) {
continue;
} else {
goto out;
}
} else if (bytes == 0) { /* no more data */
} else { /* bytes > 0 */
}
goto out;
/* could not find the end of headers */
goto out;
}
/*
* Parse the HTTP status line, which will look like this:
* "HTTP/1.1 200 OK".
*/
if (statusLineEnd == NULL) {
goto out;
}
*statusLineEnd = '\0';
goto out;
}
/*
* Check the HTTP status code. If it is not 200, the HTTP response
* is not good.
*/
goto out;
}
*space = 0;
goto out;
}
/*
* Parse the HTTP headers in the buffer. Save content-type and
* content-length only.
*/
do {
char *thisHeaderEnd = NULL;
goto out;
}
*colon = '\0';
if (*value != ' ') {
goto out;
}
value++;
if (thisHeaderEnd != NULL)
*thisHeaderEnd = '\0';
contenttype = value;
}
if (thisHeaderEnd != NULL) {
} else {
nextHeader = NULL;
}
/* Check the contenttype if this is an OCSP response */
if (resptype == KMF_RESPONSE_OCSP) {
if (contenttype == NULL) {
goto out;
} else if (strcasecmp(contenttype,
"application/ocsp-response") != 0) {
goto out;
}
}
/* Now we are ready to read the body of the response */
if (offset) {
/* move all data to the beginning of the buffer */
}
/* resize buffer to only what's needed to hold the current response */
(buflen < maxBufSize)) {
/* we still need to receive more content data */
goto out;
}
}
if (poll_ret == 0) {
break;
} else if (poll_ret < 0) {
goto out;
} else {
goto out;
}
}
if (bytes < 0) {
if (errno == EWOULDBLOCK) {
continue;
} else {
goto out;
}
} else if (bytes == 0) { /* no more data */
} else {
}
}
goto out;
offset == 0) {
goto out;
}
/* write to the file */
}
out:
return (ret);
}
unsigned int maxsecs)
{
char http_hostname[256];
int final_proxy_port, final_port;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
}
80 : proxy_port;
/* Connect to server */
} else {
}
if (sock == -1) {
return (KMF_ERR_CONNECT_SERVER);
}
/* Send the OCSP request */
} else {
}
goto out;
}
/* Retrieve the OCSP response */
if (maxsecs == 0) {
}
} else {
}
out:
return (ret);
}
static KMF_RETURN
char *loc)
{
char url[256];
char req_header[1024];
static char req_format[] =
"GET %s HTTP/1.0\r\n\
Host: %s:%d\r\n\
Accept: */*\r\n\r\n";
if (is_proxy) {
} else {
}
}
return (ret);
}
static KMF_RETURN
{
int sock;
int final_proxy_port;
int port;
return (KMF_ERR_BAD_PARAMETER);
/* Parse URI */
goto out;
}
goto out;
}
/* get the host name */
goto out;
}
/* get the port number */
if (port == 0) {
port = 80;
}
/* Get the path */
goto out;
}
/* Connect to server */
80 : proxy_port;
} else {
}
if (sock == -1) {
goto out;
}
/* Send the request */
goto out;
}
/* Retrieve the response */
goto out;
}
out:
if (sock != -1)
return (ret);
}
{
char tempfn[MAXPATHLEN];
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_OPEN_FILE);
/*
* Download the file and save it to a temp file. To make rename()
* happy, the temp file needs to be created in the same directory as
* the target file.
*/
goto out;
}
if (tmpfd == -1) {
goto out;
} else {
}
goto out;
}
/* Check if it is a CRL file and get its format */
goto out;
}
/* Finally, change the temp filename to the target crlfile */
goto out;
}
out:
if (fd != -1)
return (ret);
}
{
char tempfn[MAXPATHLEN];
return (ret);
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_OPEN_FILE);
/*
* Download the file and save it to a temp file. To make rename()
* happy, the temp file needs to be created in the same directory as
* the target file.
*/
goto out;
}
if (tmpfd == -1) {
goto out;
} else {
}
goto out;
}
/* Check if it is a Cert file and get its format */
goto out;
}
/* Finally, change the temp filename to the target filename */
goto out;
}
out:
if (fd != -1)
return (ret);
}
{
char *proxy_port_s = NULL;
int host_port = 0, proxy_port = 0;
char ocsp_reqname[MAXPATHLEN];
char ocsp_respname[MAXPATHLEN];
int i;
return (ret);
return (KMF_ERR_BAD_PARAMETER);
/* Create an OCSP request */
/*
* Create temporary files to hold the OCSP request & response data.
*/
sizeof (ocsp_reqname));
return (KMF_ERR_INTERNAL);
}
sizeof (ocsp_respname));
return (KMF_ERR_INTERNAL);
}
goto out;
}
goto out;
}
} else {
/*
* Get the responder URI from certificate
* Authority Information Access
* thru OID_PKIX_AD_OCSP
*/
goto out;
}
for (i = 0; i < aia.numberOfAccessDescription; i++) {
(KMF_OID *)&KMFOID_PkixAdOcsp)) {
host_uri =
break;
}
}
if (!found) {
goto out;
}
}
/* Parse the URI string; get the hostname and port */
goto out;
}
goto out;
}
goto out;
}
if (host_port == 0)
host_port = 80;
/* get the proxy info */
char *last;
if (proxy_port_s != NULL) {
} else {
}
}
/*
* Send the request to an OCSP responder and receive an
* OCSP response.
*/
ocsp_respname, 30);
goto out;
}
out:
(void) unlink(ocsp_reqname);
(void) unlink(ocsp_respname);
return (ret);
}