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 <sys/types.h> 20 #include <fcntl.h> 21 #include <unistd.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "ustream-ssl.h" 26 #include "ustream-internal.h" 27 28 static int urandom_fd = -1; 29 30 static int s_ustream_read(void *ctx, unsigned char *buf, size_t len) 31 { 32 struct ustream *s = ctx; 33 char *sbuf; 34 int slen; 35 36 if (s->eof) 37 return 0; 38 39 sbuf = ustream_get_read_buf(s, &slen); 40 if ((size_t) slen > len) 41 slen = len; 42 43 if (!slen) 44 return MBEDTLS_ERR_SSL_WANT_READ; 45 46 memcpy(buf, sbuf, slen); 47 ustream_consume(s, slen); 48 49 return slen; 50 } 51 52 static int s_ustream_write(void *ctx, const unsigned char *buf, size_t len) 53 { 54 struct ustream *s = ctx; 55 int ret; 56 57 ret = ustream_write(s, (const char *) buf, len, false); 58 if (ret < 0 || s->write_error) 59 return MBEDTLS_ERR_NET_SEND_FAILED; 60 61 return ret; 62 } 63 64 __hidden void ustream_set_io(struct ustream_ssl_ctx *ctx, void *ssl, struct ustream *conn) 65 { 66 mbedtls_ssl_set_bio(ssl, conn, s_ustream_write, s_ustream_read, NULL); 67 } 68 69 static bool urandom_init(void) 70 { 71 if (urandom_fd > -1) 72 return true; 73 74 urandom_fd = open("/dev/urandom", O_RDONLY); 75 if (urandom_fd < 0) 76 return false; 77 78 return true; 79 } 80 81 static int _urandom(void *ctx, unsigned char *out, size_t len) 82 { 83 if (read(urandom_fd, out, len) < 0) 84 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 85 86 return 0; 87 } 88 89 #define AES_GCM_CIPHERS(v) \ 90 MBEDTLS_TLS_##v##_WITH_AES_128_GCM_SHA256, \ 91 MBEDTLS_TLS_##v##_WITH_AES_256_GCM_SHA384 92 93 #define AES_CBC_CIPHERS(v) \ 94 MBEDTLS_TLS_##v##_WITH_AES_128_CBC_SHA, \ 95 MBEDTLS_TLS_##v##_WITH_AES_256_CBC_SHA 96 97 #define AES_CIPHERS(v) \ 98 AES_GCM_CIPHERS(v), \ 99 AES_CBC_CIPHERS(v) 100 101 static const int default_ciphersuites_server[] = 102 { 103 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 104 AES_GCM_CIPHERS(ECDHE_ECDSA), 105 MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 106 AES_GCM_CIPHERS(ECDHE_RSA), 107 AES_CBC_CIPHERS(ECDHE_RSA), 108 AES_CIPHERS(RSA), 109 0 110 }; 111 112 static const int default_ciphersuites_client[] = 113 { 114 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 115 AES_GCM_CIPHERS(ECDHE_ECDSA), 116 MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 117 AES_GCM_CIPHERS(ECDHE_RSA), 118 MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 119 AES_GCM_CIPHERS(DHE_RSA), 120 AES_CBC_CIPHERS(ECDHE_ECDSA), 121 AES_CBC_CIPHERS(ECDHE_RSA), 122 AES_CBC_CIPHERS(DHE_RSA), 123 MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 124 AES_CIPHERS(RSA), 125 MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, 126 0 127 }; 128 129 130 __hidden struct ustream_ssl_ctx * 131 __ustream_ssl_context_new(bool server) 132 { 133 struct ustream_ssl_ctx *ctx; 134 mbedtls_ssl_config *conf; 135 int ep; 136 137 if (!urandom_init()) 138 return NULL; 139 140 ctx = calloc(1, sizeof(*ctx)); 141 if (!ctx) 142 return NULL; 143 144 ctx->server = server; 145 mbedtls_pk_init(&ctx->key); 146 mbedtls_x509_crt_init(&ctx->cert); 147 mbedtls_x509_crt_init(&ctx->ca_cert); 148 149 #if defined(MBEDTLS_SSL_CACHE_C) 150 mbedtls_ssl_cache_init(&ctx->cache); 151 mbedtls_ssl_cache_set_timeout(&ctx->cache, 30 * 60); 152 mbedtls_ssl_cache_set_max_entries(&ctx->cache, 5); 153 #endif 154 155 conf = &ctx->conf; 156 mbedtls_ssl_config_init(conf); 157 158 ep = server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT; 159 160 mbedtls_ssl_config_defaults(conf, ep, MBEDTLS_SSL_TRANSPORT_STREAM, 161 MBEDTLS_SSL_PRESET_DEFAULT); 162 mbedtls_ssl_conf_rng(conf, _urandom, NULL); 163 164 if (server) { 165 mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE); 166 mbedtls_ssl_conf_ciphersuites(conf, default_ciphersuites_server); 167 mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, 168 MBEDTLS_SSL_MINOR_VERSION_3); 169 } else { 170 mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_OPTIONAL); 171 mbedtls_ssl_conf_ciphersuites(conf, default_ciphersuites_client); 172 } 173 174 #if defined(MBEDTLS_SSL_CACHE_C) 175 mbedtls_ssl_conf_session_cache(conf, &ctx->cache, 176 mbedtls_ssl_cache_get, 177 mbedtls_ssl_cache_set); 178 #endif 179 return ctx; 180 } 181 182 static void ustream_ssl_update_own_cert(struct ustream_ssl_ctx *ctx) 183 { 184 if (!ctx->cert.version) 185 return; 186 187 if (!ctx->key.pk_info) 188 return; 189 190 mbedtls_ssl_conf_own_cert(&ctx->conf, &ctx->cert, &ctx->key); 191 } 192 193 __hidden int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx *ctx, const char *file) 194 { 195 int ret; 196 197 ret = mbedtls_x509_crt_parse_file(&ctx->ca_cert, file); 198 if (ret) 199 return -1; 200 201 mbedtls_ssl_conf_ca_chain(&ctx->conf, &ctx->ca_cert, NULL); 202 mbedtls_ssl_conf_authmode(&ctx->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); 203 return 0; 204 } 205 206 __hidden int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx *ctx, const char *file) 207 { 208 int ret; 209 210 ret = mbedtls_x509_crt_parse_file(&ctx->cert, file); 211 if (ret) 212 return -1; 213 214 ustream_ssl_update_own_cert(ctx); 215 return 0; 216 } 217 218 __hidden int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char *file) 219 { 220 int ret; 221 222 ret = mbedtls_pk_parse_keyfile(&ctx->key, file, NULL); 223 if (ret) 224 return -1; 225 226 ustream_ssl_update_own_cert(ctx); 227 return 0; 228 } 229 230 __hidden int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *ciphers) 231 { 232 int *ciphersuites = NULL, *tmp, id; 233 char *cipherstr, *p, *last, c; 234 size_t len = 0; 235 236 if (ciphers == NULL) 237 return -1; 238 239 cipherstr = strdup(ciphers); 240 241 if (cipherstr == NULL) 242 return -1; 243 244 for (p = cipherstr, last = p;; p++) { 245 if (*p == ':' || *p == 0) { 246 c = *p; 247 *p = 0; 248 249 id = mbedtls_ssl_get_ciphersuite_id(last); 250 251 if (id != 0) { 252 tmp = realloc(ciphersuites, (len + 2) * sizeof(int)); 253 254 if (tmp == NULL) { 255 free(ciphersuites); 256 free(cipherstr); 257 258 return -1; 259 } 260 261 ciphersuites = tmp; 262 ciphersuites[len++] = id; 263 ciphersuites[len] = 0; 264 } 265 266 if (c == 0) 267 break; 268 269 last = p + 1; 270 } 271 272 /* 273 * mbedTLS expects cipher names with dashes while many sources elsewhere 274 * like the Firefox wiki or Wireshark specify ciphers with underscores, 275 * so simply convert all underscores to dashes to accept both notations. 276 */ 277 else if (*p == '_') { 278 *p = '-'; 279 } 280 } 281 282 free(cipherstr); 283 284 if (len == 0) 285 return -1; 286 287 mbedtls_ssl_conf_ciphersuites(&ctx->conf, ciphersuites); 288 free(ctx->ciphersuites); 289 290 ctx->ciphersuites = ciphersuites; 291 292 return 0; 293 } 294 295 __hidden int __ustream_ssl_set_require_validation(struct ustream_ssl_ctx *ctx, bool require) 296 { 297 int mode = MBEDTLS_SSL_VERIFY_OPTIONAL; 298 299 if (!require) 300 mode = MBEDTLS_SSL_VERIFY_NONE; 301 302 mbedtls_ssl_conf_authmode(&ctx->conf, mode); 303 304 return 0; 305 } 306 307 __hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx) 308 { 309 #if defined(MBEDTLS_SSL_CACHE_C) 310 mbedtls_ssl_cache_free(&ctx->cache); 311 #endif 312 mbedtls_pk_free(&ctx->key); 313 mbedtls_x509_crt_free(&ctx->ca_cert); 314 mbedtls_x509_crt_free(&ctx->cert); 315 mbedtls_ssl_config_free(&ctx->conf); 316 free(ctx->ciphersuites); 317 free(ctx); 318 } 319 320 static void ustream_ssl_error(struct ustream_ssl *us, int ret) 321 { 322 us->error = ret; 323 uloop_timeout_set(&us->error_timer, 0); 324 } 325 326 static bool ssl_do_wait(int ret) 327 { 328 switch(ret) { 329 case MBEDTLS_ERR_SSL_WANT_READ: 330 case MBEDTLS_ERR_SSL_WANT_WRITE: 331 return true; 332 default: 333 return false; 334 } 335 } 336 337 static void ustream_ssl_verify_cert(struct ustream_ssl *us) 338 { 339 void *ssl = us->ssl; 340 const char *msg = NULL; 341 bool cn_mismatch; 342 int r; 343 344 r = mbedtls_ssl_get_verify_result(ssl); 345 cn_mismatch = r & MBEDTLS_X509_BADCERT_CN_MISMATCH; 346 r &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH; 347 348 if (r & MBEDTLS_X509_BADCERT_EXPIRED) 349 msg = "certificate has expired"; 350 else if (r & MBEDTLS_X509_BADCERT_REVOKED) 351 msg = "certificate has been revoked"; 352 else if (r & MBEDTLS_X509_BADCERT_NOT_TRUSTED) 353 msg = "certificate is self-signed or not signed by a trusted CA"; 354 else 355 msg = "unknown error"; 356 357 if (r) { 358 if (us->notify_verify_error) 359 us->notify_verify_error(us, r, msg); 360 return; 361 } 362 363 if (!cn_mismatch) 364 us->valid_cn = true; 365 } 366 367 __hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us) 368 { 369 void *ssl = us->ssl; 370 int r; 371 372 r = mbedtls_ssl_handshake(ssl); 373 if (r == 0) { 374 ustream_ssl_verify_cert(us); 375 return U_SSL_OK; 376 } 377 378 if (ssl_do_wait(r)) 379 return U_SSL_PENDING; 380 381 ustream_ssl_error(us, r); 382 return U_SSL_ERROR; 383 } 384 385 __hidden int __ustream_ssl_write(struct ustream_ssl *us, const char *buf, int len) 386 { 387 void *ssl = us->ssl; 388 int done = 0, ret = 0; 389 390 while (done != len) { 391 ret = mbedtls_ssl_write(ssl, (const unsigned char *) buf + done, len - done); 392 393 if (ret < 0) { 394 if (ssl_do_wait(ret)) 395 return done; 396 397 ustream_ssl_error(us, ret); 398 return -1; 399 } 400 401 done += ret; 402 } 403 404 return done; 405 } 406 407 __hidden int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len) 408 { 409 int ret = mbedtls_ssl_read(us->ssl, (unsigned char *) buf, len); 410 411 if (ret < 0) { 412 if (ssl_do_wait(ret)) 413 return U_SSL_PENDING; 414 415 if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) 416 return 0; 417 418 ustream_ssl_error(us, ret); 419 return U_SSL_ERROR; 420 } 421 422 return ret; 423 } 424 425 __hidden void *__ustream_ssl_session_new(struct ustream_ssl_ctx *ctx) 426 { 427 mbedtls_ssl_context *ssl; 428 429 ssl = calloc(1, sizeof(*ssl)); 430 if (!ssl) 431 return NULL; 432 433 mbedtls_ssl_init(ssl); 434 435 if (mbedtls_ssl_setup(ssl, &ctx->conf)) { 436 free(ssl); 437 return NULL; 438 } 439 440 return ssl; 441 } 442 443 __hidden void __ustream_ssl_session_free(void *ssl) 444 { 445 mbedtls_ssl_free(ssl); 446 free(ssl); 447 } 448
This page was automatically generated by LXR 0.3.1. • OpenWrt