Add HTTP GET support to OCSP server
[openssl.git] / apps / ocsp.c
index 840e506a5cec1078c664caf371c9587e17ab6856..fb60e3b669b4f675522ec5572d75900a0857f44d 100644 (file)
@@ -132,7 +132,7 @@ typedef enum OPTION_choice {
     OPT_REQIN, OPT_RESPIN, OPT_SIGNER, OPT_VAFILE, OPT_SIGN_OTHER,
     OPT_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH,
     OPT_VALIDITY_PERIOD, OPT_STATUS_AGE, OPT_SIGNKEY, OPT_REQOUT,
-    OPT_RESPOUT, OPT_PATH, OPT_CERT, OPT_SERIAL,
+    OPT_RESPOUT, OPT_PATH, OPT_ISSUER, OPT_CERT, OPT_SERIAL,
     OPT_INDEX, OPT_CA, OPT_NMIN, OPT_REQUEST, OPT_NDAYS, OPT_RSIGNER,
     OPT_RKEY, OPT_ROTHER, OPT_RMD, OPT_HEADER,
     OPT_V_ENUM,
@@ -189,6 +189,7 @@ OPTIONS ocsp_options[] = {
     {"reqout", OPT_REQOUT, 's', "Output file for the DER-encoded request"},
     {"respout", OPT_RESPOUT, 's', "Output file for the DER-encoded response"},
     {"path", OPT_PATH, 's', "Path to use in OCSP request"},
+    {"issuer", OPT_ISSUER, '<', "Issuer certificate"},
     {"cert", OPT_CERT, '<', "Certificate to check"},
     {"serial", OPT_SERIAL, 's', "Nerial number to check"},
     {"index", OPT_INDEX, '<', "Certificate status index file"},
@@ -221,6 +222,7 @@ int ocsp_main(int argc, char **argv)
     STACK_OF(OCSP_CERTID) *ids = NULL;
     STACK_OF(OPENSSL_STRING) *reqnames = NULL;
     STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
+    STACK_OF(X509) *issuers = NULL;
     X509 *issuer = NULL, *cert = NULL, *rca_cert = NULL;
     X509 *signer = NULL, *rsigner = NULL;
     X509_STORE *store = NULL;
@@ -391,6 +393,16 @@ int ocsp_main(int argc, char **argv)
         case OPT_PATH:
             path = opt_arg();
             break;
+        case OPT_ISSUER:
+            X509_free(issuer);
+            issuer = load_cert(opt_arg(), FORMAT_PEM,
+                               NULL, NULL, "issuer certificate");
+            if (issuer == NULL)
+                goto end;
+            if ((issuers = sk_X509_new_null()) == NULL)
+                goto end;
+            sk_X509_push(issuers, issuer);
+            break;
         case OPT_CERT:
             X509_free(cert);
             cert = load_cert(opt_arg(), FORMAT_PEM,
@@ -703,6 +715,11 @@ int ocsp_main(int argc, char **argv)
         }
 
         i = OCSP_basic_verify(bs, verify_other, store, verify_flags);
+        if (i <= 0 && issuers) {
+            i = OCSP_basic_verify(bs, issuers, store, OCSP_TRUSTOTHER);
+            if (i > 0)
+                ERR_clear_error();
+        }
         if (i <= 0) {
             BIO_printf(bio_err, "Response Verify Failure\n");
             ERR_print_errors(bio_err);
@@ -1026,13 +1043,32 @@ static BIO *init_responder(const char *port)
     return NULL;
 }
 
+
+static char *urldecode(char *p)
+{
+    unsigned char *out = (unsigned char *)p;
+    char *save = p;
+
+    for (; *p; p++) {
+        if (*p != '%')
+            *out++ = *p;
+        else if (p[1] && p[2]) {
+            *out++ = (app_hex(p[1]) << 4) | app_hex(p[2]);
+            p += 2;
+        }
+    }
+    *p = '\0';
+    return save;
+}
+
 static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
                         const char *port)
 {
     int len;
     OCSP_REQUEST *req = NULL;
     char inbuf[2048];
-    BIO *cbio = NULL;
+    char *p, *q;
+    BIO *cbio = NULL, *getbio = NULL, *b64 = NULL;
 
     if (BIO_do_accept(acbio) <= 0) {
         BIO_printf(bio_err, "Error accepting connection\n");
@@ -1047,7 +1083,29 @@ static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
     len = BIO_gets(cbio, inbuf, sizeof inbuf);
     if (len <= 0)
         return 1;
-    if (strncmp(inbuf, "POST", 4) != 0) {
+    if (strncmp(inbuf, "GET", 3) == 0) {
+        /* Expecting GET {sp} /URL {sp} HTTP/1.x */
+        for (p = inbuf + 3; *p == ' ' || *p == '\t'; ++p)
+            continue;
+        if (*p) {
+            /* Move past the slash before the URL part. */
+            p++;
+        }
+        /* Splice off the HTTP version identifier. */
+        for (q = p; *q; q++)
+            if (*q == ' ' || *q == '\t')
+                break;
+        if (*q == '\0') {
+            BIO_printf(bio_err, "Invalid request\n");
+            return 1;
+        }
+        *q = '\0';
+        p = urldecode(p);
+        getbio = BIO_new_mem_buf(p, strlen(p));
+        b64 = BIO_new(BIO_f_base64());
+        BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+        getbio = BIO_push(b64, getbio);
+    } else if (strncmp(inbuf, "POST", 4) != 0) {
         BIO_printf(bio_err, "Invalid request\n");
         return 1;
     }
@@ -1061,7 +1119,11 @@ static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
     }
 
     /* Try to read OCSP request */
-    req = d2i_OCSP_REQUEST_bio(cbio, NULL);
+    if (getbio) {
+        req = d2i_OCSP_REQUEST_bio(getbio, NULL);
+        BIO_free_all(getbio);
+    } else
+        req = d2i_OCSP_REQUEST_bio(cbio, NULL);
 
     if (!req) {
         BIO_printf(bio_err, "Error parsing OCSP request\n");