New function OCSP_parse_url() and -url option for ocsp utility.

Doesn't handle SSL URLs yet.
diff --git a/CHANGES b/CHANGES
index 2ff3d56..97ba972 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,11 @@
 
  Changes between 0.9.6 and 0.9.7  [xx XXX 2000]
 
+  *) New function OCSP_parse_url(). This splits up a URL into its host,
+     port and path components: primarily to parse OCSP URLs. New -url
+     option to ocsp utility.
+     [Steve Henson]
+
   *) New nonce behavior. The return value of OCSP_check_nonce() now 
      reflects the various checks performed. Applications can decide
      whether to tolerate certain situations such as an absent nonce
diff --git a/apps/ocsp.c b/apps/ocsp.c
index 9a04dd7..a2501c6 100644
--- a/apps/ocsp.c
+++ b/apps/ocsp.c
@@ -78,12 +78,12 @@
 int MAIN(int argc, char **argv)
 	{
 	char **args;
-	char *host = NULL, *path = "/";
+	char *host = NULL, *port = NULL, *path = "/";
 	char *reqin = NULL, *respin = NULL;
 	char *reqout = NULL, *respout = NULL;
 	char *signfile = NULL, *keyfile = NULL;
 	char *outfile = NULL;
-	int add_nonce = 1, noverify = 0;
+	int add_nonce = 1, noverify = 0, use_ssl = -1;
 	OCSP_REQUEST *req = NULL;
 	OCSP_RESPONSE *resp = NULL;
 	OCSP_BASICRESP *bs = NULL;
@@ -119,6 +119,19 @@
 				}
 			else badarg = 1;
 			}
+		else if (!strcmp(*args, "-url"))
+			{
+			if (args[1])
+				{
+				args++;
+				if (!OCSP_parse_url(*args, &host, &port, &path, &use_ssl))
+					{
+					BIO_printf(bio_err, "Error parsing URL\n");
+					badarg = 1;
+					}
+				}
+			else badarg = 1;
+			}
 		else if (!strcmp(*args, "-host"))
 			{
 			if (args[1])
@@ -335,6 +348,7 @@
 		BIO_printf (bio_err, "-respin file       read DER encoded OCSP reponse from \"file\"\n");
 		BIO_printf (bio_err, "-nonce             add OCSP nonce to request\n");
 		BIO_printf (bio_err, "-no_nonce          don't add OCSP nonce to request\n");
+		BIO_printf (bio_err, "-url URL           OCSP responder URL\n");
 		BIO_printf (bio_err, "-host host:n       send OCSP request to host on port n\n");
 		BIO_printf (bio_err, "-path              path to use in OCSP request\n");
 		BIO_printf (bio_err, "-CApath dir        trusted certificates directory\n");
@@ -436,6 +450,7 @@
 			BIO_printf(bio_err, "Error creating connect BIO\n");
 			goto end;
 			}
+		if (port) BIO_set_conn_port(cbio, port);
 		if (BIO_do_connect(cbio) <= 0)
 			{
 			BIO_printf(bio_err, "Error connecting BIO\n");
@@ -561,6 +576,13 @@
 	sk_X509_pop_free(sign_other, X509_free);
 	sk_X509_pop_free(verify_other, X509_free);
 
+	if (use_ssl != -1)
+		{
+		OPENSSL_free(host);
+		OPENSSL_free(port);
+		OPENSSL_free(path);
+		}
+
 	EXIT(ret);
 }
 
diff --git a/crypto/ocsp/ocsp.h b/crypto/ocsp/ocsp.h
index 1463e2f..5562820 100644
--- a/crypto/ocsp/ocsp.h
+++ b/crypto/ocsp/ocsp.h
@@ -447,6 +447,8 @@
 
 int OCSP_request_verify(OCSP_REQUEST *req, EVP_PKEY *pkey);
 
+int OCSP_parse_url(char *url, char **phost, char **pport, char **ppath, int *pssl);
+
 int OCSP_id_issuer_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
 int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
 
@@ -568,6 +570,7 @@
 #define OCSP_F_OCSP_CHECK_IDS				 107
 #define OCSP_F_OCSP_CHECK_ISSUER			 108
 #define OCSP_F_OCSP_MATCH_ISSUERID			 109
+#define OCSP_F_OCSP_PARSE_URL				 114
 #define OCSP_F_OCSP_REQUEST_SIGN			 110
 #define OCSP_F_OCSP_RESPONSE_GET1_BASIC			 111
 #define OCSP_F_OCSP_SENDREQ_BIO				 112
@@ -577,6 +580,7 @@
 #define OCSP_R_BAD_DATA					 100
 #define OCSP_R_CERTIFICATE_VERIFY_ERROR			 101
 #define OCSP_R_DIGEST_ERR				 102
+#define OCSP_R_ERROR_PARSING_URL			 121
 #define OCSP_R_MISSING_OCSPSIGNING_USAGE		 103
 #define OCSP_R_NOT_BASIC_RESPONSE			 104
 #define OCSP_R_NO_CERTIFICATES_IN_CHAIN			 105
diff --git a/crypto/ocsp/ocsp_err.c b/crypto/ocsp/ocsp_err.c
index c7a1604..63677b5 100644
--- a/crypto/ocsp/ocsp_err.c
+++ b/crypto/ocsp/ocsp_err.c
@@ -76,6 +76,7 @@
 {ERR_PACK(0,OCSP_F_OCSP_CHECK_IDS,0),	"OCSP_CHECK_IDS"},
 {ERR_PACK(0,OCSP_F_OCSP_CHECK_ISSUER,0),	"OCSP_CHECK_ISSUER"},
 {ERR_PACK(0,OCSP_F_OCSP_MATCH_ISSUERID,0),	"OCSP_MATCH_ISSUERID"},
+{ERR_PACK(0,OCSP_F_OCSP_PARSE_URL,0),	"OCSP_parse_url"},
 {ERR_PACK(0,OCSP_F_OCSP_REQUEST_SIGN,0),	"OCSP_request_sign"},
 {ERR_PACK(0,OCSP_F_OCSP_RESPONSE_GET1_BASIC,0),	"OCSP_response_get1_basic"},
 {ERR_PACK(0,OCSP_F_OCSP_SENDREQ_BIO,0),	"OCSP_sendreq_bio"},
@@ -88,6 +89,7 @@
 {OCSP_R_BAD_DATA                         ,"bad data"},
 {OCSP_R_CERTIFICATE_VERIFY_ERROR         ,"certificate verify error"},
 {OCSP_R_DIGEST_ERR                       ,"digest err"},
+{OCSP_R_ERROR_PARSING_URL                ,"error parsing url"},
 {OCSP_R_MISSING_OCSPSIGNING_USAGE        ,"missing ocspsigning usage"},
 {OCSP_R_NOT_BASIC_RESPONSE               ,"not basic response"},
 {OCSP_R_NO_CERTIFICATES_IN_CHAIN         ,"no certificates in chain"},
diff --git a/crypto/ocsp/ocsp_lib.c b/crypto/ocsp/ocsp_lib.c
index 18511e4..aaa4bec 100644
--- a/crypto/ocsp/ocsp_lib.c
+++ b/crypto/ocsp/ocsp_lib.c
@@ -164,3 +164,105 @@
 		}
 	return OCSP_REQUEST_verify(req, pkey);
         }
+
+
+/* Parse a URL and split it up into host, port and path components and whether
+ * it is SSL.
+ */
+
+int OCSP_parse_url(char *url, char **phost, char **pport, char **ppath, int *pssl)
+	{
+	char *p, *buf;
+
+	char *host, *port;
+
+	/* dup the buffer since we are going to mess with it */
+	buf = BUF_strdup(url);
+	if (!buf) goto mem_err;
+
+	*phost = NULL;
+	*pport = NULL;
+	*ppath = NULL;
+
+	/* Check for initial colon */
+	p = strchr(buf, ':');
+
+	if (!p) goto parse_err;
+
+	*(p++) = '\0';
+
+	if (!strcmp(buf, "http"))
+		{
+		*pssl = 0;
+		port = "80";
+		}
+	else if (!strcmp(buf, "https"))
+		{
+		*pssl = 1;
+		port = "443";
+		}
+	else
+		goto parse_err;
+
+	/* Check for double slash */
+	if ((p[0] != '/') || (p[1] != '/'))
+		goto parse_err;
+
+	p += 2;
+
+	host = p;
+
+	/* Check for trailing part of path */
+
+	p = strchr(p, '/');
+
+	if (!p) 
+		*ppath = BUF_strdup("/");
+	else
+		{
+		*ppath = BUF_strdup(p);
+		/* Set start of path to 0 so hostname is valid */
+		*p = '\0';
+		}
+
+	if (!*ppath) goto mem_err;
+
+	/* Look for optional ':' for port number */
+	if ((p = strchr(host, ':')))
+		{
+		*p = 0;
+		port = p + 1;
+		}
+	else
+		{
+		/* Not found: set default port */
+		if (*pssl) port = "443";
+		else port = "80";
+		}
+
+	*pport = BUF_strdup(port);
+	if (!*pport) goto mem_err;
+
+	*phost = BUF_strdup(host);
+
+	if (!*phost) goto mem_err;
+
+	OPENSSL_free(buf);
+
+	return 1;
+
+	mem_err:
+	OCSPerr(OCSP_F_OCSP_PARSE_URL, ERR_R_MALLOC_FAILURE);
+	goto err;
+
+	parse_err:
+	OCSPerr(OCSP_F_OCSP_PARSE_URL, OCSP_R_ERROR_PARSING_URL);
+
+
+	err:
+	if (*ppath) OPENSSL_free(*ppath);
+	if (*pport) OPENSSL_free(*pport);
+	if (*phost) OPENSSL_free(*phost);
+	return 0;
+
+	}