├── README.md ├── include ├── bio.h ├── tls_engine.h └── uv_tls.h └── src ├── bio.c ├── tls_engine.c └── uv_tls.c /README.md: -------------------------------------------------------------------------------- 1 | # What is this 2 | Port [mbedTLS](https://github.com/ARMmbed/mbedtls) on libuv, based on BIO which refers to [wolfSSL/src/bio.c](https://github.com/wolfSSL/wolfssl/blob/master/src/bio.c) and the project is inspired by [libuv-tls](https://github.com/deleisha/libuv-tls) 3 | 4 | ses API in uv_tls.c. 5 | just use 6 | 7 | 0. `uv_tls_init` for `uv_tcp_init` 8 | 0. `uv_tls_connect` for `uv_tcp_connect` 9 | 0. `uv_tls_read` for `uv_read_start` 10 | 0. `uv_tls_write` for `uv_write` 11 | 12 | # TODO 13 | add a fully example. -------------------------------------------------------------------------------- /include/bio.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gemini on 2017/6/23. 3 | // 4 | 5 | #ifndef CHAT_BIO_H 6 | #define CHAT_BIO_H 7 | 8 | #include "strings.h" 9 | #include "stdlib.h" 10 | #include "mbedtls/ssl.h" 11 | #include "ssl.h" 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | typedef unsigned char BYTE; 18 | 19 | struct _BIO; 20 | typedef struct _BIO BIO; 21 | 22 | struct _BIO { 23 | BIO* prev; /* previous in chain */ 24 | BIO* next; /* next in chain */ 25 | BIO* pair; /* BIO paired with */ 26 | BYTE* mem; /* memory buffer */ 27 | int wrSz; /* write buffer size (mem) */ 28 | int wrIdx; /* current index for write buffer */ 29 | int rdIdx; /* current read index */ 30 | int readRq; /* read request */ 31 | int memLen; /* memory buffer length */ 32 | int type; /* method type */ 33 | }; 34 | 35 | enum { 36 | SSL_BIO_ERROR = -1, 37 | SSL_BIO_UNSET = -2, 38 | SSL_BIO_SIZE = 17000 /* default BIO write size if not set */ 39 | }; 40 | 41 | enum BIO_TYPE { 42 | BIO_BUFFER = 1, 43 | BIO_SOCKET = 2, 44 | BIO_SSL = 3, 45 | BIO_MEMORY = 4, 46 | BIO_BIO = 5, 47 | BIO_FILE = 6 48 | }; 49 | 50 | 51 | // 抽象 IO API 52 | 53 | BIO *SSL_BIO_new(int type); 54 | int BIO_make_bio_pair(BIO *b1, BIO *b2); 55 | 56 | 57 | size_t BIO_ctrl_pending(BIO *bio); 58 | int BIO_read(BIO *bio, const char *buf, size_t size); 59 | int BIO_write(BIO *bio, const char *buf, size_t size); 60 | 61 | int BIO_net_recv( void *ctx, unsigned char *buf, size_t len); 62 | int BIO_net_send( void *ctx, const unsigned char *buf, size_t len ); 63 | int BIO_free_all(BIO* bio); 64 | int BIO_free(BIO* bio); 65 | 66 | #ifdef __cplusplus 67 | }; 68 | #endif 69 | 70 | #endif //CHAT_BIO_H 71 | -------------------------------------------------------------------------------- /include/tls_engine.h: -------------------------------------------------------------------------------- 1 | 2 | /*////////////////////////////////////////////////////////////////////////////// 3 | 4 | * Copyright (c) 2015 libuv-tls contributors 5 | 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | **////////////////////////////////////////////////////////////////////////////*/ 24 | 25 | 26 | #ifndef __UV_TLS_ENGINE_H__ 27 | #define __UV_TLS_ENGINE_H__ 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #include "assert.h" 34 | #include "log.h" 35 | 36 | #if !defined(MBEDTLS_CONFIG_FILE) 37 | #include "mbedtls/config.h" 38 | #else 39 | #include MBEDTLS_CONFIG_FILE 40 | #endif 41 | 42 | #if defined(MBEDTLS_PLATFORM_C) 43 | #include "mbedtls/platform.h" 44 | #else 45 | #include 46 | #include 47 | #define mbedtls_time time 48 | #define mbedtls_time_t time_t 49 | #define mbedtls_fprintf fprintf 50 | #define mbedtls_printf __log 51 | #endif 52 | 53 | #include "mbedtls/net_sockets.h" 54 | #include "mbedtls/debug.h" 55 | #include "mbedtls/ssl.h" 56 | #include "mbedtls/entropy.h" 57 | #include "mbedtls/ctr_drbg.h" 58 | #include "mbedtls/error.h" 59 | #include "mbedtls/certs.h" 60 | #include "bio.h" 61 | 62 | #include 63 | 64 | 65 | enum uv_tls_state { 66 | STATE_INIT = 0x0 67 | ,STATE_HANDSHAKING = 0x1 68 | ,STATE_IO = 0x2 //read or write mode 69 | ,STATE_CLOSING = 0x4 // This means closed state also 70 | }; 71 | 72 | //TODO: improve the error handling 73 | enum uv_tls_error { 74 | ERR_TLS_ERROR = -1 //use OpenSSL error handling technique for this 75 | ,ERR_TLS_OK 76 | }; 77 | 78 | 79 | struct tls_engine_s { 80 | BIO *app_bio_; //Our BIO, All IO should be through this 81 | // SSL *ssl; 82 | // SSL_CTX *ctx; 83 | BIO *ssl_bio_; //the ssl BIO used only by openSSL 84 | mbedtls_net_context ctx; 85 | 86 | mbedtls_entropy_context entropy; 87 | mbedtls_ctr_drbg_context ctr_drbg; 88 | mbedtls_ssl_context ssl; 89 | mbedtls_ssl_config conf; 90 | mbedtls_x509_crt cacert; 91 | }; 92 | 93 | typedef struct tls_engine_s tls_engine; 94 | 95 | int tls_engine_init(tls_engine *tls); 96 | void tls_engine_stop(tls_engine *tls); 97 | 98 | 99 | 100 | #ifdef __cplusplus 101 | } 102 | #endif 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /include/uv_tls.h: -------------------------------------------------------------------------------- 1 | 2 | /*////////////////////////////////////////////////////////////////////////////// 3 | 4 | * Copyright (c) 2015 libuv-tls contributors 5 | 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | **////////////////////////////////////////////////////////////////////////////*/ 24 | 25 | 26 | #ifndef __UV_TLS_H__ 27 | #define __UV_TLS_H__ 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | 34 | #include "uv.h" 35 | #include "stdio.h" 36 | #include "stdlib.h" 37 | #include "unistd.h" 38 | #include "assert.h" 39 | #include "defs.h" 40 | #include "sys/socket.h" 41 | #include "stdlib.h" 42 | #include "tls_engine.h" 43 | 44 | typedef struct uv_tls_s uv_tls_t; 45 | 46 | typedef void (*tls_rd_cb)(uv_tls_t* h, int nrd, uv_buf_t* dcrypted); 47 | typedef void (*tls_close_cb)(uv_tls_t* h); 48 | typedef void (*tls_connect_cb)(uv_connect_t* req, int status); 49 | 50 | //Most used members are put first 51 | struct uv_tls_s { 52 | uv_tcp_t socket_; //handle that encapsulate the socket 53 | tls_engine tls_eng; //the tls engine representation 54 | void *data; 55 | int oprn_state; // operational state 56 | tls_rd_cb rd_cb; 57 | tls_close_cb close_cb; 58 | tls_connect_cb on_tls_connect; 59 | uv_connect_t *con_req; 60 | }; 61 | 62 | 63 | /* 64 | *Initialize the common part of SSL startup both for client and server 65 | Only uv_tls_init at max will return TLS engine related issue other will have 66 | libuv error 67 | */ 68 | int uv_tls_init(uv_loop_t* loop, uv_tls_t* stream); 69 | int uv_tls_read(uv_tls_t* client, tls_rd_cb on_read); 70 | int uv_tls_write(uv_write_t* req, uv_tls_t *client, uv_buf_t* buf, uv_write_cb cb); 71 | 72 | int uv_tls_close(uv_tls_t* session, tls_close_cb close_cb); 73 | //shutdown should go away 74 | int uv_tls_shutdown(uv_tls_t* session); 75 | 76 | int uv_tls_connect (uv_connect_t *req, 77 | uv_tls_t* hdl, 78 | const char *host, 79 | int port, 80 | uv_connect_cb cb); 81 | 82 | #ifdef __cplusplus 83 | } 84 | #endif 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /src/bio.c: -------------------------------------------------------------------------------- 1 | #include "bio.h" 2 | 3 | /* Return the number of pending bytes in read and write buffers */ 4 | size_t BIO_ctrl_pending(BIO *bio) { 5 | if (bio == NULL) { 6 | return 0; 7 | } 8 | 9 | if (bio->type == BIO_MEMORY) { 10 | return bio->memLen; 11 | } 12 | 13 | /* type BIO_BIO then check paired buffer */ 14 | if (bio->type == BIO_BIO && bio->pair != NULL) { 15 | BIO *pair = bio->pair; 16 | if (pair->wrIdx > 0 && pair->wrIdx <= pair->rdIdx) { 17 | /* in wrap around state where begining of buffer is being 18 | * overwritten */ 19 | return pair->wrSz - pair->rdIdx + pair->wrIdx; 20 | } else { 21 | /* simple case where has not wrapped around */ 22 | return pair->wrIdx - pair->rdIdx; 23 | } 24 | } 25 | 26 | return 0; 27 | } 28 | 29 | 30 | 31 | int BIO_set_write_buf_size(BIO *bio, long size) { 32 | if (bio == NULL || bio->type != BIO_BIO || size < 0) { 33 | return SSL_FAILURE; 34 | } 35 | 36 | /* if already in pair then do not change size */ 37 | if (bio->pair != NULL) { 38 | return SSL_FAILURE; 39 | } 40 | 41 | bio->wrSz = (int) size; 42 | if (bio->wrSz < 0) { 43 | return SSL_FAILURE; 44 | } 45 | 46 | if (bio->mem != NULL) { 47 | free(bio->mem); 48 | } 49 | 50 | bio->mem = (BYTE *) malloc(bio->wrSz); 51 | if (bio->mem == NULL) { 52 | return SSL_FAILURE; 53 | } 54 | bio->wrIdx = 0; 55 | bio->rdIdx = 0; 56 | 57 | return SSL_SUCCESS; 58 | } 59 | 60 | 61 | /* Joins two BIO_BIO types. The write of b1 goes to the read of b2 and vise 62 | * versa. Creating something similar to a two way pipe. 63 | * Reading and writing between the two BIOs is not thread safe, they are 64 | * expected to be used by the same thread. */ 65 | int BIO_make_bio_pair(BIO *b1, BIO *b2) { 66 | if (b1 == NULL || b2 == NULL) { 67 | return SSL_FAILURE; 68 | } 69 | 70 | /* both are expected to be of type BIO and not already paired */ 71 | if (b1->type != BIO_BIO || b2->type != BIO_BIO || 72 | b1->pair != NULL || b2->pair != NULL) { 73 | return SSL_FAILURE; 74 | } 75 | 76 | /* set default write size if not already set */ 77 | if (b1->mem == NULL && BIO_set_write_buf_size(b1, SSL_BIO_SIZE) != SSL_SUCCESS) { 78 | return SSL_FAILURE; 79 | } 80 | 81 | if (b2->mem == NULL && BIO_set_write_buf_size(b2, SSL_BIO_SIZE) != SSL_SUCCESS) { 82 | return SSL_FAILURE; 83 | } 84 | 85 | b1->pair = b2; 86 | b2->pair = b1; 87 | 88 | return SSL_SUCCESS; 89 | } 90 | 91 | 92 | /* Does not advance read index pointer */ 93 | int BIO_nread0(BIO *bio, char **buf) { 94 | if (bio == NULL || buf == NULL) { 95 | return 0; 96 | } 97 | 98 | /* if paired read from pair */ 99 | if (bio->pair != NULL) { 100 | BIO *pair = bio->pair; 101 | 102 | /* case where have wrapped around write buffer */ 103 | *buf = (char *) pair->mem + pair->rdIdx; 104 | if (pair->wrIdx > 0 && pair->rdIdx >= pair->wrIdx) { 105 | return pair->wrSz - pair->rdIdx; 106 | } else { 107 | return pair->wrIdx - pair->rdIdx; 108 | } 109 | } 110 | 111 | return 0; 112 | } 113 | 114 | 115 | /* similar to SSL_BIO_nread0 but advances the read index */ 116 | int BIO_nread(BIO *bio, char **buf, size_t num) { 117 | int sz = SSL_BIO_UNSET; 118 | 119 | if (bio == NULL || buf == NULL) { 120 | return SSL_FAILURE; 121 | } 122 | 123 | if (bio->pair != NULL) { 124 | /* special case if asking to read 0 bytes */ 125 | if (num == 0) { 126 | *buf = (char *) bio->pair->mem + bio->pair->rdIdx; 127 | return 0; 128 | } 129 | 130 | /* get amount able to read and set buffer pointer */ 131 | sz = BIO_nread0(bio, buf); 132 | if (sz == 0) { 133 | return SSL_BIO_ERROR; 134 | } 135 | 136 | if (num < sz) { 137 | sz = num; 138 | } 139 | bio->pair->rdIdx += sz; 140 | 141 | /* check if have read to the end of the buffer and need to reset */ 142 | if (bio->pair->rdIdx == bio->pair->wrSz) { 143 | bio->pair->rdIdx = 0; 144 | if (bio->pair->wrIdx == bio->pair->wrSz) { 145 | bio->pair->wrIdx = 0; 146 | } 147 | } 148 | 149 | /* check if read up to write index, if so then reset indexs */ 150 | if (bio->pair->rdIdx == bio->pair->wrIdx) { 151 | bio->pair->rdIdx = 0; 152 | bio->pair->wrIdx = 0; 153 | } 154 | } 155 | 156 | return sz; 157 | } 158 | 159 | 160 | int BIO_nwrite(BIO *bio, char **buf, int num) { 161 | int sz = SSL_BIO_UNSET; 162 | 163 | if (bio == NULL || buf == NULL) { 164 | return 0; 165 | } 166 | 167 | if (bio->pair != NULL) { 168 | if (num == 0) { 169 | *buf = (char *) bio->mem + bio->wrIdx; 170 | return 0; 171 | } 172 | 173 | if (bio->wrIdx < bio->rdIdx) { 174 | /* if wrapped around only write up to read index. In this case 175 | * rdIdx is always greater then wrIdx so sz will not be negative. */ 176 | sz = bio->rdIdx - bio->wrIdx; 177 | } else if (bio->rdIdx > 0 && bio->wrIdx == bio->rdIdx) { 178 | return SSL_BIO_ERROR; /* no more room to write */ 179 | } else { 180 | /* write index is past read index so write to end of buffer */ 181 | sz = bio->wrSz - bio->wrIdx; 182 | 183 | if (sz <= 0) { 184 | /* either an error has occured with write index or it is at the 185 | * end of the write buffer. */ 186 | if (bio->rdIdx == 0) { 187 | /* no more room, nothing has been read */ 188 | return SSL_BIO_ERROR; 189 | } 190 | 191 | bio->wrIdx = 0; 192 | 193 | /* check case where read index is not at 0 */ 194 | if (bio->rdIdx > 0) { 195 | sz = bio->rdIdx; /* can write up to the read index */ 196 | } else { 197 | sz = bio->wrSz; /* no restriction other then buffer size */ 198 | } 199 | } 200 | } 201 | 202 | if (num < sz) { 203 | sz = num; 204 | } 205 | *buf = (char *) bio->mem + bio->wrIdx; 206 | bio->wrIdx += sz; 207 | 208 | /* if at the end of the buffer and space for wrap around then set 209 | * write index back to 0 */ 210 | if (bio->wrIdx == bio->wrSz && bio->rdIdx > 0) { 211 | bio->wrIdx = 0; 212 | } 213 | } 214 | 215 | return sz; 216 | } 217 | 218 | 219 | /* Reset BIO to initial state */ 220 | int BIO_reset(BIO *bio) { 221 | 222 | if (bio == NULL) { 223 | /* -1 is consistent failure even for FILE type */ 224 | return SSL_BIO_ERROR; 225 | } 226 | 227 | switch (bio->type) { 228 | case BIO_BIO: 229 | bio->rdIdx = 0; 230 | bio->wrIdx = 0; 231 | return 0; 232 | 233 | default: { 234 | break; 235 | } 236 | } 237 | 238 | return SSL_BIO_ERROR; 239 | } 240 | 241 | 242 | int BIO_read(BIO *bio, const char *buf, size_t size) { 243 | int sz; 244 | char* pt; 245 | 246 | sz = BIO_nread(bio, &pt, size); 247 | 248 | if (sz > 0) { 249 | memcpy(buf, pt, sz); 250 | } 251 | 252 | return sz; 253 | } 254 | 255 | int BIO_write(BIO *bio, const char *buf, size_t size) { 256 | /* internal function where arguments have already been sanity checked */ 257 | int sz; 258 | char* data; 259 | 260 | sz = BIO_nwrite(bio, &data, size); 261 | 262 | /* test space for write */ 263 | if (sz <= 0) { 264 | return sz; 265 | } 266 | 267 | memcpy(data, buf, sz); 268 | 269 | return sz; 270 | } 271 | 272 | 273 | /** 274 | * support bio type only 275 | *e 276 | * @param type 277 | * @return 278 | */ 279 | BIO *SSL_BIO_new(int type) { 280 | BIO *bio = (BIO *) malloc(sizeof(BIO)); 281 | if (bio) { 282 | bzero(bio, sizeof(BIO)); 283 | bio->type = type; 284 | bio->mem = NULL; 285 | bio->prev = NULL; 286 | bio->next = NULL; 287 | } 288 | return bio; 289 | } 290 | 291 | int BIO_free(BIO* bio) 292 | { 293 | /* unchain?, doesn't matter in goahead since from free all */ 294 | if (bio) { 295 | /* remove from pair by setting the paired bios pair to NULL */ 296 | if (bio->pair != NULL) { 297 | bio->pair->pair = NULL; 298 | } 299 | if (bio->mem) free(bio->mem); 300 | free(bio); 301 | } 302 | return 0; 303 | } 304 | 305 | 306 | int BIO_free_all(BIO* bio) 307 | { 308 | while (bio) { 309 | BIO* next = bio->next; 310 | BIO_free(bio); 311 | bio = next; 312 | } 313 | return 0; 314 | } 315 | 316 | int BIO_net_send( void *ctx, const unsigned char *buf, size_t len ) { 317 | BIO *bio = (BIO*)ctx; 318 | 319 | int sz; 320 | sz = BIO_write(bio, (const char *)buf, len); 321 | if (sz <= 0) { 322 | return MBEDTLS_ERR_SSL_WANT_WRITE; 323 | } 324 | return sz; 325 | } 326 | 327 | int BIO_net_recv( void *ctx, unsigned char *buf, size_t len) { 328 | BIO *bio = (BIO*)ctx; 329 | 330 | int sz; 331 | 332 | sz = BIO_read(bio, (const char *)buf, len); 333 | 334 | if (sz <= 0) { 335 | return MBEDTLS_ERR_SSL_WANT_READ; 336 | } 337 | return sz; 338 | } -------------------------------------------------------------------------------- /src/tls_engine.c: -------------------------------------------------------------------------------- 1 | 2 | #include "tls_engine.h" 3 | 4 | const char certs[] = 5 | // GlobalSign Root CA 6 | "-----BEGIN CERTIFICATE-----\r\n" \ 7 | "MIIE0DCCBDmgAwIBAgIQJQzo4DBhLp8rifcFTXz4/TANBgkqhkiG9w0BAQUFADBf\r\n"\ 8 | "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT\r\n"\ 9 | "LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw\r\n"\ 10 | "HhcNMDYxMTA4MDAwMDAwWhcNMjExMTA3MjM1OTU5WjCByjELMAkGA1UEBhMCVVMx\r\n"\ 11 | "FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz\r\n"\ 12 | "dCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZv\r\n"\ 13 | "ciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAz\r\n"\ 14 | "IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEi\r\n"\ 15 | "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8\r\n"\ 16 | "RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs70Pb\r\n"\ 17 | "ZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pSS9KP6HBR\r\n"\ 18 | "TdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/\r\n"\ 19 | "Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNH\r\n"\ 20 | "iDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMB\r\n"\ 21 | "AAGjggGbMIIBlzAPBgNVHRMBAf8EBTADAQH/MDEGA1UdHwQqMCgwJqAkoCKGIGh0\r\n"\ 22 | "dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA4GA1UdDwEB/wQEAwIBBjA9\r\n"\ 23 | "BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVy\r\n"\ 24 | "aXNpZ24uY29tL2NwczAdBgNVHQ4EFgQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwbQYI\r\n"\ 25 | "KwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQU\r\n"\ 26 | "j+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29t\r\n"\ 27 | "L3ZzbG9nby5naWYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v\r\n"\ 28 | "b2NzcC52ZXJpc2lnbi5jb20wPgYDVR0lBDcwNQYIKwYBBQUHAwEGCCsGAQUFBwMC\r\n"\ 29 | "BggrBgEFBQcDAwYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEBBQUA\r\n"\ 30 | "A4GBABMC3fjohgDyWvj4IAxZiGIHzs73Tvm7WaGY5eE43U68ZhjTresY8g3JbT5K\r\n"\ 31 | "lCDDPLq9ZVTGr0SzEK0saz6r1we2uIFjxfleLuUqZ87NMwwq14lWAyMfs77oOghZ\r\n"\ 32 | "tOxFNfeKW/9mz1Cvxm1XjRl4t7mi0VfqH5pLr7rJjhJ+xr3/\r\n"\ 33 | "-----END CERTIFICATE-----\r\n" 34 | "-----BEGIN CERTIFICATE-----\r\n" \ 35 | "MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh\r\n" \ 36 | "MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE\r\n" \ 37 | "YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3\r\n" \ 38 | "MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo\r\n" \ 39 | "ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg\r\n" \ 40 | "MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN\r\n" \ 41 | "ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA\r\n" \ 42 | "PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w\r\n" \ 43 | "wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi\r\n" \ 44 | "EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY\r\n" \ 45 | "avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+\r\n" \ 46 | "YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE\r\n" \ 47 | "sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h\r\n" \ 48 | "/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5\r\n" \ 49 | "IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj\r\n" \ 50 | "YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD\r\n" \ 51 | "ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy\r\n" \ 52 | "OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P\r\n" \ 53 | "TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ\r\n" \ 54 | "HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER\r\n" \ 55 | "dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf\r\n" \ 56 | "ReYNnyicsbkqWletNw+vHX/bvZ8=\r\n" \ 57 | "-----END CERTIFICATE-----\r\n" 58 | ""; 59 | 60 | int tls_engine_init(tls_engine *tls) 61 | { 62 | int ret; 63 | /* 64 | * 0. Initialize the RNG and the session data 65 | */ 66 | mbedtls_net_init( &tls->ctx ); 67 | mbedtls_ssl_init( &tls->ssl ); 68 | mbedtls_ssl_config_init( &tls->conf ); 69 | mbedtls_x509_crt_init( &tls->cacert ); 70 | mbedtls_ctr_drbg_init( &tls->ctr_drbg ); 71 | const char *pers = "chat"; 72 | 73 | mbedtls_printf( "\n . Seeding the random number generator...\n" ); 74 | 75 | mbedtls_entropy_init( &tls->entropy ); 76 | if( ( ret = mbedtls_ctr_drbg_seed( &tls->ctr_drbg, 77 | mbedtls_entropy_func, 78 | &tls->entropy, 79 | (const unsigned char *) pers, 80 | strlen( pers ) ) ) != 0 ) 81 | { 82 | mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret ); 83 | return ERR_TLS_ERROR; 84 | } 85 | 86 | mbedtls_printf( " ok\n" ); 87 | 88 | /* 89 | * 0. Initialize certificates 90 | */ 91 | mbedtls_printf( " . Loading the CA root certificate ...\n" ); 92 | 93 | ret = mbedtls_x509_crt_parse( &tls->cacert, 94 | (const unsigned char *) certs, 95 | sizeof(certs) ); 96 | if( ret < 0 ) 97 | { 98 | mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret ); 99 | return ERR_TLS_ERROR; 100 | } 101 | 102 | mbedtls_printf( " ok (%d skipped)\n", ret ); 103 | 104 | return ERR_TLS_OK; 105 | } 106 | 107 | 108 | void tls_engine_stop(tls_engine *tls) 109 | { 110 | mbedtls_net_free( &tls->ctx ); 111 | 112 | mbedtls_x509_crt_free( &tls->cacert ); 113 | mbedtls_ssl_free( &tls->ssl ); 114 | mbedtls_ssl_config_free( &tls->conf ); 115 | mbedtls_ctr_drbg_free( &tls->ctr_drbg ); 116 | mbedtls_entropy_free( &tls->entropy ); 117 | 118 | } 119 | 120 | -------------------------------------------------------------------------------- /src/uv_tls.c: -------------------------------------------------------------------------------- 1 | #include "uv_tls.h" 2 | 3 | uv_stream_t *uv_tls_get_stream(uv_tls_t *tls) { 4 | return (uv_stream_t *) &tls->socket_; 5 | } 6 | 7 | int uv_tls_init(uv_loop_t *loop, uv_tls_t *strm) { 8 | uv_tcp_init(loop, &strm->socket_); 9 | strm->socket_.data = strm; 10 | 11 | tls_engine *ng = &(strm->tls_eng); 12 | tls_engine_init(ng); 13 | 14 | ng->ssl_bio_ = 0; 15 | ng->app_bio_ = 0; 16 | strm->oprn_state = STATE_INIT; 17 | strm->rd_cb = NULL; 18 | strm->close_cb = NULL; 19 | strm->on_tls_connect = NULL; 20 | return 0; 21 | } 22 | 23 | void stay_uptodate(uv_tls_t *sec_strm, uv_alloc_cb uv__tls_alloc) { 24 | uv_stream_t * client = uv_tls_get_stream(sec_strm); 25 | 26 | size_t pending = BIO_ctrl_pending(sec_strm->tls_eng.app_bio_); 27 | if( pending > 0) { 28 | 29 | //Need to free the memory 30 | uv_buf_t mybuf; 31 | 32 | if(uv__tls_alloc) { 33 | uv__tls_alloc((uv_handle_t*)client, (size_t)pending, &mybuf); 34 | } 35 | 36 | int rv = BIO_read(sec_strm->tls_eng.app_bio_, mybuf.base, pending); 37 | assert( rv == pending ); 38 | 39 | rv = uv_try_write(client, &mybuf, 1); 40 | assert(rv == pending); 41 | 42 | free(mybuf.base); 43 | mybuf.base = 0; 44 | } 45 | } 46 | 47 | static void uv__tls_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf) { 48 | buf->base = malloc(size); 49 | assert(buf->base != NULL && "Memory allocation failed"); 50 | buf->len = size; 51 | } 52 | 53 | //handle only non fatal error currently 54 | int uv__tls_err_hdlr(uv_tls_t *k, const int err_code) { 55 | switch(err_code) { 56 | case MBEDTLS_ERR_SSL_WANT_WRITE: 57 | case MBEDTLS_ERR_SSL_WANT_READ: { 58 | stay_uptodate(k, uv__tls_alloc); 59 | break; 60 | } 61 | case OK: { 62 | return OK; 63 | } 64 | default: { 65 | char buf[512]; 66 | mbedtls_strerror(err_code, buf, 512); 67 | __log(0, "uv__tls_err_hdlr error:%s\n", buf); 68 | return err_code; 69 | } 70 | } 71 | return err_code; 72 | } 73 | 74 | void after_close(uv_handle_t *hdl) { 75 | uv_tls_t *s = CONTAINER_OF((uv_tcp_t*)hdl, uv_tls_t, socket_); 76 | if( s->close_cb) { 77 | s->close_cb(s); 78 | s = NULL; 79 | } 80 | } 81 | 82 | int uv__tls_close(uv_tls_t *session) { 83 | 84 | tls_engine *tls = &(session->tls_eng); 85 | 86 | if (tls->app_bio_) { 87 | BIO_free_all(tls->app_bio_); 88 | } 89 | if (tls->ssl_bio_) { 90 | BIO_free_all(tls->ssl_bio_); 91 | } 92 | 93 | // int rv = SSL_shutdown(ng->ssl); 94 | // int ssl_error; 95 | // uv__tls_err_hdlr(session, rv); 96 | // 97 | // if( rv == 0) { 98 | // session->oprn_state = STATE_CLOSING; 99 | // rv = SSL_shutdown(ng->ssl); 100 | // uv__tls_err_hdlr(session, rv); 101 | // } 102 | // 103 | // if( rv == 1) { 104 | 105 | // } 106 | // 107 | // BIO_free(ng->app_bio_); 108 | // ng->app_bio_ = NULL; 109 | // SSL_free(ng->ssl); 110 | // ng->ssl = NULL; 111 | // 112 | // uv_close( (uv_handle_t*)uv_tls_get_stream(session), after_close); 113 | // 114 | // return rv; 115 | session->oprn_state = STATE_CLOSING; 116 | uv_close( (uv_handle_t*)uv_tls_get_stream(session), after_close); 117 | return 0; 118 | } 119 | 120 | //shutdown the ssl session then stream 121 | int uv_tls_close(uv_tls_t *session, tls_close_cb cb) { 122 | session->close_cb = cb; 123 | return uv__tls_close(session); 124 | } 125 | 126 | int uv__tls_handshake(uv_tls_t *tls) { 127 | if( tls->oprn_state & STATE_IO) { 128 | return 1; 129 | } 130 | int rv = 0, ssl_error; 131 | rv = mbedtls_ssl_handshake(&tls->tls_eng.ssl); 132 | rv = uv__tls_err_hdlr(tls, rv); 133 | 134 | tls->oprn_state = STATE_HANDSHAKING; 135 | 136 | if(rv == 0) { 137 | tls->oprn_state = STATE_IO; 138 | int status = mbedtls_ssl_get_verify_result(&tls->tls_eng.ssl); 139 | 140 | if (status) { 141 | char vrfy_buf[512]; 142 | 143 | mbedtls_printf( " failed\n" ); 144 | 145 | mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", status ); 146 | 147 | mbedtls_printf( "%s\n", vrfy_buf ); 148 | } 149 | 150 | 151 | if(tls->on_tls_connect) { 152 | assert(tls->con_req); 153 | tls->on_tls_connect(tls->con_req, status); 154 | } 155 | } 156 | return 0; 157 | } 158 | 159 | int uv_tls_shutdown(uv_tls_t *session) { 160 | // assert( session != NULL && "Invalid session"); 161 | // 162 | // SSL_CTX_free(session->tls_eng.ctx); 163 | // session->tls_eng.ctx = NULL; 164 | 165 | return 0; 166 | } 167 | 168 | uv_buf_t encode_data(uv_tls_t *sessn, uv_buf_t *data2encode) { 169 | //this should give me something to write to client 170 | size_t rv = (size_t)mbedtls_ssl_write(&sessn->tls_eng.ssl,(const unsigned char *) data2encode->base, data2encode->len); 171 | 172 | size_t pending = 0; 173 | uv_buf_t encoded_data = {.base = 0, .len = 0}; 174 | if( (pending = BIO_ctrl_pending(sessn->tls_eng.app_bio_) ) > 0 ) { 175 | 176 | encoded_data.base = (char*)malloc(pending); 177 | encoded_data.len = pending; 178 | 179 | rv = BIO_read(sessn->tls_eng.app_bio_, encoded_data.base, pending); 180 | data2encode->len = rv; 181 | } 182 | return encoded_data; 183 | } 184 | 185 | int uv_tls_write(uv_write_t *req, 186 | uv_tls_t *client, 187 | uv_buf_t *buf, 188 | uv_write_cb on_tls_write) { 189 | 190 | const uv_buf_t data = encode_data(client, buf); 191 | 192 | int rv = uv_write(req, uv_tls_get_stream(client), &data, 1, on_tls_write); 193 | if (data.base != NULL) { 194 | free(data.base); 195 | } 196 | return rv; 197 | } 198 | 199 | size_t uv__tls_read(uv_tls_t *tls, uv_buf_t *dcrypted, int sz) { 200 | 201 | if( 1 != uv__tls_handshake(tls)) { 202 | //recheck if handshake is complete now 203 | return STATE_HANDSHAKING; 204 | } 205 | // 206 | // //clean the slate 207 | memset( dcrypted->base, 0, sz); 208 | int rv = mbedtls_ssl_read(&tls->tls_eng.ssl, (unsigned char *)dcrypted->base, sz); 209 | uv__tls_err_hdlr(tls, rv); 210 | 211 | dcrypted->len = (size_t) rv; 212 | if( tls->rd_cb) { 213 | tls->rd_cb(tls, rv, dcrypted); 214 | } 215 | return rv; 216 | } 217 | 218 | void on_tcp_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { 219 | 220 | uv_tls_t *parent = CONTAINER_OF(client, uv_tls_t, socket_); 221 | assert( parent != NULL); 222 | 223 | if( nread <= 0 224 | // ( parent->oprn_state & STATE_IO) 225 | ) { 226 | printf("on_tcp_read error: %s\n", uv_strerror(nread)); 227 | if (parent->rd_cb) parent->rd_cb(parent, nread, (uv_buf_t*)buf); 228 | } else { 229 | BIO_write( parent->tls_eng.app_bio_, buf->base, nread); 230 | uv__tls_read(parent, (uv_buf_t*)buf, nread); 231 | } 232 | free(buf->base); 233 | } 234 | 235 | //uv_alloc_cb is unused, but here for cosmetic reasons 236 | //Need improvement 237 | int uv_tls_read(uv_tls_t *sclient, tls_rd_cb on_read) { 238 | sclient->rd_cb = on_read; 239 | return 0; 240 | } 241 | 242 | 243 | void on_tcp_conn(uv_connect_t *c, int status) { 244 | uv_tls_t *sclnt = c->handle->data; 245 | assert(sclnt != 0); 246 | 247 | if (status < 0) { 248 | sclnt->on_tls_connect(c, status); 249 | } else { //tcp connection established 250 | uv__tls_handshake(sclnt); 251 | uv_read_start((uv_stream_t *) &sclnt->socket_, uv__tls_alloc, on_tcp_read); 252 | } 253 | } 254 | 255 | static int assume_role(tls_engine *tls) { 256 | mbedtls_ssl_context ctx = tls->ssl; 257 | 258 | // tls_ngin->ssl = SSL_new(tls_ngin->ctx); 259 | // if(!tls_ngin->ssl) { 260 | // return ERR_TLS_ERROR; 261 | // } 262 | // 263 | // if( endpt_role == 1) { 264 | // SSL_set_accept_state(tls_ngin->ssl); 265 | // } 266 | // else { 267 | // //set in client mode 268 | // SSL_set_connect_state(tls_ngin->ssl); 269 | // } 270 | // 271 | // //use default buf size for now. 272 | // if( !BIO_new_bio_pair(&(tls_ngin->ssl_bio_), 0, &(tls_ngin->app_bio_), 0)) { 273 | // return ERR_TLS_ERROR; 274 | // } 275 | // SSL_set_bio(tls_ngin->ssl, tls_ngin->ssl_bio_, tls_ngin->ssl_bio_); 276 | int ret; 277 | mbedtls_printf(" . Setting up the SSL/TLS structure...\n"); 278 | 279 | if ((ret = mbedtls_ssl_config_defaults(&tls->conf, 280 | MBEDTLS_SSL_IS_CLIENT, 281 | MBEDTLS_SSL_TRANSPORT_STREAM, 282 | MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { 283 | mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret); 284 | } 285 | 286 | mbedtls_printf(" ok\n"); 287 | 288 | /* OPTIONAL is not optimal for security, 289 | * but makes interop easier in this simplified example */ 290 | mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); 291 | mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->cacert, NULL); 292 | mbedtls_ssl_conf_rng(&tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg); 293 | // mbedtls_ssl_conf_dbg( &tls->conf, my_debug, stdout ); 294 | 295 | if ((ret = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) { 296 | mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned %d\n", ret); 297 | return ERR_TLS_ERROR; 298 | } 299 | 300 | 301 | tls->ssl_bio_ = SSL_BIO_new(BIO_BIO); 302 | tls->app_bio_ = SSL_BIO_new(BIO_BIO); 303 | BIO_make_bio_pair(tls->ssl_bio_, tls->app_bio_); 304 | 305 | // mbedtls_ssl_set_bio( &tls->ssl, tls->ssl_bio_, mbedtls_net_send, mbedtls_net_recv, NULL ); 306 | mbedtls_ssl_set_bio(&tls->ssl, tls->ssl_bio_, BIO_net_send, BIO_net_recv, NULL); 307 | return ERR_TLS_OK; 308 | } 309 | 310 | 311 | int uv_tls_connect( 312 | uv_connect_t *req, 313 | uv_tls_t *hdl, 314 | const char *host, 315 | int port, 316 | uv_connect_cb cb) { 317 | 318 | tls_engine *tls_ngin = &(hdl->tls_eng); 319 | int rv = assume_role(tls_ngin); 320 | // 321 | if( ( rv = mbedtls_ssl_set_hostname( &tls_ngin->ssl, host) ) != 0 ) 322 | { 323 | mbedtls_printf( " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", rv ); 324 | rv = ERR_TLS_ERROR; 325 | } 326 | 327 | struct sockaddr_in addr_in; 328 | struct addrinfo *req_addr; 329 | 330 | int ret = getaddrinfo(host, NULL, NULL, &req_addr); 331 | if (ret) { 332 | __log(LOG_VERBOSE, "get address info error"); 333 | return -1; 334 | } 335 | 336 | memcpy(&addr_in, req_addr->ai_addr, sizeof(struct sockaddr_in)); 337 | addr_in.sin_port = htons(port); 338 | 339 | freeaddrinfo(req_addr); 340 | 341 | 342 | if (rv != ERR_TLS_OK) { 343 | return rv; 344 | } 345 | 346 | hdl->on_tls_connect = cb; 347 | hdl->con_req = req; 348 | 349 | return uv_tcp_connect(req, &(hdl->socket_), (const struct sockaddr *)&addr_in, on_tcp_conn); 350 | } 351 | 352 | 353 | --------------------------------------------------------------------------------