├── .gitignore ├── openssl_bio_compat.h ├── .gitlab-ci.yml ├── example.crt ├── example.key ├── ustream-openssl.h ├── CMakeLists.txt ├── ustream-mbedtls.h ├── ustream-io-wolfssl.c ├── ustream-internal.h ├── ustream-ssl.h ├── ustream-io-openssl.c ├── ustream-example-client.c ├── ustream-example-server.c ├── ustream-ssl.c ├── ustream-openssl.c └── ustream-mbedtls.c /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | CMakeCache.txt 3 | CMakeFiles 4 | *.cmake 5 | *.a 6 | *.so 7 | *.dylib 8 | install_manifest.txt 9 | ustream-example-client 10 | ustream-example-server 11 | -------------------------------------------------------------------------------- /openssl_bio_compat.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENSSL_BIO_COMPAT_H 2 | #define OPENSSL_BIO_COMPAT_H 3 | 4 | #include 5 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 6 | 7 | #include 8 | #include 9 | 10 | #define BIO_get_data(b) (b->ptr) 11 | #define BIO_set_data(b, v) (b->ptr = v) 12 | #define BIO_set_init(b, v) (b->init = v) 13 | #define BIO_meth_set_write(m, f) (m->bwrite = f) 14 | #define BIO_meth_set_read(m, f) (m->bread = f) 15 | #define BIO_meth_set_puts(m, f) (m->bputs = f) 16 | #define BIO_meth_set_gets(m, f) (m->bgets = f) 17 | #define BIO_meth_set_ctrl(m, f) (m->ctrl = f) 18 | #define BIO_meth_set_create(m, f) (m->create = f) 19 | #define BIO_meth_set_destroy(m, f) (m->destroy = f) 20 | 21 | static inline BIO_METHOD *BIO_meth_new(int type, const char *name) 22 | { 23 | BIO_METHOD *bm = calloc(1, sizeof(BIO_METHOD)); 24 | if (bm) { 25 | bm->type = type; 26 | bm->name = name; 27 | } 28 | return bm; 29 | } 30 | 31 | #endif /* OPENSSL_VERSION_NUMBER */ 32 | 33 | #endif /* OPENSSL_BIO_COMPAT_H */ 34 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | CI_TARGET_BUILD_DEPENDS: libubox openssl 3 | 4 | include: 5 | - remote: https://gitlab.com/ynezz/openwrt-ci/raw/master/openwrt-ci/gitlab/main.yml 6 | 7 | various native checks with ustream-ssl/OpenSSL backend: 8 | extends: .openwrt-native-build 9 | 10 | various native checks with ustream-ssl/mbedTLS backend: 11 | extends: .openwrt-native-build 12 | variables: 13 | CI_CMAKE_EXTRA_BUILD_ARGS: -DMBEDTLS=on 14 | 15 | various native checks with ustream-ssl/wolfSSL backend: 16 | extends: .openwrt-native-build 17 | variables: 18 | CI_CMAKE_EXTRA_BUILD_ARGS: -DWOLFSSL=on 19 | 20 | build with Atheros ATH79 SDK (out of tree): 21 | extends: .openwrt-sdk-oot-build_ath79-generic 22 | 23 | build with Freescale i.MX Cortex-A9 SDK (out of tree): 24 | extends: .openwrt-sdk-oot-build_imx-cortexa9 25 | 26 | build with MIPS Malta CoreLV BE SDK (out of tree): 27 | extends: .openwrt-sdk-oot-build_malta-be 28 | 29 | build with Marvell Armada Cortex A-53 SDK (out of tree): 30 | extends: .openwrt-sdk-oot-build_mvebu-cortexa53 31 | -------------------------------------------------------------------------------- /example.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICujCCAaKgAwIBAgIUFbx+9AS987R558tX05mGOXzSqN8wDQYJKoZIhvcNAQEL 3 | BQAwFjEUMBIGA1UEAwwLZm9vQGJhci5jb20wIBcNMTkwOTE4MTczMTI3WhgPMjEx 4 | OTA5MTkxNzMxMjdaMBYxFDASBgNVBAMMC2Zvb0BiYXIuY29tMIIBIjANBgkqhkiG 5 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnvZT9GbaEiwcDFNl7cNSSvzK2cvQr1QmtpmF 6 | VEMeLPwXRxnvEJNvRMFXGWCYhmKMakdOdgcqKM8c6j5TbphYtGAXQRXGV3y0+1wW 7 | StTTaAkIIaarhZpmwgrT6agPYXUzXqhtOk8VmSwlUif/nQFYnOezgd9MR8Fo+Min 8 | YZJPAMWs7yUzQzCgq0S2YguVPUQ/NiXeNzRpxrl42Gh5kotd2RlJ8Ue7oxPOZs4W 9 | L7UH8hBZeRQj3CzWpI5fqOwmozl1LW8GUd91E4+YR+Hm043huhNjvwbA2asIduqd 10 | wXHcVDvKQXwuSojwC9Uo4eN/dMNSZd7q4k0gu3QmgNJZIMbO7QIDAQABMA0GCSqG 11 | SIb3DQEBCwUAA4IBAQAzNar5A+k6fHh3aGw3KB5/4jE7UxRAvTk9mp69/uc4V+qj 12 | oWEtGqP4nPmfL4+nFwoJJ5hvSWzRFvXRr2AtURMV/1anQk41gcMb3G7lNDC+X/zf 13 | t+xPx75O4heIALW84gdHZ7MY7guEFiLfprnX1l65uJeYvrKeG3cHY0YlDd2WFZGF 14 | DLPK61P/wGfOL4U1oDQF2rb09Wwx3rV8IfyPYu6ZTS+u6P43kF/4w+EJHexKhNyX 15 | Utym2sK05eMUWnraZouTeoRri2wvvjmIPZyldNsJ5HI6hU7fhT0B/BjJMrDXWRRS 16 | w72acdYB9pcu+2ABAKIwn07keYntiE4TjG9vBYqJ 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /example.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCe9lP0ZtoSLBwM 3 | U2Xtw1JK/MrZy9CvVCa2mYVUQx4s/BdHGe8Qk29EwVcZYJiGYoxqR052Byoozxzq 4 | PlNumFi0YBdBFcZXfLT7XBZK1NNoCQghpquFmmbCCtPpqA9hdTNeqG06TxWZLCVS 5 | J/+dAVic57OB30xHwWj4yKdhkk8AxazvJTNDMKCrRLZiC5U9RD82Jd43NGnGuXjY 6 | aHmSi13ZGUnxR7ujE85mzhYvtQfyEFl5FCPcLNakjl+o7CajOXUtbwZR33UTj5hH 7 | 4ebTjeG6E2O/BsDZqwh26p3BcdxUO8pBfC5KiPAL1Sjh4390w1Jl3uriTSC7dCaA 8 | 0lkgxs7tAgMBAAECggEAFPk9VIbpiPJG9R1f2oIl7nzyKtBohWmd/gO9gsOkTJ0q 9 | WRhD4bUCPlkgK9oB5eFE05T69jm1x1KkZwe4LGRvd8Uh7FV6KPrsSin5SwBPsG9Y 10 | olACW4tmuX2CPlcNSHeVQo0IdGQQ3nfjqLZcVJPj5DfyCFW1E9aiCgk3hHkwcVJu 11 | ZJIqYyHfnRzVsTZrZZjYoeYWg1+oNozW3nlzs0CWi9hRGq9I1fASm1LMRDITgFpW 12 | 8zXSrvKY4WALCaqCX1vFBfo/f3pmm0SIom4apTvyH+U+tHFmJofP0Y49cDc/ngHe 13 | fbug/Od5ScfDTu111Fqb5NWz8ju6B7odhBj1RFvWIQKBgQDMzXOOZ969AjEyRsaH 14 | 1aG+MNEwU32fSHhiDr7vGTgeAf2Zn2b0/NLxxn5l7dF6t0bvo5hNCIa4q0YTuv62 15 | grtssbOvKFGb+xdQufYH6gRMFjjGs83QYXoDpDNHjdscBjaTy9aEoo1wUQbYfAaF 16 | 4zZqLKQB0Crfaj28lwXqDaCMdQKBgQDGs0cnWX3NTwCpu+CF7czkeUZWgnRWq3Xk 17 | oGHrcPAx4hiNU2+E2+5dR9ZvmU3f4DpSA8ObPMUtsfb1KfOYRq3se98tyB/6nnX5 18 | IU5WPhpvL+CxxutLt1doMsjknuspbUT/hfTOjwLddCK/KWpRxO7OPwt1hZsCPmie 19 | IZ7rUf/JmQKBgHhlgzxBRcj5Q/CZeNabuST0z9VID76WvOZwYsBuo/XIF8y6z6zQ 20 | ADZQCThksVQh8FqqYrtOetyPG3g34stqWUJRyR78ZdV7q74yRDds1C/ilGgDhcet 21 | tivz2I2FED0OTgFewHJimSFhENQtPSxyYSfTrGrAdKO4ciiu47QvZKWNAoGAKqld 22 | UpaFSyp2Mvsypq66+icLshFKVz1zD4Zb38gc2ij4KofKftUVpZOB9+4LaVDkVK2Y 23 | NuFiWIBITLUYJw6t0wN5lIPOUenp3HaJMj0dQdgevyy9YkFYE/grZ+KzDO74DIC/ 24 | YgYUkGWZ/D8xI6NLvp6MoEvyTxYFMkZ3r4CokakCgYBRma6oAv94NOyAPgqshY8d 25 | vxouqB07N8Km6Helfi5cnuihBejS5q1MJ15IOHdJXTW1mKpTNDT4y5ARzEcBXKNV 26 | 3DmOQ4bKhOameOCyG3RCWLOdjXxy4siIfMFkVC29/vlr+O6qZq1sSh355Qzx62Kw 27 | FC1yIKb5d4EfoAejMuKWAA== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /ustream-openssl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ustream-ssl - library for SSL over ustream 3 | * 4 | * Copyright (C) 2012 Felix Fietkau 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 | #ifndef __USTREAM_OPENSSL_H 20 | #define __USTREAM_OPENSSL_H 21 | 22 | #if defined(HAVE_WOLFSSL) 23 | #include 24 | #include 25 | #else 26 | #include 27 | #include 28 | #endif 29 | 30 | #include 31 | 32 | struct ustream_ssl_ctx { 33 | SSL_CTX *ssl; 34 | BIO *debug_bio; 35 | ustream_ssl_debug_cb debug_cb; 36 | void *debug_cb_priv; 37 | }; 38 | 39 | struct bio_ctx { 40 | BIO_METHOD *meth; 41 | struct ustream *stream; 42 | }; 43 | 44 | static inline void *__ustream_ssl_session_new(struct ustream_ssl_ctx *ctx) 45 | { 46 | return SSL_new(ctx->ssl); 47 | } 48 | 49 | static inline char *__ustream_ssl_strerror(int error, char *buffer, int len) 50 | { 51 | return ERR_error_string(error, buffer); 52 | } 53 | 54 | static inline void __ustream_ssl_update_peer_cn(struct ustream_ssl *us) 55 | { 56 | } 57 | 58 | static inline void __ustream_ssl_set_server_name(struct ustream_ssl *us) 59 | { 60 | SSL_set_tlsext_host_name(us->ssl, us->server_name); 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | PROJECT(ustream-ssl C) 4 | 5 | ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3) 6 | IF(CMAKE_C_COMPILER_VERSION VERSION_GREATER 6) 7 | ADD_DEFINITIONS(-Wextra -Werror=implicit-function-declaration) 8 | ADD_DEFINITIONS(-Wformat -Werror=format-security -Werror=format-nonliteral) 9 | ENDIF() 10 | ADD_DEFINITIONS(-Wno-unused-parameter -Wmissing-declarations) 11 | 12 | SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") 13 | IF (NOT APPLE) 14 | SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") 15 | ENDIF() 16 | 17 | IF(MBEDTLS) 18 | ADD_DEFINITIONS(-DHAVE_MBEDTLS) 19 | SET(SSL_SRC ustream-mbedtls.c) 20 | FIND_LIBRARY(mbedtls_library mbedtls) 21 | FIND_LIBRARY(mbedx509_library mbedx509) 22 | FIND_LIBRARY(mbedcrypto_library mbedcrypto) 23 | SET(SSL_LIB ${mbedtls_library} ${mbedx509_library} ${mbedcrypto_library} m) 24 | ELSEIF(WOLFSSL) 25 | ADD_DEFINITIONS(-DHAVE_WOLFSSL) 26 | FIND_LIBRARY(wolfssl_library wolfssl) 27 | SET(SSL_SRC ustream-io-wolfssl.c ustream-openssl.c) 28 | SET(SSL_LIB ${wolfssl_library} m) 29 | SET(CMAKE_REQUIRED_LIBRARIES "${wolfssl_library} -lm") 30 | ELSE() 31 | SET(SSL_SRC ustream-io-openssl.c ustream-openssl.c) 32 | SET(SSL_LIB crypto ssl) 33 | ENDIF() 34 | 35 | FIND_PATH(ubox_include_dir libubox/ustream.h) 36 | INCLUDE_DIRECTORIES(${ubox_include_dir}) 37 | FIND_LIBRARY(ubox_library NAMES ubox) 38 | 39 | ADD_LIBRARY(ustream-ssl SHARED ustream-ssl.c ${SSL_SRC}) 40 | TARGET_LINK_LIBRARIES(ustream-ssl ${ubox_library} ${SSL_LIB}) 41 | 42 | ADD_EXECUTABLE(ustream-example-server ustream-example-server.c) 43 | TARGET_LINK_LIBRARIES(ustream-example-server ustream-ssl) 44 | 45 | ADD_EXECUTABLE(ustream-example-client ustream-example-client.c) 46 | TARGET_LINK_LIBRARIES(ustream-example-client ustream-ssl) 47 | 48 | TARGET_COMPILE_DEFINITIONS(ustream-ssl PRIVATE $<$:DEBUG>) 49 | 50 | INSTALL(FILES ustream-ssl.h 51 | DESTINATION include/libubox 52 | ) 53 | INSTALL(TARGETS ustream-ssl 54 | LIBRARY DESTINATION lib 55 | ) 56 | 57 | IF(ABIVERSION) 58 | SET_TARGET_PROPERTIES(ustream-ssl PROPERTIES VERSION ${ABIVERSION}) 59 | ENDIF() 60 | -------------------------------------------------------------------------------- /ustream-mbedtls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ustream-ssl - library for SSL over ustream 3 | * 4 | * Copyright (C) 2012 Felix Fietkau 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 | #ifndef __USTREAM_POLARSSL_H 20 | #define __USTREAM_POLARSSL_H 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #if defined(MBEDTLS_SSL_CACHE_C) 31 | #include 32 | #endif 33 | 34 | struct ustream_ssl_ctx { 35 | mbedtls_ssl_config conf; 36 | mbedtls_pk_context key; 37 | mbedtls_x509_crt ca_cert; 38 | mbedtls_x509_crt cert; 39 | #if defined(MBEDTLS_SSL_CACHE_C) 40 | mbedtls_ssl_cache_context cache; 41 | #endif 42 | ustream_ssl_debug_cb debug_cb; 43 | void *debug_cb_priv; 44 | bool server; 45 | int *ciphersuites; 46 | 47 | void *session_data; 48 | size_t session_data_len; 49 | }; 50 | 51 | static inline char *__ustream_ssl_strerror(int error, char *buffer, int len) 52 | { 53 | mbedtls_strerror(error, buffer, len); 54 | return buffer; 55 | } 56 | 57 | static inline void __ustream_ssl_set_server_name(struct ustream_ssl *us) 58 | { 59 | mbedtls_ssl_set_hostname(us->ssl, us->server_name); 60 | } 61 | 62 | static inline void __ustream_ssl_update_peer_cn(struct ustream_ssl *us) 63 | { 64 | mbedtls_ssl_set_hostname(us->ssl, us->peer_cn); 65 | } 66 | 67 | void *__ustream_ssl_session_new(struct ustream_ssl_ctx *ctx); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /ustream-io-wolfssl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ustream-ssl - library for SSL over ustream 3 | * 4 | * Copyright (C) 2012 Felix Fietkau 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 20 | 21 | #include 22 | 23 | #include "ustream-ssl.h" 24 | #include "ustream-internal.h" 25 | 26 | static int s_ustream_read(char *buf, int len, void *ctx) 27 | { 28 | struct ustream *s = ctx; 29 | char *sbuf; 30 | int slen; 31 | 32 | if (s->eof) 33 | return -3; 34 | 35 | sbuf = ustream_get_read_buf(s, &slen); 36 | if (slen > len) 37 | slen = len; 38 | 39 | if (!slen) 40 | return -2; 41 | 42 | memcpy(buf, sbuf, slen); 43 | ustream_consume(s, slen); 44 | 45 | return slen; 46 | } 47 | 48 | static int s_ustream_write(char *buf, int len, void *ctx) 49 | { 50 | struct ustream *s = ctx; 51 | 52 | if (s->write_error) 53 | return len; 54 | 55 | return ustream_write(s, buf, len, false); 56 | } 57 | 58 | static int io_recv_cb(SSL* ssl, char *buf, int sz, void *ctx) 59 | { 60 | return s_ustream_read(buf, sz, ctx); 61 | } 62 | 63 | static int io_send_cb(SSL* ssl, char *buf, int sz, void *ctx) 64 | { 65 | return s_ustream_write(buf, sz, ctx); 66 | } 67 | 68 | __hidden void ustream_set_io(struct ustream_ssl *us) 69 | { 70 | if (!us->conn) { 71 | wolfSSL_set_fd(us->ssl, us->fd.fd); 72 | return; 73 | } 74 | 75 | wolfSSL_SSLSetIORecv(us->ssl, io_recv_cb); 76 | wolfSSL_SSLSetIOSend(us->ssl, io_send_cb); 77 | wolfSSL_SetIOReadCtx(us->ssl, us->conn); 78 | wolfSSL_SetIOWriteCtx(us->ssl, us->conn); 79 | } 80 | -------------------------------------------------------------------------------- /ustream-internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ustream-ssl - library for SSL over ustream 3 | * 4 | * Copyright (C) 2012 Felix Fietkau 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 | #ifndef __USTREAM_BIO_H 20 | #define __USTREAM_BIO_H 21 | 22 | #define __hidden __attribute__((visibility("hidden"))) 23 | 24 | #if defined(HAVE_MBEDTLS) 25 | #include "ustream-mbedtls.h" 26 | #else 27 | #include "ustream-openssl.h" 28 | #endif 29 | 30 | enum ssl_conn_status { 31 | U_SSL_OK = 0, 32 | U_SSL_PENDING = -1, 33 | U_SSL_ERROR = -2, 34 | U_SSL_RETRY = -3, 35 | }; 36 | 37 | void ustream_set_io(struct ustream_ssl *us); 38 | struct ustream_ssl_ctx *__ustream_ssl_context_new(bool server); 39 | int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx *ctx, const char *file); 40 | int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx *ctx, const char *file); 41 | int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char *file); 42 | int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *ciphers); 43 | int __ustream_ssl_set_require_validation(struct ustream_ssl_ctx *ctx, bool require); 44 | void __ustream_ssl_set_debug(struct ustream_ssl_ctx *ctx, int level, ustream_ssl_debug_cb cb, void *cb_priv); 45 | void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx); 46 | enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us); 47 | int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len); 48 | int __ustream_ssl_write(struct ustream_ssl *us, const char *buf, int len); 49 | void __ustream_ssl_session_free(struct ustream_ssl *us); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /ustream-ssl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ustream-ssl - library for SSL over ustream 3 | * 4 | * Copyright (C) 2012 Felix Fietkau 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 | #ifndef __USTREAM_SSL_H 20 | #define __USTREAM_SSL_H 21 | 22 | #include 23 | 24 | struct ustream_ssl { 25 | struct ustream stream; 26 | struct ustream *conn; 27 | struct uloop_timeout error_timer; 28 | struct uloop_fd fd; 29 | 30 | void (*notify_connected)(struct ustream_ssl *us); 31 | void (*notify_error)(struct ustream_ssl *us, int error, const char *str); 32 | void (*notify_verify_error)(struct ustream_ssl *us, int error, const char *str); 33 | 34 | struct ustream_ssl_ctx *ctx; 35 | void *ssl; 36 | 37 | char *peer_cn; 38 | const char *server_name; 39 | 40 | int error; 41 | bool connected; 42 | bool server; 43 | 44 | bool valid_cert; 45 | bool valid_cn; 46 | bool require_validation; 47 | }; 48 | 49 | struct ustream_ssl_ctx; 50 | 51 | typedef void (*ustream_ssl_debug_cb)(void *priv, int level, const char *msg); 52 | 53 | struct ustream_ssl_ops { 54 | struct ustream_ssl_ctx *(*context_new)(bool server); 55 | int (*context_set_crt_file)(struct ustream_ssl_ctx *ctx, const char *file); 56 | int (*context_set_key_file)(struct ustream_ssl_ctx *ctx, const char *file); 57 | int (*context_add_ca_crt_file)(struct ustream_ssl_ctx *ctx, const char *file); 58 | void (*context_free)(struct ustream_ssl_ctx *ctx); 59 | 60 | int (*init_fd)(struct ustream_ssl *us, int fd, struct ustream_ssl_ctx *ctx, bool server); 61 | int (*init)(struct ustream_ssl *us, struct ustream *conn, struct ustream_ssl_ctx *ctx, bool server); 62 | int (*set_peer_cn)(struct ustream_ssl *conn, const char *name); 63 | 64 | int (*context_set_ciphers)(struct ustream_ssl_ctx *ctx, const char *ciphers); 65 | void (*context_set_debug)(struct ustream_ssl_ctx *ctx, int level, ustream_ssl_debug_cb cb, void *cb_priv); 66 | int (*context_set_require_validation)(struct ustream_ssl_ctx *ctx, bool require); 67 | }; 68 | 69 | extern const struct ustream_ssl_ops ustream_ssl_ops; 70 | 71 | #define ustream_ssl_context_new ustream_ssl_ops.context_new 72 | #define ustream_ssl_context_set_crt_file ustream_ssl_ops.context_set_crt_file 73 | #define ustream_ssl_context_set_key_file ustream_ssl_ops.context_set_key_file 74 | #define ustream_ssl_context_add_ca_crt_file ustream_ssl_ops.context_add_ca_crt_file 75 | #define ustream_ssl_context_set_ciphers ustream_ssl_ops.context_set_ciphers 76 | #define ustream_ssl_context_set_debug ustream_ssl_ops.context_set_debug 77 | #define ustream_ssl_context_set_require_validation ustream_ssl_ops.context_set_require_validation 78 | #define ustream_ssl_context_free ustream_ssl_ops.context_free 79 | #define ustream_ssl_init ustream_ssl_ops.init 80 | #define ustream_ssl_set_peer_cn ustream_ssl_ops.set_peer_cn 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /ustream-io-openssl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ustream-ssl - library for SSL over ustream 3 | * 4 | * Copyright (C) 2012 Felix Fietkau 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 20 | 21 | #include 22 | 23 | #include "ustream-ssl.h" 24 | #include "openssl_bio_compat.h" 25 | #include "ustream-internal.h" 26 | 27 | static int 28 | s_ustream_new(BIO *b) 29 | { 30 | BIO_set_init(b, 1); 31 | BIO_set_data(b, NULL); 32 | BIO_clear_flags(b, ~0); 33 | return 1; 34 | } 35 | 36 | static int 37 | s_ustream_free(BIO *b) 38 | { 39 | if (!b) 40 | return 0; 41 | 42 | BIO_set_data(b, NULL); 43 | BIO_set_init(b, 0); 44 | BIO_clear_flags(b, ~0); 45 | return 1; 46 | } 47 | 48 | static int 49 | s_ustream_read(BIO *b, char *buf, int len) 50 | { 51 | struct bio_ctx *ctx; 52 | char *sbuf; 53 | int slen; 54 | 55 | if (!buf || len <= 0) 56 | return 0; 57 | 58 | ctx = (struct bio_ctx *)BIO_get_data(b); 59 | if (!ctx || !ctx->stream) 60 | return 0; 61 | 62 | sbuf = ustream_get_read_buf(ctx->stream, &slen); 63 | 64 | BIO_clear_retry_flags(b); 65 | if (!slen) { 66 | BIO_set_retry_read(b); 67 | return -1; 68 | } 69 | 70 | if (slen > len) 71 | slen = len; 72 | 73 | memcpy(buf, sbuf, slen); 74 | ustream_consume(ctx->stream, slen); 75 | 76 | return slen; 77 | } 78 | 79 | static int 80 | s_ustream_write(BIO *b, const char *buf, int len) 81 | { 82 | struct bio_ctx *ctx; 83 | 84 | if (!buf || len <= 0) 85 | return 0; 86 | 87 | ctx = (struct bio_ctx *)BIO_get_data(b); 88 | if (!ctx || !ctx->stream) 89 | return 0; 90 | 91 | if (ctx->stream->write_error) 92 | return len; 93 | 94 | return ustream_write(ctx->stream, buf, len, false); 95 | } 96 | 97 | static int 98 | s_ustream_gets(BIO *b, char *buf, int len) 99 | { 100 | return -1; 101 | } 102 | 103 | static int 104 | s_ustream_puts(BIO *b, const char *str) 105 | { 106 | return s_ustream_write(b, str, strlen(str)); 107 | } 108 | 109 | static long s_ustream_ctrl(BIO *b, int cmd, long num, void *ptr) 110 | { 111 | switch (cmd) { 112 | case BIO_CTRL_FLUSH: 113 | return 1; 114 | default: 115 | return 0; 116 | }; 117 | } 118 | 119 | static BIO *ustream_bio_new(struct ustream *s) 120 | { 121 | BIO *bio; 122 | struct bio_ctx *ctx = calloc(1, sizeof(struct bio_ctx)); 123 | 124 | ctx->stream = s; 125 | ctx->meth = BIO_meth_new(100 | BIO_TYPE_SOURCE_SINK, "ustream"); 126 | 127 | BIO_meth_set_write(ctx->meth, s_ustream_write); 128 | BIO_meth_set_read(ctx->meth, s_ustream_read); 129 | BIO_meth_set_puts(ctx->meth, s_ustream_puts); 130 | BIO_meth_set_gets(ctx->meth, s_ustream_gets); 131 | BIO_meth_set_ctrl(ctx->meth, s_ustream_ctrl); 132 | BIO_meth_set_create(ctx->meth, s_ustream_new); 133 | BIO_meth_set_destroy(ctx->meth, s_ustream_free); 134 | bio = BIO_new(ctx->meth); 135 | BIO_set_data(bio, ctx); 136 | 137 | return bio; 138 | } 139 | 140 | static BIO *fd_bio_new(int fd) 141 | { 142 | BIO *bio = BIO_new(BIO_s_socket()); 143 | 144 | BIO_set_fd(bio, fd, BIO_NOCLOSE); 145 | 146 | return bio; 147 | } 148 | 149 | __hidden void ustream_set_io(struct ustream_ssl *us) 150 | { 151 | BIO *bio; 152 | 153 | if (us->conn) 154 | bio = ustream_bio_new(us->conn); 155 | else 156 | bio = fd_bio_new(us->fd.fd); 157 | 158 | SSL_set_bio(us->ssl, bio, bio); 159 | } 160 | -------------------------------------------------------------------------------- /ustream-example-client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include "ustream-ssl.h" 8 | 9 | static struct uloop_fd fd; 10 | 11 | static struct ustream_fd stream, s_input; 12 | static struct ustream_ssl ssl; 13 | static const char *host, *port; 14 | 15 | static void *ctx; 16 | 17 | static void client_teardown(void) 18 | { 19 | if (s_input.fd.registered) 20 | ustream_free(&s_input.stream); 21 | 22 | ustream_free(&ssl.stream); 23 | ustream_free(&stream.stream); 24 | close(stream.fd.fd); 25 | uloop_end(); 26 | } 27 | 28 | static void client_input_notify_read(struct ustream *s, int bytes) 29 | { 30 | char *buf; 31 | int len; 32 | 33 | buf = ustream_get_read_buf(s, &len); 34 | ustream_write(&ssl.stream, buf, len, false); 35 | ustream_consume(s, len); 36 | } 37 | 38 | static void client_ssl_notify_read(struct ustream *s, int bytes) 39 | { 40 | char *buf; 41 | int len; 42 | 43 | buf = ustream_get_read_buf(s, &len); 44 | fwrite(buf, len, 1, stdout); 45 | fflush(stdout); 46 | ustream_consume(s, len); 47 | } 48 | 49 | static void client_ssl_notify_write(struct ustream *s, int bytes) 50 | { 51 | fprintf(stderr, "Wrote %d bytes, pending %d\n", bytes, s->w.data_bytes); 52 | } 53 | 54 | static void client_notify_connected(struct ustream_ssl *ssl) 55 | { 56 | fprintf(stderr, "SSL connection established (CN verified: %d)\n", ssl->valid_cn); 57 | s_input.stream.notify_read = client_input_notify_read; 58 | ustream_fd_init(&s_input, 0); 59 | } 60 | 61 | static void client_notify_error(struct ustream_ssl *ssl, int error, const char *str) 62 | { 63 | fprintf(stderr, "SSL connection error(%d): %s\n", error, str); 64 | client_teardown(); 65 | } 66 | 67 | static void client_notify_verify_error(struct ustream_ssl *ssl, int error, const char *str) 68 | { 69 | fprintf(stderr, "WARNING: SSL certificate error(%d): %s\n", error, str); 70 | } 71 | 72 | static void client_notify_state(struct ustream *us) 73 | { 74 | if (!us->write_error && !us->eof) 75 | return; 76 | 77 | fprintf(stderr, "Connection closed\n"); 78 | client_teardown(); 79 | } 80 | 81 | static void example_connect_ssl(int fd) 82 | { 83 | fprintf(stderr, "Starting SSL negotiation\n"); 84 | 85 | ssl.notify_error = client_notify_error; 86 | ssl.notify_verify_error = client_notify_verify_error; 87 | ssl.notify_connected = client_notify_connected; 88 | ssl.stream.notify_read = client_ssl_notify_read; 89 | ssl.stream.notify_write = client_ssl_notify_write; 90 | ssl.stream.notify_state = client_notify_state; 91 | 92 | ustream_fd_init(&stream, fd); 93 | ustream_ssl_init(&ssl, &stream.stream, ctx, false); 94 | ustream_ssl_set_peer_cn(&ssl, host); 95 | } 96 | 97 | static void example_connect_cb(struct uloop_fd *f, unsigned int events) 98 | { 99 | if (fd.eof || fd.error) { 100 | fprintf(stderr, "Connection failed\n"); 101 | uloop_end(); 102 | return; 103 | } 104 | 105 | fprintf(stderr, "Connection established\n"); 106 | uloop_fd_delete(&fd); 107 | example_connect_ssl(fd.fd); 108 | } 109 | 110 | static void connect_client(void) 111 | { 112 | fd.fd = usock(USOCK_TCP | USOCK_NONBLOCK, host, port); 113 | fd.cb = example_connect_cb; 114 | uloop_fd_add(&fd, ULOOP_WRITE | ULOOP_EDGE_TRIGGER); 115 | } 116 | 117 | static int usage(const char *progname) 118 | { 119 | fprintf(stderr, 120 | "Usage: %s [options] \n" 121 | "Options:\n" 122 | " -c : Load CA certificates from file \n" 123 | "\n", progname); 124 | return 1; 125 | } 126 | 127 | int main(int argc, char **argv) 128 | { 129 | const char *progname = argv[0]; 130 | int ch; 131 | 132 | ctx = ustream_ssl_context_new(false); 133 | 134 | while ((ch = getopt(argc, argv, "c:")) != -1) { 135 | switch(ch) { 136 | case 'c': 137 | ustream_ssl_context_add_ca_crt_file(ctx, optarg); 138 | break; 139 | default: 140 | return usage(progname); 141 | } 142 | } 143 | 144 | argv += optind; 145 | argc -= optind; 146 | 147 | if (argc != 2) 148 | return usage(progname); 149 | 150 | uloop_init(); 151 | host = argv[0]; 152 | port = argv[1]; 153 | connect_client(); 154 | uloop_run(); 155 | 156 | close(fd.fd); 157 | uloop_done(); 158 | return 0; 159 | } 160 | -------------------------------------------------------------------------------- /ustream-example-server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ustream-ssl - library for SSL over ustream 3 | * 4 | * Copyright (C) 2012 Felix Fietkau 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 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include "ustream-ssl.h" 33 | 34 | static struct ustream_ssl_ctx *ctx; 35 | 36 | static struct uloop_fd server; 37 | static const char *port = "10000"; 38 | static struct client *next_client = NULL; 39 | 40 | struct client { 41 | struct sockaddr_in sin; 42 | 43 | struct ustream_fd s; 44 | struct ustream_ssl ssl; 45 | int ctr; 46 | 47 | int state; 48 | }; 49 | 50 | enum { 51 | STATE_INITIAL, 52 | STATE_HEADERS, 53 | STATE_DONE, 54 | }; 55 | 56 | static void client_read_cb(struct ustream *s, int bytes) 57 | { 58 | struct client *cl = container_of(s, struct client, ssl.stream); 59 | struct ustream_buf *buf = s->r.head; 60 | char *newline, *str; 61 | 62 | do { 63 | str = ustream_get_read_buf(s, NULL); 64 | if (!str) 65 | break; 66 | 67 | newline = strchr(buf->data, '\n'); 68 | if (!newline) 69 | break; 70 | 71 | *newline = 0; 72 | switch (cl->state) { 73 | case STATE_INITIAL: 74 | ustream_printf(s, "HTTP/1.1 200 OK\nContent-Type:text/plain\n\n"); 75 | ustream_printf(s, "Got request header: %s\n", str); 76 | cl->state++; 77 | break; 78 | case STATE_HEADERS: 79 | switch(str[0]) { 80 | case '\r': 81 | case '\n': 82 | s->eof = true; 83 | ustream_state_change(s); 84 | cl->state++; 85 | break; 86 | default: 87 | ustream_printf(s, "%s\n", str); 88 | break; 89 | } 90 | break; 91 | default: 92 | break; 93 | } 94 | ustream_consume(s, newline + 1 - str); 95 | cl->ctr += newline + 1 - str; 96 | } while(1); 97 | 98 | if (s->w.data_bytes > 256 && !ustream_read_blocked(s)) { 99 | fprintf(stderr, "Block read, bytes: %d\n", s->w.data_bytes); 100 | ustream_set_read_blocked(s, true); 101 | } 102 | } 103 | 104 | static void client_close(struct client *cl) 105 | { 106 | fprintf(stderr, "Connection closed\n"); 107 | ustream_free(&cl->ssl.stream); 108 | ustream_free(&cl->s.stream); 109 | close(cl->s.fd.fd); 110 | free(cl); 111 | } 112 | 113 | static void client_notify_write(struct ustream *s, int bytes) 114 | { 115 | fprintf(stderr, "Wrote %d bytes, pending: %d\n", bytes, s->w.data_bytes); 116 | 117 | if (s->w.data_bytes < 128 && ustream_read_blocked(s)) { 118 | fprintf(stderr, "Unblock read\n"); 119 | ustream_set_read_blocked(s, false); 120 | } 121 | } 122 | 123 | static void client_notify_state(struct ustream *s) 124 | { 125 | struct client *cl = container_of(s, struct client, ssl.stream); 126 | 127 | if (!s->eof) 128 | return; 129 | 130 | fprintf(stderr, "eof!, pending: %d, total: %d\n", s->w.data_bytes, cl->ctr); 131 | if (!s->w.data_bytes) 132 | return client_close(cl); 133 | } 134 | 135 | static void client_notify_connected(struct ustream_ssl *ssl) 136 | { 137 | fprintf(stderr, "SSL connection established\n"); 138 | } 139 | 140 | static void client_notify_error(struct ustream_ssl *ssl, int error, const char *str) 141 | { 142 | struct client *cl = container_of(ssl, struct client, ssl); 143 | 144 | fprintf(stderr, "SSL connection error(%d): %s\n", error, str); 145 | client_close(cl); 146 | } 147 | 148 | static void server_cb(struct uloop_fd *fd, unsigned int events) 149 | { 150 | struct client *cl; 151 | unsigned int sl = sizeof(struct sockaddr_in); 152 | int sfd; 153 | 154 | if (!next_client) 155 | next_client = calloc(1, sizeof(*next_client)); 156 | 157 | cl = next_client; 158 | sfd = accept(server.fd, (struct sockaddr *) &cl->sin, &sl); 159 | if (sfd < 0) { 160 | fprintf(stderr, "Accept failed\n"); 161 | return; 162 | } 163 | 164 | cl->ssl.stream.string_data = true; 165 | cl->ssl.stream.notify_read = client_read_cb; 166 | cl->ssl.stream.notify_state = client_notify_state; 167 | cl->ssl.stream.notify_write = client_notify_write; 168 | cl->ssl.notify_connected = client_notify_connected; 169 | cl->ssl.notify_error = client_notify_error; 170 | 171 | ustream_fd_init(&cl->s, sfd); 172 | ustream_ssl_init(&cl->ssl, &cl->s.stream, ctx, true); 173 | next_client = NULL; 174 | fprintf(stderr, "New connection\n"); 175 | } 176 | 177 | static int run_server(void) 178 | { 179 | 180 | server.cb = server_cb; 181 | server.fd = usock(USOCK_TCP | USOCK_SERVER | USOCK_IPV4ONLY | USOCK_NUMERIC, "127.0.0.1", port); 182 | if (server.fd < 0) { 183 | perror("usock"); 184 | return 1; 185 | } 186 | 187 | uloop_init(); 188 | uloop_fd_add(&server, ULOOP_READ); 189 | uloop_run(); 190 | 191 | return 0; 192 | } 193 | 194 | static int usage(const char *name) 195 | { 196 | fprintf(stderr, "Usage: %s -p \n", name); 197 | return 1; 198 | } 199 | 200 | int main(int argc, char **argv) 201 | { 202 | int ch; 203 | 204 | signal(SIGPIPE, SIG_IGN); 205 | ctx = ustream_ssl_context_new(true); 206 | ustream_ssl_context_set_crt_file(ctx, "example.crt"); 207 | ustream_ssl_context_set_key_file(ctx, "example.key"); 208 | 209 | while ((ch = getopt(argc, argv, "p:")) != -1) { 210 | switch(ch) { 211 | case 'p': 212 | port = optarg; 213 | break; 214 | default: 215 | return usage(argv[0]); 216 | } 217 | } 218 | 219 | return run_server(); 220 | } 221 | -------------------------------------------------------------------------------- /ustream-ssl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ustream-ssl - library for SSL over ustream 3 | * 4 | * Copyright (C) 2012 Felix Fietkau 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 20 | #include 21 | #include 22 | #include 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_ssl *us) 71 | { 72 | char *buf; 73 | int len, ret; 74 | bool more = false; 75 | 76 | ustream_ssl_check_conn(us); 77 | if (!us->connected || us->error) 78 | return false; 79 | 80 | do { 81 | buf = ustream_reserve(&us->stream, 1, &len); 82 | if (!len) 83 | break; 84 | 85 | ret = __ustream_ssl_read(us, buf, len); 86 | if (ret == U_SSL_PENDING) { 87 | if (us->conn) 88 | ustream_poll(us->conn); 89 | ret = __ustream_ssl_read(us, buf, len); 90 | } 91 | 92 | switch (ret) { 93 | case U_SSL_PENDING: 94 | return more; 95 | case U_SSL_ERROR: 96 | return false; 97 | case 0: 98 | us->stream.eof = true; 99 | ustream_state_change(&us->stream); 100 | return false; 101 | default: 102 | ustream_fill_read(&us->stream, ret); 103 | more = true; 104 | continue; 105 | } 106 | } while (1); 107 | 108 | return more; 109 | } 110 | 111 | static void ustream_ssl_notify_read(struct ustream *s, int bytes) 112 | { 113 | struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream); 114 | 115 | __ustream_ssl_poll(us); 116 | } 117 | 118 | static void ustream_ssl_notify_write(struct ustream *s, int bytes) 119 | { 120 | struct ustream_ssl *us = container_of(s->next, struct ustream_ssl, stream); 121 | 122 | ustream_ssl_check_conn(us); 123 | ustream_write_pending(s->next); 124 | } 125 | 126 | static void ustream_ssl_notify_state(struct ustream *s) 127 | { 128 | s->next->write_error = true; 129 | ustream_state_change(s->next); 130 | } 131 | 132 | static int ustream_ssl_write(struct ustream *s, const char *buf, int len, bool more) 133 | { 134 | struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream); 135 | 136 | if (!us->connected || us->error) 137 | return 0; 138 | 139 | if (us->conn && us->conn->w.data_bytes) 140 | return 0; 141 | 142 | return __ustream_ssl_write(us, buf, len); 143 | } 144 | 145 | static void ustream_ssl_set_read_blocked(struct ustream *s) 146 | { 147 | struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream); 148 | unsigned int ev = ULOOP_WRITE | ULOOP_EDGE_TRIGGER; 149 | 150 | if (us->conn) { 151 | ustream_set_read_blocked(us->conn, !!s->read_blocked); 152 | return; 153 | } 154 | 155 | if (!s->read_blocked) 156 | ev |= ULOOP_READ; 157 | 158 | uloop_fd_add(&us->fd, ev); 159 | } 160 | 161 | static void ustream_ssl_free(struct ustream *s) 162 | { 163 | struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream); 164 | 165 | if (us->conn) { 166 | us->conn->next = NULL; 167 | us->conn->notify_read = NULL; 168 | us->conn->notify_write = NULL; 169 | us->conn->notify_state = NULL; 170 | } else { 171 | uloop_fd_delete(&us->fd); 172 | } 173 | 174 | uloop_timeout_cancel(&us->error_timer); 175 | __ustream_ssl_session_free(us); 176 | free(us->peer_cn); 177 | 178 | us->ctx = NULL; 179 | us->ssl = NULL; 180 | us->conn = NULL; 181 | us->peer_cn = NULL; 182 | us->connected = false; 183 | us->error = false; 184 | us->valid_cert = false; 185 | us->valid_cn = false; 186 | } 187 | 188 | static bool ustream_ssl_poll(struct ustream *s) 189 | { 190 | struct ustream_ssl *us = container_of(s, struct ustream_ssl, stream); 191 | bool fd_poll = false; 192 | 193 | if (us->conn) 194 | fd_poll = ustream_poll(us->conn); 195 | 196 | return __ustream_ssl_poll(us) || fd_poll; 197 | } 198 | 199 | static void ustream_ssl_fd_cb(struct uloop_fd *fd, unsigned int events) 200 | { 201 | struct ustream_ssl *us = container_of(fd, struct ustream_ssl, fd); 202 | 203 | __ustream_ssl_poll(us); 204 | } 205 | 206 | static void ustream_ssl_stream_init(struct ustream_ssl *us) 207 | { 208 | struct ustream *conn = us->conn; 209 | struct ustream *s = &us->stream; 210 | 211 | if (conn) { 212 | conn->notify_read = ustream_ssl_notify_read; 213 | conn->notify_write = ustream_ssl_notify_write; 214 | conn->notify_state = ustream_ssl_notify_state; 215 | } else { 216 | us->fd.cb = ustream_ssl_fd_cb; 217 | uloop_fd_add(&us->fd, ULOOP_READ | ULOOP_WRITE | ULOOP_EDGE_TRIGGER); 218 | } 219 | 220 | s->set_read_blocked = ustream_ssl_set_read_blocked; 221 | s->free = ustream_ssl_free; 222 | s->write = ustream_ssl_write; 223 | s->poll = ustream_ssl_poll; 224 | ustream_init_defaults(s); 225 | } 226 | 227 | static int _ustream_ssl_init_common(struct ustream_ssl *us) 228 | { 229 | us->error_timer.cb = ustream_ssl_error_cb; 230 | 231 | us->ssl = __ustream_ssl_session_new(us->ctx); 232 | if (!us->ssl) 233 | return -ENOMEM; 234 | 235 | ustream_set_io(us); 236 | ustream_ssl_stream_init(us); 237 | 238 | if (us->server_name) 239 | __ustream_ssl_set_server_name(us); 240 | 241 | ustream_ssl_check_conn(us); 242 | 243 | return 0; 244 | } 245 | 246 | static int _ustream_ssl_init_fd(struct ustream_ssl *us, int fd, struct ustream_ssl_ctx *ctx, bool server) 247 | { 248 | us->server = server; 249 | us->ctx = ctx; 250 | us->fd.fd = fd; 251 | 252 | return _ustream_ssl_init_common(us); 253 | } 254 | 255 | static int _ustream_ssl_init(struct ustream_ssl *us, struct ustream *conn, struct ustream_ssl_ctx *ctx, bool server) 256 | { 257 | us->server = server; 258 | us->ctx = ctx; 259 | 260 | us->conn = conn; 261 | conn->r.max_buffers = 4; 262 | conn->next = &us->stream; 263 | 264 | return _ustream_ssl_init_common(us); 265 | } 266 | 267 | static int _ustream_ssl_set_peer_cn(struct ustream_ssl *us, const char *name) 268 | { 269 | us->peer_cn = strdup(name); 270 | __ustream_ssl_update_peer_cn(us); 271 | 272 | return 0; 273 | } 274 | 275 | const struct ustream_ssl_ops ustream_ssl_ops = { 276 | .context_new = __ustream_ssl_context_new, 277 | .context_set_crt_file = __ustream_ssl_set_crt_file, 278 | .context_set_key_file = __ustream_ssl_set_key_file, 279 | .context_add_ca_crt_file = __ustream_ssl_add_ca_crt_file, 280 | .context_set_ciphers = __ustream_ssl_set_ciphers, 281 | .context_set_require_validation = __ustream_ssl_set_require_validation, 282 | .context_set_debug = __ustream_ssl_set_debug, 283 | .context_free = __ustream_ssl_context_free, 284 | .init = _ustream_ssl_init, 285 | .init_fd = _ustream_ssl_init_fd, 286 | .set_peer_cn = _ustream_ssl_set_peer_cn, 287 | }; 288 | -------------------------------------------------------------------------------- /ustream-openssl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ustream-ssl - library for SSL over ustream 3 | * 4 | * Copyright (C) 2012 Felix Fietkau 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 20 | #include 21 | #include "ustream-ssl.h" 22 | #include "ustream-internal.h" 23 | 24 | #if !defined(HAVE_WOLFSSL) 25 | #include 26 | #endif 27 | 28 | #if defined(HAVE_WOLFSSL) && defined(DEBUG) 29 | #include 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 | -------------------------------------------------------------------------------- /ustream-mbedtls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ustream-ssl - library for SSL over ustream 3 | * 4 | * Copyright (C) 2012 Felix Fietkau 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 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "ustream-ssl.h" 27 | #include "ustream-internal.h" 28 | #include 29 | #include 30 | 31 | static void debug_cb(void *ctx_p, int level, 32 | const char *file, int line, 33 | const char *str) 34 | { 35 | struct ustream_ssl_ctx *ctx = ctx_p; 36 | const char *fstr; 37 | char buf[512]; 38 | int len; 39 | 40 | if (!ctx->debug_cb) 41 | return; 42 | 43 | while ((fstr = strstr(file + 1, "library/")) != NULL) 44 | file = fstr; 45 | 46 | len = snprintf(buf, sizeof(buf), "%s:%04d: %s", file, line, str); 47 | if (len >= (int)sizeof(buf)) 48 | len = (int)sizeof(buf) - 1; 49 | if (buf[len - 1] == '\n') 50 | buf[len - 1] = 0; 51 | ctx->debug_cb(ctx->debug_cb_priv, level, buf); 52 | } 53 | 54 | static int s_ustream_read(void *ctx, unsigned char *buf, size_t len) 55 | { 56 | struct ustream *s = ctx; 57 | char *sbuf; 58 | int slen; 59 | 60 | if (s->eof) 61 | return 0; 62 | 63 | sbuf = ustream_get_read_buf(s, &slen); 64 | if ((size_t) slen > len) 65 | slen = len; 66 | 67 | if (!slen) 68 | return MBEDTLS_ERR_SSL_WANT_READ; 69 | 70 | memcpy(buf, sbuf, slen); 71 | ustream_consume(s, slen); 72 | 73 | return slen; 74 | } 75 | 76 | static int s_ustream_write(void *ctx, const unsigned char *buf, size_t len) 77 | { 78 | struct ustream *s = ctx; 79 | int ret; 80 | 81 | ret = ustream_write(s, (const char *) buf, len, false); 82 | if (ret < 0 || s->write_error) 83 | return MBEDTLS_ERR_NET_SEND_FAILED; 84 | 85 | return ret; 86 | } 87 | 88 | static int s_fd_read(void *ctx, unsigned char *buf, size_t len) 89 | { 90 | struct uloop_fd *ufd = ctx; 91 | mbedtls_net_context net = { 92 | .fd = ufd->fd 93 | }; 94 | 95 | return mbedtls_net_recv(&net, buf, len); 96 | } 97 | 98 | static int s_fd_write(void *ctx, const unsigned char *buf, size_t len) 99 | { 100 | struct uloop_fd *ufd = ctx; 101 | mbedtls_net_context net = { 102 | .fd = ufd->fd 103 | }; 104 | 105 | return mbedtls_net_send(&net, buf, len); 106 | } 107 | 108 | __hidden void ustream_set_io(struct ustream_ssl *us) 109 | { 110 | if (us->conn) 111 | mbedtls_ssl_set_bio(us->ssl, us->conn, s_ustream_write, s_ustream_read, NULL); 112 | else 113 | mbedtls_ssl_set_bio(us->ssl, &us->fd, s_fd_write, s_fd_read, NULL); 114 | } 115 | 116 | static int _random(void *ctx, unsigned char *out, size_t len) 117 | { 118 | #ifdef linux 119 | if (getrandom(out, len, 0) != (ssize_t) len) 120 | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 121 | #else 122 | static FILE *f; 123 | 124 | if (!f) 125 | f = fopen("/dev/urandom", "r"); 126 | if (fread(out, len, 1, f) != 1) 127 | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 128 | #endif 129 | 130 | return 0; 131 | } 132 | 133 | #define AES_GCM_CIPHERS(v) \ 134 | MBEDTLS_TLS_##v##_WITH_AES_128_GCM_SHA256, \ 135 | MBEDTLS_TLS_##v##_WITH_AES_256_GCM_SHA384 136 | 137 | #define AES_CBC_CIPHERS(v) \ 138 | MBEDTLS_TLS_##v##_WITH_AES_128_CBC_SHA, \ 139 | MBEDTLS_TLS_##v##_WITH_AES_256_CBC_SHA 140 | 141 | #define AES_CIPHERS(v) \ 142 | AES_GCM_CIPHERS(v), \ 143 | AES_CBC_CIPHERS(v) 144 | 145 | static const int default_ciphersuites_server[] = 146 | { 147 | #ifdef MBEDTLS_SSL_PROTO_TLS1_3 148 | MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256, 149 | MBEDTLS_TLS1_3_AES_256_GCM_SHA384, 150 | MBEDTLS_TLS1_3_AES_128_GCM_SHA256, 151 | MBEDTLS_TLS1_3_AES_128_CCM_SHA256, 152 | MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256, 153 | #endif 154 | 155 | MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 156 | AES_GCM_CIPHERS(ECDHE_ECDSA), 157 | MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 158 | AES_GCM_CIPHERS(ECDHE_RSA), 159 | AES_CBC_CIPHERS(ECDHE_RSA), 160 | AES_CIPHERS(RSA), 161 | 0 162 | }; 163 | 164 | static const int default_ciphersuites_client[] = 165 | { 166 | #ifdef MBEDTLS_SSL_PROTO_TLS1_3 167 | MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256, 168 | MBEDTLS_TLS1_3_AES_256_GCM_SHA384, 169 | MBEDTLS_TLS1_3_AES_128_GCM_SHA256, 170 | MBEDTLS_TLS1_3_AES_128_CCM_SHA256, 171 | MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256, 172 | #endif 173 | 174 | MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 175 | AES_GCM_CIPHERS(ECDHE_ECDSA), 176 | MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 177 | AES_GCM_CIPHERS(ECDHE_RSA), 178 | MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 179 | AES_GCM_CIPHERS(DHE_RSA), 180 | AES_CBC_CIPHERS(ECDHE_ECDSA), 181 | AES_CBC_CIPHERS(ECDHE_RSA), 182 | AES_CBC_CIPHERS(DHE_RSA), 183 | /* Removed in Mbed TLS 3.0.0 */ 184 | #ifdef MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 185 | MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 186 | #endif 187 | AES_CIPHERS(RSA), 188 | /* Removed in Mbed TLS 3.0.0 */ 189 | #ifdef MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA 190 | MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, 191 | #endif 192 | 0 193 | }; 194 | 195 | 196 | __hidden struct ustream_ssl_ctx * 197 | __ustream_ssl_context_new(bool server) 198 | { 199 | struct ustream_ssl_ctx *ctx; 200 | mbedtls_ssl_config *conf; 201 | int ep; 202 | 203 | #ifdef MBEDTLS_PSA_CRYPTO_C 204 | static bool psa_init; 205 | 206 | if (!psa_init && !psa_crypto_init()) 207 | psa_init = true; 208 | #endif 209 | 210 | ctx = calloc(1, sizeof(*ctx)); 211 | if (!ctx) 212 | return NULL; 213 | 214 | ctx->server = server; 215 | mbedtls_pk_init(&ctx->key); 216 | mbedtls_x509_crt_init(&ctx->cert); 217 | mbedtls_x509_crt_init(&ctx->ca_cert); 218 | 219 | #if defined(MBEDTLS_SSL_CACHE_C) 220 | mbedtls_ssl_cache_init(&ctx->cache); 221 | mbedtls_ssl_cache_set_timeout(&ctx->cache, 30 * 60); 222 | mbedtls_ssl_cache_set_max_entries(&ctx->cache, 5); 223 | #endif 224 | 225 | conf = &ctx->conf; 226 | mbedtls_ssl_config_init(conf); 227 | 228 | ep = server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT; 229 | 230 | mbedtls_ssl_config_defaults(conf, ep, MBEDTLS_SSL_TRANSPORT_STREAM, 231 | MBEDTLS_SSL_PRESET_DEFAULT); 232 | mbedtls_ssl_conf_rng(conf, _random, NULL); 233 | 234 | if (server) { 235 | mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE); 236 | mbedtls_ssl_conf_ciphersuites(conf, default_ciphersuites_server); 237 | mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, 238 | MBEDTLS_SSL_MINOR_VERSION_3); 239 | } else { 240 | mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_OPTIONAL); 241 | mbedtls_ssl_conf_ciphersuites(conf, default_ciphersuites_client); 242 | } 243 | 244 | #if defined(MBEDTLS_SSL_CACHE_C) 245 | mbedtls_ssl_conf_session_cache(conf, &ctx->cache, 246 | mbedtls_ssl_cache_get, 247 | mbedtls_ssl_cache_set); 248 | #endif 249 | return ctx; 250 | } 251 | 252 | static void ustream_ssl_update_own_cert(struct ustream_ssl_ctx *ctx) 253 | { 254 | if (!ctx->cert.version) 255 | return; 256 | 257 | if (mbedtls_pk_get_type(&ctx->key) == MBEDTLS_PK_NONE) 258 | return; 259 | 260 | mbedtls_ssl_conf_own_cert(&ctx->conf, &ctx->cert, &ctx->key); 261 | } 262 | 263 | __hidden int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx *ctx, const char *file) 264 | { 265 | int ret; 266 | 267 | ret = mbedtls_x509_crt_parse_file(&ctx->ca_cert, file); 268 | if (ret) 269 | return -1; 270 | 271 | mbedtls_ssl_conf_ca_chain(&ctx->conf, &ctx->ca_cert, NULL); 272 | mbedtls_ssl_conf_authmode(&ctx->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); 273 | return 0; 274 | } 275 | 276 | __hidden int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx *ctx, const char *file) 277 | { 278 | int ret; 279 | 280 | ret = mbedtls_x509_crt_parse_file(&ctx->cert, file); 281 | if (ret) 282 | return -1; 283 | 284 | ustream_ssl_update_own_cert(ctx); 285 | return 0; 286 | } 287 | 288 | __hidden int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char *file) 289 | { 290 | int ret; 291 | 292 | #if (MBEDTLS_VERSION_NUMBER >= 0x03000000) 293 | ret = mbedtls_pk_parse_keyfile(&ctx->key, file, NULL, _random, NULL); 294 | #else 295 | ret = mbedtls_pk_parse_keyfile(&ctx->key, file, NULL); 296 | #endif 297 | if (ret) 298 | return -1; 299 | 300 | ustream_ssl_update_own_cert(ctx); 301 | return 0; 302 | } 303 | 304 | __hidden int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *ciphers) 305 | { 306 | int *ciphersuites = NULL, *tmp, id; 307 | char *cipherstr, *p, *last, c; 308 | size_t len = 0; 309 | 310 | if (ciphers == NULL) 311 | return -1; 312 | 313 | cipherstr = strdup(ciphers); 314 | 315 | if (cipherstr == NULL) 316 | return -1; 317 | 318 | for (p = cipherstr, last = p;; p++) { 319 | if (*p == ':' || *p == 0) { 320 | c = *p; 321 | *p = 0; 322 | 323 | id = mbedtls_ssl_get_ciphersuite_id(last); 324 | 325 | if (id != 0) { 326 | tmp = realloc(ciphersuites, (len + 2) * sizeof(int)); 327 | 328 | if (tmp == NULL) { 329 | free(ciphersuites); 330 | free(cipherstr); 331 | 332 | return -1; 333 | } 334 | 335 | ciphersuites = tmp; 336 | ciphersuites[len++] = id; 337 | ciphersuites[len] = 0; 338 | } 339 | 340 | if (c == 0) 341 | break; 342 | 343 | last = p + 1; 344 | } 345 | 346 | /* 347 | * mbedTLS expects cipher names with dashes while many sources elsewhere 348 | * like the Firefox wiki or Wireshark specify ciphers with underscores, 349 | * so simply convert all underscores to dashes to accept both notations. 350 | */ 351 | else if (*p == '_') { 352 | *p = '-'; 353 | } 354 | } 355 | 356 | free(cipherstr); 357 | 358 | if (len == 0) 359 | return -1; 360 | 361 | mbedtls_ssl_conf_ciphersuites(&ctx->conf, ciphersuites); 362 | free(ctx->ciphersuites); 363 | 364 | ctx->ciphersuites = ciphersuites; 365 | 366 | return 0; 367 | } 368 | 369 | __hidden int __ustream_ssl_set_require_validation(struct ustream_ssl_ctx *ctx, bool require) 370 | { 371 | int mode = MBEDTLS_SSL_VERIFY_OPTIONAL; 372 | 373 | if (!require) 374 | mode = MBEDTLS_SSL_VERIFY_NONE; 375 | 376 | /* force TLS 1.2 when not requiring validation for now */ 377 | if (!require && !ctx->server) 378 | mbedtls_ssl_conf_max_version(&ctx->conf, MBEDTLS_SSL_MAJOR_VERSION_3, 379 | MBEDTLS_SSL_MINOR_VERSION_3); 380 | mbedtls_ssl_conf_authmode(&ctx->conf, mode); 381 | 382 | return 0; 383 | } 384 | 385 | __hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx) 386 | { 387 | free(ctx->session_data); 388 | #if defined(MBEDTLS_SSL_CACHE_C) 389 | mbedtls_ssl_cache_free(&ctx->cache); 390 | #endif 391 | mbedtls_pk_free(&ctx->key); 392 | mbedtls_x509_crt_free(&ctx->ca_cert); 393 | mbedtls_x509_crt_free(&ctx->cert); 394 | mbedtls_ssl_config_free(&ctx->conf); 395 | free(ctx->ciphersuites); 396 | free(ctx); 397 | } 398 | 399 | static void ustream_ssl_error(struct ustream_ssl *us, int ret) 400 | { 401 | us->error = ret; 402 | uloop_timeout_set(&us->error_timer, 0); 403 | } 404 | 405 | #ifdef MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET 406 | static void 407 | __ustream_ssl_save_session(struct ustream_ssl *us) 408 | { 409 | struct ustream_ssl_ctx *ctx = us->ctx; 410 | mbedtls_ssl_session sess; 411 | 412 | if (ctx->server) 413 | return; 414 | 415 | free(ctx->session_data); 416 | ctx->session_data = NULL; 417 | 418 | mbedtls_ssl_session_init(&sess); 419 | if (mbedtls_ssl_get_session(us->ssl, &sess) != 0) 420 | return; 421 | 422 | mbedtls_ssl_session_save(&sess, NULL, 0, &ctx->session_data_len); 423 | ctx->session_data = malloc(ctx->session_data_len); 424 | if (mbedtls_ssl_session_save(&sess, ctx->session_data, ctx->session_data_len, 425 | &ctx->session_data_len)) 426 | ctx->session_data_len = 0; 427 | mbedtls_ssl_session_free(&sess); 428 | } 429 | #endif 430 | 431 | static int ssl_check_return(struct ustream_ssl *us, int ret) 432 | { 433 | switch(ret) { 434 | case MBEDTLS_ERR_SSL_WANT_READ: 435 | case MBEDTLS_ERR_SSL_WANT_WRITE: 436 | return U_SSL_PENDING; 437 | #ifdef MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET 438 | case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET: 439 | __ustream_ssl_save_session(us); 440 | return U_SSL_RETRY; 441 | #endif 442 | #ifdef MBEDTLS_ECP_RESTARTABLE 443 | case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS: 444 | return U_SSL_RETRY; 445 | #endif 446 | case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: 447 | case MBEDTLS_ERR_NET_CONN_RESET: 448 | return 0; 449 | default: 450 | ustream_ssl_error(us, ret); 451 | return U_SSL_ERROR; 452 | } 453 | } 454 | 455 | static void ustream_ssl_verify_cert(struct ustream_ssl *us) 456 | { 457 | void *ssl = us->ssl; 458 | const char *msg = NULL; 459 | bool cn_mismatch; 460 | int r; 461 | 462 | r = mbedtls_ssl_get_verify_result(ssl); 463 | cn_mismatch = r & MBEDTLS_X509_BADCERT_CN_MISMATCH; 464 | r &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH; 465 | 466 | if (r & MBEDTLS_X509_BADCERT_EXPIRED) 467 | msg = "certificate has expired"; 468 | else if (r & MBEDTLS_X509_BADCERT_REVOKED) 469 | msg = "certificate has been revoked"; 470 | else if (r & MBEDTLS_X509_BADCERT_NOT_TRUSTED) 471 | msg = "certificate is self-signed or not signed by a trusted CA"; 472 | else 473 | msg = "unknown error"; 474 | 475 | if (r) { 476 | if (us->notify_verify_error) 477 | us->notify_verify_error(us, r, msg); 478 | return; 479 | } 480 | 481 | if (!cn_mismatch) 482 | us->valid_cn = true; 483 | } 484 | 485 | __hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us) 486 | { 487 | void *ssl = us->ssl; 488 | int r; 489 | 490 | do { 491 | r = mbedtls_ssl_handshake(ssl); 492 | if (r == 0) { 493 | ustream_ssl_verify_cert(us); 494 | return U_SSL_OK; 495 | } 496 | 497 | r = ssl_check_return(us, r); 498 | } while (r == U_SSL_RETRY); 499 | 500 | return r; 501 | } 502 | 503 | __hidden int __ustream_ssl_write(struct ustream_ssl *us, const char *buf, int len) 504 | { 505 | void *ssl = us->ssl; 506 | int done = 0, ret = 0; 507 | 508 | while (done != len) { 509 | ret = mbedtls_ssl_write(ssl, (const unsigned char *) buf + done, len - done); 510 | if (ret < 0) { 511 | ret = ssl_check_return(us, ret); 512 | if (ret == U_SSL_RETRY) 513 | continue; 514 | 515 | if (ret == U_SSL_PENDING) 516 | return done; 517 | 518 | return -1; 519 | } 520 | 521 | done += ret; 522 | } 523 | 524 | return done; 525 | } 526 | 527 | __hidden int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len) 528 | { 529 | int ret; 530 | 531 | do { 532 | ret = mbedtls_ssl_read(us->ssl, (unsigned char *) buf, len); 533 | if (ret >= 0) 534 | return ret; 535 | 536 | ret = ssl_check_return(us, ret); 537 | } while (ret == U_SSL_RETRY); 538 | 539 | return ret; 540 | } 541 | 542 | __hidden void __ustream_ssl_set_debug(struct ustream_ssl_ctx *ctx, int level, 543 | ustream_ssl_debug_cb cb, void *cb_priv) 544 | { 545 | ctx->debug_cb = cb; 546 | ctx->debug_cb_priv = cb_priv; 547 | mbedtls_ssl_conf_dbg(&ctx->conf, debug_cb, ctx); 548 | #ifdef MBEDTLS_DEBUG_C 549 | mbedtls_debug_set_threshold(level); 550 | #endif 551 | } 552 | 553 | __hidden void *__ustream_ssl_session_new(struct ustream_ssl_ctx *ctx) 554 | { 555 | mbedtls_ssl_context *ssl; 556 | mbedtls_ssl_session sess; 557 | 558 | ssl = calloc(1, sizeof(*ssl)); 559 | if (!ssl) 560 | return NULL; 561 | 562 | mbedtls_ssl_init(ssl); 563 | 564 | if (mbedtls_ssl_setup(ssl, &ctx->conf)) { 565 | free(ssl); 566 | return NULL; 567 | } 568 | 569 | if (!ctx->session_data_len) 570 | return ssl; 571 | 572 | mbedtls_ssl_session_init(&sess); 573 | if (mbedtls_ssl_session_load(&sess, ctx->session_data, ctx->session_data_len) == 0) 574 | mbedtls_ssl_set_session(ssl, &sess); 575 | 576 | return ssl; 577 | } 578 | 579 | __hidden void __ustream_ssl_session_free(struct ustream_ssl *us) 580 | { 581 | mbedtls_ssl_free(us->ssl); 582 | free(us->ssl); 583 | } 584 | --------------------------------------------------------------------------------