From 5146779c44ea588090e5a6a600251b5da7f396c4 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 26 May 2014 15:48:07 +0100 Subject: [PATCH] Add client test for encrypted x509 keys. --- test/lib/08-ssl-connect-cert-auth-enc.py | 73 +++++++++++++++++++ test/lib/Makefile | 1 + test/lib/c/08-ssl-connect-cert-auth-enc.c | 53 ++++++++++++++ test/lib/c/Makefile | 5 +- test/lib/cpp/08-ssl-connect-cert-auth-enc.cpp | 62 ++++++++++++++++ test/lib/cpp/Makefile | 5 +- test/ssl/client-encrypted.crt | 59 +++++++++++++++ test/ssl/client-encrypted.key | 18 +++++ test/ssl/gen.sh | 5 ++ test/ssl/signingCA/index.txt | 1 + test/ssl/signingCA/serial | 2 +- 11 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 test/lib/08-ssl-connect-cert-auth-enc.py create mode 100644 test/lib/c/08-ssl-connect-cert-auth-enc.c create mode 100644 test/lib/cpp/08-ssl-connect-cert-auth-enc.cpp create mode 100644 test/ssl/client-encrypted.crt create mode 100644 test/ssl/client-encrypted.key diff --git a/test/lib/08-ssl-connect-cert-auth-enc.py b/test/lib/08-ssl-connect-cert-auth-enc.py new file mode 100644 index 00000000..0c7f20a5 --- /dev/null +++ b/test/lib/08-ssl-connect-cert-auth-enc.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +# Test whether a client produces a correct connect and subsequent disconnect when using SSL. +# Client must provide a certificate. + +# The client should connect to port 1888 with keepalive=60, clean session set, +# and client id 08-ssl-connect-crt-auth +# It should use the CA certificate ssl/test-root-ca.crt for verifying the server. +# The test will send a CONNACK message to the client with rc=0. Upon receiving +# the CONNACK and verifying that rc=0, the client should send a DISCONNECT +# message. If rc!=0, the client should exit with an error. + +import inspect +import os +import subprocess +import socket +import ssl +import sys +import time + +# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder +cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) +if cmd_subfolder not in sys.path: + sys.path.insert(0, cmd_subfolder) + +import mosq_test + +if sys.version < '2.7': + print("WARNING: SSL not supported on Python 2.6") + exit(0) + +rc = 1 +keepalive = 60 +connect_packet = mosq_test.gen_connect("08-ssl-connect-crt-auth-enc", keepalive=keepalive) +connack_packet = mosq_test.gen_connack(rc=0) +disconnect_packet = mosq_test.gen_disconnect() + +sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +ssock = ssl.wrap_socket(sock, ca_certs="../ssl/all-ca.crt", + keyfile="../ssl/server.key", certfile="../ssl/server.crt", + server_side=True, ssl_version=ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_REQUIRED) +ssock.settimeout(10) +ssock.bind(('', 1888)) +ssock.listen(5) + +client_args = sys.argv[1:] +env = dict(os.environ) +env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' +try: + pp = env['PYTHONPATH'] +except KeyError: + pp = '' +env['PYTHONPATH'] = '../../lib/python:'+pp +client = subprocess.Popen(client_args, env=env) + +try: + (conn, address) = ssock.accept() + conn.settimeout(10) + + if mosq_test.expect_packet(conn, "connect", connect_packet): + conn.send(connack_packet) + + if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): + rc = 0 + + conn.close() +finally: + client.terminate() + client.wait() + ssock.close() + +exit(rc) diff --git a/test/lib/Makefile b/test/lib/Makefile index 187901bf..aab2c657 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -38,6 +38,7 @@ c cpp : test-compile ./04-retain-qos0.py $@/04-retain-qos0.test ./08-ssl-connect-no-auth.py $@/08-ssl-connect-no-auth.test ./08-ssl-connect-cert-auth.py $@/08-ssl-connect-cert-auth.test + ./08-ssl-connect-cert-auth-enc.py $@/08-ssl-connect-cert-auth-enc.test ./08-ssl-bad-cacert.py $@/08-ssl-bad-cacert.test ./08-ssl-fake-cacert.py $@/08-ssl-fake-cacert.test ./09-util-topic-matching.py $@/09-util-topic-matching.test diff --git a/test/lib/c/08-ssl-connect-cert-auth-enc.c b/test/lib/c/08-ssl-connect-cert-auth-enc.c new file mode 100644 index 00000000..12b26381 --- /dev/null +++ b/test/lib/c/08-ssl-connect-cert-auth-enc.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + mosquitto_disconnect(mosq); + } +} + +void on_disconnect(struct mosquitto *mosq, void *obj, int rc) +{ + run = rc; +} + +static int password_callback(char* buf, int size, int rwflag, void* userdata) +{ + strncpy(buf, "password", size); + buf[size-1] = '\0'; + + return strlen(buf); +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + + mosquitto_lib_init(); + + mosq = mosquitto_new("08-ssl-connect-crt-auth-enc", true, NULL); + mosquitto_tls_opts_set(mosq, 1, "tlsv1", NULL); + mosquitto_tls_set(mosq, "../ssl/test-root-ca.crt", "../ssl/certs", "../ssl/client-encrypted.crt", "../ssl/client-encrypted.key", password_callback); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_disconnect_callback_set(mosq, on_disconnect); + + rc = mosquitto_connect(mosq, "localhost", 1888, 60); + + while(run == -1){ + mosquitto_loop(mosq, -1, 1); + } + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 17262d0b..570b7ad3 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -71,6 +71,9 @@ all : 01 02 03 04 08 09 08-ssl-connect-cert-auth.test : 08-ssl-connect-cert-auth.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) +08-ssl-connect-cert-auth-enc.test : 08-ssl-connect-cert-auth-enc.c + $(CC) $< -o $@ $(CFLAGS) $(LIBS) + 08-ssl-bad-cacert.test : 08-ssl-bad-cacert.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) @@ -91,7 +94,7 @@ all : 01 02 03 04 08 09 04 : 04-retain-qos0.test -08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test +08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-connect-cert-auth-enc.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test 09 : 09-util-topic-matching.test 09-util-topic-tokenise.test diff --git a/test/lib/cpp/08-ssl-connect-cert-auth-enc.cpp b/test/lib/cpp/08-ssl-connect-cert-auth-enc.cpp new file mode 100644 index 00000000..ed2edbad --- /dev/null +++ b/test/lib/cpp/08-ssl-connect-cert-auth-enc.cpp @@ -0,0 +1,62 @@ +#include +#include + +static int run = -1; + +static int password_callback(char* buf, int size, int rwflag, void* userdata) +{ + strncpy(buf, "password", size); + buf[size-1] = '\0'; + + return strlen(buf); +} + +class mosquittopp_test : public mosqpp::mosquittopp +{ + public: + mosquittopp_test(const char *id); + + void on_connect(int rc); + void on_disconnect(int rc); +}; + +mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) +{ +} + +void mosquittopp_test::on_connect(int rc) +{ + if(rc){ + exit(1); + }else{ + disconnect(); + } +} + +void mosquittopp_test::on_disconnect(int rc) +{ + run = rc; +} + + +int main(int argc, char *argv[]) +{ + struct mosquittopp_test *mosq; + + mosqpp::lib_init(); + + mosq = new mosquittopp_test("08-ssl-connect-crt-auth-enc"); + + mosq->tls_opts_set(1, "tlsv1", NULL); + //mosq->tls_set("../ssl/test-ca.crt", NULL, "../ssl/client.crt", "../ssl/client.key"); + mosq->tls_set("../ssl/all-ca.crt", NULL, "../ssl/client-encrypted.crt", "../ssl/client-encrypted.key", password_callback); + mosq->connect("localhost", 1888, 60); + + while(run == -1){ + mosq->loop(); + } + + mosqpp::lib_cleanup(); + + return run; +} diff --git a/test/lib/cpp/Makefile b/test/lib/cpp/Makefile index 5f26990b..91583f6c 100644 --- a/test/lib/cpp/Makefile +++ b/test/lib/cpp/Makefile @@ -71,6 +71,9 @@ all : 01 02 03 04 08 09 08-ssl-connect-cert-auth.test : 08-ssl-connect-cert-auth.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) +08-ssl-connect-cert-auth-enc.test : 08-ssl-connect-cert-auth-enc.cpp + $(CXX) $< -o $@ $(CFLAGS) $(LIBS) + 08-ssl-bad-cacert.test : 08-ssl-bad-cacert.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) @@ -91,7 +94,7 @@ all : 01 02 03 04 08 09 04 : 04-retain-qos0.test -08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test +08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-connect-cert-auth-enc.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test 09 : 09-util-topic-matching.test 09-util-topic-tokenise.test diff --git a/test/ssl/client-encrypted.crt b/test/ssl/client-encrypted.crt new file mode 100644 index 00000000..8e79a7b3 --- /dev/null +++ b/test/ssl/client-encrypted.crt @@ -0,0 +1,59 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 5 (0x5) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=GB, ST=Derbyshire, O=Mosquitto Project, OU=Testing, CN=Signing CA + Validity + Not Before: May 26 12:50:49 2014 GMT + Not After : May 25 12:50:49 2019 GMT + Subject: CN=test client encrypted + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:b5:a1:d6:a3:c8:4d:a1:e8:6a:4e:cc:ae:c0:42: + 2b:4a:37:38:8e:60:2f:0d:b0:c7:30:b9:d7:f2:01: + 2a:ce:5c:1e:c1:5e:e5:d8:a3:99:03:55:9f:62:ee: + 9a:2f:5a:04:26:5a:88:79:86:cf:0c:fb:d1:7e:4e: + 41:91:0f:07:27:14:bc:0e:bd:e1:4a:b8:9d:68:52: + 42:91:d7:70:f1:94:64:3c:ad:35:5e:00:41:7d:65: + cb:a5:6d:7f:c0:92:e8:bd:8f:06:20:c3:1e:ca:dd: + a6:80:1a:53:78:3f:5a:27:6d:62:63:7a:2b:3d:15: + 24:3e:1e:ee:6d:ad:ef:32:3d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 9D:E6:CA:2F:54:0A:F5:E4:D0:A1:44:C7:EE:D4:78:FB:75:23:C2:BF + X509v3 Authority Key Identifier: + keyid:40:43:50:14:D1:63:7E:0B:7C:97:14:20:63:E5:8A:95:96:9F:D4:AB + + Signature Algorithm: sha256WithRSAEncryption + 1e:6e:24:24:4f:ae:5d:8a:82:8f:ea:77:76:2d:2a:96:b8:f0: + b0:f1:16:b7:fc:35:ff:96:98:c6:08:aa:8f:93:2f:6a:5f:09: + e7:f2:9b:30:53:01:e1:04:8e:55:4e:fe:8e:2f:d8:14:80:35: + d0:29:03:6d:b4:bd:05:c9:fb:71:c5:7f:25:3c:4d:67:d4:7b: + 33:f5:a3:ec:cd:2e:dd:4b:a9:60:80:d2:e3:74:37:ee:b7:4c: + 22:eb:b2:e2:47:d0:42:9c:e6:74:7d:8a:d4:a9:22:5c:08:20: + 2b:97:68:3f:de:3d:6a:37:57:9e:2c:af:84:b3:74:e9:0d:36: + 40:e1 +-----BEGIN CERTIFICATE----- +MIICdjCCAd+gAwIBAgIBBTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJHQjET +MBEGA1UECAwKRGVyYnlzaGlyZTEaMBgGA1UECgwRTW9zcXVpdHRvIFByb2plY3Qx +EDAOBgNVBAsMB1Rlc3RpbmcxEzARBgNVBAMMClNpZ25pbmcgQ0EwHhcNMTQwNTI2 +MTI1MDQ5WhcNMTkwNTI1MTI1MDQ5WjAgMR4wHAYDVQQDDBV0ZXN0IGNsaWVudCBl +bmNyeXB0ZWQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALWh1qPITaHoak7M +rsBCK0o3OI5gLw2wxzC51/IBKs5cHsFe5dijmQNVn2Lumi9aBCZaiHmGzwz70X5O +QZEPBycUvA694Uq4nWhSQpHXcPGUZDytNV4AQX1ly6Vtf8CS6L2PBiDDHsrdpoAa +U3g/WidtYmN6Kz0VJD4e7m2t7zI9AgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZI +AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW +BBSd5sovVAr15NChRMfu1Hj7dSPCvzAfBgNVHSMEGDAWgBRAQ1AU0WN+C3yXFCBj +5YqVlp/UqzANBgkqhkiG9w0BAQsFAAOBgQAebiQkT65dioKP6nd2LSqWuPCw8Ra3 +/DX/lpjGCKqPky9qXwnn8pswUwHhBI5VTv6OL9gUgDXQKQNttL0FyftxxX8lPE1n +1Hsz9aPszS7dS6lggNLjdDfut0wi67LiR9BCnOZ0fYrUqSJcCCArl2g/3j1qN1ee +LK+Es3TpDTZA4Q== +-----END CERTIFICATE----- diff --git a/test/ssl/client-encrypted.key b/test/ssl/client-encrypted.key new file mode 100644 index 00000000..0947ae19 --- /dev/null +++ b/test/ssl/client-encrypted.key @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,A17B16521713FB61 + +B/x474t6DV07g7r7Le3Ekh/ggZ7ZM8EdwdzqiXom4ZR8eSCk4gIDpQrfn7bqzVY2 +25CG1qc4xadk4gFV8GKQeXn3/bVdqfOsTnawq6X9RylwA1HV1st2fVows2DSqskg +tHS+tAYW1ZEu1qGEM5g1zmAuE4odtMD7jzZR2JMEHHFi5O1XY31EHY25jifDjIml +370zKyPV5VxjrvJRFJq+aY7gn+jnEeVUnF6RtG11RPb101a+vyax4C5z9xO+JfNQ +JkEDdFTEejHWabz43gSju8lwgrrzlhR5Yo/AbItk5XduG9VkJX27Jezr87Cn7IqX +Xqja+DCUSFGX++nUCDWLs46Pw9VCp6kZsZt/yUa2cA/JGnmZv06aEf1tn6WsGY5/ +Fnq7K5RJTwbkpPdUckXK6OQZdRwb4uRqbj7F2OaWLYwr/jfj2innk+TQXmcxs4xz +d6greZqyKmx0LcXlI3mpcY3CqKXFazl1pVqiIDdYNMWrNucvMnWX1D5YlCCoyICl +xMtOjk3I2nVba1bdOPtHSXb+BiGkf2Y67ffNCtg2Z7YMCF2yVLVXFuuf4hoRwbOU +fTwdPcdNZeAMF86stw71hMVq0SDagPV4kTO2IuzbJAWts8sUI0xpZnqZ5AxbQF0v +uuE5Q259K+dneI7NaLpSidWW6+wslMABwuKEhGRlO6vZcpN7bqtGbRKKvHoj2ii3 +ebVhk44meh74aWYDoVbtY5HeKFqMSOo6gz6vyZ4udXKM9YpMX4xPx66BBI+8SGez +vouO1xEE1mTtxcQcSHdDFSE8aKdOX1sVwaq/S++dXBFklbwZzj0bAw== +-----END RSA PRIVATE KEY----- diff --git a/test/ssl/gen.sh b/test/ssl/gen.sh index 047a1418..0d6ec458 100755 --- a/test/ssl/gen.sh +++ b/test/ssl/gen.sh @@ -63,6 +63,11 @@ openssl ca -config openssl.cnf -name CA_signing -out client-revoked.crt -infiles openssl ca -config openssl.cnf -name CA_signing -revoke client-revoked.crt openssl ca -config openssl.cnf -name CA_signing -gencrl -out crl.pem +# Valid client key and certificate, encrypted (use "password" as password) +openssl genrsa -des3 -out client-encrypted.key 1024 +openssl req -new -key client-encrypted.key -out client-encrypted.csr -config openssl.cnf -subj "${SBASESUBJ}/CN=test client encrypted/" +openssl ca -config openssl.cnf -name CA_signing -out client-encrypted.crt -infiles client-encrypted.csr + cat test-signing-ca.crt test-root-ca.crt > all-ca.crt #mkdir certs #cp test-signing-ca.crt certs/test-signing-ca.pem diff --git a/test/ssl/signingCA/index.txt b/test/ssl/signingCA/index.txt index 7ca764ef..b1224683 100644 --- a/test/ssl/signingCA/index.txt +++ b/test/ssl/signingCA/index.txt @@ -2,3 +2,4 @@ V 180829220329Z 01 unknown /C=GB/ST=Nottinghamshire/L=Nottingham/O=Server/OU=Pr V 180829220331Z 02 unknown /C=GB/ST=Nottinghamshire/L=Nottingham/O=Server/OU=Production/CN=test client V 120821000000Z 03 unknown /C=GB/ST=Nottinghamshire/L=Nottingham/O=Server/OU=Production/CN=test client expired R 180829220334Z 130830220335Z 04 unknown /C=GB/ST=Nottinghamshire/L=Nottingham/O=Server/OU=Production/CN=test client revoked +V 190525125049Z 05 unknown /CN=test client encrypted diff --git a/test/ssl/signingCA/serial b/test/ssl/signingCA/serial index eeee65ec..cd672a53 100644 --- a/test/ssl/signingCA/serial +++ b/test/ssl/signingCA/serial @@ -1 +1 @@ -05 +06