| /* |
| * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. |
| * |
| * Licensed under the OpenSSL license (the "License"). You may not use |
| * this file except in compliance with the License. You can obtain a copy |
| * in the file LICENSE in the source distribution or at |
| * https://www.openssl.org/source/license.html |
| */ |
| |
| #include "ssltestlib.h" |
| |
| int create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm, |
| SSL_CTX **sctx, SSL_CTX **cctx, char *certfile, |
| char *privkeyfile) |
| { |
| SSL_CTX *serverctx = NULL; |
| SSL_CTX *clientctx = NULL; |
| |
| serverctx = SSL_CTX_new(sm); |
| clientctx = SSL_CTX_new(cm); |
| if (serverctx == NULL || clientctx == NULL) { |
| printf("Failed to create SSL_CTX\n"); |
| goto err; |
| } |
| |
| if (SSL_CTX_use_certificate_file(serverctx, certfile, |
| SSL_FILETYPE_PEM) <= 0) { |
| printf("Failed to load server certificate\n"); |
| goto err; |
| } |
| if (SSL_CTX_use_PrivateKey_file(serverctx, privkeyfile, |
| SSL_FILETYPE_PEM) <= 0) { |
| printf("Failed to load server private key\n"); |
| } |
| if (SSL_CTX_check_private_key(serverctx) <= 0) { |
| printf("Failed to check private key\n"); |
| goto err; |
| } |
| |
| *sctx = serverctx; |
| *cctx = clientctx; |
| |
| return 1; |
| err: |
| SSL_CTX_free(serverctx); |
| SSL_CTX_free(clientctx); |
| return 0; |
| } |
| |
| #define MAXLOOPS 100000 |
| |
| /* |
| * NOTE: Transfers control of the BIOs - this function will free them on error |
| */ |
| int create_ssl_connection(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl, |
| SSL **cssl, BIO *s_to_c_fbio, BIO *c_to_s_fbio) |
| { |
| int retc = -1, rets = -1, err, abortctr = 0; |
| SSL *serverssl, *clientssl; |
| BIO *s_to_c_bio = NULL, *c_to_s_bio = NULL; |
| |
| serverssl = SSL_new(serverctx); |
| clientssl = SSL_new(clientctx); |
| |
| if (serverssl == NULL || clientssl == NULL) { |
| printf("Failed to create SSL object\n"); |
| goto error; |
| } |
| |
| s_to_c_bio = BIO_new(BIO_s_mem()); |
| c_to_s_bio = BIO_new(BIO_s_mem()); |
| if (s_to_c_bio == NULL || c_to_s_bio == NULL) { |
| printf("Failed to create mem BIOs\n"); |
| goto error; |
| } |
| |
| if (s_to_c_fbio != NULL) |
| s_to_c_bio = BIO_push(s_to_c_fbio, s_to_c_bio); |
| if (c_to_s_fbio != NULL) |
| c_to_s_bio = BIO_push(c_to_s_fbio, c_to_s_bio); |
| if (s_to_c_bio == NULL || c_to_s_bio == NULL) { |
| printf("Failed to create chained BIOs\n"); |
| goto error; |
| } |
| |
| /* Set Non-blocking IO behaviour */ |
| BIO_set_mem_eof_return(s_to_c_bio, -1); |
| BIO_set_mem_eof_return(c_to_s_bio, -1); |
| |
| /* Up ref these as we are passing them to two SSL objects */ |
| BIO_up_ref(s_to_c_bio); |
| BIO_up_ref(c_to_s_bio); |
| |
| SSL_set_bio(serverssl, c_to_s_bio, s_to_c_bio); |
| SSL_set_bio(clientssl, s_to_c_bio, c_to_s_bio); |
| |
| /* BIOs will now be freed when SSL objects are freed */ |
| s_to_c_bio = c_to_s_bio = NULL; |
| s_to_c_fbio = c_to_s_fbio = NULL; |
| |
| do { |
| err = SSL_ERROR_WANT_WRITE; |
| while (retc <= 0 && err == SSL_ERROR_WANT_WRITE) { |
| retc = SSL_connect(clientssl); |
| if (retc <= 0) |
| err = SSL_get_error(clientssl, retc); |
| } |
| |
| if (retc <= 0 && err != SSL_ERROR_WANT_READ) { |
| printf("SSL_connect() failed %d, %d\n", retc, err); |
| goto error; |
| } |
| |
| err = SSL_ERROR_WANT_WRITE; |
| while (rets <= 0 && err == SSL_ERROR_WANT_WRITE) { |
| rets = SSL_accept(serverssl); |
| if (rets <= 0) |
| err = SSL_get_error(serverssl, rets); |
| } |
| |
| if (rets <= 0 && err != SSL_ERROR_WANT_READ) { |
| printf("SSL_accept() failed %d, %d\n", retc, err); |
| goto error; |
| } |
| if (++abortctr == MAXLOOPS) { |
| printf("No progress made\n"); |
| goto error; |
| } |
| } while (retc <=0 || rets <= 0); |
| |
| *sssl = serverssl; |
| *cssl = clientssl; |
| |
| return 1; |
| |
| error: |
| SSL_free(serverssl); |
| SSL_free(clientssl); |
| BIO_free(s_to_c_bio); |
| BIO_free(c_to_s_bio); |
| BIO_free(s_to_c_fbio); |
| BIO_free(c_to_s_fbio); |
| |
| return 0; |
| } |