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 <string.h> 20 #include <ctype.h> 21 #include "ustream-ssl.h" 22 #include "ustream-internal.h" 23 24 #if !defined(HAVE_WOLFSSL) 25 #include <openssl/x509v3.h> 26 #endif 27 28 #if defined(HAVE_WOLFSSL) && defined(DEBUG) 29 #include <wolfssl/test.h> 30 #endif 31 32 /* Ciphersuite preference: 33 * - for server, no weak ciphers are used if you use an ECDSA key. 34 * - forward-secret (pfs), authenticated (AEAD) ciphers are at the top: 35 * chacha20-poly1305, the fastest in software, 256-bits 36 * aes128-gcm, 128-bits 37 * aes256-gcm, 256-bits 38 * - key exchange: prefer ECDHE, then DHE (client only) 39 * - forward-secret ECDSA CBC ciphers (client-only) 40 * - forward-secret RSA CBC ciphers 41 * - non-pfs ciphers 42 * aes128, aes256, 3DES(client only) 43 */ 44 45 #ifdef WOLFSSL_SSL_H 46 # define top_ciphers \ 47 "TLS13-CHACHA20-POLY1305-SHA256:" \ 48 "TLS13-AES128-GCM-SHA256:" \ 49 "TLS13-AES256-GCM-SHA384:" \ 50 ecdhe_aead_ciphers 51 #else 52 # define tls13_ciphersuites "TLS_CHACHA20_POLY1305_SHA256:" \ 53 "TLS_AES_128_GCM_SHA256:" \ 54 "TLS_AES_256_GCM_SHA384" 55 56 # define top_ciphers \ 57 ecdhe_aead_ciphers 58 #endif 59 60 #define ecdhe_aead_ciphers \ 61 "ECDHE-ECDSA-CHACHA20-POLY1305:" \ 62 "ECDHE-ECDSA-AES128-GCM-SHA256:" \ 63 "ECDHE-ECDSA-AES256-GCM-SHA384:" \ 64 "ECDHE-RSA-CHACHA20-POLY1305:" \ 65 "ECDHE-RSA-AES128-GCM-SHA256:" \ 66 "ECDHE-RSA-AES256-GCM-SHA384" 67 68 #define dhe_aead_ciphers \ 69 "DHE-RSA-CHACHA20-POLY1305:" \ 70 "DHE-RSA-AES128-GCM-SHA256:" \ 71 "DHE-RSA-AES256-GCM-SHA384" 72 73 #define ecdhe_ecdsa_cbc_ciphers \ 74 "ECDHE-ECDSA-AES128-SHA:" \ 75 "ECDHE-ECDSA-AES256-SHA" 76 77 #define ecdhe_rsa_cbc_ciphers \ 78 "ECDHE-RSA-AES128-SHA:" \ 79 "ECDHE-RSA-AES256-SHA" 80 81 #define dhe_cbc_ciphers \ 82 "DHE-RSA-AES128-SHA:" \ 83 "DHE-RSA-AES256-SHA:" \ 84 "DHE-DES-CBC3-SHA" 85 86 #define non_pfs_aes \ 87 "AES128-GCM-SHA256:" \ 88 "AES256-GCM-SHA384:" \ 89 "AES128-SHA:" \ 90 "AES256-SHA" 91 92 #define server_cipher_list \ 93 top_ciphers ":" \ 94 ecdhe_rsa_cbc_ciphers ":" \ 95 non_pfs_aes 96 97 #define client_cipher_list \ 98 top_ciphers ":" \ 99 dhe_aead_ciphers ":" \ 100 ecdhe_ecdsa_cbc_ciphers ":" \ 101 ecdhe_rsa_cbc_ciphers ":" \ 102 dhe_cbc_ciphers ":" \ 103 non_pfs_aes ":" \ 104 "DES-CBC3-SHA" 105 106 __hidden struct ustream_ssl_ctx * 107 __ustream_ssl_context_new(bool server) 108 { 109 struct ustream_ssl_ctx *ctx; 110 const void *m; 111 SSL_CTX *c; 112 113 #if OPENSSL_VERSION_NUMBER < 0x10100000L 114 static bool _init = false; 115 116 if (!_init) { 117 SSL_load_error_strings(); 118 SSL_library_init(); 119 _init = true; 120 } 121 # ifndef TLS_server_method 122 # define TLS_server_method SSLv23_server_method 123 # endif 124 # ifndef TLS_client_method 125 # define TLS_client_method SSLv23_client_method 126 # endif 127 #endif 128 129 if (server) { 130 m = TLS_server_method(); 131 } else 132 m = TLS_client_method(); 133 134 c = SSL_CTX_new((void *) m); 135 if (!c) 136 return NULL; 137 138 ctx = calloc(1, sizeof(*ctx)); 139 ctx->ssl = c; 140 141 #if defined(HAVE_WOLFSSL) 142 if (server) 143 SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL); 144 else 145 SSL_CTX_set_verify(c, SSL_VERIFY_PEER, NULL); 146 #else 147 SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL); 148 #endif 149 150 SSL_CTX_set_options(c, SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_ECDH_USE | 151 SSL_OP_CIPHER_SERVER_PREFERENCE); 152 #if defined(SSL_CTX_set_ecdh_auto) && OPENSSL_VERSION_NUMBER < 0x10100000L 153 SSL_CTX_set_ecdh_auto(c, 1); 154 #elif OPENSSL_VERSION_NUMBER >= 0x10101000L 155 SSL_CTX_set_ciphersuites(c, tls13_ciphersuites); 156 #endif 157 if (server) { 158 #if OPENSSL_VERSION_NUMBER >= 0x10100000L 159 SSL_CTX_set_min_proto_version(c, TLS1_2_VERSION); 160 #else 161 SSL_CTX_set_options(c, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | 162 SSL_OP_NO_TLSv1_1); 163 #endif 164 #if defined(HAVE_WOLFSSL) 165 SSL_CTX_set_options(c, SSL_AD_NO_RENEGOTIATION); 166 #else 167 SSL_CTX_set_options(c, SSL_OP_NO_RENEGOTIATION); 168 #endif 169 170 SSL_CTX_set_cipher_list(c, server_cipher_list); 171 } else { 172 SSL_CTX_set_cipher_list(c, client_cipher_list); 173 } 174 SSL_CTX_set_quiet_shutdown(c, 1); 175 176 return ctx; 177 } 178 179 __hidden int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx *ctx, const char *file) 180 { 181 int ret; 182 183 ret = SSL_CTX_load_verify_locations(ctx->ssl, file, NULL); 184 if (ret < 1) 185 return -1; 186 187 return 0; 188 } 189 190 __hidden int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx *ctx, const char *file) 191 { 192 int ret; 193 194 ret = SSL_CTX_use_certificate_chain_file(ctx->ssl, file); 195 if (ret < 1) 196 ret = SSL_CTX_use_certificate_file(ctx->ssl, file, SSL_FILETYPE_ASN1); 197 198 if (ret < 1) 199 return -1; 200 201 return 0; 202 } 203 204 __hidden int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char *file) 205 { 206 int ret; 207 208 ret = SSL_CTX_use_PrivateKey_file(ctx->ssl, file, SSL_FILETYPE_PEM); 209 if (ret < 1) 210 ret = SSL_CTX_use_PrivateKey_file(ctx->ssl, file, SSL_FILETYPE_ASN1); 211 212 if (ret < 1) 213 return -1; 214 215 return 0; 216 } 217 218 __hidden int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *ciphers) 219 { 220 int ret = SSL_CTX_set_cipher_list(ctx->ssl, ciphers); 221 222 if (ret == 0) 223 return -1; 224 225 return 0; 226 } 227 228 __hidden int __ustream_ssl_set_require_validation(struct ustream_ssl_ctx *ctx, bool require) 229 { 230 int mode = SSL_VERIFY_PEER; 231 232 if (!require) 233 mode = SSL_VERIFY_NONE; 234 235 SSL_CTX_set_verify(ctx->ssl, mode, NULL); 236 237 return 0; 238 } 239 240 __hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx) 241 { 242 SSL_CTX_free(ctx->ssl); 243 if (ctx->debug_bio) 244 BIO_free(ctx->debug_bio); 245 free(ctx); 246 } 247 248 __hidden void __ustream_ssl_session_free(struct ustream_ssl *us) 249 { 250 BIO *bio = SSL_get_wbio(us->ssl); 251 struct bio_ctx *ctx; 252 253 SSL_shutdown(us->ssl); 254 SSL_free(us->ssl); 255 256 if (!us->conn) 257 return; 258 259 ctx = BIO_get_data(bio); 260 if (ctx) { 261 BIO_meth_free(ctx->meth); 262 free(ctx); 263 } 264 } 265 266 static void ustream_ssl_error(struct ustream_ssl *us, int ret) 267 { 268 us->error = ret; 269 uloop_timeout_set(&us->error_timer, 0); 270 } 271 272 static bool ustream_ssl_verify_cn(struct ustream_ssl *us, X509 *cert) 273 { 274 int ret; 275 276 if (!us->peer_cn) 277 return false; 278 279 # ifndef WOLFSSL_OPENSSL_H_ 280 ret = X509_check_host(cert, us->peer_cn, 0, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS, NULL); 281 # else 282 ret = wolfSSL_X509_check_host(cert, us->peer_cn, 0, 0, NULL); 283 # endif 284 return ret == 1; 285 } 286 287 static void ustream_ssl_verify_cert(struct ustream_ssl *us) 288 { 289 void *ssl = us->ssl; 290 X509 *cert; 291 int res; 292 293 #if defined(HAVE_WOLFSSL) && defined(DEBUG) 294 showPeer(ssl); 295 #endif 296 297 res = SSL_get_verify_result(ssl); 298 if (res != X509_V_OK) { 299 if (us->notify_verify_error) 300 us->notify_verify_error(us, res, X509_verify_cert_error_string(res)); 301 return; 302 } 303 304 #if defined(HAVE_WOLFSSL) 305 cert = SSL_get_peer_certificate(ssl); 306 #else 307 cert = SSL_get1_peer_certificate(ssl); 308 #endif 309 if (!cert) 310 return; 311 312 us->valid_cert = true; 313 us->valid_cn = ustream_ssl_verify_cn(us, cert); 314 315 X509_free(cert); 316 } 317 318 #ifdef WOLFSSL_SSL_H 319 static bool handle_wolfssl_asn_error(struct ustream_ssl *us, int r) 320 { 321 switch (r) { 322 case ASN_PARSE_E: 323 case ASN_VERSION_E: 324 case ASN_GETINT_E: 325 case ASN_RSA_KEY_E: 326 case ASN_OBJECT_ID_E: 327 case ASN_TAG_NULL_E: 328 case ASN_EXPECT_0_E: 329 case ASN_BITSTR_E: 330 case ASN_UNKNOWN_OID_E: 331 case ASN_DATE_SZ_E: 332 case ASN_BEFORE_DATE_E: 333 case ASN_AFTER_DATE_E: 334 case ASN_SIG_OID_E: 335 case ASN_TIME_E: 336 case ASN_INPUT_E: 337 case ASN_SIG_CONFIRM_E: 338 case ASN_SIG_HASH_E: 339 case ASN_SIG_KEY_E: 340 case ASN_DH_KEY_E: 341 #if LIBWOLFSSL_VERSION_HEX < 0x05000000 342 case ASN_NTRU_KEY_E: 343 #endif 344 case ASN_CRIT_EXT_E: 345 case ASN_ALT_NAME_E: 346 case ASN_NO_PEM_HEADER: 347 case ASN_ECC_KEY_E: 348 case ASN_NO_SIGNER_E: 349 case ASN_CRL_CONFIRM_E: 350 case ASN_CRL_NO_SIGNER_E: 351 case ASN_OCSP_CONFIRM_E: 352 case ASN_NAME_INVALID_E: 353 case ASN_NO_SKID: 354 case ASN_NO_AKID: 355 case ASN_NO_KEYUSAGE: 356 case ASN_COUNTRY_SIZE_E: 357 case ASN_PATHLEN_SIZE_E: 358 case ASN_PATHLEN_INV_E: 359 case ASN_SELF_SIGNED_E: 360 if (us->notify_verify_error) 361 us->notify_verify_error(us, r, wc_GetErrorString(r)); 362 return true; 363 } 364 365 return false; 366 } 367 #endif 368 369 __hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us) 370 { 371 void *ssl = us->ssl; 372 int r; 373 374 ERR_clear_error(); 375 376 if (us->server) 377 r = SSL_accept(ssl); 378 else 379 r = SSL_connect(ssl); 380 381 if (r == 1) { 382 ustream_ssl_verify_cert(us); 383 return U_SSL_OK; 384 } 385 386 r = SSL_get_error(ssl, r); 387 if (r == SSL_ERROR_WANT_READ || r == SSL_ERROR_WANT_WRITE) 388 return U_SSL_PENDING; 389 390 #ifdef WOLFSSL_SSL_H 391 if (handle_wolfssl_asn_error(us, r)) 392 return U_SSL_OK; 393 #endif 394 395 ustream_ssl_error(us, r); 396 return U_SSL_ERROR; 397 } 398 399 __hidden int __ustream_ssl_write(struct ustream_ssl *us, const char *buf, int len) 400 { 401 void *ssl = us->ssl; 402 int ret; 403 404 ERR_clear_error(); 405 406 ret = SSL_write(ssl, buf, len); 407 408 if (ret < 0) { 409 int err = SSL_get_error(ssl, ret); 410 if (err == SSL_ERROR_WANT_WRITE) 411 return 0; 412 413 ustream_ssl_error(us, err); 414 return -1; 415 } 416 417 return ret; 418 } 419 420 __hidden int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len) 421 { 422 int ret; 423 424 ERR_clear_error(); 425 426 ret = SSL_read(us->ssl, buf, len); 427 428 if (ret < 0) { 429 ret = SSL_get_error(us->ssl, ret); 430 if (ret == SSL_ERROR_WANT_READ) 431 return U_SSL_PENDING; 432 433 ustream_ssl_error(us, ret); 434 return U_SSL_ERROR; 435 } 436 437 return ret; 438 } 439 440 #ifndef WOLFSSL_SSL_H 441 static long 442 debug_cb(BIO *bio, int cmd, const char *argp, size_t len, int argi, long argl, 443 int ret, size_t *processed) 444 { 445 struct ustream_ssl_ctx *ctx = (void *)BIO_get_callback_arg(bio); 446 char buf[256]; 447 char *str, *sep; 448 ssize_t cur_len; 449 450 if (cmd != (BIO_CB_WRITE|BIO_CB_RETURN)) 451 goto out; 452 453 while (1) { 454 cur_len = BIO_get_mem_data(bio, (void *)&str); 455 if (!cur_len) 456 break; 457 458 sep = memchr(str, '\n', cur_len); 459 if (!sep) 460 break; 461 462 cur_len = sep + 1 - str; 463 if (cur_len >= (ssize_t)sizeof(buf)) 464 cur_len = sizeof(buf) - 1; 465 466 cur_len = BIO_read(bio, buf, cur_len); 467 if (cur_len <= 1) 468 break; 469 470 cur_len--; 471 buf[cur_len] = 0; 472 if (ctx->debug_cb) 473 ctx->debug_cb(ctx->debug_cb_priv, 1, buf); 474 } 475 476 out: 477 return ret; 478 } 479 #endif 480 481 __hidden void __ustream_ssl_set_debug(struct ustream_ssl_ctx *ctx, int level, 482 ustream_ssl_debug_cb cb, void *cb_priv) 483 { 484 #ifndef WOLFSSL_SSL_H 485 if (!ctx->debug_bio) 486 ctx->debug_bio = BIO_new(BIO_s_mem()); 487 488 ctx->debug_cb = cb; 489 ctx->debug_cb_priv = cb_priv; 490 SSL_CTX_set_msg_callback(ctx->ssl, SSL_trace); 491 SSL_CTX_set_msg_callback_arg(ctx->ssl, ctx->debug_bio); 492 493 BIO_set_callback_ex(ctx->debug_bio, debug_cb); 494 BIO_set_callback_arg(ctx->debug_bio, (void *)ctx); 495 #endif 496 } 497
This page was automatically generated by LXR 0.3.1. • OpenWrt