Repository: qpid-proton Updated Branches: refs/heads/master a49e36db8 -> e0feb3f2f
PROTON-1620: set locking function for old versions of openssl Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/434a2e77 Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/434a2e77 Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/434a2e77 Branch: refs/heads/master Commit: 434a2e7731b757ac6a303725122d811aa90ff023 Parents: a49e36d Author: Alan Conway <acon...@redhat.com> Authored: Mon Oct 16 16:53:48 2017 +0100 Committer: Alan Conway <acon...@redhat.com> Committed: Tue Oct 17 11:04:55 2017 +0100 ---------------------------------------------------------------------- examples/c/CMakeLists.txt | 2 +- examples/c/broker.c | 28 +- examples/c/example_test.py | 6 + examples/c/send-ssl.c | 229 ++++++++++++ examples/c/ssl_certs/README.txt | 24 ++ examples/c/ssl_certs/tclient-certificate.p12 | Bin 0 -> 1032 bytes examples/c/ssl_certs/tclient-certificate.pem | 19 + examples/c/ssl_certs/tclient-full.p12 | Bin 0 -> 2476 bytes examples/c/ssl_certs/tclient-private-key.pem | 30 ++ examples/c/ssl_certs/tserver-certificate.p12 | Bin 0 -> 1032 bytes examples/c/ssl_certs/tserver-certificate.pem | 19 + examples/c/ssl_certs/tserver-full.p12 | Bin 0 -> 2476 bytes examples/c/ssl_certs/tserver-private-key.pem | 30 ++ proton-c/src/ssl/openssl.c | 406 +++++++++++++--------- proton-c/src/tests/proactor.c | 1 - 15 files changed, 627 insertions(+), 167 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 4bfff2d..48ae9b2 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -34,7 +34,7 @@ else() set(test_path "${CMAKE_CURRENT_BINARY_DIR}:$ENV{PATH}") endif() -foreach (name broker send receive direct send-abort) +foreach (name broker send receive direct send-abort send-ssl) add_executable(c-${name} ${name}.c) target_link_libraries(c-${name} ${Proton_Proactor_LIBRARIES} ${Proton_Core_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) set_target_properties(c-${name} PROPERTIES http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/broker.c ---------------------------------------------------------------------- diff --git a/examples/c/broker.c b/examples/c/broker.c index d6cb753..541fbff 100644 --- a/examples/c/broker.c +++ b/examples/c/broker.c @@ -23,12 +23,27 @@ #include <proton/listener.h> #include <proton/proactor.h> #include <proton/sasl.h> +#include <proton/ssl.h> #include <proton/transport.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +/* The ssl_certs subdir must be in the current directory for an ssl-enabled broker */ +#define SSL_FILE(NAME) "ssl_certs/" NAME +#define SSL_PW "tserverpw" +/* Windows vs. OpenSSL certificates */ +#if defined(_WIN32) +# define CERTIFICATE(NAME) SSL_FILE(NAME "-certificate.p12") +# define SET_CREDENTIALS(DOMAIN, NAME) \ + pn_ssl_domain_set_credentials(DOMAIN, SSL_FILE(NAME "-full.p12"), "", SSL_PW) +#else +# define CERTIFICATE(NAME) SSL_FILE(NAME "-certificate.pem") +# define SET_CREDENTIALS(DOMAIN, NAME) \ + pn_ssl_domain_set_credentials(DOMAIN, CERTIFICATE(NAME), SSL_FILE(NAME "-private-key.pem"), SSL_PW) +#endif + /* Simple re-sizable vector that acts as a queue */ #define VEC(T) struct { T* data; size_t len, cap; } @@ -199,6 +214,7 @@ typedef struct broker_t { const char *container_id; /* AMQP container-id */ queues_t queues; bool finished; + pn_ssl_domain_t *ssl_domain; } broker_t; void broker_stop(broker_t *b) { @@ -283,10 +299,15 @@ static void handle(broker_t* b, pn_event_t* e) { break; case PN_CONNECTION_BOUND: { - /* Turn off security */ + /* Allow anonymous connections by SASL */ pn_transport_t *t = pn_connection_transport(c); pn_transport_require_auth(t, false); pn_sasl_allowed_mechs(pn_sasl(t), "ANONYMOUS"); + /* Accept SSL connections if possible, but also plain connections. + See the call to pn_ssl_domain_allow_unsecured_client() in main() */ + if (b->ssl_domain) { + pn_ssl_init(pn_ssl(pn_event_transport(e)), b->ssl_domain, NULL); + } break; } case PN_CONNECTION_REMOTE_OPEN: { @@ -427,7 +448,9 @@ int main(int argc, char **argv) { queues_init(&b.queues); b.container_id = argv[0]; b.threads = 4; - + b.ssl_domain = pn_ssl_domain(PN_SSL_MODE_SERVER); + SET_CREDENTIALS(b.ssl_domain, "tserver"); + pn_ssl_domain_allow_unsecured_client(b.ssl_domain); /* Allow SSL and plain connections */ { /* Listen on addr */ char addr[PN_MAX_ADDR]; @@ -449,6 +472,7 @@ int main(int argc, char **argv) { } pn_proactor_free(b.proactor); free(threads); + pn_ssl_domain_free(b.ssl_domain); return 0; } } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/example_test.py ---------------------------------------------------------------------- diff --git a/examples/c/example_test.py b/examples/c/example_test.py index 9cd0b13..31d941f 100644 --- a/examples/c/example_test.py +++ b/examples/c/example_test.py @@ -116,5 +116,11 @@ class CExampleTest(ProcTestCase): self.maxDiff = None self.assertMultiLineEqual(expect, d.wait_exit()) + def test_send_ssl_receive(self): + """Send first then receive""" + with Broker(self) as b: + self.assertEqual(send_expect(), self.runex("send-ssl", b.port)) + self.assertMultiLineEqual(receive_expect(), self.runex("receive", b.port)) + if __name__ == "__main__": unittest.main() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/send-ssl.c ---------------------------------------------------------------------- diff --git a/examples/c/send-ssl.c b/examples/c/send-ssl.c new file mode 100644 index 0000000..8e0722e --- /dev/null +++ b/examples/c/send-ssl.c @@ -0,0 +1,229 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <proton/connection.h> +#include <proton/condition.h> +#include <proton/delivery.h> +#include <proton/link.h> +#include <proton/message.h> +#include <proton/proactor.h> +#include <proton/session.h> +#include <proton/ssl.h> +#include <proton/transport.h> + +#include <stdio.h> +#include <stdlib.h> + +typedef struct app_data_t { + const char *host, *port; + const char *amqp_address; + const char *container_id; + int message_count; + + pn_proactor_t *proactor; + pn_rwbytes_t message_buffer; + int sent; + int acknowledged; + pn_ssl_domain_t *ssl_domain; +} app_data_t; + +static int exit_code = 0; + +/* Note must be run in the current directory to find certificate files */ +#define SSL_FILE(NAME) CMAKE_CURRENT_SOURCE_DIR "/ssl_certs/" NAME +#define SSL_PW "tclientpw" +/* Windows vs. OpenSSL certificates */ +#if defined(_WIN32) +# define CERTIFICATE(NAME) SSL_FILE(NAME "-certificate.p12") +# define SET_CREDENTIALS(DOMAIN, NAME) \ + pn_ssl_domain_set_credentials(DOMAIN, SSL_FILE(NAME "-full.p12"), "", SSL_PW) +#else +# define CERTIFICATE(NAME) SSL_FILE(NAME "-certificate.pem") +# define SET_CREDENTIALS(DOMAIN, NAME) \ + pn_ssl_domain_set_credentials(DOMAIN, CERTIFICATE(NAME), SSL_FILE(NAME "-private-key.pem"), SSL_PW) +#endif + + +static void check_condition(pn_event_t *e, pn_condition_t *cond) { + if (pn_condition_is_set(cond)) { + fprintf(stderr, "%s: %s: %s\n", pn_event_type_name(pn_event_type(e)), + pn_condition_get_name(cond), pn_condition_get_description(cond)); + pn_connection_close(pn_event_connection(e)); + exit_code = 1; + } +} + +/* Create a message with a map { "sequence" : number } encode it and return the encoded buffer. */ +static pn_bytes_t encode_message(app_data_t* app) { + /* Construct a message with the map { "sequence": app.sent } */ + pn_message_t* message = pn_message(); + pn_data_t* body = pn_message_body(message); + pn_data_put_int(pn_message_id(message), app->sent); /* Set the message_id also */ + pn_data_put_map(body); + pn_data_enter(body); + pn_data_put_string(body, pn_bytes(sizeof("sequence")-1, "sequence")); + pn_data_put_int(body, app->sent); /* The sequence number */ + pn_data_exit(body); + + /* encode the message, expanding the encode buffer as needed */ + if (app->message_buffer.start == NULL) { + static const size_t initial_size = 128; + app->message_buffer = pn_rwbytes(initial_size, (char*)malloc(initial_size)); + } + /* app->message_buffer is the total buffer space available. */ + /* mbuf wil point at just the portion used by the encoded message */ + { + pn_rwbytes_t mbuf = pn_rwbytes(app->message_buffer.size, app->message_buffer.start); + int status = 0; + while ((status = pn_message_encode(message, mbuf.start, &mbuf.size)) == PN_OVERFLOW) { + app->message_buffer.size *= 2; + app->message_buffer.start = (char*)realloc(app->message_buffer.start, app->message_buffer.size); + mbuf.size = app->message_buffer.size; + mbuf.start = app->message_buffer.start; + } + if (status != 0) { + fprintf(stderr, "error encoding message: %s\n", pn_error_text(pn_message_error(message))); + exit(1); + } + pn_message_free(message); + return pn_bytes(mbuf.size, mbuf.start); + } +} + +/* Returns true to continue, false if finished */ +static bool handle(app_data_t* app, pn_event_t* event) { + switch (pn_event_type(event)) { + + case PN_CONNECTION_INIT: { + pn_connection_t* c = pn_event_connection(event); + pn_session_t* s = pn_session(pn_event_connection(event)); + pn_connection_set_container(c, app->container_id); + pn_connection_open(c); + pn_session_open(s); + { + pn_link_t* l = pn_sender(s, "my_sender"); + pn_terminus_set_address(pn_link_target(l), app->amqp_address); + pn_link_open(l); + break; + } + } + + case PN_CONNECTION_BOUND: { + int err = pn_ssl_init(pn_ssl(pn_event_transport(event)), app->ssl_domain, NULL); + if (err) fprintf(stderr, "error encoding message: %s\n", pn_code(err)); + } + + case PN_LINK_FLOW: { + /* The peer has given us some credit, now we can send messages */ + pn_link_t *sender = pn_event_link(event); + while (pn_link_credit(sender) > 0 && app->sent < app->message_count) { + ++app->sent; + /* Use sent counter as unique delivery tag. */ + pn_delivery(sender, pn_dtag((const char *)&app->sent, sizeof(app->sent))); + { + pn_bytes_t msgbuf = encode_message(app); + pn_link_send(sender, msgbuf.start, msgbuf.size); + } + pn_link_advance(sender); + } + break; + } + + case PN_DELIVERY: { + /* We received acknowledgedment from the peer that a message was delivered. */ + pn_delivery_t* d = pn_event_delivery(event); + if (pn_delivery_remote_state(d) == PN_ACCEPTED) { + if (++app->acknowledged == app->message_count) { + printf("%d messages sent and acknowledged\n", app->acknowledged); + pn_connection_close(pn_event_connection(event)); + /* Continue handling events till we receive TRANSPORT_CLOSED */ + } + } else { + fprintf(stderr, "unexpected delivery state %d\n", (int)pn_delivery_remote_state(d)); + pn_connection_close(pn_event_connection(event)); + exit_code=1; + } + break; + } + + case PN_TRANSPORT_CLOSED: + check_condition(event, pn_transport_condition(pn_event_transport(event))); + break; + + case PN_CONNECTION_REMOTE_CLOSE: + check_condition(event, pn_connection_remote_condition(pn_event_connection(event))); + pn_connection_close(pn_event_connection(event)); + break; + + case PN_SESSION_REMOTE_CLOSE: + check_condition(event, pn_session_remote_condition(pn_event_session(event))); + pn_connection_close(pn_event_connection(event)); + break; + + case PN_LINK_REMOTE_CLOSE: + case PN_LINK_REMOTE_DETACH: + check_condition(event, pn_link_remote_condition(pn_event_link(event))); + pn_connection_close(pn_event_connection(event)); + break; + + case PN_PROACTOR_INACTIVE: + return false; + + default: break; + } + return true; +} + +void run(app_data_t *app) { + /* Loop and handle events */ + do { + pn_event_batch_t *events = pn_proactor_wait(app->proactor); + pn_event_t *e; + for (e = pn_event_batch_next(events); e; e = pn_event_batch_next(events)) { + if (!handle(app, e)) { + return; + } + } + pn_proactor_done(app->proactor, events); + } while(true); +} + +int main(int argc, char **argv) { + struct app_data_t app = {0}; + char addr[PN_MAX_ADDR]; + + app.container_id = argv[0]; /* Should be unique */ + app.host = (argc > 1) ? argv[1] : ""; + app.port = (argc > 2) ? argv[2] : "amqp"; + app.amqp_address = (argc > 3) ? argv[3] : "examples"; + app.message_count = (argc > 4) ? atoi(argv[4]) : 10; + app.ssl_domain = pn_ssl_domain(PN_SSL_MODE_CLIENT); + + app.proactor = pn_proactor(); + pn_proactor_addr(addr, sizeof(addr), app.host, app.port); + pn_proactor_connect(app.proactor, pn_connection(), addr); + run(&app); + + pn_ssl_domain_free(app.ssl_domain); + pn_proactor_free(app.proactor); + free(app.message_buffer.start); + return exit_code; +} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/ssl_certs/README.txt ---------------------------------------------------------------------- diff --git a/examples/c/ssl_certs/README.txt b/examples/c/ssl_certs/README.txt new file mode 100644 index 0000000..9a8a4f9 --- /dev/null +++ b/examples/c/ssl_certs/README.txt @@ -0,0 +1,24 @@ +This directory contains basic self signed test certificates for use by +proton examples. + +The ".pem" files are in the format expected by proton implementations +using OpenSSL. The ".p12" file are for Windows implementations using +SChannel. + +The commands used to generate the certificates follow. + + +make_pn_cert() +{ + name=$1 + subject=$2 + passwd=$3 + # create the pem files + openssl req -newkey rsa:2048 -keyout $name-private-key.pem -out $name-certificate.pem -subj $subject -passout pass:$passwd -x509 -days 3650 + # create the p12 files + openssl pkcs12 -export -out $name-full.p12 -passin pass:$passwd -passout pass:$passwd -inkey $name-private-key.pem -in $name-certificate.pem -name $name + openssl pkcs12 -export -out $name-certificate.p12 -in $name-certificate.pem -name $name -nokeys -passout pass: +} + +make_pn_cert tserver /CN=test_server/OU=proton_test tserverpw +make_pn_cert tclient /CN=test_client/OU=proton_test tclientpw http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/ssl_certs/tclient-certificate.p12 ---------------------------------------------------------------------- diff --git a/examples/c/ssl_certs/tclient-certificate.p12 b/examples/c/ssl_certs/tclient-certificate.p12 new file mode 100644 index 0000000..4d0e000 Binary files /dev/null and b/examples/c/ssl_certs/tclient-certificate.p12 differ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/ssl_certs/tclient-certificate.pem ---------------------------------------------------------------------- diff --git a/examples/c/ssl_certs/tclient-certificate.pem b/examples/c/ssl_certs/tclient-certificate.pem new file mode 100644 index 0000000..8088e2e --- /dev/null +++ b/examples/c/ssl_certs/tclient-certificate.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDKzCCAhOgAwIBAgIJAIV7frIjftgcMA0GCSqGSIb3DQEBCwUAMCwxFDASBgNV +BAMMC3Rlc3RfY2xpZW50MRQwEgYDVQQLDAtwcm90b25fdGVzdDAeFw0xNTExMjcx +ODEwMzlaFw0yNTExMjQxODEwMzlaMCwxFDASBgNVBAMMC3Rlc3RfY2xpZW50MRQw +EgYDVQQLDAtwcm90b25fdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAPCIS4qUdOtQplUxZ6WW0LXcvosqFP6qOiCARLSEWpR3B8bq213rzefwwfcM +4TtMr88bP+huLKmlyMfwpl8yB88eXkscPgaAce2zk24urWkFXKSQ6GPitWBLGqBa +V+W0wJ4mfW7MwefVslWfGXI381QEUlBHjkFG30AtzMMTRj2GK2JqUlRXZPljGyB7 +WcXwxcoS+HkKV7FtHWSkLAzyXwQ9vsCUEYdWTUaGXfCUNRSRV7h1LIANbu03NxV0 +XdEl7WXcr7tuTw3axeUGhRFVhLegrxKLuZTTno4aAJnEr8uaDzjxvXnv3Ne2igvy +gRfZgOMx+XrZEob9OpAoRghQt4cCAwEAAaNQME4wHQYDVR0OBBYEFE4vbyiM0RjG +TLMLLGGhMZE/5x1GMB8GA1UdIwQYMBaAFE4vbyiM0RjGTLMLLGGhMZE/5x1GMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAErr/rvLS9Ig0UCMwh1J1lA9 +/gvXf93iIK/SjrFIAqYRmfZxg4husfoes8t2hFUeuqoH05TuSOoXG8p8DpgTSGmF +jAFe+T90vJZTm0oqZkkkI/hdzjGQoHURRp9/O2Z/lm39KSKGVAN5pUWCUDi/G5iS +P9LZPJN6a5syXMrR6x62IPxAXowlpXkRghKClF3zPOaOBTzT1V27EkI8IEgC+p45 +246EooLnw8ibB+ucNc3KHNzpgKGVd/622+I+Q5eg9AT9PLFttP+R2ECsrVDDPYuA +p0qaSnwgeozj/d6K3FOgKKEKbzBmpWgkv0jdcVk18aPMHypI/RDtZ/+3ET2Ksi8= +-----END CERTIFICATE----- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/ssl_certs/tclient-full.p12 ---------------------------------------------------------------------- diff --git a/examples/c/ssl_certs/tclient-full.p12 b/examples/c/ssl_certs/tclient-full.p12 new file mode 100644 index 0000000..ad2d7d3 Binary files /dev/null and b/examples/c/ssl_certs/tclient-full.p12 differ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/ssl_certs/tclient-private-key.pem ---------------------------------------------------------------------- diff --git a/examples/c/ssl_certs/tclient-private-key.pem b/examples/c/ssl_certs/tclient-private-key.pem new file mode 100644 index 0000000..e5c114d --- /dev/null +++ b/examples/c/ssl_certs/tclient-private-key.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQICy6ghWp45z4CAggA +MBQGCCqGSIb3DQMHBAiVdDoo4NIghQSCBMixGm1bm/omMxsaKnIPO7zm5dyLexJ+ +yTFpmh2KV7kQqmpzCyIOdoG6K8YqFnie2XdFWm3S8faRHoMq54bDmyEWIxfQPq5f +I1iYFbIZkbnhUvK53RActsEUMf0locS4xylU7VQK3XTAwp0TVip3Lp3ehEMEdcXL +iUWibGsoTPKcY9MIWGXZAJXsEXoeHt6k2hHo1G4E0/Bi6mLW1LY/cxZCjHTGD6qI +Kt54SCCDvinqVa+rixw6yX9F14EA6bhALami8e+Ccd3lqHOyYlXcBaSS1ezCg6ig +oNK97mC+gEGy1KlkZDKWXclFoOCBXRBe4DByre6Rlq3yeI9L42bvAuSBSmf5QT5g +73Yl8vjEAKR65awBT09dPuKu7t+Fb6vkwF8/t+uyj9IuL+42UuXhMLK3ohf+6DbU +8/zB4y3GXI80QmWM0+Wx4n6khFhPFLHt2q0Sn6V9PG1vtHyiq50oSCoyrPQLaecp +hefnMCFBYTcT3JUwmoVGGy0boIAwL7T4aGsMt7QhwOx5tU35tKFxyY7m4fX14AKo +2EIy+TPQwCGkGf3Puy/Pc9VA8IAxB5+WwSrjk+NeCv88eIX7gy43k4rCr+OmD9FF +wknr3xoP3KYhNXjdZ4Ep/1UHSK+JAtzzbNLQjDcqN+gQPg/yUX6ih0j5K3Wvh9bK +E/DvzbpJroUZPgzR+8z5O68CfsD+OIdpHBFTKqAFmzvUuqpADpr998LdCjD+lW+V +xZZgZa8KEblwgiH3fdGbYl46Ho1zrZisf439DbqyybAuBIQB4NSZcL/MAgVGO17k +QDpVElWZWYrFm4CFTcvS2HvIzRmbefF5m5oJedsN7Q6WQCp+3gnwYx1xIOknd7pW +N4AHNnqjscSj9yACj/EiBVKAKNnC5H7ZGZTsaAjMETZyjLXfI2AZ3Fviz4zFR+oz +NkAfFB6WUpRpl7H02FzrzYT7XkkLcXd6H6g+mv2iDa9uKWk/PS2QlqnJt8/dHEHD +JKTG331yDK5GHlKAVGF3nP5BwFGgTQMuSoeiOervMXPUwDpQ8OaYkuaRej0cZLgT +kAF9sUjqdsoYNcXDFHALp6y5g8qYkfrxrlIbKs82zIsmB5I+dtZbUaD3a0zAUrmW +5Xm3Pc9dVP0EXKwfHz6zqPReEw2yYLisB5IoHd4M2wa3GzHBdra1ij4QTmvd3o7e +buGFoX8KJQAcig0zpbYkoDP2gPhIh9rY4unVPQNX1Q8/wRsiJAZZsYvZY+A+SmuZ +bwSwk+8ZJRsFzdYYYhQeRytD5cDAIQiClcI5Yj4T9dWQV/gf0N/wIBDNTMp0jJAy +1l7PuXTfGZodNJWZH0oqsrNoWbn/k67NildvvofIKX+h09Nxszr670Pvj0qoHd5/ +CWq30lnxoJBUgbikFOz6ZuuHi/ZiCXL+haH+v8hJKN5ptRKnyYJQHchRB/IOGRoT +5lmWxo8a7K+yXhp0VBDHJfw3685ms0xQX8Xj4X3MEuN64zd0fB1JmhtP12ydK85J +ABawNKlRQPw5weckwtCviXQX+vX25S/xu3xA6IuqlHyqL/1t3DICzuxeOyT2mZxD +tKQxEgNihPvu32vn9m74qA3adEaxuWPRkPZuTeITHOkMTZolvqYX/5olBsSgYwka +7/g= +-----END ENCRYPTED PRIVATE KEY----- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/ssl_certs/tserver-certificate.p12 ---------------------------------------------------------------------- diff --git a/examples/c/ssl_certs/tserver-certificate.p12 b/examples/c/ssl_certs/tserver-certificate.p12 new file mode 100644 index 0000000..f38b67d Binary files /dev/null and b/examples/c/ssl_certs/tserver-certificate.p12 differ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/ssl_certs/tserver-certificate.pem ---------------------------------------------------------------------- diff --git a/examples/c/ssl_certs/tserver-certificate.pem b/examples/c/ssl_certs/tserver-certificate.pem new file mode 100644 index 0000000..86231f3 --- /dev/null +++ b/examples/c/ssl_certs/tserver-certificate.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDKzCCAhOgAwIBAgIJAPnYOOQCJ3kDMA0GCSqGSIb3DQEBCwUAMCwxFDASBgNV +BAMMC3Rlc3Rfc2VydmVyMRQwEgYDVQQLDAtwcm90b25fdGVzdDAeFw0xNTExMjcx +ODEwMzlaFw0yNTExMjQxODEwMzlaMCwxFDASBgNVBAMMC3Rlc3Rfc2VydmVyMRQw +EgYDVQQLDAtwcm90b25fdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAKJNB78lgw4KtXDAvXocTLud6mbn6zgfB6ETIF+kcrukOH9DnPxjLBBM4Lig +sp1+kmeudFK5/X8riDrvIW52b/rlEBLgLB+oDtI74m6OTbBs9L+FUFYOuxApetQF +qoJy2vf9pWfy4uku24vCpeo7eVLi6ypu4lXE3LR+Km3FruHI1NKonHBMhwXSOWqF +pYM6/4IZJ4fbV0+eU0Jrx+05s6XHg5vone2BVJKxeSIBje+zWnNnh8+qG0Z70Jgp +aMetME5KGnLNgD1okpH0vb3lwjvuqkkx4WswGVZGbLLkSqqBpXPyM9fCFVy5aKSL +DBq7IABQtO67O2nBzK3OyigHrUUCAwEAAaNQME4wHQYDVR0OBBYEFGV1PY0FCFbJ +gpcDVKI6JGiRTt3kMB8GA1UdIwQYMBaAFGV1PY0FCFbJgpcDVKI6JGiRTt3kMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAIx1TOTGWnnbpan4bse7wuvH +GYSNDJhoTVS+X1TC63xukJD1JBAsCNTqg/ZV6lN3XEl7vvOXfGoCiyXM6a9XOKUo +gSDtMrIr+wTh6Ss1yRO8QcCJmxH5JDXNu1ojtwsjFW/vneI4IL9kwpDsSlMQEX/E +EkkQwtAx/Cvfe7pecZL4qSeykJOUMTts9H8fCAZqEiRZBA3ugJxqF8jwLP3DoFVQ +6QZzKDY6CSPqfMnVb5i0MAIYVDpau+e3N9dgQpZD22F/zbua0OVbfAPdiRMnYxML +FT4sxLnh+5YVqwpVWbEKp4onHe2Fq6YIvAxUYAJ3SBA2C8O2RAVKWxf1jko3jYI= +-----END CERTIFICATE----- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/ssl_certs/tserver-full.p12 ---------------------------------------------------------------------- diff --git a/examples/c/ssl_certs/tserver-full.p12 b/examples/c/ssl_certs/tserver-full.p12 new file mode 100644 index 0000000..d4a0e40 Binary files /dev/null and b/examples/c/ssl_certs/tserver-full.p12 differ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/examples/c/ssl_certs/tserver-private-key.pem ---------------------------------------------------------------------- diff --git a/examples/c/ssl_certs/tserver-private-key.pem b/examples/c/ssl_certs/tserver-private-key.pem new file mode 100644 index 0000000..91dcf0e --- /dev/null +++ b/examples/c/ssl_certs/tserver-private-key.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI1cT0c2J3GcQCAggA +MBQGCCqGSIb3DQMHBAi1hxSX2LJ+EgSCBMheHJ0iXr5A36Natjk/LcAEeKUMT9s+ +sMzoQceCWe8qMlQluWksr9iDdZ4JRIE8cpK8dbmx4dLY/SShUzdlhJHCSa4zZBHq +8cZ/jGUF/RF1rqdgjK589eUq+uOl3/gXKzG/SxBqayy6PSn12kX3qnvmlkXCmtwU +lg+iBm5wRcJ0MyVHaJkyA8sW8gr186C/VAau6Yu0crQXN7NRo9snrd4ewuYMIEhZ +hgaG9XsYQWB1bPhAaKj80CZGxsQbJyTwcbKKkB3IY4WXx8mmhuiNl+vKT3HBJ9Ju +YB6tgIjs8CJ4X2P4aU3yNJwG1QldgHSqmFGQ19bcZAw3s3kzwjdzRf4H2V16XOBd +zQ5AEs/ffVMzMIAfkb1gYwgunZ2CVwwDJ2mi1RcgkX+Og2aFQc+fxXcVOnDcGLxV +6fuCuZ2lsXfoiIyRh9kj3L75N12GtVUvgBdnMuOc1wPw6XnGQtDwt0acJpdexLMG +k0j57r/gcgzTcmF3qNM+y9L/HLssgrJkvVJw2Np5gmtIyfDocsDUWUbClS4dTpYf +oTngUTU+vWtHBuaUnb+f5/WJaRS/S7mmR8usbVG3i9WnEr/vlPJpbJFSjW2S6u/H +7cFxKUmmBZsSuEv/EKt9a+Sh62kprOChm4myqfCI1/gvNKfUZC6m0Vp8zf+2LgAq +2RgbMuqysMjWUtV4kDRZT7oCYckUDwsCHdbLES3nmVrtBk2ShMKHBpDp8/GoRuiV +jdV7/EjKM/M1kXtFYYe3z7Mxv++lKYIJ7bNwVrQ8nrhce/VwHw6D5emWXNCJXhKZ +FW7EM2ZOZ9eaKOlCsIi8sbjV6Yie9IY6HJKKmi3CpO0Tv5kLBdHkru8vGCSFm3O1 +n7wz7Ys5FBSlZ19X0NwQSCQX1Q4w+tido6i1SCRX0qJEdTNGuGwVXMHCf4/1zyHV +hj8vnxh8fzo79LFrwlTTgwLg1Mr8sEUFFDJ/raJ1AhFXi8n24trtNR8EHxRW8wtD +CLCKaqkEqfBiFXK/Yq3RrefCayPHiD+DaNsI8BwefMGpED3vD8YYCjAzXNPh/CSF +sc1i1jWMzbJhzOoFSPNXhlfusbUFMFQ/6olatmH47SY6HBBOL3DDP5uQ0jw8P454 +QBjlMOpEZmZxO6TcEtJwu0vzgog4rQ5g3NWy6SIpjWehNwTynLt7yM3R5WTI6cZs +0GTv/rqo2/SUoNsFmnGIUwj/DrBe4XOAq1nS2ZlEctxKhBsKH0hMFp6D1rXOzrgl +bwcq+oistoB0TLcThShyNgSqzW1znQ1n5SVUk9b5rRhSttJxn3yOMewH0i3v8bPo +HOhP5kaGjblPsCYyhlL/SNVF0OXEGTwLNey7FQdWFOwVwTRRXe7k+uGZ2d5hg+Jn +It/trDZ1RDYbVmB7/Qy73c16J4mvhOUJ2de5ZciFBjkidbiiUKLj9xnjK9k9Sauo +MKhNnDMAEU5VDQM3xNe5BRdX8dFLwfF5H64sU3nROF83aUnDgvfFEowYPnCuPYfm +m4aQHfoBSg4j3v1OeOwktcl+Q2TjxPHfWhbWeRBfxOTqQ/suYhnQChuFSK/qyo9K +ccgotqghhunRsWMoZT25H7AZM6yKb1sMz/0oyMRIKeGqoYh+ULM5XLY0xNYd4/xU +WtQ= +-----END ENCRYPTED PRIVATE KEY----- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/proton-c/src/ssl/openssl.c ---------------------------------------------------------------------- diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c index 3929f88..f8479f0 100644 --- a/proton-c/src/ssl/openssl.c +++ b/proton-c/src/ssl/openssl.c @@ -57,11 +57,10 @@ * This file contains an OpenSSL-based implemention of the SSL/TLS API. */ -static int ssl_initialized; -static int ssl_ex_data_index; - typedef struct pn_ssl_session_t pn_ssl_session_t; +static int ssl_ex_data_index; + struct pn_ssl_domain_t { SSL_CTX *ctx; @@ -119,14 +118,14 @@ struct pni_ssl_t { static inline pn_transport_t *get_transport_internal(pn_ssl_t *ssl) { - // The external pn_sasl_t is really a pointer to the internal pni_transport_t - return ((pn_transport_t *)ssl); + // The external pn_sasl_t is really a pointer to the internal pni_transport_t + return ((pn_transport_t *)ssl); } static inline pni_ssl_t *get_ssl_internal(pn_ssl_t *ssl) { - // The external pn_sasl_t is really a pointer to the internal pni_transport_t - return ssl ? ((pn_transport_t *)ssl)->ssl : NULL; + // The external pn_sasl_t is really a pointer to the internal pni_transport_t + return ssl ? ((pn_transport_t *)ssl)->ssl : NULL; } // define two sets of allowable ciphers: those that require authentication, and those @@ -265,8 +264,8 @@ static bool match_dns_pattern( const char *hostname, int suffix_len = strlen(suffix); if (prefix_len && pn_strncasecmp( prefix, slabel, prefix_len )) return false; if (suffix_len && pn_strncasecmp( suffix, - slabel + (strlen(slabel) - suffix_len), - suffix_len )) return false; + slabel + (strlen(slabel) - suffix_len), + suffix_len )) return false; } } @@ -348,7 +347,7 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) if (!matched) { ssl_log(transport, "Error: no name matching %s found in peer cert - rejecting handshake.", - ssl->peer_hostname); + ssl->peer_hostname); preverify_ok = 0; #ifdef X509_V_ERR_APPLICATION_VERIFICATION X509_STORE_CTX_set_error( ctx, X509_V_ERR_APPLICATION_VERIFICATION ); @@ -477,18 +476,14 @@ bool pn_ssl_present(void) return true; } +static bool ensure_initialized(void); + pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode ) { - if (!ssl_initialized) { - ssl_initialized = 1; - SSL_library_init(); - SSL_load_error_strings(); - OpenSSL_add_all_algorithms(); - ssl_ex_data_index = SSL_get_ex_new_index( 0, (void *) "org.apache.qpid.proton.ssl", - NULL, NULL, NULL); - ssn_init(); + if (!ensure_initialized()) { + ssl_log_error("Unable to initialize OpenSSL library"); + return NULL; } - pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t)); if (!domain) return NULL; @@ -499,7 +494,7 @@ pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode ) // known vulnerable ones. This should allow us to use the latest version // of the TLS standard that the installed library supports. switch(mode) { - case PN_SSL_MODE_CLIENT: + case PN_SSL_MODE_CLIENT: domain->ctx = SSL_CTX_new(SSLv23_client_method()); // and TLSv1+ SSL_CTX_set_session_cache_mode(domain->ctx, SSL_SESS_CACHE_CLIENT); if (!domain->ctx) { @@ -509,7 +504,7 @@ pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode ) } break; - case PN_SSL_MODE_SERVER: + case PN_SSL_MODE_SERVER: domain->ctx = SSL_CTX_new(SSLv23_server_method()); // and TLSv1+ if (!domain->ctx) { ssl_log_error("Unable to initialize OpenSSL context."); @@ -518,7 +513,7 @@ pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode ) } break; - default: + default: pn_transport_logf(NULL, "Invalid value for pn_ssl_mode_t: %d", mode); free(domain); return NULL; @@ -530,7 +525,7 @@ pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode ) SSL_CTX_set_options(domain->ctx, SSL_OP_NO_COMPRESSION); #endif #if OPENSSL_VERSION_NUMBER >= 0x10100000 - domain->default_seclevel = SSL_CTX_get_security_level(domain->ctx); + domain->default_seclevel = SSL_CTX_get_security_level(domain->ctx); #endif // by default, allow anonymous ciphers so certificates are not required 'out of the box' @@ -570,9 +565,9 @@ void pn_ssl_domain_free( pn_ssl_domain_t *domain ) int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain, - const char *certificate_file, - const char *private_key_file, - const char *password) + const char *certificate_file, + const char *private_key_file, + const char *password) { if (!domain || !domain->ctx) return -1; @@ -594,7 +589,7 @@ int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain, if (SSL_CTX_check_private_key(domain->ctx) != 1) { ssl_log_error("The key file %s is not consistent with the certificate %s", - private_key_file, certificate_file); + private_key_file, certificate_file); return -5; } @@ -604,8 +599,8 @@ int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain, // cipher was negotiated. TLSv1 will reject such a request. Hack: once a cert is // configured, allow only authenticated ciphers. if (!domain->ciphers && !SSL_CTX_set_cipher_list( domain->ctx, CIPHERS_AUTHENTICATE )) { - ssl_log_error("Failed to set cipher list to %s", CIPHERS_AUTHENTICATE); - return -6; + ssl_log_error("Failed to set cipher list to %s", CIPHERS_AUTHENTICATE); + return -6; } return 0; @@ -664,8 +659,8 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain, if (!domain) return -1; switch (mode) { - case PN_SSL_VERIFY_PEER: - case PN_SSL_VERIFY_PEER_NAME: + case PN_SSL_VERIFY_PEER: + case PN_SSL_VERIFY_PEER_NAME: #if OPENSSL_VERSION_NUMBER >= 0x10100000 SSL_CTX_set_security_level(domain->ctx, domain->default_seclevel); @@ -673,7 +668,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain, if (!domain->has_ca_db) { pn_transport_logf(NULL, "Error: cannot verify peer without a trusted CA configured.\n" - " Use pn_ssl_domain_set_trusted_ca_db()"); + " Use pn_ssl_domain_set_trusted_ca_db()"); return -1; } @@ -686,7 +681,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain, } if (!domain->has_certificate) { pn_transport_logf(NULL, "Error: Server cannot verify peer without configuring a certificate.\n" - " Use pn_ssl_domain_set_credentials()"); + " Use pn_ssl_domain_set_credentials()"); } if (domain->trusted_CAs) free(domain->trusted_CAs); @@ -708,7 +703,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain, #endif break; - case PN_SSL_ANONYMOUS_PEER: // hippie free love mode... :) + case PN_SSL_ANONYMOUS_PEER: // hippie free love mode... :) #if OPENSSL_VERSION_NUMBER >= 0x10100000 // Must use lowest OpenSSL security level to enable anonymous ciphers. SSL_CTX_set_security_level(domain->ctx, 0); @@ -716,7 +711,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain, SSL_CTX_set_verify( domain->ctx, SSL_VERIFY_NONE, NULL ); break; - default: + default: pn_transport_logf(NULL, "Invalid peer authentication mode given." ); return -1; } @@ -726,35 +721,35 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain, } const pn_io_layer_t ssl_layer = { - process_input_ssl, - process_output_ssl, - handle_error_ssl, - NULL, - buffered_output + process_input_ssl, + process_output_ssl, + handle_error_ssl, + NULL, + buffered_output }; const pn_io_layer_t ssl_input_closed_layer = { - process_input_done, - process_output_ssl, - handle_error_ssl, - NULL, - buffered_output + process_input_done, + process_output_ssl, + handle_error_ssl, + NULL, + buffered_output }; const pn_io_layer_t ssl_output_closed_layer = { - process_input_ssl, - process_output_done, - handle_error_ssl, - NULL, - buffered_output + process_input_ssl, + process_output_done, + handle_error_ssl, + NULL, + buffered_output }; const pn_io_layer_t ssl_closed_layer = { - process_input_done, - process_output_done, - handle_error_ssl, - NULL, - buffered_output + process_input_done, + process_output_done, + handle_error_ssl, + NULL, + buffered_output }; int pn_ssl_init(pn_ssl_t *ssl0, pn_ssl_domain_t *domain, const char *session_id) @@ -886,9 +881,9 @@ pn_ssl_t *pn_ssl(pn_transport_t *transport) static int keyfile_pw_cb(char *buf, int size, int rwflag, void *userdata) { - strncpy(buf, (char *)userdata, size); // @todo: un-obfuscate me!!! - buf[size - 1] = '\0'; - return(strlen(buf)); + strncpy(buf, (char *)userdata, size); // @todo: un-obfuscate me!!! + buf[size - 1] = '\0'; + return(strlen(buf)); } @@ -958,13 +953,13 @@ static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, if (!BIO_should_retry(ssl->bio_ssl)) { int reason = SSL_get_error( ssl->ssl, read ); switch (reason) { - case SSL_ERROR_ZERO_RETURN: + case SSL_ERROR_ZERO_RETURN: // SSL closed cleanly ssl_log(transport, "SSL connection has closed"); start_ssl_shutdown(transport); // KAG: not sure - this may not be necessary ssl->ssl_closed = true; break; - default: + default: // unexpected error return (ssize_t)ssl_failed(transport); } @@ -994,7 +989,7 @@ static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, ssl_log( transport, "Application consumed %d bytes from peer", (int) consumed ); } else if (consumed < 0) { ssl_log(transport, "Application layer closed its input, error=%d (discarding %d bytes)", - (int) consumed, (int)ssl->in_count); + (int) consumed, (int)ssl->in_count); ssl->in_count = 0; // discard any pending input ssl->app_input_closed = consumed; if (ssl->app_output_closed && ssl->out_count == 0) { @@ -1086,7 +1081,7 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer } else { if (app_bytes < 0) { ssl_log(transport, "Application layer closed its output, error=%d (%d bytes pending send)", - (int) app_bytes, (int) ssl->out_count); + (int) app_bytes, (int) ssl->out_count); ssl->app_output_closed = app_bytes; } } @@ -1107,14 +1102,14 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer if (!BIO_should_retry(ssl->bio_ssl)) { int reason = SSL_get_error( ssl->ssl, wrote ); switch (reason) { - case SSL_ERROR_ZERO_RETURN: + case SSL_ERROR_ZERO_RETURN: // SSL closed cleanly ssl_log(transport, "SSL connection has closed"); start_ssl_shutdown(transport); // KAG: not sure - this may not be necessary ssl->out_count = 0; // can no longer write to socket, so erase app output data ssl->ssl_closed = true; break; - default: + default: // unexpected error return (ssize_t)ssl_failed(transport); } @@ -1236,7 +1231,7 @@ static void release_ssl_socket(pni_ssl_t *ssl) { if (ssl->bio_ssl) BIO_free(ssl->bio_ssl); if (ssl->ssl) { - SSL_free(ssl->ssl); // will free bio_ssl_io + SSL_free(ssl->ssl); // will free bio_ssl_io } else { if (ssl->bio_ssl_io) BIO_free(ssl->bio_ssl_io); } @@ -1254,9 +1249,9 @@ pn_ssl_resume_status_t pn_ssl_resume_status(pn_ssl_t *ssl0) pni_ssl_t *ssl = get_ssl_internal(ssl0); if (!ssl || !ssl->ssl) return PN_SSL_RESUME_UNKNOWN; switch (SSL_session_reused( ssl->ssl )) { - case 0: return PN_SSL_RESUME_NEW; - case 1: return PN_SSL_RESUME_REUSED; - default: break; + case 0: return PN_SSL_RESUME_NEW; + case 1: return PN_SSL_RESUME_REUSED; + default: break; } return PN_SSL_RESUME_UNKNOWN; } @@ -1332,124 +1327,124 @@ const char* pn_ssl_get_remote_subject(pn_ssl_t *ssl0) int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0, char *fingerprint, size_t fingerprint_length, pn_ssl_hash_alg hash_alg) { - const char *digest_name = NULL; - size_t min_required_length; - - // old versions of python expect fingerprint to contain a valid string on - // return from this function - fingerprint[0] = 0; - - // Assign the correct digest_name value based on the enum values. - switch (hash_alg) { - case PN_SSL_SHA1 : - min_required_length = 41; // 40 hex characters + 1 '\0' character - digest_name = "sha1"; - break; - case PN_SSL_SHA256 : - min_required_length = 65; // 64 hex characters + 1 '\0' character - digest_name = "sha256"; - break; - case PN_SSL_SHA512 : - min_required_length = 129; // 128 hex characters + 1 '\0' character - digest_name = "sha512"; - break; - case PN_SSL_MD5 : - min_required_length = 33; // 32 hex characters + 1 '\0' character - digest_name = "md5"; - break; - default: - ssl_log_error("Unknown or unhandled hash algorithm %i \n", hash_alg); - return PN_ERR; - - } + const char *digest_name = NULL; + size_t min_required_length; + + // old versions of python expect fingerprint to contain a valid string on + // return from this function + fingerprint[0] = 0; + + // Assign the correct digest_name value based on the enum values. + switch (hash_alg) { + case PN_SSL_SHA1 : + min_required_length = 41; // 40 hex characters + 1 '\0' character + digest_name = "sha1"; + break; + case PN_SSL_SHA256 : + min_required_length = 65; // 64 hex characters + 1 '\0' character + digest_name = "sha256"; + break; + case PN_SSL_SHA512 : + min_required_length = 129; // 128 hex characters + 1 '\0' character + digest_name = "sha512"; + break; + case PN_SSL_MD5 : + min_required_length = 33; // 32 hex characters + 1 '\0' character + digest_name = "md5"; + break; + default: + ssl_log_error("Unknown or unhandled hash algorithm %i \n", hash_alg); + return PN_ERR; - if(fingerprint_length < min_required_length) { - ssl_log_error("Insufficient fingerprint_length %i. fingerprint_length must be %i or above for %s digest\n", - fingerprint_length, min_required_length, digest_name); - return PN_ERR; - } + } - const EVP_MD *digest = EVP_get_digestbyname(digest_name); + if(fingerprint_length < min_required_length) { + ssl_log_error("Insufficient fingerprint_length %i. fingerprint_length must be %i or above for %s digest\n", + fingerprint_length, min_required_length, digest_name); + return PN_ERR; + } - pni_ssl_t *ssl = get_ssl_internal(ssl0); - X509 *cert = get_peer_certificate(ssl); + const EVP_MD *digest = EVP_get_digestbyname(digest_name); - if(cert) { - unsigned int len; + pni_ssl_t *ssl = get_ssl_internal(ssl0); + X509 *cert = get_peer_certificate(ssl); - unsigned char bytes[64]; // sha512 uses 64 octets, we will use that as the maximum. + if(cert) { + unsigned int len; - if (X509_digest(cert, digest, bytes, &len) != 1) { - ssl_log_error("Failed to extract X509 digest\n"); - return PN_ERR; - } + unsigned char bytes[64]; // sha512 uses 64 octets, we will use that as the maximum. - char *cursor = fingerprint; + if (X509_digest(cert, digest, bytes, &len) != 1) { + ssl_log_error("Failed to extract X509 digest\n"); + return PN_ERR; + } - for (size_t i=0; i<len ; i++) { - cursor += pni_snprintf((char *)cursor, fingerprint_length, "%02x", bytes[i]); - fingerprint_length = fingerprint_length - 2; - } + char *cursor = fingerprint; - return PN_OK; - } - else { - ssl_log_error("No certificate is available yet \n"); - return PN_ERR; + for (size_t i=0; i<len ; i++) { + cursor += pni_snprintf((char *)cursor, fingerprint_length, "%02x", bytes[i]); + fingerprint_length = fingerprint_length - 2; } - return 0; + return PN_OK; + } + else { + ssl_log_error("No certificate is available yet \n"); + return PN_ERR; + } + + return 0; } const char* pn_ssl_get_remote_subject_subfield(pn_ssl_t *ssl0, pn_ssl_cert_subject_subfield field) { - int openssl_field = 0; + int openssl_field = 0; - // Assign openssl internal representations of field values to openssl_field - switch (field) { - case PN_SSL_CERT_SUBJECT_COUNTRY_NAME : - openssl_field = NID_countryName; - break; - case PN_SSL_CERT_SUBJECT_STATE_OR_PROVINCE : - openssl_field = NID_stateOrProvinceName; - break; - case PN_SSL_CERT_SUBJECT_CITY_OR_LOCALITY : - openssl_field = NID_localityName; - break; - case PN_SSL_CERT_SUBJECT_ORGANIZATION_NAME : - openssl_field = NID_organizationName; - break; - case PN_SSL_CERT_SUBJECT_ORGANIZATION_UNIT : - openssl_field = NID_organizationalUnitName; - break; - case PN_SSL_CERT_SUBJECT_COMMON_NAME : - openssl_field = NID_commonName; - break; - default: - ssl_log_error("Unknown or unhandled certificate subject subfield %i \n", field); - return NULL; - } + // Assign openssl internal representations of field values to openssl_field + switch (field) { + case PN_SSL_CERT_SUBJECT_COUNTRY_NAME : + openssl_field = NID_countryName; + break; + case PN_SSL_CERT_SUBJECT_STATE_OR_PROVINCE : + openssl_field = NID_stateOrProvinceName; + break; + case PN_SSL_CERT_SUBJECT_CITY_OR_LOCALITY : + openssl_field = NID_localityName; + break; + case PN_SSL_CERT_SUBJECT_ORGANIZATION_NAME : + openssl_field = NID_organizationName; + break; + case PN_SSL_CERT_SUBJECT_ORGANIZATION_UNIT : + openssl_field = NID_organizationalUnitName; + break; + case PN_SSL_CERT_SUBJECT_COMMON_NAME : + openssl_field = NID_commonName; + break; + default: + ssl_log_error("Unknown or unhandled certificate subject subfield %i \n", field); + return NULL; + } - pni_ssl_t *ssl = get_ssl_internal(ssl0); - X509 *cert = get_peer_certificate(ssl); - if (!cert) return NULL; + pni_ssl_t *ssl = get_ssl_internal(ssl0); + X509 *cert = get_peer_certificate(ssl); + if (!cert) return NULL; - X509_NAME *subject_name = X509_get_subject_name(cert); + X509_NAME *subject_name = X509_get_subject_name(cert); - // TODO (gmurthy) - A server side cert subject field can have more than one common name like this - Subject: CN=www.domain1.com, CN=www.domain2.com, see https://bugzilla.mozilla.org/show_bug.cgi?id=380656 - // For now, we will only return the first common name if there is more than one common name in the cert - int index = X509_NAME_get_index_by_NID(subject_name, openssl_field, -1); + // TODO (gmurthy) - A server side cert subject field can have more than one common name like this - Subject: CN=www.domain1.com, CN=www.domain2.com, see https://bugzilla.mozilla.org/show_bug.cgi?id=380656 + // For now, we will only return the first common name if there is more than one common name in the cert + int index = X509_NAME_get_index_by_NID(subject_name, openssl_field, -1); - if (index > -1) { - X509_NAME_ENTRY *ne = X509_NAME_get_entry(subject_name, index); - if(ne) { - ASN1_STRING *name_asn1 = X509_NAME_ENTRY_get_data(ne); - return (char *) name_asn1->data; - } + if (index > -1) { + X509_NAME_ENTRY *ne = X509_NAME_get_entry(subject_name, index); + if(ne) { + ASN1_STRING *name_asn1 = X509_NAME_ENTRY_get_data(ne); + return (char *) name_asn1->data; } + } - return NULL; + return NULL; } static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len) @@ -1474,3 +1469,88 @@ static size_t buffered_output(pn_transport_t *transport) } return count; } + + +/* Thread-safe locking and initialization for POSIX and Windows */ + +static bool init_ok = false; + +#ifdef _WIN32 + +typedef CRITICAL_SECTION pni_mutex_t; +static inline void pni_mutex_init(pni_mutex_t *m) { InitializeCriticalSection(m); } +static inline void pni_mutex_lock(pni_mutex_t *m) { EnterCriticalSection(m); } +static inline void pni_mutex_unlock(pni_mutex_t *m) { LeaveCriticalSection(m); } +static inline unsigned long id_callback(void) { return (unsigned long)GetCurrentThreadId(); } +INIT_ONCE initialize_once = INIT_ONCE_STATIC_INIT; +static inline bool ensure_initialized(void) { + void* dummy; + InitOnceExecuteOnce(&initialize_once, &initialize, NULL, &dummy); + return init_ok; +} + +#else /* POSIX */ + +#include <pthread.h> + +static void initialize(void); + +typedef pthread_mutex_t pni_mutex_t; +static inline int pni_mutex_init(pni_mutex_t *m) { return pthread_mutex_init(m, NULL); } +static inline int pni_mutex_lock(pni_mutex_t *m) { return pthread_mutex_lock(m); } +static inline int pni_mutex_unlock(pni_mutex_t *m) { return pthread_mutex_unlock(m); } +static inline unsigned long id_callback(void) { return (unsigned long)pthread_self(); } +static pthread_once_t initialize_once = PTHREAD_ONCE_INIT; +static inline bool ensure_initialized(void) { + pthread_once(&initialize_once, &initialize); + return init_ok; +} + +#endif + +static pni_mutex_t *locks = NULL; /* Lock array for openssl */ + +/* Callback function for openssl locking */ +static void locking_callback(int mode, int n, const char *file, int line) { + if(mode & CRYPTO_LOCK) + pni_mutex_lock(&locks[n]); + else + pni_mutex_unlock(&locks[n]); +} + +static void initialize(void) { + int i; + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + ssl_ex_data_index = SSL_get_ex_new_index( 0, (void *) "org.apache.qpid.proton.ssl", + NULL, NULL, NULL); + ssn_init(); + locks = (pni_mutex_t*)malloc(CRYPTO_num_locks() * sizeof(pni_mutex_t)); + if (!locks) return; + for(i = 0; i < CRYPTO_num_locks(); i++) + pni_mutex_init(&locks[i]); + CRYPTO_set_id_callback(&id_callback); + CRYPTO_set_locking_callback(&locking_callback); + /* In recent versions of openssl, the set_callback functions are no-op macros, + so we need to take steps to stop the compiler complaining about unused functions. */ + (void)&id_callback; + (void)&locking_callback; + init_ok = true; +} + +/* TODO aconway 2017-10-16: There is no opportunity to clean up the locks as proton has no + final shut-down call. If it did, we should call this: */ +/* +static void shutdown(void) { + CRYPTO_set_id_callback(NULL); + CRYPTO_set_locking_callback(NULL); + if(locks) { + int i; + for(i = 0; i < CRYPTO_num_locks(); i++) + pni_mutex_destroy(&locks[i]); + free(locks); + locks = NULL; + } +} +*/ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/434a2e77/proton-c/src/tests/proactor.c ---------------------------------------------------------------------- diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c index 5f84bfe..a0b2a15 100644 --- a/proton-c/src/tests/proactor.c +++ b/proton-c/src/tests/proactor.c @@ -686,7 +686,6 @@ static void test_release_free(test_t *t) { # define CERTIFICATE(NAME) SSL_FILE(NAME "-certificate.p12") # define SET_CREDENTIALS(DOMAIN, NAME) \ pn_ssl_domain_set_credentials(DOMAIN, SSL_FILE(NAME "-full.p12"), "", SSL_PW) - #else # define CERTIFICATE(NAME) SSL_FILE(NAME "-certificate.pem") # define SET_CREDENTIALS(DOMAIN, NAME) \ --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org