diff --git a/platforms/unix/plugins/SqueakSSL/Makefile.inc b/platforms/unix/plugins/SqueakSSL/Makefile.inc index 524eda7d29..56bbe5138f 100644 --- a/platforms/unix/plugins/SqueakSSL/Makefile.inc +++ b/platforms/unix/plugins/SqueakSSL/Makefile.inc @@ -1,2 +1,9 @@ +# +# For platform builds, use + #XLDFLAGS= -lcrypto -lssl -XLDFLAGS= -Wl,--no-as-needed -lrt -Wl,-Bstatic -lcrypto -lssl -Wl,-Bdynamic -lrt +#XCFLAGS= -DSQSSL_OPENSSL_LINKED + +# otherwise the OpenSSL libs will be looked up at runtime. +# +# diff --git a/platforms/unix/plugins/SqueakSSL/config.cmake b/platforms/unix/plugins/SqueakSSL/config.cmake index 08b53ce4da..07c14cfbe1 100644 --- a/platforms/unix/plugins/SqueakSSL/config.cmake +++ b/platforms/unix/plugins/SqueakSSL/config.cmake @@ -1 +1,9 @@ -PLUGIN_REQUIRE_PACKAGE (OPENSSL openssl) +# +# For platform builds, use + +# PLUGIN_REQUIRE_PACKAGE (OPENSSL openssl) +# add_definitions(-DSQSSL_OPENSSL_LINKED) + +# otherwise the OpenSSL libs will be looked up at runtime. +# +# \ No newline at end of file diff --git a/platforms/unix/plugins/SqueakSSL/openssl_overlay.h b/platforms/unix/plugins/SqueakSSL/openssl_overlay.h new file mode 100644 index 0000000000..81d1510a20 --- /dev/null +++ b/platforms/unix/plugins/SqueakSSL/openssl_overlay.h @@ -0,0 +1,366 @@ +#ifndef SQ_OPENSSL_OVERLAY_H +#define SQ_OPENSSL_OVERLAY_H 1 +/**************************************************************************** + * PROJECT: SqueakSSL implementation for Linux/Unix + * FILE: openssl_overlay.h + * CONTENT: Overlay OpenSSL for Linux/Unix + * + * AUTHORS: Tobias Pape (topa) + * Hasso Plattner Institute, Potsdam, Germany + ***************************************************************************** + * When we dynamically link against OpenSSL, the bundles are not + * portable, as CentOS and friends use other SO_NAMEs than Debian and + * friends. Also, soft-fallback for later features such as host name + * verification is hard. + * + * When we statically link, we might lack behind the OS, the binaries + * are bigger, and the legal situation is less clear. + * + * So we now support not linking at all but rather lookup all necessary + * functions/symbols at runtime. + * + * This can be disabled with SQSSL_OPENSSL_LINKED which effectively + * results in the dynamically-linked behavior. (This is preferable for + * platform builds, eg, debs and rpms) + *****************************************************************************/ +#include +#include +#include +#include + +/* + * List of all used OpenSSL functions in the following format: + * + * SQO_DECL___(RETURN_TYPE, NAME, ARGS...) + * + * For symbols that appeared first version XYZ (X >=1) use SQO_DECLXYZ, + * for example: + * + * SQO_DECL102 (Available since OpenSSL 1.0.2) + * (NAME will have value NULL in OpenSSL < 1.0.2) + * + * SPECIAL CASE FOR OLD OPENSSL + * For symbols with different types in 0.9.8 / 1.0.0 use: + * + * SQO_DECL098 (OpenSSL <= 0.9.8) + * (NAME will not be defined in > 0.9.8) + * SQO_DECL100 (OpenSSL >= 1.0.0) + * (NAME will not be defined in < 1.0.0) + * + */ +#define SQO_DECLARATIONS \ + /**/ \ + SQO_DECL___(unsigned char *, ASN1_STRING_data, ASN1_STRING *x) \ + SQO_DECL___(int, ASN1_STRING_length, const ASN1_STRING *x) \ + SQO_DECL___(void, BIO_free_all, BIO *a) \ + SQO_DECL___(BIO *, BIO_new, BIO_METHOD *type) \ + SQO_DECL___(BIO_METHOD *, BIO_s_mem, void) \ + SQO_DECL___(size_t, BIO_ctrl_pending, BIO *bp) \ + SQO_DECL___(long, BIO_ctrl, BIO *bp, int cmd, long larg, void *parg) \ + SQO_DECL___(int, BIO_write, BIO *b, const void *data, int len) \ + SQO_DECL___(int, BIO_read, BIO *b, void *data, int len) \ + SQO_DECL___(void, ERR_print_errors_fp, FILE *fp) \ + SQO_DECL___(void, SSL_CTX_free, SSL_CTX *) \ + SQO_DECL___(int, SSL_CTX_set_cipher_list, SSL_CTX *, const char *str) \ + SQO_DECL___(int, SSL_CTX_set_default_verify_paths, SSL_CTX *ctx) \ + SQO_DECL___(long, SSL_CTX_ctrl, SSL_CTX *ctx, int cmd, long larg, void *parg) \ + SQO_DECL___(int, SSL_CTX_use_PrivateKey_file, SSL_CTX *ctx, const char *file, int type) \ + SQO_DECL___(int, SSL_CTX_use_certificate_file, SSL_CTX *ctx, const char *file, int type) \ + SQO_DECL___(int, SSL_accept, SSL *ssl) \ + SQO_DECL___(int, SSL_connect, SSL *ssl) \ + SQO_DECL___(void, SSL_free, SSL *ssl) \ + SQO_DECL___(long, SSL_ctrl, SSL *ssl, int cmd, long larg, void *parg) \ + SQO_DECL___(int, SSL_get_error, const SSL *s, int ret_code) \ + SQO_DECL___(X509 *, SSL_get_peer_certificate, const SSL *s) \ + SQO_DECL___(long, SSL_get_verify_result, const SSL *ssl) \ + SQO_DECL___(int, SSL_library_init, void) \ + SQO_DECL___(void, SSL_load_error_strings, void) \ + SQO_DECL___(SSL *, SSL_new, SSL_CTX *ctx) \ + SQO_DECL___(int, SSL_read, SSL *ssl, void *buf, int num) \ + SQO_DECL___(void, SSL_set_accept_state, SSL *s) \ + SQO_DECL___(void, SSL_set_bio, SSL *s, BIO *rbio, BIO *wbio) \ + SQO_DECL___(void, SSL_set_connect_state, SSL *s) \ + SQO_DECL___(int, SSL_write, SSL *ssl, const void *buf, int num) \ + SQO_DECL___(int, X509_NAME_get_text_by_NID, X509_NAME *name, int nid, char *buf, int len) \ + SQO_DECL___(X509_NAME *, X509_get_subject_name, X509 *a) \ + SQO_DECL___(void *, X509_get_ext_d2i, X509 *x, int nid, int *crit, int *idx) \ + SQO_DECL___(void, X509_free, X509 *ssl) \ + \ + SQO_DECL102(int, X509_check_ip_asc, X509 *x, const char *ipasc, unsigned int flags) \ + SQO_DECL102(int, X509_check_host, X509 *x, const char *chk, size_t chklen, unsigned int flags, char **peername) \ + \ + SQO_DECL100(_STACK *, sk_new_null, void) \ + SQO_DECL100(int, sk_push, _STACK *st, void *data) \ + SQO_DECL100(void, sk_free, _STACK *st) \ + SQO_DECL100(void *, sk_value, const _STACK *st, int i) \ + SQO_DECL100(int, sk_num, const _STACK *st) \ + SQO_DECL100(void, sk_pop_free, _STACK *st, void (*func) (void *)) \ + SQO_DECL100(const SSL_METHOD *, SSLv23_method, void) \ + SQO_DECL100(SSL_CTX *, SSL_CTX_new, const SSL_METHOD *a) \ + \ + SQO_DECL098(STACK *, sk_new_null, void) \ + SQO_DECL098(int, sk_push, STACK *st, char *data) \ + SQO_DECL098(void, sk_free, STACK *st) \ + SQO_DECL098(char *, sk_value, STACK *st, int i) \ + SQO_DECL098(int, sk_num, STACK *st) \ + SQO_DECL098(void, sk_pop_free, STACK *st, void (*func) (void *)) \ + SQO_DECL098(SSL_METHOD *, SSLv23_method, void) \ + SQO_DECL098(SSL_CTX *, SSL_CTX_new, SSL_METHOD *a) \ + /* backstop */ + +/* + * List of re-defined OpenSSL macros + * + * This is necessary to "redirect" the usage of un-prefixed symbols to + * sqo_-prefixed ones. + */ +#define sqo_BIO_set_close(b,c) (int)sqo_BIO_ctrl(b,BIO_CTRL_SET_CLOSE,(c),NULL) +#define sqo_SSL_set_tlsext_host_name(s,name) sqo_SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name) +#define sqo_SSL_CTX_set_options(ctx,op) sqo_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL) +#define sqo_SKM_sk_num(type, st) sqo_sk_num(CHECKED_STACK_OF(type, st)) +#define sqo_SKM_sk_value(type, st,i) ((type *)sqo_sk_value(CHECKED_STACK_OF(type, st), i)) +#define sqo_SKM_sk_free(type, st) sqo_sk_free(CHECKED_STACK_OF(type, st)) +#define sqo_SKM_sk_pop_free(type, st, free_func) sqo_sk_pop_free(CHECKED_STACK_OF(type, st), CHECKED_SK_FREE_FUNC(type, free_func)) +#define sqo_sk_GENERAL_NAME_num(st) sqo_SKM_sk_num(GENERAL_NAME, (st)) +#define sqo_sk_GENERAL_NAME_value(st, i) sqo_SKM_sk_value(GENERAL_NAME, (st), (i)) +#define sqo_sk_GENERAL_NAME_free(st) sqo_SKM_sk_free(GENERAL_NAME, (st)) +#define sqo_sk_GENERAL_NAME_pop_free(st, free_func) sqo_SKM_sk_pop_free(GENERAL_NAME, (st), (free_func)) + +/* + * List of optional OpenSSL constants + * + * This is necessary to allow usage of those constants with newer + * dynamically loaded libraries, but whilst using older versions at + * compile time. + */ +#if defined(X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS) +#define sqo_X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS +#else +#define sqo_X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10 +#endif + + +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L +#define SQO_DECL098 SQO_DECL_NO +#define SQO_DECL100 SQO_DECL___ +#else +#define SQO_DECL098 SQO_DECL___ +#define SQO_DECL100 SQO_DECL_NO +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +#define SQO_DECL102 SQO_DECL___ +#else +#define SQO_DECL102 SQO_DECL_IF +#endif + +/* + * WARNING: Here be dragons! + * + * Only change things beyond this line if you know exactly what + * will happen. + * + * The following stanzas will do this: + * + * * When compiling non-linked (dynamically loaded): + * * find dl-header, define helper macros for symbol lookup + * * define static handles for dynamic libraries + * * helper function that does actual lookup + * * helper function that unloads libraries on SqueakSSL unload + * + * * Declare all necessary OpenSSL symbols, prefixed with sqo_ + * + * * "loadLibrary" function to be called once by SqueakSSL: + * * When compiling linked (not dynamically loaded): + * * alias all necessary OpenSSL symbols to sqo_ prefixed + * * otherwise, when compiling non-linked (dynamically loaded): + * * lookup every symbol and assign to sqo_ prefixed name + * + * That's it, essentially. + */ +#if !defined(SQSSL_OPENSSL_LINKED) + +#include + +#if !defined(SQO_DL_FLAGS) +# if !defined(__OpenBSD__) +# define SQO_DL_FLAGS RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE +# else +# define SQO_DL_FLAGS RTLD_NOW | RTLD_GLOBAL +# endif +#endif /* !defined(SQO_DL_FLAGS) */ + +/* + * Handles for the dlopen'ed dynamic libraries + * + */ +static void* dlhandle_self = NULL; +static void* dlhandle_crypto = NULL; +static void* dlhandle_ssl = NULL; + + +/* + * Helpers to make sure the loaded library handles are closed when + * this module is unloaded (w/ care for at lease GCC and llvm/clang) + */ +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#if __has_attribute(destructor) \ + || defined(__GNUC__) +#define SQO_DESTRUCTOR __attribute__((destructor)) +#else +#define SQO_DESTRUCTOR /**/ +#endif + +void SQO_DESTRUCTOR fini(void) +{ + if (dlhandle_self) { dlclose(dlhandle_self); } + if (dlhandle_crypto) { dlclose(dlhandle_crypto); } + if (dlhandle_ssl) { dlclose(dlhandle_ssl);} +} + +/* + * Macro that lookups a symbol in a library and does immediately + * return the address when found. + * + * (with optional debug output) + */ +#if (defined(DEBUG) || defined(DEBUGVM)) && !defined(NDEBUG) +#define SQO_HAS_FOUND_SYM(s,n,h) \ + do { \ + s = dlsym(h, n); \ + if (s) { \ + fprintf(stderr, "Found symbol %s in " #h "\n", n); \ + return s; \ + } \ + } while (0) +#else +#define SQO_HAS_FOUND_SYM(s,n,h) \ + do { \ + if ((s = dlsym(h, n))) { \ + return s; \ + } \ + } while (0) +#endif + +/* + * Macro that lookups a symbol in a _named_ library. + * Loads library if not yet done. + * Uses SQO_HAS_FOUND_SYM, therefore immediately returns when found. + */ +#define SQO_FIND_SYM(sym, name, where, dlname) \ + do { \ + if (!dlhandle_ ## where) { \ + dlhandle_ ## where = dlopen(dlname, SQO_DL_FLAGS); \ + } \ + if (dlhandle_ ## where) { \ + SQO_HAS_FOUND_SYM(sym, name, dlhandle_ ## where); \ + } \ + } while (0) + + +/* + * Find symbol named "name" in one of the following namespaces + * (in order): + * + * 1. Already loaded dynamic objects + * 2. The running executable itself + * 3. libssl.so (as in OpenSSL) + * 4. libcrypto.so (as in OpenSSL) + */ +static inline void* _sqo_find(const char* name) +{ + void* sym = NULL; + SQO_HAS_FOUND_SYM(sym, name, RTLD_DEFAULT); + SQO_FIND_SYM(sym, name, self, NULL); + SQO_FIND_SYM(sym, name, ssl, "libssl.so"); + SQO_FIND_SYM(sym, name, crypto, "libcrypto.so"); + return sym; +} + +#endif /* !defined(SQSSL_OPENSSL_LINKED) */ + + +/* + * + * + * + * DECLARE ALL NECESSARY SYMBOLS AS FOUND IN SQO_DECLARATIONS + * + * + * + * + */ +#define SQO_DECL___(ret, name, ...) ret (*sqo_ ## name)(__VA_ARGS__); +#define SQO_DECL_IF(ret, name, ...) ret (*sqo_ ## name)(__VA_ARGS__); +#define SQO_DECL_NO(ret, name, ...) /**/ + +/* THIS LINE IS VITAL */ +SQO_DECLARATIONS + +#undef SQO_DECL___ +#undef SQO_DECL_NO +#undef SQO_DECL_IF + +/* + * Function that makes sure that all sqo_ prefixed OpenSSL names are + * actually available. + * + * Returns + * true when all required symbols could be loaded/are linked + * false when at least one required symbol could not be loaded + * + * Call this exactly once! + */ +bool loadLibrary(void) +{ + +/* + * + * + * + * ASSING ALL NECESSARY SYMBOLS AS FOUND IN SQO_DECLARATIONS + * + * + * + * + */ +#if defined(SQSSL_OPENSSL_LINKED) +# define SQO_DECL___(ret, name, ...) sqo_ ## name = &name; +# define SQO_DECL_NO(ret, name, ...) /**/ +# define SQO_DECL_IF(ret, name, ...) sqo_ ## name = NULL; +#else /* defined(SQSSL_OPENSSL_LINKED) */ +# define SQO_DECL___(ret, name, ...) \ + if (NULL == \ + (sqo_ ## name = (ret (*)(__VA_ARGS__)) _sqo_find(#name))) { \ + return false; \ + } +# define SQO_DECL_IF(ret, name, ...) \ + sqo_ ## name =(ret (*)(__VA_ARGS__)) _sqo_find(#name); +# define SQO_DECL_NO(ret, name, ...) /**/ +#endif /* defined(SQSSL_OPENSSL_LINKED) */ + +/* THIS LINE IS VITAL */ + SQO_DECLARATIONS + + +#undef SQO_DECL___ +#undef SQO_DECL_NO +#undef SQO_DECL_IF + + return true; +} + +#undef SQO_DECLARATIONS +/* !defined(SQ_OPENSSL_OVERLAY_H) */ +#endif +/* EOF */ diff --git a/platforms/unix/plugins/SqueakSSL/sqUnixOpenSSL.c b/platforms/unix/plugins/SqueakSSL/sqUnixOpenSSL.c index 39f38ca4b8..ed8d560a34 100644 --- a/platforms/unix/plugins/SqueakSSL/sqUnixOpenSSL.c +++ b/platforms/unix/plugins/SqueakSSL/sqUnixOpenSSL.c @@ -1,13 +1,12 @@ #include "sq.h" #include "SqueakSSL.h" -#include "openssl/ssl.h" -#include "openssl/err.h" -#include "openssl/x509v3.h" +#include "openssl_overlay.h" #include #include #include +#include #include @@ -30,6 +29,8 @@ typedef struct sqSSL { } sqSSL; +static bool wasInitialized = false; + static sqSSL **handleBuf = NULL; static sqInt handleMax = 0; @@ -56,21 +57,20 @@ static sqSSL *sslFromHandle(sqInt handle) { /* sqCopyBioSSL: Copies data from a BIO into an out buffer */ sqInt sqCopyBioSSL(sqSSL *ssl, BIO *bio, char *dstBuf, sqInt dstLen) { - int nbytes = BIO_ctrl_pending(bio); + int nbytes = sqo_BIO_ctrl_pending(bio); if(ssl->loglevel) printf("sqCopyBioSSL: %d bytes pending; buffer size %ld\n", nbytes, (long)dstLen); if(nbytes > dstLen) return -1; - return BIO_read(bio, dstBuf, dstLen); + return sqo_BIO_read(bio, dstBuf, dstLen); } -#ifndef X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS enum sqMatchResult sqVerifyIP(sqSSL* ssl, X509* cert, const char* serverName, const size_t serverNameLength); enum sqMatchResult sqVerifyDNS(sqSSL* ssl, X509* cert, const char* serverName, const size_t serverNameLength); -enum sqMatchResult sqVerifyNameInner(sqSSL* ssl, X509* cert, void* serverName, const size_t serverNameLength, const int matchType); +enum sqMatchResult sqVerifyNameInner(sqSSL* ssl, X509* cert, const void* serverName, const size_t serverNameLength, const int matchType); char* sqVerifyFindStar(char* sANData, size_t sANDataSize); -sqInt sqVerifySAN(sqSSL* ssl, const GENERAL_NAME* sAN, void* data, const size_t dataSizeIn, const int matchType); +sqInt sqVerifySAN(sqSSL* ssl, const GENERAL_NAME* sAN, const void* data, const size_t dataSizeIn, const int matchType); enum sqMatchResult sqVerifyIP(sqSSL* ssl, X509* cert, const char* serverName, const size_t serverNameLength) { struct in6_addr addr = { 0 }; // placeholder, longest of in_addr and in6_addr @@ -95,25 +95,25 @@ enum sqMatchResult sqVerifyDNS(sqSSL* ssl, X509* cert, const char* serverName, c return sqVerifyNameInner(ssl, cert, serverName, serverNameLength, GEN_DNS); } -enum sqMatchResult sqVerifyNameInner(sqSSL* ssl, X509* cert, void* serverName, const size_t serverNameLength, const int matchType) { +enum sqMatchResult sqVerifyNameInner(sqSSL* ssl, X509* cert, const void* serverName, const size_t serverNameLength, const int matchType) { enum sqMatchResult matchFound = NO_MATCH_FOUND; - STACK_OF(GENERAL_NAME)* sANs = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + STACK_OF(GENERAL_NAME)* sANs = sqo_X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (!sANs) { if (ssl->loglevel) printf("sqVerifyNameInner: No sAN names\n"); matchFound = NO_SAN_PRESENT; } else { int i = 0; - int sANCount = sk_GENERAL_NAME_num(sANs); + int sANCount = sqo_sk_GENERAL_NAME_num(sANs); for (i = 0; i < sANCount && matchFound != MATCH_FOUND; ++i) { - const GENERAL_NAME* sAN = sk_GENERAL_NAME_value(sANs, i); + const GENERAL_NAME* sAN = sqo_sk_GENERAL_NAME_value(sANs, i); if ((sAN->type == matchType) && sqVerifySAN(ssl, sAN, serverName, serverNameLength, matchType)) { matchFound = MATCH_FOUND; break; } } - sk_GENERAL_NAME_pop_free(sANs, GENERAL_NAME_free); + sqo_sk_GENERAL_NAME_pop_free(sANs, (void(*)(void*))sqo_sk_free); } return matchFound; } @@ -157,9 +157,9 @@ char* sqVerifyFindStar(char* sANData, size_t sANDataSize) { #undef FAIL_STAR } -sqInt sqVerifySAN(sqSSL* ssl, const GENERAL_NAME* sAN, void* data, const size_t dataSizeIn, const int matchType) { - char* sANData = (char *)ASN1_STRING_data(sAN->d.ia5); - size_t sANDataSize = (size_t)ASN1_STRING_length(sAN->d.ia5); +sqInt sqVerifySAN(sqSSL* ssl, const GENERAL_NAME* sAN, const void* data, const size_t dataSizeIn, const int matchType) { + char* sANData = (char *) sqo_ASN1_STRING_data(sAN->d.ia5); + size_t sANDataSize = (size_t) sqo_ASN1_STRING_length(sAN->d.ia5); size_t dataSize = dataSizeIn; if (ssl->loglevel) printf("sqVerifyNameInner: checking sAN %.*s\n", matchType == GEN_DNS ? (int) sANDataSize : 5 , matchType == GEN_DNS ? sANData : "an IP"); @@ -223,44 +223,44 @@ sqInt sqVerifySAN(sqSSL* ssl, const GENERAL_NAME* sAN, void* data, const size_t #undef NOPE #undef YEAH } -#endif -// X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS /* sqSetupSSL: Common SSL setup tasks */ sqInt sqSetupSSL(sqSSL *ssl, int server) { - /* Fixme. Needs to use specified version */ if(ssl->loglevel) printf("sqSetupSSL: setting method\n"); - ssl->method = (SSL_METHOD*) SSLv23_method(); + ssl->method = (SSL_METHOD*) sqo_SSLv23_method(); if(ssl->loglevel) printf("sqSetupSSL: Creating context\n"); - ssl->ctx = SSL_CTX_new(ssl->method); + ssl->ctx = sqo_SSL_CTX_new(ssl->method); if(ssl->loglevel) printf("sqSetupSSL: Disabling SSLv2 and SSLv3\n"); - SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + sqo_SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); - if(!ssl->ctx) ERR_print_errors_fp(stdout); + if(!ssl->ctx) sqo_ERR_print_errors_fp(stdout); if(ssl->loglevel) printf("sqSetupSSL: setting cipher list\n"); - SSL_CTX_set_cipher_list(ssl->ctx, "!ADH:HIGH:MEDIUM:@STRENGTH"); + sqo_SSL_CTX_set_cipher_list(ssl->ctx, "!ADH:HIGH:MEDIUM:@STRENGTH"); /* if a cert is provided, use it */ if(ssl->certName) { - if(ssl->loglevel) printf("sqSetupSSL: Using cert file %s\n", ssl->certName); - if(SSL_CTX_use_certificate_file(ssl->ctx, ssl->certName, SSL_FILETYPE_PEM)<=0) - ERR_print_errors_fp(stderr); - - if(SSL_CTX_use_PrivateKey_file(ssl->ctx, ssl->certName, SSL_FILETYPE_PEM)<=0) - ERR_print_errors_fp(stderr); + if(ssl->loglevel) { + printf("sqSetupSSL: Using cert file %s\n", ssl->certName); + } + if(sqo_SSL_CTX_use_certificate_file(ssl->ctx, ssl->certName, SSL_FILETYPE_PEM)<=0) { + sqo_ERR_print_errors_fp(stderr); + } + if(sqo_SSL_CTX_use_PrivateKey_file(ssl->ctx, ssl->certName, SSL_FILETYPE_PEM)<=0) { + sqo_ERR_print_errors_fp(stderr); + } } /* Set up trusted CA */ if(ssl->loglevel) printf("sqSetupSSL: No root CA given; using default verify paths\n"); - if(SSL_CTX_set_default_verify_paths(ssl->ctx) <=0) - ERR_print_errors_fp(stderr); + if(sqo_SSL_CTX_set_default_verify_paths(ssl->ctx) <=0) + sqo_ERR_print_errors_fp(stderr); if(ssl->loglevel) printf("sqSetupSSL: Creating SSL\n"); - ssl->ssl = SSL_new(ssl->ctx); + ssl->ssl = sqo_SSL_new(ssl->ctx); if(ssl->loglevel) printf("sqSetupSSL: setting bios\n"); - SSL_set_bio(ssl->ssl, ssl->bioRead, ssl->bioWrite); + sqo_SSL_set_bio(ssl->ssl, ssl->bioRead, ssl->bioWrite); return 1; } /********************************************************************/ @@ -275,14 +275,20 @@ sqInt sqCreateSSL(void) { sqInt handle = 0; sqSSL *ssl = NULL; - SSL_library_init(); - SSL_load_error_strings(); + if (!wasInitialized) { + if (!loadLibrary()) { + return 0; + } + sqo_SSL_library_init(); + sqo_SSL_load_error_strings(); + wasInitialized = true; + } ssl = calloc(1, sizeof(sqSSL)); - ssl->bioRead = BIO_new(BIO_s_mem()); - ssl->bioWrite = BIO_new(BIO_s_mem()); - BIO_set_close(ssl->bioRead, BIO_CLOSE); - BIO_set_close(ssl->bioWrite, BIO_CLOSE); + ssl->bioRead = sqo_BIO_new(sqo_BIO_s_mem()); + ssl->bioWrite = sqo_BIO_new(sqo_BIO_s_mem()); + sqo_BIO_set_close(ssl->bioRead, BIO_CLOSE); + sqo_BIO_set_close(ssl->bioWrite, BIO_CLOSE); /* Find a free handle */ for(handle = 1; handle < handleMax; handle++) @@ -309,14 +315,14 @@ sqInt sqDestroySSL(sqInt handle) { sqSSL *ssl = sslFromHandle(handle); if(ssl == NULL) return 0; - if(ssl->ctx) SSL_CTX_free(ssl->ctx); + if(ssl->ctx) sqo_SSL_CTX_free(ssl->ctx); if(ssl->ssl) { - SSL_free(ssl->ssl); // This will also free bioRead and bioWrite + sqo_SSL_free(ssl->ssl); // This will also free bioRead and bioWrite } else { // SSL_new didn't get called, have to free bioRead and bioWrite manually - BIO_free_all(ssl->bioRead); - BIO_free_all(ssl->bioWrite); + sqo_BIO_free_all(ssl->bioRead); + sqo_BIO_free_all(ssl->bioWrite); } if(ssl->certName) free(ssl->certName); @@ -356,14 +362,14 @@ sqInt sqConnectSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt if(ssl->loglevel) printf("sqConnectSSL: Setting up SSL\n"); if(!sqSetupSSL(ssl, 0)) return SQSSL_GENERIC_ERROR; if(ssl->loglevel) printf("sqConnectSSL: Setting connect state\n"); - SSL_set_connect_state(ssl->ssl); + sqo_SSL_set_connect_state(ssl->ssl); } if(ssl->loglevel) printf("sqConnectSSL: BIO_write %ld bytes\n", (long)srcLen); if(srcLen > 0) { - int n = BIO_write(ssl->bioRead, srcBuf, srcLen); + int n = sqo_BIO_write(ssl->bioRead, srcBuf, srcLen); if(n < srcLen) { if(ssl->loglevel) printf("sqConnectSSL: BIO too small for input\n"); @@ -378,16 +384,16 @@ sqInt sqConnectSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt /* if a server name is provided, use it */ if(ssl->serverName) { if(ssl->loglevel) printf("sqSetupSSL: Using server name %s\n", ssl->serverName); - SSL_set_tlsext_host_name(ssl->ssl, ssl->serverName); + sqo_SSL_set_tlsext_host_name(ssl->ssl, ssl->serverName); } if(ssl->loglevel) printf("sqConnectSSL: SSL_connect\n"); - result = SSL_connect(ssl->ssl); + result = sqo_SSL_connect(ssl->ssl); if(result <= 0) { - int error = SSL_get_error(ssl->ssl, result); + int error = sqo_SSL_get_error(ssl->ssl, result); if(error != SSL_ERROR_WANT_READ) { if(ssl->loglevel) printf("sqConnectSSL: SSL_connect failed\n"); - ERR_print_errors_fp(stdout); + sqo_ERR_print_errors_fp(stdout); return SQSSL_GENERIC_ERROR; } if(ssl->loglevel) printf("sqConnectSSL: sqCopyBioSSL\n"); @@ -398,7 +404,7 @@ sqInt sqConnectSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt ssl->state = SQSSL_CONNECTED; if(ssl->loglevel) printf("sqConnectSSL: SSL_get_peer_certificate\n"); - cert = SSL_get_peer_certificate(ssl->ssl); + cert = sqo_SSL_get_peer_certificate(ssl->ssl); if(ssl->loglevel) printf("sqConnectSSL: cert = %p\n", cert); /* Fail if no cert received. */ if(cert) { @@ -432,19 +438,19 @@ sqInt sqConnectSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt if (ssl->serverName) { const size_t serverNameLength = strnlen(ssl->serverName, MAX_HOSTNAME_LENGTH); -#ifdef X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS - if(ssl->loglevel) printf("sqConnectSSL: X509_check_host."); - /* Try IP first, expect INVALID_IP_STRING to continue with hostname */ - matched = (enum sqMatchResult) X509_check_ip_asc(cert, ssl->serverName, 0); - if (matched == INVALID_IP_STRING) { - matched = (enum sqMatchResult) X509_check_host(cert, ssl->serverName, serverNameLength, X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS, NULL); - } -#else - matched = sqVerifyIP(ssl, cert, ssl->serverName, serverNameLength); - if (matched == INVALID_IP_STRING) { - matched = sqVerifyDNS(ssl, cert, ssl->serverName, serverNameLength); + if (sqo_X509_check_ip_asc && sqo_X509_check_host) { + if(ssl->loglevel) printf("sqConnectSSL: X509_check_host."); + /* Try IP first, expect INVALID_IP_STRING to continue with hostname */ + matched = (enum sqMatchResult) sqo_X509_check_ip_asc(cert, ssl->serverName, 0); + if (matched == INVALID_IP_STRING) { + matched = (enum sqMatchResult) sqo_X509_check_host(cert, ssl->serverName, serverNameLength, sqo_X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS, NULL); + } + } else { + matched = sqVerifyIP(ssl, cert, ssl->serverName, serverNameLength); + if (matched == INVALID_IP_STRING) { + matched = sqVerifyDNS(ssl, cert, ssl->serverName, serverNameLength); + } } -#endif if (matched == MATCH_FOUND) { if (ssl->loglevel) printf("sqConnectSSL: check hostname OK\n"); ssl->peerName = strndup(ssl->serverName, serverNameLength); @@ -454,16 +460,16 @@ sqInt sqConnectSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt } // fallback for missing sAN or non-provided serverName if (matched == NO_MATCH_DONE_YET || matched == NO_SAN_PRESENT) { - X509_NAME_get_text_by_NID(X509_get_subject_name(cert), - NID_commonName, peerName, - sizeof(peerName)); + sqo_X509_NAME_get_text_by_NID(sqo_X509_get_subject_name(cert), + NID_commonName, peerName, + sizeof(peerName)); if(ssl->loglevel) printf("sqConnectSSL: peerName = %s\n", peerName); ssl->peerName = strndup(peerName, sizeof(peerName) - 1); } - X509_free(cert); + sqo_X509_free(cert); /* Check the result of verification */ - result = SSL_get_verify_result(ssl->ssl); + result = sqo_SSL_get_verify_result(ssl->ssl); if(ssl->loglevel) printf("sqConnectSSL: SSL_get_verify_result = %d\n", result); /* FIXME: Figure out the actual failure reason */ ssl->certFlags = result ? SQSSL_OTHER_ISSUE : SQSSL_OK; @@ -499,13 +505,13 @@ sqInt sqAcceptSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt if(ssl->loglevel) printf("sqAcceptSSL: Setting up SSL\n"); if(!sqSetupSSL(ssl, 1)) return SQSSL_GENERIC_ERROR; if(ssl->loglevel) printf("sqAcceptSSL: setting accept state\n"); - SSL_set_accept_state(ssl->ssl); + sqo_SSL_set_accept_state(ssl->ssl); } if(ssl->loglevel) printf("sqAcceptSSL: BIO_write %ld bytes\n", (long)srcLen); if(srcLen > 0) { - int n = BIO_write(ssl->bioRead, srcBuf, srcLen); + int n = sqo_BIO_write(ssl->bioRead, srcBuf, srcLen); if(n < srcLen) { if(ssl->loglevel) printf("sqAcceptSSL: BIO_write wrote less than expected\n"); @@ -518,14 +524,14 @@ sqInt sqAcceptSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt } if(ssl->loglevel) printf("sqAcceptSSL: SSL_accept\n"); - result = SSL_accept(ssl->ssl); + result = sqo_SSL_accept(ssl->ssl); if(result <= 0) { int count = 0; - int error = SSL_get_error(ssl->ssl, result); + int error = sqo_SSL_get_error(ssl->ssl, result); if(error != SSL_ERROR_WANT_READ) { if(ssl->loglevel) printf("sqAcceptSSL: SSL_accept failed\n"); - ERR_print_errors_fp(stdout); + sqo_ERR_print_errors_fp(stdout); return SQSSL_GENERIC_ERROR; } if(ssl->loglevel) printf("sqAcceptSSL: sqCopyBioSSL\n"); @@ -537,19 +543,19 @@ sqInt sqAcceptSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt ssl->state = SQSSL_CONNECTED; if(ssl->loglevel) printf("sqAcceptSSL: SSL_get_peer_certificate\n"); - cert = SSL_get_peer_certificate(ssl->ssl); + cert = sqo_SSL_get_peer_certificate(ssl->ssl); if(ssl->loglevel) printf("sqAcceptSSL: cert = %p\n", cert); if(cert) { - X509_NAME_get_text_by_NID(X509_get_subject_name(cert), - NID_commonName, peerName, - sizeof(peerName)); + sqo_X509_NAME_get_text_by_NID(sqo_X509_get_subject_name(cert), + NID_commonName, peerName, + sizeof(peerName)); if(ssl->loglevel) printf("sqAcceptSSL: peerName = %s\n", peerName); ssl->peerName = strndup(peerName, sizeof(peerName) - 1); - X509_free(cert); + sqo_X509_free(cert); /* Check the result of verification */ - result = SSL_get_verify_result(ssl->ssl); + result = sqo_SSL_get_verify_result(ssl->ssl); if(ssl->loglevel) printf("sqAcceptSSL: SSL_get_verify_result = %d\n", result); /* FIXME: Figure out the actual failure reason */ ssl->certFlags = result ? SQSSL_OTHER_ISSUE : SQSSL_OK; @@ -576,7 +582,7 @@ sqInt sqEncryptSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt if(ssl->loglevel) printf("sqEncryptSSL: Encrypting %ld bytes\n", (long)srcLen); - nbytes = SSL_write(ssl->ssl, srcBuf, srcLen); + nbytes = sqo_SSL_write(ssl->ssl, srcBuf, srcLen); if(nbytes != srcLen) return SQSSL_GENERIC_ERROR; return sqCopyBioSSL(ssl, ssl->bioWrite, dstBuf, dstLen); } @@ -596,11 +602,11 @@ sqInt sqDecryptSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt if(ssl == NULL || ssl->state != SQSSL_CONNECTED) return SQSSL_INVALID_STATE; - nbytes = BIO_write(ssl->bioRead, srcBuf, srcLen); + nbytes = sqo_BIO_write(ssl->bioRead, srcBuf, srcLen); if(nbytes != srcLen) return SQSSL_GENERIC_ERROR; - nbytes = SSL_read(ssl->ssl, dstBuf, dstLen); + nbytes = sqo_SSL_read(ssl->ssl, dstBuf, dstLen); if(nbytes <= 0) { - int error = SSL_get_error(ssl->ssl, nbytes); + int error = sqo_SSL_get_error(ssl->ssl, nbytes); if(error != SSL_ERROR_WANT_READ && error != SSL_ERROR_ZERO_RETURN) { return SQSSL_GENERIC_ERROR; }