vconn: Test SSL vconns too.
authorBen Pfaff <blp@nicira.com>
Thu, 7 Jan 2010 22:00:58 +0000 (14:00 -0800)
committerBen Pfaff <blp@nicira.com>
Thu, 7 Jan 2010 23:00:51 +0000 (15:00 -0800)
This test should help avoid simple bugs in the SSL vconn and SSL stream
implementations in the future.  It would have found the bugs fixed by
recent commits.

tests/library.at
tests/test-vconn.c
tests/testpki-cacert.pem [new file with mode: 0644]
tests/testpki-cert.pem [new file with mode: 0644]
tests/testpki-privkey.pem [new file with mode: 0644]
tests/testpki-req.pem [new file with mode: 0644]

index ffcd4b835759d4ff5c352d91e9e08cd56e6b19e3..eab14241eba47c388ec6ed50d0d367c73bdd3de6 100644 (file)
@@ -36,5 +36,6 @@ OVS_CHECK_LCOV([test-type-props], [0], [ignore])
 AT_CLEANUP
 
 AT_SETUP([test vconn library])
-OVS_CHECK_LCOV([test-vconn], [0], [ignore])
+AT_CHECK([cp $abs_top_srcdir/tests/testpki*.pem .])
+OVS_CHECK_LCOV([test-vconn], [0], [], [ignore])
 AT_CLEANUP
index 87e35c4ae0604b94b10f2a93760d1bbbd54a56c8..948f30ad1f52cdbda359947662cc3eefb8693c57 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,6 +23,8 @@
 #include <unistd.h>
 #include "poll-loop.h"
 #include "socket-util.h"
+#include "stream.h"
+#include "stream-ssl.h"
 #include "timeval.h"
 #include "util.h"
 #include "vlog.h"
@@ -34,9 +36,31 @@ struct fake_pvconn {
     const char *type;
     char *pvconn_name;
     char *vconn_name;
-    int fd;
+    struct pstream *pstream;
 };
 
+static void
+check(int a, int b, const char *as, const char *file, int line)
+{
+    if (a != b) {
+        ovs_fatal(0, "%s:%d: %s is %d but should be %d", file, line, as, a, b);
+    }
+}
+
+
+#define CHECK(A, B) check(A, B, #A, __FILE__, __LINE__)
+
+static void
+check_errno(int a, int b, const char *as, const char *file, int line)
+{
+    if (a != b) {
+        ovs_fatal(0, "%s:%d: %s is %d (%s) but should be %d (%s)",
+                  file, line, as, a, strerror(abs(a)), b, strerror(abs(b)));
+    }
+}
+
+#define CHECK_ERRNO(A, B) check_errno(A, B, #A, __FILE__, __LINE__)
+
 static void
 fpv_create(const char *type, struct fake_pvconn *fpv)
 {
@@ -44,84 +68,50 @@ fpv_create(const char *type, struct fake_pvconn *fpv)
     if (!strcmp(type, "unix")) {
         static int unix_count = 0;
         char *bind_path;
-        int fd;
 
         bind_path = xasprintf("fake-pvconn.%d", unix_count++);
-        fd = make_unix_socket(SOCK_STREAM, false, false, bind_path, NULL);
-        if (fd < 0) {
-            ovs_fatal(-fd, "%s: could not bind to Unix domain socket",
-                      bind_path);
-        }
-
         fpv->pvconn_name = xasprintf("punix:%s", bind_path);
         fpv->vconn_name = xasprintf("unix:%s", bind_path);
-        fpv->fd = fd;
+        CHECK_ERRNO(pstream_open(fpv->pvconn_name, &fpv->pstream), 0);
         free(bind_path);
-    } else if (!strcmp(type, "tcp")) {
-        struct sockaddr_in sin;
-        socklen_t sin_len;
-        int fd;
-
-        /* Create TCP socket. */
-        fd = socket(PF_INET, SOCK_STREAM, 0);
-        if (fd < 0) {
-            ovs_fatal(errno, "failed to create TCP socket");
-        }
+    } else if (!strcmp(type, "tcp") || !strcmp(type, "ssl")) {
+        char *s, *method, *port, *save_ptr = NULL;
+        char *open_name;
 
-        /* Bind TCP socket to localhost on any available port. */
-        sin.sin_family = AF_INET;
-        sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-        sin.sin_port = htons(0);
-        if (bind(fd, (struct sockaddr *) &sin, sizeof sin) < 0) {
-            ovs_fatal(errno, "failed to bind TCP socket");
-        }
+        open_name = xasprintf("p%s:0:127.0.0.1", type);
+        CHECK_ERRNO(pstream_open(open_name, &fpv->pstream), 0);
 
-        /* Retrieve socket's port number. */
-        sin_len = sizeof sin;
-        if (getsockname(fd, (struct sockaddr *)&sin, &sin_len) < 0) {
-            ovs_fatal(errno, "failed to read TCP socket name");
-        }
-        if (sin_len != sizeof sin || sin.sin_family != AF_INET) {
-            ovs_fatal(errno, "bad TCP socket name");
-        }
+        /* Extract bound port number from pstream name. */
+        s = xstrdup(pstream_get_name(fpv->pstream));
+        method = strtok_r(s, ":", &save_ptr);
+        port = strtok_r(NULL, ":", &save_ptr);
 
         /* Save info. */
-        fpv->pvconn_name = xasprintf("ptcp:%"PRIu16":127.0.0.1",
-                                    ntohs(sin.sin_port));
-        fpv->vconn_name = xasprintf("tcp:127.0.0.1:%"PRIu16,
-                                    ntohs(sin.sin_port));
-        fpv->fd = fd;
+        fpv->pvconn_name = xstrdup(pstream_get_name(fpv->pstream));
+        fpv->vconn_name = xasprintf("%s:127.0.0.1:%s", type, port);
+
+        free(open_name);
+        free(s);
     } else {
         abort();
     }
-
-    /* Listen. */
-    if (listen(fpv->fd, 0) < 0) {
-        ovs_fatal(errno, "%s: listen failed", fpv->vconn_name);
-    }
 }
 
-static int
+static struct stream *
 fpv_accept(struct fake_pvconn *fpv)
 {
-    int fd;
+    struct stream *stream;
 
-    fd = accept(fpv->fd, NULL, NULL);
-    if (fd < 0) {
-        ovs_fatal(errno, "%s: accept failed", fpv->pvconn_name);
-    }
-    return fd;
+    CHECK_ERRNO(pstream_accept_block(fpv->pstream, &stream), 0);
+
+    return stream;
 }
 
 static void
 fpv_close(struct fake_pvconn *fpv)
 {
-    if (fpv->fd >= 0) {
-        if (close(fpv->fd) < 0) {
-            ovs_fatal(errno, "failed to close %s fake pvconn", fpv->type);
-        }
-        fpv->fd = -1;
-    }
+    pstream_close(fpv->pstream);
+    fpv->pstream = NULL;
 }
 
 static void
@@ -141,10 +131,10 @@ test_refuse_connection(const char *type, int expected_error)
     struct vconn *vconn;
 
     fpv_create(type, &fpv);
-    assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
+    CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP_VERSION, &vconn), 0);
     fpv_close(&fpv);
     vconn_run(vconn);
-    assert(vconn_connect(vconn) == expected_error);
+    CHECK_ERRNO(vconn_connect(vconn), expected_error);
     vconn_close(vconn);
     fpv_destroy(&fpv);
 }
@@ -159,11 +149,11 @@ test_accept_then_close(const char *type, int expected_error)
     struct vconn *vconn;
 
     fpv_create(type, &fpv);
-    assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
+    CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP_VERSION, &vconn), 0);
     vconn_run(vconn);
-    close(fpv_accept(&fpv));
+    stream_close(fpv_accept(&fpv));
     fpv_close(&fpv);
-    assert(vconn_connect(vconn) == expected_error);
+    CHECK_ERRNO(vconn_connect(vconn), expected_error);
     vconn_close(vconn);
     fpv_destroy(&fpv);
 }
@@ -176,37 +166,36 @@ test_read_hello(const char *type, int expected_error)
 {
     struct fake_pvconn fpv;
     struct vconn *vconn;
-    int fd;
+    struct stream *stream;
 
     fpv_create(type, &fpv);
-    assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
+    CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP_VERSION, &vconn), 0);
     vconn_run(vconn);
-    fd = fpv_accept(&fpv);
+    stream = fpv_accept(&fpv);
     fpv_destroy(&fpv);
-    assert(!set_nonblocking(fd));
     for (;;) {
        struct ofp_header hello;
        int retval;
 
-       retval = read(fd, &hello, sizeof hello);
+       retval = stream_recv(stream, &hello, sizeof hello);
        if (retval == sizeof hello) {
-           assert(hello.version == OFP_VERSION);
-           assert(hello.type == OFPT_HELLO);
-           assert(hello.length == htons(sizeof hello));
+           CHECK(hello.version, OFP_VERSION);
+           CHECK(hello.type, OFPT_HELLO);
+           CHECK(hello.length, htons(sizeof hello));
            break;
        } else {
-           assert(errno == EAGAIN);
+           CHECK_ERRNO(retval, -EAGAIN);
        }
 
        vconn_run(vconn);
-       assert(vconn_connect(vconn) == EAGAIN);
+       CHECK_ERRNO(vconn_connect(vconn), EAGAIN);
        vconn_run_wait(vconn);
        vconn_connect_wait(vconn);
-       poll_fd_wait(fd, POLLIN);
+       stream_recv_wait(stream);
        poll_block();
     }
-    close(fd);
-    assert(vconn_connect(vconn) == expected_error);
+    stream_close(stream);
+    CHECK_ERRNO(vconn_connect(vconn), expected_error);
     vconn_close(vconn);
 }
 
@@ -222,30 +211,46 @@ test_send_hello(const char *type, const void *out, size_t out_size,
     struct vconn *vconn;
     bool read_hello, connected;
     struct ofpbuf *msg;
-    int fd;
+    struct stream *stream;
+    size_t n_sent;
 
     fpv_create(type, &fpv);
-    assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
+    CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP_VERSION, &vconn), 0);
     vconn_run(vconn);
-    fd = fpv_accept(&fpv);
+    stream = fpv_accept(&fpv);
     fpv_destroy(&fpv);
 
-    assert(write(fd, out, out_size) == out_size);
-
-    assert(!set_nonblocking(fd));
+    n_sent = 0;
+    while (n_sent < out_size) {
+        int retval;
+
+        retval = stream_send(stream, (char *) out + n_sent, out_size - n_sent);
+        if (retval > 0) {
+            n_sent += retval;
+        } else if (retval == -EAGAIN) {
+            stream_run(stream);
+            vconn_run(vconn);
+            stream_recv_wait(stream);
+            vconn_connect_wait(vconn);
+            vconn_run_wait(vconn);
+            poll_block();
+        } else {
+            ovs_fatal(0, "stream_send returned unexpected value %d", retval);
+        }
+    }
 
     read_hello = connected = false;
     for (;;) {
        if (!read_hello) {
            struct ofp_header hello;
-           int retval = read(fd, &hello, sizeof hello);
+           int retval = stream_recv(stream, &hello, sizeof hello);
            if (retval == sizeof hello) {
-               assert(hello.version == OFP_VERSION);
-               assert(hello.type == OFPT_HELLO);
-               assert(hello.length == htons(sizeof hello));
+               CHECK(hello.version, OFP_VERSION);
+               CHECK(hello.type, OFPT_HELLO);
+               CHECK(hello.length, htons(sizeof hello));
                read_hello = true;
            } else {
-               assert(errno == EAGAIN);
+               CHECK_ERRNO(retval, -EAGAIN);
            }
        }
 
@@ -256,12 +261,12 @@ test_send_hello(const char *type, const void *out, size_t out_size,
                if (!error) {
                    connected = true;
                } else {
-                   close(fd);
+                   stream_close(stream);
                    vconn_close(vconn);
                    return;
                }
            } else {
-               assert(error == EAGAIN);
+               CHECK_ERRNO(error, EAGAIN);
            }
        }
 
@@ -274,12 +279,12 @@ test_send_hello(const char *type, const void *out, size_t out_size,
            vconn_connect_wait(vconn);
        }
        if (!read_hello) {
-           poll_fd_wait(fd, POLLIN);
+           stream_recv_wait(stream);
        }
        poll_block();
     }
-    close(fd);
-    assert(vconn_recv(vconn, &msg) == EOF);
+    stream_close(stream);
+    CHECK_ERRNO(vconn_recv(vconn, &msg), EOF);
     vconn_close(vconn);
 }
 
@@ -360,33 +365,41 @@ main(int argc UNUSED, char *argv[])
     time_init();
     vlog_init();
     signal(SIGPIPE, SIG_IGN);
-    vlog_set_levels(VLM_ANY_MODULE, VLF_ANY_FACILITY, VLL_EMER);
 
     time_alarm(10);
 
     test_refuse_connection("unix", EPIPE);
-    test_refuse_connection("tcp", ECONNRESET);
-
     test_accept_then_close("unix", EPIPE);
-    test_accept_then_close("tcp", ECONNRESET);
-
     test_read_hello("unix", ECONNRESET);
-    test_read_hello("tcp", ECONNRESET);
-
     test_send_plain_hello("unix");
-    test_send_plain_hello("tcp");
-
     test_send_long_hello("unix");
-    test_send_long_hello("tcp");
-
     test_send_echo_hello("unix");
-    test_send_echo_hello("tcp");
-
     test_send_short_hello("unix");
-    test_send_short_hello("tcp");
-
     test_send_invalid_version_hello("unix");
+
+    test_accept_then_close("tcp", ECONNRESET);
+    test_refuse_connection("tcp", ECONNRESET);
+    test_read_hello("tcp", ECONNRESET);
+    test_send_plain_hello("tcp");
+    test_send_long_hello("tcp");
+    test_send_echo_hello("tcp");
+    test_send_short_hello("tcp");
     test_send_invalid_version_hello("tcp");
 
+#ifdef HAVE_OPENSSL
+    stream_ssl_set_private_key_file("testpki-privkey.pem");
+    stream_ssl_set_certificate_file("testpki-cert.pem");
+    stream_ssl_set_ca_cert_file("testpki-cacert.pem", false);
+
+    test_accept_then_close("ssl", EPROTO);
+    test_refuse_connection("ssl", ECONNRESET);
+    test_read_hello("ssl", ECONNRESET);
+    test_send_plain_hello("ssl");
+    test_send_long_hello("ssl");
+    test_send_echo_hello("ssl");
+    test_send_short_hello("ssl");
+    test_send_invalid_version_hello("ssl");
+#endif  /* HAVE_OPENSSL */
+
     return 0;
 }
diff --git a/tests/testpki-cacert.pem b/tests/testpki-cacert.pem
new file mode 100644 (file)
index 0000000..e888505
--- /dev/null
@@ -0,0 +1,70 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=US, ST=CA, O=Open vSwitch, OU=switchca, CN=OVS switchca CA Certificate (2010 Jan 06 17:08:30)
+        Validity
+            Not Before: Jan  7 01:08:32 2010 GMT
+            Not After : Jan  7 01:08:32 2016 GMT
+        Subject: C=US, ST=CA, O=Open vSwitch, OU=switchca, CN=OVS switchca CA Certificate (2010 Jan 06 17:08:30)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:cc:b2:25:ba:07:b8:d6:e1:23:20:1e:41:a1:49:
+                    35:68:09:71:19:ef:68:a0:45:e0:bd:33:41:0d:2b:
+                    b7:7d:33:16:57:d4:16:da:ba:a0:7e:ae:9c:76:5b:
+                    92:93:96:a9:5b:bd:6f:b3:fd:6a:62:b9:10:46:98:
+                    d9:b4:ea:ab:99:f3:72:4b:d1:11:81:77:75:09:be:
+                    fd:9f:55:f7:6c:78:0a:b1:9d:f8:c5:c5:a0:de:05:
+                    0d:78:62:66:ed:b1:0f:b3:9a:69:fd:13:9f:43:a7:
+                    aa:e4:3c:a1:63:68:46:c2:a1:56:56:eb:62:b5:0e:
+                    2b:be:7b:8e:c9:aa:c2:6f:04:af:7b:5a:ed:4b:16:
+                    fb:47:4d:45:81:d8:b8:2e:08:21:a7:4d:cc:78:9b:
+                    b0:b0:a0:18:91:53:ab:64:c3:eb:66:74:93:cc:8a:
+                    b4:40:c5:4e:2e:cc:c5:63:c0:6b:2d:6e:cd:b9:1c:
+                    a9:45:ad:82:0a:d2:1f:5d:84:bc:29:a1:82:0d:75:
+                    1c:1a:21:8b:15:03:88:94:e5:89:ed:48:22:e0:7e:
+                    b9:15:f1:13:fb:6c:a2:48:c7:2d:e5:01:04:b7:23:
+                    6a:06:45:7b:e3:14:59:ac:1d:87:e6:a5:ec:7c:86:
+                    80:17:64:71:a0:43:27:27:f5:2c:bd:34:60:c7:a1:
+                    22:3f
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: md5WithRSAEncryption
+        c7:85:13:17:b6:ca:c8:1b:8a:8e:eb:3b:64:05:e4:d5:a2:2c:
+        6b:ee:83:d8:e0:67:f9:99:59:15:59:9d:6d:16:c0:6b:c3:ed:
+        61:31:0a:40:1b:63:1d:57:a5:67:3d:46:55:6b:9f:ed:18:79:
+        45:fc:db:d9:48:d2:86:0f:aa:e0:43:18:3f:f4:e3:71:a3:28:
+        d4:00:ae:7c:0e:91:2c:5b:5b:ff:be:ad:b6:4b:b7:0e:e3:ea:
+        7a:66:69:6c:83:90:0c:59:c1:d7:4d:1a:b9:69:0d:ac:6e:07:
+        b3:42:3c:3e:54:ac:85:c5:58:67:51:2a:c0:05:1f:70:6a:07:
+        86:2c:42:56:ee:3b:69:7b:db:35:e6:c6:5b:eb:25:66:ca:89:
+        bb:d7:37:ae:d2:b9:e8:56:38:a2:ec:ff:45:38:97:ae:43:20:
+        c8:55:c9:c8:0f:45:37:70:97:b9:8a:2e:56:52:6f:20:f3:08:
+        b7:1a:26:98:b9:d9:7d:52:69:b3:95:2b:c5:4e:0c:7b:fd:cd:
+        6a:a2:23:cf:eb:ee:de:74:17:0b:cc:a3:91:f1:41:0b:1e:94:
+        e2:ea:52:85:c1:3d:de:f9:e6:44:5a:f6:fe:7d:2f:fb:6f:60:
+        89:2c:f0:0c:c7:c7:fb:6f:23:4d:a1:18:89:28:ea:61:f4:3a:
+        9d:ca:1f:60
+-----BEGIN CERTIFICATE-----
+MIIDeDCCAmACAQEwDQYJKoZIhvcNAQEEBQAwgYExCzAJBgNVBAYTAlVTMQswCQYD
+VQQIEwJDQTEVMBMGA1UEChMMT3BlbiB2U3dpdGNoMREwDwYDVQQLEwhzd2l0Y2hj
+YTE7MDkGA1UEAxMyT1ZTIHN3aXRjaGNhIENBIENlcnRpZmljYXRlICgyMDEwIEph
+biAwNiAxNzowODozMCkwHhcNMTAwMTA3MDEwODMyWhcNMTYwMTA3MDEwODMyWjCB
+gTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRUwEwYDVQQKEwxPcGVuIHZTd2l0
+Y2gxETAPBgNVBAsTCHN3aXRjaGNhMTswOQYDVQQDEzJPVlMgc3dpdGNoY2EgQ0Eg
+Q2VydGlmaWNhdGUgKDIwMTAgSmFuIDA2IDE3OjA4OjMwKTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAMyyJboHuNbhIyAeQaFJNWgJcRnvaKBF4L0zQQ0r
+t30zFlfUFtq6oH6unHZbkpOWqVu9b7P9amK5EEaY2bTqq5nzckvREYF3dQm+/Z9V
+92x4CrGd+MXFoN4FDXhiZu2xD7Oaaf0Tn0OnquQ8oWNoRsKhVlbrYrUOK757jsmq
+wm8Er3ta7UsW+0dNRYHYuC4IIadNzHibsLCgGJFTq2TD62Z0k8yKtEDFTi7MxWPA
+ay1uzbkcqUWtggrSH12EvCmhgg11HBohixUDiJTlie1IIuB+uRXxE/tsokjHLeUB
+BLcjagZFe+MUWawdh+al7HyGgBdkcaBDJyf1LL00YMehIj8CAwEAATANBgkqhkiG
+9w0BAQQFAAOCAQEAx4UTF7bKyBuKjus7ZAXk1aIsa+6D2OBn+ZlZFVmdbRbAa8Pt
+YTEKQBtjHVelZz1GVWuf7Rh5Rfzb2UjShg+q4EMYP/TjcaMo1ACufA6RLFtb/76t
+tku3DuPqemZpbIOQDFnB100auWkNrG4Hs0I8PlSshcVYZ1EqwAUfcGoHhixCVu47
+aXvbNebGW+slZsqJu9c3rtK56FY4ouz/RTiXrkMgyFXJyA9FN3CXuYouVlJvIPMI
+txommLnZfVJps5UrxU4Me/3NaqIjz+vu3nQXC8yjkfFBCx6U4upShcE93vnmRFr2
+/n0v+29giSzwDMfH+28jTaEYiSjqYfQ6ncofYA==
+-----END CERTIFICATE-----
diff --git a/tests/testpki-cert.pem b/tests/testpki-cert.pem
new file mode 100644 (file)
index 0000000..75d815d
--- /dev/null
@@ -0,0 +1,70 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 2 (0x2)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=US, ST=CA, O=Open vSwitch, OU=switchca, CN=OVS switchca CA Certificate (2010 Jan 06 17:08:30)
+        Validity
+            Not Before: Jan  7 01:08:59 2010 GMT
+            Not After : Jan  7 01:08:59 2011 GMT
+        Subject: C=US, ST=CA, O=Open vSwitch, OU=Open vSwitch certifier, CN=Open vSwitch certificate for testpki
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:ac:3f:c6:b1:ef:a3:e3:68:98:2c:91:a1:3a:21:
+                    02:38:87:5b:75:7a:1c:17:c9:b0:64:a9:f7:80:17:
+                    08:0f:b5:25:b4:46:80:6b:7e:92:ab:f8:93:05:17:
+                    77:e4:12:86:eb:54:5d:a7:a0:45:70:16:5e:d7:4f:
+                    6b:7c:9f:fe:83:a4:c1:62:83:33:71:6f:4f:4e:68:
+                    84:a6:92:a5:77:8f:ad:cd:ee:bf:61:72:24:c0:64:
+                    df:73:98:de:37:6b:b8:4d:78:f4:ba:06:95:64:ef:
+                    82:b1:2f:71:01:44:ca:3c:de:fa:32:28:b6:ea:72:
+                    7b:4d:d6:a0:fb:4b:73:de:a9:7f:25:ad:20:02:3d:
+                    5f:7f:7f:8e:91:34:97:0a:10:96:be:3d:ee:37:5b:
+                    a9:91:9e:7f:d5:ac:7b:e3:56:47:a4:14:15:dd:48:
+                    ce:32:6f:c4:83:09:07:31:bb:34:77:4d:f7:12:70:
+                    86:b8:b2:64:16:3b:ea:d2:72:e0:73:6b:6f:ce:59:
+                    cf:56:6d:a8:94:3c:10:d7:47:7e:b2:91:9d:c7:65:
+                    23:8a:b1:ca:9c:15:36:c5:d9:db:b1:e7:b8:1f:09:
+                    20:1d:da:97:de:93:7c:e2:5d:94:ea:38:d8:ce:60:
+                    c9:9e:43:da:6d:9d:c9:d2:a0:e9:6d:5a:9b:57:53:
+                    86:7d
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: md5WithRSAEncryption
+        19:a9:2a:66:fc:09:78:c9:87:e6:73:be:9a:d2:b7:87:07:7b:
+        93:70:04:cd:f2:c9:47:a3:8f:9f:c4:af:92:ef:cf:07:d3:83:
+        90:f7:8a:f0:55:f6:8a:2e:af:57:b9:e4:9c:72:37:b7:af:12:
+        fb:dc:07:9b:94:7b:18:c8:53:86:6d:02:77:eb:e3:ac:21:e1:
+        6d:b5:fe:04:6b:a1:d2:78:a6:58:4b:5d:a7:17:e1:3b:d9:94:
+        ab:81:5e:c1:9a:b5:34:a5:a7:9a:2b:1b:74:d7:a4:aa:fa:81:
+        5c:e5:5f:1a:07:54:36:21:76:04:a9:5e:11:38:46:b8:1c:11:
+        15:78:f8:0c:31:8d:9a:a3:e4:d0:72:a8:29:80:c2:3d:9d:f6:
+        61:dd:ca:c9:6c:7e:ca:c0:0d:61:28:4d:3e:ea:51:9d:c2:c4:
+        7c:47:da:cc:24:35:9c:2a:0d:ac:ea:5f:33:5a:ab:b7:94:cb:
+        3f:91:38:92:a3:62:3b:40:ef:79:55:96:b3:24:5a:19:a2:53:
+        99:63:f9:85:d4:b6:48:b8:9a:f8:bc:b7:74:f8:cf:95:dc:1a:
+        f2:66:cd:2b:4b:d4:c1:19:69:77:f9:f6:08:04:61:cd:80:ee:
+        46:44:27:82:49:60:a9:be:4b:51:75:ca:15:16:0b:97:c2:2f:
+        26:f2:dd:42
+-----BEGIN CERTIFICATE-----
+MIIDeDCCAmACAQIwDQYJKoZIhvcNAQEEBQAwgYExCzAJBgNVBAYTAlVTMQswCQYD
+VQQIEwJDQTEVMBMGA1UEChMMT3BlbiB2U3dpdGNoMREwDwYDVQQLEwhzd2l0Y2hj
+YTE7MDkGA1UEAxMyT1ZTIHN3aXRjaGNhIENBIENlcnRpZmljYXRlICgyMDEwIEph
+biAwNiAxNzowODozMCkwHhcNMTAwMTA3MDEwODU5WhcNMTEwMTA3MDEwODU5WjCB
+gTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRUwEwYDVQQKEwxPcGVuIHZTd2l0
+Y2gxHzAdBgNVBAsTFk9wZW4gdlN3aXRjaCBjZXJ0aWZpZXIxLTArBgNVBAMTJE9w
+ZW4gdlN3aXRjaCBjZXJ0aWZpY2F0ZSBmb3IgdGVzdHBraTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKw/xrHvo+NomCyRoTohAjiHW3V6HBfJsGSp94AX
+CA+1JbRGgGt+kqv4kwUXd+QShutUXaegRXAWXtdPa3yf/oOkwWKDM3FvT05ohKaS
+pXePrc3uv2FyJMBk33OY3jdruE149LoGlWTvgrEvcQFEyjze+jIotupye03WoPtL
+c96pfyWtIAI9X39/jpE0lwoQlr497jdbqZGef9Wse+NWR6QUFd1IzjJvxIMJBzG7
+NHdN9xJwhriyZBY76tJy4HNrb85Zz1ZtqJQ8ENdHfrKRncdlI4qxypwVNsXZ27Hn
+uB8JIB3al96TfOJdlOo42M5gyZ5D2m2dydKg6W1am1dThn0CAwEAATANBgkqhkiG
+9w0BAQQFAAOCAQEAGakqZvwJeMmH5nO+mtK3hwd7k3AEzfLJR6OPn8Svku/PB9OD
+kPeK8FX2ii6vV7nknHI3t68S+9wHm5R7GMhThm0Cd+vjrCHhbbX+BGuh0nimWEtd
+pxfhO9mUq4FewZq1NKWnmisbdNekqvqBXOVfGgdUNiF2BKleEThGuBwRFXj4DDGN
+mqPk0HKoKYDCPZ32Yd3KyWx+ysANYShNPupRncLEfEfazCQ1nCoNrOpfM1qrt5TL
+P5E4kqNiO0DveVWWsyRaGaJTmWP5hdS2SLia+Ly3dPjPldwa8mbNK0vUwRlpd/n2
+CARhzYDuRkQngklgqb5LUXXKFRYLl8IvJvLdQg==
+-----END CERTIFICATE-----
diff --git a/tests/testpki-privkey.pem b/tests/testpki-privkey.pem
new file mode 100644 (file)
index 0000000..759f58a
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEArD/Gse+j42iYLJGhOiECOIdbdXocF8mwZKn3gBcID7UltEaA
+a36Sq/iTBRd35BKG61Rdp6BFcBZe109rfJ/+g6TBYoMzcW9PTmiEppKld4+tze6/
+YXIkwGTfc5jeN2u4TXj0ugaVZO+CsS9xAUTKPN76Mii26nJ7Tdag+0tz3ql/Ja0g
+Aj1ff3+OkTSXChCWvj3uN1upkZ5/1ax741ZHpBQV3UjOMm/EgwkHMbs0d033EnCG
+uLJkFjvq0nLgc2tvzlnPVm2olDwQ10d+spGdx2UjirHKnBU2xdnbsee4HwkgHdqX
+3pN84l2U6jjYzmDJnkPabZ3J0qDpbVqbV1OGfQIDAQABAoIBADr/MSAa82hdl9mU
+G8PcMHWKLxJCu8KOC0O/T41o1hMDOaHQkAXBeZ07a6fPzPmqOtn5sIZMh9wHXX6j
+ri4mYrdWRAJo68LLnD8/30dqbRBRfvdM8fH/dYUMR9jBIEOdOqgWaMQaoyrKOlpT
+5IHJvPcybEGn3lbY1VDo1YSc6Ff36AGLdORVH8dY9tYx/IKbyzRmDvzai6EVSDtl
+yp2zinXRNJ+AVwB0epsKbOVZa0WaYN1KclqOtFn7xANoUvy5YBHZDedC3yWxuZvZ
+dNeTjUniauukz7ivKg9/rWZFfYZ2251mrOfO9aIHOUzBurbDS/rzjVgwQmv483T9
+2cDL/IUCgYEA3tXDA0Mcv1d7IzP6A4CQ6o49JyWVkMHxKkhZy1cR+pBRc7tgpQrF
+YrtEWdsDvUJLGMUQBmm7VMpMjTRQ/YuBcdIB2USkJcDHPaZRAA1mlDPG6cSsy7yI
+d2qZFOOkUEjLqKicxiHTrCOz9HBb1McolTo9h5SdfBy5bHb9LPul3E8CgYEAxeKk
+L3m1C1rFVpVF8zoHF+zK3/d9zwzdLzmFfFrKqzIT3/6cJKEwHLJN69mja60+MKLZ
+6F1G+R4/JxE8TnCSXHh7UYULhyFolZaWwZn5xVld0210QU+f4EBUZMt4bZjDxEyr
+/vxDZaqu7SB5Mmqq++C9YzdeIk1GGJ0TE2MmwXMCgYEAuPJ+ayS2pXD8ONmY9nMs
+1CC+TNF686ykd02ZiZV4zJgfooiwzArGjQ2Uy2dmER0Gq0ZT6J605skJBGGZnva8
+tzVwZ137R4JbW6XAsORucS8QN1IPgQG32jVVXOsbo67nqdJYXHIS91qir4zaCx5J
+ZqHyE6ebljlZBNc1hrJOlS0CgYEAhoc/626oYCHDistMlMBcVi2K9pwAkaRDMnm+
+f/4RTjVrQZqMeHKEjN3DD5YT/X33i4UK82eGepHPiTW0c/cf6XGXFKKIZcOWoCuS
+LegJ39qTaMs+f7AsFn5lYWjaZFe4r1kYjO7eut1AssCi5F2UBEyTNEJN4q/5+X2/
+nCyKCnUCgYBzxbUnJBhuA8ivNb/lXdGCvqnBaZb1Bjb+Ljv0yDhMVEJwKpGpm5H3
+DySodzklBrU+eL9TLPcFM6N+okmDsMQqUygUJ1PXLRZKnpLVRILmHcMWbgCrbw4Q
+pd22A01NncdtPY2107ZeVZnjzqHF+5CXxMlKBl4QG07KFtzbNOcQuA==
+-----END RSA PRIVATE KEY-----
diff --git a/tests/testpki-req.pem b/tests/testpki-req.pem
new file mode 100644 (file)
index 0000000..da53b10
--- /dev/null
@@ -0,0 +1,63 @@
+Certificate Request:
+    Data:
+        Version: 0 (0x0)
+        Subject: C=US, ST=CA, L=Palo Alto, O=Open vSwitch, OU=Open vSwitch certifier, CN=Open vSwitch certificate for testpki
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:ac:3f:c6:b1:ef:a3:e3:68:98:2c:91:a1:3a:21:
+                    02:38:87:5b:75:7a:1c:17:c9:b0:64:a9:f7:80:17:
+                    08:0f:b5:25:b4:46:80:6b:7e:92:ab:f8:93:05:17:
+                    77:e4:12:86:eb:54:5d:a7:a0:45:70:16:5e:d7:4f:
+                    6b:7c:9f:fe:83:a4:c1:62:83:33:71:6f:4f:4e:68:
+                    84:a6:92:a5:77:8f:ad:cd:ee:bf:61:72:24:c0:64:
+                    df:73:98:de:37:6b:b8:4d:78:f4:ba:06:95:64:ef:
+                    82:b1:2f:71:01:44:ca:3c:de:fa:32:28:b6:ea:72:
+                    7b:4d:d6:a0:fb:4b:73:de:a9:7f:25:ad:20:02:3d:
+                    5f:7f:7f:8e:91:34:97:0a:10:96:be:3d:ee:37:5b:
+                    a9:91:9e:7f:d5:ac:7b:e3:56:47:a4:14:15:dd:48:
+                    ce:32:6f:c4:83:09:07:31:bb:34:77:4d:f7:12:70:
+                    86:b8:b2:64:16:3b:ea:d2:72:e0:73:6b:6f:ce:59:
+                    cf:56:6d:a8:94:3c:10:d7:47:7e:b2:91:9d:c7:65:
+                    23:8a:b1:ca:9c:15:36:c5:d9:db:b1:e7:b8:1f:09:
+                    20:1d:da:97:de:93:7c:e2:5d:94:ea:38:d8:ce:60:
+                    c9:9e:43:da:6d:9d:c9:d2:a0:e9:6d:5a:9b:57:53:
+                    86:7d
+                Exponent: 65537 (0x10001)
+        Attributes:
+            a0:00
+    Signature Algorithm: sha1WithRSAEncryption
+        21:46:4c:7a:a9:da:58:cf:ee:d3:0a:81:ee:cd:bf:73:cf:05:
+        93:2b:ef:f5:c7:7d:5e:96:a5:82:d2:62:34:26:8f:1e:f6:db:
+        6f:0e:05:39:a5:3c:df:bb:51:02:2f:bc:5b:a8:a0:a5:5e:ce:
+        e4:55:21:73:92:1d:bf:53:a4:f5:dc:7e:0e:f8:b1:05:57:3d:
+        0c:04:5e:a6:35:c6:ae:81:59:6c:28:c5:19:4b:8c:da:dd:1e:
+        97:51:bf:8b:f8:21:dc:c9:23:07:7a:66:66:fc:e2:b6:c6:e7:
+        f3:b4:e4:3e:7e:be:72:3e:3a:65:98:f1:6c:4f:79:8a:3c:11:
+        59:3d:9f:28:c8:80:eb:9d:e3:1d:6c:4e:b7:59:4e:48:b9:f8:
+        87:cf:35:13:f8:15:d3:6f:fb:1c:89:6f:ec:2c:24:5c:7b:9f:
+        fa:f0:a9:61:7b:4d:ab:40:84:dc:f8:5a:13:13:7a:b2:f4:09:
+        36:95:76:1d:c8:d8:33:eb:67:c8:c9:a9:de:98:9a:77:33:46:
+        83:37:19:60:d0:38:6f:dd:39:14:d7:a0:74:40:91:1f:60:bc:
+        0b:f8:ca:81:7d:88:67:c7:89:cf:4c:c5:95:65:66:f5:c2:98:
+        29:77:a2:93:b6:37:55:cc:f4:85:01:58:30:30:54:9a:c4:57:
+        35:e4:21:bd
+-----BEGIN CERTIFICATE REQUEST-----
+MIIC2zCCAcMCAQAwgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UE
+BxMJUGFsbyBBbHRvMRUwEwYDVQQKEwxPcGVuIHZTd2l0Y2gxHzAdBgNVBAsTFk9w
+ZW4gdlN3aXRjaCBjZXJ0aWZpZXIxLTArBgNVBAMTJE9wZW4gdlN3aXRjaCBjZXJ0
+aWZpY2F0ZSBmb3IgdGVzdHBraTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAKw/xrHvo+NomCyRoTohAjiHW3V6HBfJsGSp94AXCA+1JbRGgGt+kqv4kwUX
+d+QShutUXaegRXAWXtdPa3yf/oOkwWKDM3FvT05ohKaSpXePrc3uv2FyJMBk33OY
+3jdruE149LoGlWTvgrEvcQFEyjze+jIotupye03WoPtLc96pfyWtIAI9X39/jpE0
+lwoQlr497jdbqZGef9Wse+NWR6QUFd1IzjJvxIMJBzG7NHdN9xJwhriyZBY76tJy
+4HNrb85Zz1ZtqJQ8ENdHfrKRncdlI4qxypwVNsXZ27HnuB8JIB3al96TfOJdlOo4
+2M5gyZ5D2m2dydKg6W1am1dThn0CAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4IBAQAh
+Rkx6qdpYz+7TCoHuzb9zzwWTK+/1x31elqWC0mI0Jo8e9ttvDgU5pTzfu1ECL7xb
+qKClXs7kVSFzkh2/U6T13H4O+LEFVz0MBF6mNcaugVlsKMUZS4za3R6XUb+L+CHc
+ySMHemZm/OK2xufztOQ+fr5yPjplmPFsT3mKPBFZPZ8oyIDrneMdbE63WU5IufiH
+zzUT+BXTb/sciW/sLCRce5/68Klhe02rQITc+FoTE3qy9Ak2lXYdyNgz62fIyane
+mJp3M0aDNxlg0Dhv3TkU16B0QJEfYLwL+MqBfYhnx4nPTMWVZWb1wpgpd6KTtjdV
+zPSFAVgwMFSaxFc15CG9
+-----END CERTIFICATE REQUEST-----