Add OCSP API test executable
authorBenjamin Kaduk <bkaduk@akamai.com>
Thu, 19 Oct 2017 19:44:10 +0000 (14:44 -0500)
committerBen Kaduk <kaduk@mit.edu>
Wed, 13 Dec 2017 01:08:22 +0000 (19:08 -0600)
Some of the OCSP APIs (such as the recently added OCSP_resp_get0_signer)
do not really merit inclusion in the ocsp(1) utility, but we should still
have unit tests for them.

For now, only test OCSP_resp_get0_signer(), but it should be easy to
add more tests in the future.

Provide an X509 cert and private key in the test's data directory
to use for signing responses, since constructing those on the fly
is more effort than is needed.

Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(cherry picked from commit 27da13430bfb3c178716cec10e8d5d6134e54f90)

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/4723)

test/build.info
test/ocspapitest.c [new file with mode: 0644]
test/recipes/80-test_ocsp.t
test/recipes/80-test_ocsp_data/cert.pem [new file with mode: 0644]
test/recipes/80-test_ocsp_data/key.pem [new file with mode: 0644]

index 199fe13a1170452d02b7f722f8661d94932df6bd..c262248b6f2748ba1305ac7f817203429050d9e7 100644 (file)
@@ -17,7 +17,7 @@ IF[{- !$disabled{tests} -}]
           dtlsv1listentest ct_test threadstest afalgtest d2i_test \
           ssl_test_ctx_test ssl_test x509aux cipherlist_test asynciotest \
           bioprinttest sslapitest dtlstest sslcorrupttest bio_enc_test \
-          fatalerrtest
+          ocspapitest fatalerrtest
 
   SOURCE[aborttest]=aborttest.c
   INCLUDE[aborttest]=../include
@@ -276,6 +276,10 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[sslapitest]=../include ..
   DEPEND[sslapitest]=../libcrypto ../libssl
 
+  SOURCE[ocspapitest]=ocspapitest.c testutil.c
+  INCLUDE[ocspapitest]=../include ..
+  DEPEND[ocspapitest]=../libcrypto
+
   SOURCE[dtlstest]=dtlstest.c ssltestlib.c testutil.c
   INCLUDE[dtlstest]=../include .
   DEPEND[dtlstest]=../libcrypto ../libssl
diff --git a/test/ocspapitest.c b/test/ocspapitest.c
new file mode 100644 (file)
index 0000000..2c235fb
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+
+#include <openssl/opensslconf.h>
+#include <openssl/crypto.h>
+#include <openssl/ocsp.h>
+#include <openssl/x509.h>
+#include <openssl/asn1.h>
+#include <openssl/pem.h>
+
+#include "testutil.h"
+
+static const char *certstr;
+static const char *privkeystr;
+
+static int get_cert_and_key(X509 **cert_out, EVP_PKEY **key_out)
+{
+    BIO *certbio, *keybio;
+    X509 *cert = NULL;
+    EVP_PKEY *key = NULL;
+
+    if ((certbio = BIO_new_file(certstr, "r")) == NULL)
+        return 0;
+    cert = PEM_read_bio_X509(certbio, NULL, NULL, NULL);
+    BIO_free(certbio);
+    if ((keybio = BIO_new_file(privkeystr, "r")) == NULL)
+        goto end;
+    key = PEM_read_bio_PrivateKey(keybio, NULL, NULL, NULL);
+    BIO_free(keybio);
+    if (cert == NULL || key == NULL)
+        goto end;
+    *cert_out = cert;
+    *key_out = key;
+    return 1;
+ end:
+    X509_free(cert);
+    EVP_PKEY_free(key);
+    return 0;
+}
+
+static OCSP_BASICRESP *make_dummy_resp(void)
+{
+    const unsigned char namestr[] = "openssl.example.com";
+    unsigned char keybytes[128] = {7};
+    OCSP_BASICRESP *bs = OCSP_BASICRESP_new();
+    OCSP_CERTID *cid;
+    ASN1_TIME *thisupd = ASN1_TIME_set(NULL, time(NULL));
+    ASN1_TIME *nextupd = ASN1_TIME_set(NULL, time(NULL) + 200);
+    X509_NAME *name = X509_NAME_new();
+    ASN1_BIT_STRING *key = ASN1_BIT_STRING_new();
+    ASN1_INTEGER *serial = ASN1_INTEGER_new();
+
+    if (!X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC,
+                                   namestr, -1, -1, 1)
+        || !ASN1_BIT_STRING_set(key, keybytes, sizeof(keybytes)
+        || !ASN1_INTEGER_set_uint64(serial, (uint64_t)1)))
+        return NULL;
+    cid = OCSP_cert_id_new(EVP_sha256(), name, key, serial);
+    if (bs == NULL
+        || thisupd == NULL
+        || nextupd == NULL
+        || cid == NULL
+        || !OCSP_basic_add1_status(bs, cid,
+                                   V_OCSP_CERTSTATUS_UNKNOWN,
+                                   0, NULL, thisupd, nextupd))
+        return NULL;
+    ASN1_TIME_free(thisupd);
+    ASN1_TIME_free(nextupd);
+    ASN1_BIT_STRING_free(key);
+    ASN1_INTEGER_free(serial);
+    OCSP_CERTID_free(cid);
+    X509_NAME_free(name);
+    return bs;
+}
+
+#ifndef OPENSSL_NO_OCSP
+static int test_resp_signer(void)
+{
+    OCSP_BASICRESP *bs;
+    X509 *signer = NULL, *tmp;
+    EVP_PKEY *key = NULL;
+    STACK_OF(X509) *extra_certs;
+
+    /*
+     * Test a response with no certs at all; get the signer from the
+     * extra certs given to OCSP_resp_get0_signer().
+     */
+    bs = make_dummy_resp();
+    extra_certs = sk_X509_new_null();
+    if (bs == NULL
+        || extra_certs == NULL
+        || !get_cert_and_key(&signer, &key)
+        || !sk_X509_push(extra_certs, signer)
+        || !OCSP_basic_sign(bs, signer, key, EVP_sha1(),
+                                      NULL, OCSP_NOCERTS))
+        return 0;
+    if (!OCSP_resp_get0_signer(bs, &tmp, extra_certs)
+        || X509_cmp(tmp, signer) != 0)
+        return 0;
+    OCSP_BASICRESP_free(bs);
+
+    /* Do it again but include the signer cert */
+    bs = make_dummy_resp();
+    tmp = NULL;
+    if (bs == NULL
+        || !OCSP_basic_sign(bs, signer, key, EVP_sha1(),
+                            NULL, 0))
+        return 0;
+    if (!OCSP_resp_get0_signer(bs, &tmp, NULL)
+        || X509_cmp(tmp, signer) != 0)
+        return 0;
+    OCSP_BASICRESP_free(bs);
+    sk_X509_free(extra_certs);
+    X509_free(signer);
+    EVP_PKEY_free(key);
+    return 1;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+    int testresult = 1;
+    BIO *err = NULL;
+
+    if (argc != 3) {
+        printf("Invalid argument count\n");
+        return 1;
+    }
+    if ((certstr = argv[1]) == NULL
+        || (privkeystr = argv[2]) == NULL)
+        return 1;
+    err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+
+    CRYPTO_set_mem_debug(1);
+    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+
+#ifndef OPENSSL_NO_OCSP
+    ADD_TEST(test_resp_signer);
+#endif
+    testresult = run_tests(argv[0]);
+
+#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+    if (CRYPTO_mem_leaks(err) <= 0)
+        testresult = 1;
+#endif
+    BIO_free(err);
+
+    if (!testresult)
+        printf("PASS\n");
+
+    return testresult;
+}
index 9f178dec62c299ad7cec71bf9324d26751148675..e9ed7b4d519bb95bdd889612c1a8e3e3a6383dcb 100644 (file)
@@ -13,7 +13,7 @@ use warnings;
 use POSIX;
 use File::Spec::Functions qw/devnull catfile/;
 use File::Copy;
-use OpenSSL::Test qw/:DEFAULT with pipe srctop_dir/;
+use OpenSSL::Test qw/:DEFAULT with pipe srctop_dir data_file/;
 use OpenSSL::Test::Utils;
 
 setup("test_ocsp");
@@ -48,7 +48,7 @@ sub test_ocsp {
     unlink "ocsp-resp-fff.dat";
 }
 
-plan tests => 10;
+plan tests => 11;
 
 subtest "=== VALID OCSP RESPONSES ===" => sub {
     plan tests => 7;
@@ -210,3 +210,10 @@ subtest "=== INVALID SIGNATURE on the ISSUER CERTIFICATE ===" => sub {
     test_ocsp("DELEGATED; Root CA -> EE",
              "D3.ors", "ISIC_D3_Issuer_Root.pem", "", 0);
 };
+
+subtest "=== OCSP API TESTS===" => sub {
+    plan tests => 1;
+
+    ok(run(test(["ocspapitest", data_file("cert.pem"), data_file("key.pem")])),
+                 "running ocspapitest");
+}
diff --git a/test/recipes/80-test_ocsp_data/cert.pem b/test/recipes/80-test_ocsp_data/cert.pem
new file mode 100644 (file)
index 0000000..f70e792
--- /dev/null
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDLDCCAhSgAwIBAgICFs8wDQYJKoZIhvcNAQELBQAwSzEQMA4GA1UECgwHT3Bl
+blNTTDETMBEGA1UECwwKVGVzdCBTdWl0ZTEiMCAGA1UEAwwZVGVzdCBPQ1NQIHJl
+c3BvbnNlIHNpZ25lcjAeFw0xNzEwMjMxNDA4MDlaFw0yNjAxMDkxNDA4MDlaMEsx
+EDAOBgNVBAoMB09wZW5TU0wxEzARBgNVBAsMClRlc3QgU3VpdGUxIjAgBgNVBAMM
+GVRlc3QgT0NTUCByZXNwb25zZSBzaWduZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC81prq23FY2YDuwiXetb/NCs/cSm/afVnPsdSseRKi/GHi9d7b
+EEgWnQOJmz4zTuU+Bw2duHZ1X2WUR/Pjy4CvWNRq417aJ3IfyQHf8cxEplk9Ifd0
+5VEq6WzWVWAX6ki/CZIJUihzj3AAn/SYfvXw2wd319OQGvwYiQVt3Is5k4E4rAI2
+zXf5BdE9XkayM3jq6Ewc/VZ05EA/LaBLy5ujQljjfAFEy/qopYx3AJ4G8t2a5rvM
+dbNOyJCx9NNeryZMv2wRzEaYp6jYao+xxqbm5lgnwfE3jJ4aA9/oC1sUM8FokOGW
+9KAK3UEptoxux8JHH9R8X5bTVE7HADHhG5s7AgMBAAGjGjAYMAkGA1UdEwQCMAAw
+CwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBCwUAA4IBAQCPkojVPBFNT9DGpLq9Y/Hl
+XhcA+vSdt83EFzPD/nxIMp/QYSnZ9w2SWL21AH4C+HWd4JuKX5Zlsd6qYobYZLcT
+TyVfw0OMwwPUI6Mxbz395EAnVLmtddN2RDsEYvThSMMoSfhtUwyANpA0Q6M8RcGt
+LwnaC69iXhBh1xcTVVg97yEJ22yIrwQ1GhX4F1PRJIAQ/QmQhnoTGlhl2VAQ3LIk
+lNFxkWbx0rqPIcor27QDNa2DPqioyvHMlkjC1h5EPhL9Ynu011r4Dn9A34+vFxeu
+Q+emRwl/JjCNZX4l/AripU/Cy/+J2YGKilKzRcB1QMMVSl0VaeLSCwkNDQtdlwWO
+-----END CERTIFICATE-----
diff --git a/test/recipes/80-test_ocsp_data/key.pem b/test/recipes/80-test_ocsp_data/key.pem
new file mode 100644 (file)
index 0000000..cd211dc
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC81prq23FY2YDu
+wiXetb/NCs/cSm/afVnPsdSseRKi/GHi9d7bEEgWnQOJmz4zTuU+Bw2duHZ1X2WU
+R/Pjy4CvWNRq417aJ3IfyQHf8cxEplk9Ifd05VEq6WzWVWAX6ki/CZIJUihzj3AA
+n/SYfvXw2wd319OQGvwYiQVt3Is5k4E4rAI2zXf5BdE9XkayM3jq6Ewc/VZ05EA/
+LaBLy5ujQljjfAFEy/qopYx3AJ4G8t2a5rvMdbNOyJCx9NNeryZMv2wRzEaYp6jY
+ao+xxqbm5lgnwfE3jJ4aA9/oC1sUM8FokOGW9KAK3UEptoxux8JHH9R8X5bTVE7H
+ADHhG5s7AgMBAAECggEBAJLp946eeVmhpiCa5XGWPwlbzwlY1BrNCRGADbC9ZRVu
+ew1jMiWGTj9hmr31DHhIeis+u4YoW+jG9jVdoU5pJc3Fs0URbdsVc0FtVcsPyFbk
+gGsCQQ4t1m8nOaiqtV8Fw+D0piwgQh5dysqBp374z4i6Lt47CHqFs/m2qIWnXp3E
+YF3xX2Zz9rIgejERRxrUnp5998NqxSYHPF7Ts4VQ/+UezUqEpA2jBs6cJ2tWVNR9
+uf+3Fklpo7Uau+xG5xkiRYxx4mSIg6EREz5+XMPkSOcXi6tyinoKsafxTNQDil0q
+pdurVlHNgZb2QdJjHugVmbalydHIQ5c0CU1RO5CP97kCgYEA7RqrRooniil0iAKR
+6scFct0juVBW1Uw05Ejt97RtwQRf/m9SU5mSs0PfFx/l3PeNDSWnpmwunL1igYQb
++tVqDQQ9xR4owyl6/qDJSP2bS84jb+3MCR4UE/b2YR2rCDBllXeyQsDT7KMoW8lX
+gliWmYd6HYddRDOKNM/tzccFG1cCgYEAy+M6yv0ublrpTj4o8DcOi6JJrQbPSAWx
+R7zKDXSvSq5lLjfXmqX4s/jgZWgQ+kYoYZrIOqIygcZ2U6tBMCP2LAhbf86I6r27
+loMyQg7lhC5GCztpGes4/JmUvnvjTUIFspB6ReaXlBFAstzzJirgI1wmoO6+GiG/
+OUDmvCjFdL0CgYALQGa8VDYIImt7QNP31jX1+3SEiMF2IcWox6UzSgajUDfV9SZs
+/S6u/xuJF2RrFfxFkXHhPeUAXyRbjQ9e2d3MfFUKE6JPkJpblvm2UwKZmFCqMRir
+nhfJ0sBiX2wMWW+YpjN5Y3krE5sIsAdNEjMjWgB7gj70y5VVaECasUUWxQKBgQDB
+aauqSIc1VLSh7sGzLudzet5db2pPLmdAYE1kel6Xf9yn/X1gTTYitGNaj2Abq1Y/
+US/Ev30eMwCo2nqaimLK3pq+IVUtKhO78nVIyQzdWXBE03Uei0+iAKdkE+5Kqejx
+vbDggqEka0Fu678VY/MAWDikzhY0f/MBAxpfQGYgGQKBgC0tR1ymvCLkk6J5e4/G
+OD1D9m2JJjcK4eWUS4rAiEH61sI5CKQRU2pQ3f3cIGekDZZt3XzHLYwc9W2UnN2J
+glMmKXp0qqt2HoE/XKLrIc1dEDXsZxFnMZ6nmWKsl4AHxM/gyXqfDo/AUXyEGcVu
+8TbVs3nlISUy7vwjpaW1KOs1
+-----END PRIVATE KEY-----