~ubuntu-cloud-archive/ubuntu/precise/librabbitmq/precise-icehouse

« back to all changes in this revision

Viewing changes to librabbitmq/amqp_polarssl.c

  • Committer: Package Import Robot
  • Author(s): Michael Fladischer
  • Date: 2013-11-04 20:15:55 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20131104201555-wdjlgotdjansj1j9
Tags: 0.4.1-1
* Imported Upstream version 0.4.1
* Add libssl-dev to Build-Depends.
* Update librabbitmq1.symbols.
* Switch buildsystem to cmake.
  + Add cmake_multiarch.patch to fix multiarch installation paths for shared
    library files in cmake.
  * Add cmake to Build-Depends.
  * Drop dh-autoreconf from Build-Depends.
* Format packaging files with wrap-and-sort.
* Update d/watch file to use github releases instead of tags.
* Bump Standards version to 3.9.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vim:set ft=c ts=2 sw=2 sts=2 et cindent: */
 
2
/*
 
3
 * Copyright 2012-2013 Michael Steinert
 
4
 *
 
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:
 
11
 *
 
12
 * The above copyright notice and this permission notice shall be included in
 
13
 * all copies or substantial portions of the Software.
 
14
 *
 
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.
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include "config.h"
 
26
#endif
 
27
 
 
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>
 
35
#include <stdlib.h>
 
36
#include <string.h>
 
37
 
 
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
 
41
#endif
 
42
 
 
43
struct amqp_ssl_socket_t {
 
44
  const struct amqp_socket_class_t *klass;
 
45
  int sockfd;
 
46
  entropy_context *entropy;
 
47
  ctr_drbg_context *ctr_drbg;
 
48
  x509_cert *cacert;
 
49
  rsa_context *key;
 
50
  x509_cert *cert;
 
51
  ssl_context *ssl;
 
52
  ssl_session *session;
 
53
  char *buffer;
 
54
  size_t length;
 
55
  int last_error;
 
56
};
 
57
 
 
58
static ssize_t
 
59
amqp_ssl_socket_send(void *base,
 
60
                     const void *buf,
 
61
                     size_t len,
 
62
                     AMQP_UNUSED int flags)
 
63
{
 
64
  ssize_t status;
 
65
  struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
 
66
 
 
67
  self->last_error = 0;
 
68
  status = ssl_write(self->ssl, buf, len);
 
69
  if (status < 0) {
 
70
    self->last_error = AMQP_STATUS_SSL_ERROR;
 
71
  }
 
72
 
 
73
  return status;
 
74
}
 
75
 
 
76
static ssize_t
 
77
amqp_ssl_socket_writev(void *base,
 
78
                       const struct iovec *iov,
 
79
                       int iovcnt)
 
80
{
 
81
  struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
 
82
  ssize_t written = -1;
 
83
  char *bufferp;
 
84
  size_t bytes;
 
85
  int i;
 
86
  self->last_error = 0;
 
87
  bytes = 0;
 
88
  for (i = 0; i < iovcnt; ++i) {
 
89
    bytes += iov[i].iov_len;
 
90
  }
 
91
  if (self->length < bytes) {
 
92
    free(self->buffer);
 
93
    self->buffer = malloc(bytes);
 
94
    if (!self->buffer) {
 
95
      self->length = 0;
 
96
      self->last_error = AMQP_STATUS_NO_MEMORY;
 
97
      goto exit;
 
98
    }
 
99
    self->length = bytes;
 
100
  }
 
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;
 
105
  }
 
106
  written = amqp_ssl_socket_send(self, (const unsigned char *)self->buffer,
 
107
                      bytes, 0);
 
108
exit:
 
109
  return written;
 
110
}
 
111
 
 
112
static ssize_t
 
113
amqp_ssl_socket_recv(void *base,
 
114
                     void *buf,
 
115
                     size_t len,
 
116
                     AMQP_UNUSED int flags)
 
117
{
 
118
  ssize_t status;
 
119
  struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
 
120
 
 
121
  self->last_error = 0;
 
122
  status = ssl_read(self->ssl, buf, len);
 
123
  if (status < 0) {
 
124
    self->last_error = AMQP_STATUS_SSL_ERROR;
 
125
  }
 
126
 
 
127
  return status;
 
128
}
 
129
 
 
130
static int
 
131
amqp_ssl_socket_open(void *base, const char *host, int port, struct timeval *timeout)
 
132
{
 
133
  int status;
 
134
  struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
 
135
  self->last_error = 0;
 
136
 
 
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
 
141
     */
 
142
    return AMQP_STATUS_INVALID_PARAMETER;
 
143
  }
 
144
 
 
145
  status = net_connect(&self->sockfd, host, port);
 
146
  if (status) {
 
147
    /* This isn't quite right. We should probably translate between
 
148
     * POLARSSL_ERR_* to our internal error codes
 
149
     */
 
150
    self->last_error = AMQP_STATUS_SSL_ERROR;
 
151
    return -1;
 
152
  }
 
153
  if (self->cacert) {
 
154
    ssl_set_ca_chain(self->ssl, self->cacert, NULL, host);
 
155
  }
 
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);
 
160
  }
 
161
  while (0 != (status = ssl_handshake(self->ssl))) {
 
162
    switch (status) {
 
163
    case POLARSSL_ERR_NET_WANT_READ:
 
164
    case POLARSSL_ERR_NET_WANT_WRITE:
 
165
      continue;
 
166
    default:
 
167
      self->last_error = AMQP_STATUS_SSL_ERROR;
 
168
      break;
 
169
    }
 
170
  }
 
171
  return status;
 
172
}
 
173
 
 
174
static int
 
175
amqp_ssl_socket_close(void *base)
 
176
{
 
177
  int status = -1;
 
178
  struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
 
179
  if (self) {
 
180
    free(self->entropy);
 
181
    free(self->ctr_drbg);
 
182
    x509_free(self->cacert);
 
183
    free(self->cacert);
 
184
    rsa_free(self->key);
 
185
    free(self->key);
 
186
    x509_free(self->cert);
 
187
    free(self->cert);
 
188
    ssl_free(self->ssl);
 
189
    free(self->ssl);
 
190
    free(self->session);
 
191
    free(self->buffer);
 
192
    if (self->sockfd >= 0) {
 
193
      net_close(self->sockfd);
 
194
      status = 0;
 
195
    }
 
196
    free(self);
 
197
  }
 
198
  return status;
 
199
}
 
200
 
 
201
static int
 
202
amqp_ssl_socket_error(AMQP_UNUSED void *user_data)
 
203
{
 
204
  return AMQP_STATUS_SSL_ERROR;
 
205
}
 
206
 
 
207
char *
 
208
amqp_ssl_error_string(AMQP_UNUSED int err)
 
209
{
 
210
  return strdup("A SSL socket error occurred");
 
211
}
 
212
 
 
213
static int
 
214
amqp_ssl_socket_get_sockfd(void *base)
 
215
{
 
216
  struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
 
217
  return self->sockfd;
 
218
}
 
219
 
 
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 */
 
228
};
 
229
 
 
230
amqp_socket_t *
 
231
amqp_ssl_socket_new(void)
 
232
{
 
233
  struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self));
 
234
  int status;
 
235
  if (!self) {
 
236
    goto error;
 
237
  }
 
238
  self->entropy = calloc(1, sizeof(*self->entropy));
 
239
  if (!self->entropy) {
 
240
    goto error;
 
241
  }
 
242
  self->sockfd = -1;
 
243
  entropy_init(self->entropy);
 
244
  self->ctr_drbg = calloc(1, sizeof(*self->ctr_drbg));
 
245
  if (!self->ctr_drbg) {
 
246
    goto error;
 
247
  }
 
248
  status = ctr_drbg_init(self->ctr_drbg, entropy_func, self->entropy,
 
249
                         NULL, 0);
 
250
  if (status) {
 
251
    goto error;
 
252
  }
 
253
  self->ssl = calloc(1, sizeof(*self->ssl));
 
254
  if (!self->ssl) {
 
255
    goto error;
 
256
  }
 
257
  status = ssl_init(self->ssl);
 
258
  if (status) {
 
259
    goto error;
 
260
  }
 
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) {
 
267
    goto error;
 
268
  }
 
269
#if POLARSSL_VERSION_NUMBER >= 0x01020000
 
270
  ssl_set_session(self->ssl, self->session);
 
271
#else
 
272
  ssl_set_session(self->ssl, 0, 0, self->session);
 
273
#endif
 
274
 
 
275
  self->klass = &amqp_ssl_socket_class;
 
276
  return (amqp_socket_t *)self;
 
277
error:
 
278
  amqp_socket_close((amqp_socket_t *)self);
 
279
  return NULL;
 
280
}
 
281
 
 
282
int
 
283
amqp_ssl_socket_set_cacert(amqp_socket_t *base,
 
284
                           const char *cacert)
 
285
{
 
286
  int status;
 
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);
 
290
  }
 
291
  self = (struct amqp_ssl_socket_t *)base;
 
292
  self->cacert = calloc(1, sizeof(*self->cacert));
 
293
  if (!self->cacert) {
 
294
    return -1;
 
295
  }
 
296
  status = x509parse_crtfile(self->cacert, cacert);
 
297
  if (status) {
 
298
    return -1;
 
299
  }
 
300
  return 0;
 
301
}
 
302
 
 
303
int
 
304
amqp_ssl_socket_set_key(amqp_socket_t *base,
 
305
                        const char *cert,
 
306
                        const char *key)
 
307
{
 
308
  int status;
 
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);
 
312
  }
 
313
  self = (struct amqp_ssl_socket_t *)base;
 
314
  self->key = calloc(1, sizeof(*self->key));
 
315
  if (!self->key) {
 
316
    return -1;
 
317
  }
 
318
  status = x509parse_keyfile(self->key, key, NULL);
 
319
  if (status) {
 
320
    return -1;
 
321
  }
 
322
  self->cert = calloc(1, sizeof(*self->cert));
 
323
  if (!self->cert) {
 
324
    return -1;
 
325
  }
 
326
  status = x509parse_crtfile(self->cert, cert);
 
327
  if (status) {
 
328
    return -1;
 
329
  }
 
330
  return 0;
 
331
}
 
332
 
 
333
int
 
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)
 
338
{
 
339
  amqp_abort("%s is not implemented for PolarSSL", __func__);
 
340
  return -1;
 
341
}
 
342
 
 
343
void
 
344
amqp_ssl_socket_set_verify(amqp_socket_t *base,
 
345
                           amqp_boolean_t verify)
 
346
{
 
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);
 
350
  }
 
351
  self = (struct amqp_ssl_socket_t *)base;
 
352
  if (verify) {
 
353
    ssl_set_authmode(self->ssl, SSL_VERIFY_REQUIRED);
 
354
  } else {
 
355
    ssl_set_authmode(self->ssl, SSL_VERIFY_NONE);
 
356
  }
 
357
}
 
358
 
 
359
void
 
360
amqp_set_initialize_ssl_library(AMQP_UNUSED amqp_boolean_t do_initialize)
 
361
{
 
362
}