1
/* vim:set ft=c ts=2 sw=2 sts=2 et cindent: */
3
* Copyright 2012-2013 Michael Steinert
5
* Permission is hereby granted, free of charge, to any person obtaining a
6
* copy of this software and associated documentation files (the "Software"),
7
* to deal in the Software without restriction, including without limitation
8
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
* and/or sell copies of the Software, and to permit persons to whom the
10
* Software is furnished to do so, subject to the following conditions:
12
* The above copyright notice and this permission notice shall be included in
13
* all copies or substantial portions of the Software.
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
* DEALINGS IN THE SOFTWARE.
28
#include "amqp_ssl_socket.h"
29
#include "amqp_private.h"
30
#include <polarssl/ctr_drbg.h>
31
#include <polarssl/entropy.h>
32
#include <polarssl/net.h>
33
#include <polarssl/ssl.h>
34
#include <polarssl/version.h>
38
#ifndef AMQP_USE_UNTESTED_SSL_BACKEND
39
# error This SSL backend is alpha quality and likely contains errors.\
40
-DAMQP_USE_UNTESTED_SSL_BACKEND to use this backend
43
struct amqp_ssl_socket_t {
44
const struct amqp_socket_class_t *klass;
46
entropy_context *entropy;
47
ctr_drbg_context *ctr_drbg;
59
amqp_ssl_socket_send(void *base,
62
AMQP_UNUSED int flags)
65
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
68
status = ssl_write(self->ssl, buf, len);
70
self->last_error = AMQP_STATUS_SSL_ERROR;
77
amqp_ssl_socket_writev(void *base,
78
const struct iovec *iov,
81
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
88
for (i = 0; i < iovcnt; ++i) {
89
bytes += iov[i].iov_len;
91
if (self->length < bytes) {
93
self->buffer = malloc(bytes);
96
self->last_error = AMQP_STATUS_NO_MEMORY;
101
bufferp = self->buffer;
102
for (i = 0; i < iovcnt; ++i) {
103
memcpy(bufferp, iov[i].iov_base, iov[i].iov_len);
104
bufferp += iov[i].iov_len;
106
written = amqp_ssl_socket_send(self, (const unsigned char *)self->buffer,
113
amqp_ssl_socket_recv(void *base,
116
AMQP_UNUSED int flags)
119
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
121
self->last_error = 0;
122
status = ssl_read(self->ssl, buf, len);
124
self->last_error = AMQP_STATUS_SSL_ERROR;
131
amqp_ssl_socket_open(void *base, const char *host, int port, struct timeval *timeout)
134
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
135
self->last_error = 0;
137
if (timeout && (timeout->tv_sec != 0 || timeout->tv_usec != 0)) {
138
/* We don't support PolarSSL for now because it uses its own connect() wrapper
139
* It is not too hard to implement net_connect() with noblock support,
140
* but then we will have to maintain that piece of code and keep it synced with main PolarSSL code base
142
return AMQP_STATUS_INVALID_PARAMETER;
145
status = net_connect(&self->sockfd, host, port);
147
/* This isn't quite right. We should probably translate between
148
* POLARSSL_ERR_* to our internal error codes
150
self->last_error = AMQP_STATUS_SSL_ERROR;
154
ssl_set_ca_chain(self->ssl, self->cacert, NULL, host);
156
ssl_set_bio(self->ssl, net_recv, &self->sockfd,
157
net_send, &self->sockfd);
158
if (self->key && self->cert) {
159
ssl_set_own_cert(self->ssl, self->cert, self->key);
161
while (0 != (status = ssl_handshake(self->ssl))) {
163
case POLARSSL_ERR_NET_WANT_READ:
164
case POLARSSL_ERR_NET_WANT_WRITE:
167
self->last_error = AMQP_STATUS_SSL_ERROR;
175
amqp_ssl_socket_close(void *base)
178
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
181
free(self->ctr_drbg);
182
x509_free(self->cacert);
186
x509_free(self->cert);
192
if (self->sockfd >= 0) {
193
net_close(self->sockfd);
202
amqp_ssl_socket_error(AMQP_UNUSED void *user_data)
204
return AMQP_STATUS_SSL_ERROR;
208
amqp_ssl_error_string(AMQP_UNUSED int err)
210
return strdup("A SSL socket error occurred");
214
amqp_ssl_socket_get_sockfd(void *base)
216
struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
220
static const struct amqp_socket_class_t amqp_ssl_socket_class = {
221
amqp_ssl_socket_writev, /* writev */
222
amqp_ssl_socket_send, /* send */
223
amqp_ssl_socket_recv, /* recv */
224
amqp_ssl_socket_open, /* open */
225
amqp_ssl_socket_close, /* close */
226
amqp_ssl_socket_error, /* error */
227
amqp_ssl_socket_get_sockfd /* get_sockfd */
231
amqp_ssl_socket_new(void)
233
struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self));
238
self->entropy = calloc(1, sizeof(*self->entropy));
239
if (!self->entropy) {
243
entropy_init(self->entropy);
244
self->ctr_drbg = calloc(1, sizeof(*self->ctr_drbg));
245
if (!self->ctr_drbg) {
248
status = ctr_drbg_init(self->ctr_drbg, entropy_func, self->entropy,
253
self->ssl = calloc(1, sizeof(*self->ssl));
257
status = ssl_init(self->ssl);
261
ssl_set_endpoint(self->ssl, SSL_IS_CLIENT);
262
ssl_set_rng(self->ssl, ctr_drbg_random, self->ctr_drbg);
263
ssl_set_ciphersuites(self->ssl, ssl_default_ciphersuites);
264
ssl_set_authmode(self->ssl, SSL_VERIFY_REQUIRED);
265
self->session = calloc(1, sizeof(*self->session));
266
if (!self->session) {
269
#if POLARSSL_VERSION_NUMBER >= 0x01020000
270
ssl_set_session(self->ssl, self->session);
272
ssl_set_session(self->ssl, 0, 0, self->session);
275
self->klass = &amqp_ssl_socket_class;
276
return (amqp_socket_t *)self;
278
amqp_socket_close((amqp_socket_t *)self);
283
amqp_ssl_socket_set_cacert(amqp_socket_t *base,
287
struct amqp_ssl_socket_t *self;
288
if (base->klass != &amqp_ssl_socket_class) {
289
amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
291
self = (struct amqp_ssl_socket_t *)base;
292
self->cacert = calloc(1, sizeof(*self->cacert));
296
status = x509parse_crtfile(self->cacert, cacert);
304
amqp_ssl_socket_set_key(amqp_socket_t *base,
309
struct amqp_ssl_socket_t *self;
310
if (base->klass != &amqp_ssl_socket_class) {
311
amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
313
self = (struct amqp_ssl_socket_t *)base;
314
self->key = calloc(1, sizeof(*self->key));
318
status = x509parse_keyfile(self->key, key, NULL);
322
self->cert = calloc(1, sizeof(*self->cert));
326
status = x509parse_crtfile(self->cert, cert);
334
amqp_ssl_socket_set_key_buffer(AMQP_UNUSED amqp_socket_t *base,
335
AMQP_UNUSED const char *cert,
336
AMQP_UNUSED const void *key,
337
AMQP_UNUSED size_t n)
339
amqp_abort("%s is not implemented for PolarSSL", __func__);
344
amqp_ssl_socket_set_verify(amqp_socket_t *base,
345
amqp_boolean_t verify)
347
struct amqp_ssl_socket_t *self;
348
if (base->klass != &amqp_ssl_socket_class) {
349
amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
351
self = (struct amqp_ssl_socket_t *)base;
353
ssl_set_authmode(self->ssl, SSL_VERIFY_REQUIRED);
355
ssl_set_authmode(self->ssl, SSL_VERIFY_NONE);
360
amqp_set_initialize_ssl_library(AMQP_UNUSED amqp_boolean_t do_initialize)