1 /* 2 * ustream-ssl - library for SSL over ustream 3 * 4 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <errno.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <libubox/ustream.h> 23 24 #include "ustream-ssl.h" 25 #include "ustream-internal.h" 26 27 static void ustream_ssl_error_cb(struct uloop_timeout *t) 28 { 29 struct ustream_ssl *us = container_of(t, struct ustream_ssl, error_timer); 30 static char buffer[128]; 31 int error = us->error; 32 33 if (us->notify_error) 34 us->notify_error(us, error, __ustream_ssl_strerror(us->error, buffer, sizeof(buffer))); 35 } 36 37 static void ustream_ssl_check_conn(struct ustream_ssl *us) 38 { 39 if (us->connected || us->error) 40 return; 41 42 if (__ustream_ssl_connect(us) == U_SSL_OK) { 43 44 /* __ustream_ssl_connect() will also return U_SSL_OK when certificate 45 * verification failed! 46 * 47 * Applications may register a custom .notify_verify_error callback in the 48 * struct ustream_ssl which is called upon verification failures, but there 49 * is no straight forward way for the callback to terminate the connection 50 * initiation right away, e.g. through a true or false return value. 51 * 52 * Instead, existing implementations appear to set .eof field of the underlying 53 * ustream in the hope that this inhibits further operations on the stream. 54 * 55 * Declare this informal behaviour "official" and check for the state of the 56 * .eof member after __ustream_ssl_connect() returned, and do not write the 57 * pending data if it is set to true. 58 */ 59 60 if (us->stream.eof) 61 return; 62 63 us->connected = true; 64 if (us->notify_connected) 65 us->notify_connected(us); 66 ustream_write_pending(&us->stream); 67 } 68 } 69 70 static bool __ustream_ssl_poll(struct ustream *s) 71 { 72 struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream); 73 char *buf; 74 int len, ret; 75 bool more = false; 76 77 ustream_ssl_check_conn(us); 78 if (!us->connected || us->error) 79 return false; 80 81 do { 82 buf = ustream_reserve(&us->stream, 1, &len); 83 if (!len) 84 break; 85 86 ret = __ustream_ssl_read(us, buf, len); 87 switch (ret) { 88 case U_SSL_PENDING: 89 return more; 90 case U_SSL_ERROR: 91 return false; 92 case 0: 93 us->stream.eof = true; 94 ustream_state_change(&us->stream); 95 return false; 96 default: 97 ustream_fill_read(&us->stream, ret); 98 more = true; 99 continue; 100 } 101 } while (1); 102 103 return more; 104 } 105 106 static void ustream_ssl_notify_read(struct ustream *s, int bytes) 107 { 108 __ustream_ssl_poll(s); 109 } 110 111 static void ustream_ssl_notify_write(struct ustream *s, int bytes) 112 { 113 struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream); 114 115 ustream_ssl_check_conn(us); 116 ustream_write_pending(s->next); 117 } 118 119 static void ustream_ssl_notify_state(struct ustream *s) 120 { 121 s->next->write_error = true; 122 ustream_state_change(s->next); 123 } 124 125 static int ustream_ssl_write(struct ustream *s, const char *buf, int len, bool more) 126 { 127 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream); 128 129 if (!us->connected || us->error) 130 return 0; 131 132 if (us->conn->w.data_bytes) 133 return 0; 134 135 return __ustream_ssl_write(us, buf, len); 136 } 137 138 static void ustream_ssl_set_read_blocked(struct ustream *s) 139 { 140 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream); 141 142 ustream_set_read_blocked(us->conn, !!s->read_blocked); 143 } 144 145 static void ustream_ssl_free(struct ustream *s) 146 { 147 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream); 148 149 if (us->conn) { 150 us->conn->next = NULL; 151 us->conn->notify_read = NULL; 152 us->conn->notify_write = NULL; 153 us->conn->notify_state = NULL; 154 } 155 156 uloop_timeout_cancel(&us->error_timer); 157 __ustream_ssl_session_free(us->ssl); 158 free(us->peer_cn); 159 160 us->ctx = NULL; 161 us->ssl = NULL; 162 us->conn = NULL; 163 us->peer_cn = NULL; 164 us->connected = false; 165 us->error = false; 166 us->valid_cert = false; 167 us->valid_cn = false; 168 } 169 170 static bool ustream_ssl_poll(struct ustream *s) 171 { 172 struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream); 173 bool fd_poll; 174 175 fd_poll = ustream_poll(us->conn); 176 return __ustream_ssl_poll(us->conn) || fd_poll; 177 } 178 179 static void ustream_ssl_stream_init(struct ustream_ssl *us) 180 { 181 struct ustream *conn = us->conn; 182 struct ustream *s = &us->stream; 183 184 conn->notify_read = ustream_ssl_notify_read; 185 conn->notify_write = ustream_ssl_notify_write; 186 conn->notify_state = ustream_ssl_notify_state; 187 188 s->free = ustream_ssl_free; 189 s->write = ustream_ssl_write; 190 s->poll = ustream_ssl_poll; 191 s->set_read_blocked = ustream_ssl_set_read_blocked; 192 ustream_init_defaults(s); 193 } 194 195 static int _ustream_ssl_init(struct ustream_ssl *us, struct ustream *conn, struct ustream_ssl_ctx *ctx, bool server) 196 { 197 us->error_timer.cb = ustream_ssl_error_cb; 198 us->server = server; 199 us->conn = conn; 200 us->ctx = ctx; 201 202 us->ssl = __ustream_ssl_session_new(us->ctx); 203 if (!us->ssl) 204 return -ENOMEM; 205 206 conn->next = &us->stream; 207 ustream_set_io(ctx, us->ssl, conn); 208 ustream_ssl_stream_init(us); 209 210 if (us->server_name) 211 __ustream_ssl_set_server_name(us); 212 213 ustream_ssl_check_conn(us); 214 215 return 0; 216 } 217 218 static int _ustream_ssl_set_peer_cn(struct ustream_ssl *us, const char *name) 219 { 220 us->peer_cn = strdup(name); 221 __ustream_ssl_update_peer_cn(us); 222 223 return 0; 224 } 225 226 const struct ustream_ssl_ops ustream_ssl_ops = { 227 .context_new = __ustream_ssl_context_new, 228 .context_set_crt_file = __ustream_ssl_set_crt_file, 229 .context_set_key_file = __ustream_ssl_set_key_file, 230 .context_add_ca_crt_file = __ustream_ssl_add_ca_crt_file, 231 .context_set_ciphers = __ustream_ssl_set_ciphers, 232 .context_set_require_validation = __ustream_ssl_set_require_validation, 233 .context_free = __ustream_ssl_context_free, 234 .init = _ustream_ssl_init, 235 .set_peer_cn = _ustream_ssl_set_peer_cn, 236 }; 237
This page was automatically generated by LXR 0.3.1. • OpenWrt