123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879 |
- /*
- goahead-openssl.c - OpensSSL socket layer for GoAhead
- This is the interface between GoAhead and the OpenSSL stack.
- Copyright (c) All Rights Reserved. See details at the end of the file.
- */
- /************************************ Include *********************************/
- #include "goahead.h"
- #if ME_COM_OPENSSL
- #if ME_UNIX_LIKE
- /*
- Mac OS X OpenSSL stack is deprecated. Suppress those warnings.
- */
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- #endif
- /* Clashes with WinCrypt.h */
- #undef OCSP_RESPONSE
- #ifndef ME_GOAHEAD_SSL_HANDSHAKES
- #define ME_GOAHEAD_SSL_HANDSHAKES 0 /* Defaults to infinite */
- #endif
- #ifndef ME_GOAHEAD_SSL_RENEGOTIATE
- #define ME_GOAHEAD_SSL_RENEGOTIATE 1
- #endif
- /*
- Indent includes to bypass MakeMe dependencies
- */
- #include <openssl/ssl.h>
- #include <openssl/evp.h>
- #include <openssl/rand.h>
- #include <openssl/err.h>
- #include <openssl/dh.h>
- /************************************* Defines ********************************/
- /*
- Default ciphers from Mozilla (https://wiki.mozilla.org/Security/Server_Side_TLS) without SSLv3 ciphers.
- TLSv1 and TLSv2 only. Recommended RSA and DH parameter size: 2048 bits.
- */
- #define OPENSSL_DEFAULT_CIPHERS "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4:!SSLv3"
- /*
- Map Iana names to OpenSSL names
- */
- typedef struct CipherMap {
- int code;
- char *name;
- char *ossName;
- } CipherMap;
- static CipherMap cipherMap[] = {
- { 0x0004, "TLS_RSA_WITH_RC4_128_MD5", "RC4-MD5" },
- { 0x0005, "TLS_RSA_WITH_RC4_128_SHA", "RC4-SHA" },
- { 0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA", "IDEA-CBC-SHA" },
- { 0x0009, "TLS_RSA_WITH_DES_CBC_SHA", "DES-CBC-SHA" },
- { 0x000A, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "DES-CBC3-SHA" },
- { 0x000C, "TLS_DH_DSS_WITH_DES_CBC_SHA", "DH-DSS-DES-CBC-SHA" },
- { 0x000D, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", "DH-DSS-DES-CBC3-SHA" },
- { 0x000F, "TLS_DH_RSA_WITH_DES_CBC_SHA", "DH-RSA-DES-CBC-SHA" },
- { 0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", "DH-RSA-DES-CBC3-SHA" },
- { 0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA", "EDH-DSS-DES-CBC-SHA" },
- { 0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "EDH-DSS-DES-CBC3-SHA" },
- { 0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA", "EDH-RSA-DES-CBC-SHA" },
- { 0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", "EDH-RSA-DES-CBC3-SHA" },
- { 0x002F, "TLS_RSA_WITH_AES_128_CBC_SHA", "AES128-SHA" },
- { 0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA", "DH-DSS-AES128-SHA" },
- { 0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA", "DH-RSA-AES128-SHA" },
- { 0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "DHE-DSS-AES128-SHA" },
- { 0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "DHE-RSA-AES128-SHA" },
- { 0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA", "AES256-SHA" },
- { 0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA", "DH-DSS-AES256-SHA" },
- { 0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA", "DH-RSA-AES256-SHA" },
- { 0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "DHE-DSS-AES256-SHA" },
- { 0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "DHE-RSA-AES256-SHA" },
- { 0x003C, "TLS_RSA_WITH_AES_128_CBC_SHA256", "AES128-SHA256" },
- { 0x003D, "TLS_RSA_WITH_AES_256_CBC_SHA256", "AES256-SHA256" },
- { 0x003E, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", "DH-DSS-AES128-SHA256" },
- { 0x003F, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", "DH-RSA-AES128-SHA256" },
- { 0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "DHE-DSS-AES128-SHA256" },
- { 0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", "CAMELLIA128-SHA" },
- { 0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", "DH-DSS-CAMELLIA128-SHA" },
- { 0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", "DH-RSA-CAMELLIA128-SHA" },
- { 0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", "DHE-DSS-CAMELLIA128-SHA" },
- { 0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", "DHE-RSA-CAMELLIA128-SHA" },
- { 0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "DHE-RSA-AES128-SHA256" },
- { 0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256", "DH-DSS-AES256-SHA256" },
- { 0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256", "DH-RSA-AES256-SHA256" },
- { 0x006A, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "DHE-DSS-AES256-SHA256" },
- { 0x006B, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "DHE-RSA-AES256-SHA256" },
- { 0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", "CAMELLIA256-SHA" },
- { 0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", "DH-DSS-CAMELLIA256-SHA" },
- { 0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", "DH-RSA-CAMELLIA256-SHA" },
- { 0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", "DHE-DSS-CAMELLIA256-SHA" },
- { 0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", "DHE-RSA-CAMELLIA256-SHA" },
- { 0x008A, "TLS_PSK_WITH_RC4_128_SHA", "PSK-RC4-SHA" },
- { 0x008B, "TLS_PSK_WITH_3DES_EDE_CBC_SHA", "PSK-3DES-EDE-CBC-SHA" },
- { 0x008C, "TLS_PSK_WITH_AES_128_CBC_SHA", "PSK-AES128-CBC-SHA" },
- { 0x008D, "TLS_PSK_WITH_AES_256_CBC_SHA", "PSK-AES256-CBC-SHA" },
- { 0x0096, "TLS_RSA_WITH_SEED_CBC_SHA", "SEED-SHA" },
- { 0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA", "DH-DSS-SEED-SHA" },
- { 0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA", "DH-RSA-SEED-SHA" },
- { 0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA", "DHE-DSS-SEED-SHA" },
- { 0x009A, "TLS_DHE_RSA_WITH_SEED_CBC_SHA", "DHE-RSA-SEED-SHA" },
- { 0x009C, "TLS_RSA_WITH_AES_128_GCM_SHA256", "AES128-GCM-SHA256" },
- { 0x009D, "TLS_RSA_WITH_AES_256_GCM_SHA384", "AES256-GCM-SHA384" },
- { 0x009E, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "DHE-RSA-AES128-GCM-SHA256" },
- { 0x009F, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "DHE-RSA-AES256-GCM-SHA384" },
- { 0x00A0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256", "DH-RSA-AES128-GCM-SHA256" },
- { 0x00A1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384", "DH-RSA-AES256-GCM-SHA384" },
- { 0x00A2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "DHE-DSS-AES128-GCM-SHA256" },
- { 0x00A3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "DHE-DSS-AES256-GCM-SHA384" },
- { 0x00A4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256", "DH-DSS-AES128-GCM-SHA256" },
- { 0x00A5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384", "DH-DSS-AES256-GCM-SHA384" },
- { 0xC002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", "ECDH-ECDSA-RC4-SHA" },
- { 0xC003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDH-ECDSA-DES-CBC3-SHA" },
- { 0xC004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "ECDH-ECDSA-AES128-SHA" },
- { 0xC005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "ECDH-ECDSA-AES256-SHA" },
- { 0xC007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "ECDHE-ECDSA-RC4-SHA" },
- { 0xC008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-ECDSA-DES-CBC3-SHA" },
- { 0xC009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "ECDHE-ECDSA-AES128-SHA" },
- { 0xC00A, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "ECDHE-ECDSA-AES256-SHA" },
- { 0xC00C, "TLS_ECDH_RSA_WITH_RC4_128_SHA", "ECDH-RSA-RC4-SHA" },
- { 0xC00D, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "ECDH-RSA-DES-CBC3-SHA" },
- { 0xC00E, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "ECDH-RSA-AES128-SHA" },
- { 0xC00F, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", "ECDH-RSA-AES256-SHA" },
- { 0xC011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "ECDHE-RSA-RC4-SHA" },
- { 0xC012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-RSA-DES-CBC3-SHA" },
- { 0xC013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "ECDHE-RSA-AES128-SHA" },
- { 0xC014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "ECDHE-RSA-AES256-SHA" },
- { 0xC01A, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", "SRP-3DES-EDE-CBC-SHA" },
- { 0xC01B, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", "SRP-RSA-3DES-EDE-CBC-SHA" },
- { 0xC01C, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", "SRP-DSS-3DES-EDE-CBC-SHA" },
- { 0xC01D, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", "SRP-AES-128-CBC-SHA" },
- { 0xC01E, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", "SRP-RSA-AES-128-CBC-SHA" },
- { 0xC01F, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", "SRP-DSS-AES-128-CBC-SHA" },
- { 0xC020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", "SRP-AES-256-CBC-SHA" },
- { 0xC021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", "SRP-RSA-AES-256-CBC-SHA" },
- { 0xC022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", "SRP-DSS-AES-256-CBC-SHA" },
- { 0xC023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDHE-ECDSA-AES128-SHA256" },
- { 0xC024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "ECDHE-ECDSA-AES256-SHA384" },
- { 0xC025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "ECDH-ECDSA-AES128-SHA256" },
- { 0xC026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", "ECDH-ECDSA-AES256-SHA384" },
- { 0xC027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "ECDHE-RSA-AES128-SHA256" },
- { 0xC028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "ECDHE-RSA-AES256-SHA384" },
- { 0xC029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "ECDH-RSA-AES128-SHA256" },
- { 0xC02A, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", "ECDH-RSA-AES256-SHA384" },
- { 0xC02B, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256" },
- { 0xC02C, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "ECDHE-ECDSA-AES256-GCM-SHA384" },
- { 0xC02D, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "ECDH-ECDSA-AES128-GCM-SHA256" },
- { 0xC02E, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "ECDH-ECDSA-AES256-GCM-SHA384" },
- { 0xC02F, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "ECDHE-RSA-AES128-GCM-SHA256" },
- { 0xC030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "ECDHE-RSA-AES256-GCM-SHA384" },
- { 0xC031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "ECDH-RSA-AES128-GCM-SHA256" },
- { 0xC032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "ECDH-RSA-AES256-GCM-SHA384" },
- { 0x0000, 0 },
- };
- /*
- OpenSSL context (singleton)
- */
- static SSL_CTX *sslctx = NULL;
- typedef struct RandBuf {
- time_t now;
- int pid;
- } RandBuf;
- #define VERIFY_DEPTH 10
- /*
- Used for OpenSSL versions < 1.0.2
- */
- #ifndef ME_GOAHEAD_SSL_CURVE
- #define ME_GOAHEAD_SSL_CURVE "prime256v1"
- #endif
- /*
- DH parameters
- */
- static DH *dhKey;
- static int maxHandshakes;
- /************************************ Forwards ********************************/
- static DH *dhcallback(SSL *handle, int is_export, int keylength);
- static DH *getDhKey();
- static char *mapCipherNames(char *ciphers);
- static int sslSetCertFile(char *certFile);
- static int sslSetKeyFile(char *keyFile);
- static int verifyClientCertificate(int ok, X509_STORE_CTX *ctx);
- static void infoCallback(const SSL *ssl, int where, int rc);
- /************************************** Code **********************************/
- /*
- Open the SSL module
- */
- PUBLIC int sslOpen()
- {
- RandBuf randBuf;
- X509_STORE *store;
- uchar resume[16];
- char *ciphers;
- trace(7, "Initializing SSL");
- randBuf.now = time(0);
- randBuf.pid = getpid();
- RAND_seed((void*) &randBuf, sizeof(randBuf));
- #if ME_UNIX_LIKE
- trace(6, "OpenSsl: Before calling RAND_load_file");
- RAND_load_file("/dev/urandom", 256);
- trace(6, "OpenSsl: After calling RAND_load_file");
- #endif
- CRYPTO_malloc_init();
- #if !ME_WIN_LIKE
- OpenSSL_add_all_algorithms();
- #endif
- SSL_library_init();
- SSL_load_error_strings();
- SSLeay_add_ssl_algorithms();
- if ((sslctx = SSL_CTX_new(SSLv23_server_method())) == 0) {
- error("Unable to create SSL context");
- return -1;
- }
- /*
- Set the server certificate and key files
- */
- if (*ME_GOAHEAD_SSL_KEY && sslSetKeyFile(ME_GOAHEAD_SSL_KEY) < 0) {
- sslClose();
- return -1;
- }
- if (*ME_GOAHEAD_SSL_CERTIFICATE && sslSetCertFile(ME_GOAHEAD_SSL_CERTIFICATE) < 0) {
- sslClose();
- return -1;
- }
- if (ME_GOAHEAD_SSL_VERIFY_PEER) {
- SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verifyClientCertificate);
- SSL_CTX_set_verify_depth(sslctx, VERIFY_DEPTH);
- } else {
- SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, verifyClientCertificate);
- }
- /*
- Set the client certificate verification locations
- */
- if (ME_GOAHEAD_SSL_AUTHORITY && *ME_GOAHEAD_SSL_AUTHORITY) {
- if ((!SSL_CTX_load_verify_locations(sslctx, ME_GOAHEAD_SSL_AUTHORITY, NULL)) ||
- (!SSL_CTX_set_default_verify_paths(sslctx))) {
- error("Unable to read cert verification locations");
- sslClose();
- return -1;
- }
- /*
- Define the list of CA certificates to send to the client before they send their client
- certificate for validation
- */
- SSL_CTX_set_client_CA_list(sslctx, SSL_load_client_CA_file(ME_GOAHEAD_SSL_AUTHORITY));
- }
- if (ME_GOAHEAD_SSL_REVOKE && *ME_GOAHEAD_SSL_REVOKE) {
- store = SSL_CTX_get_cert_store(sslctx);
- if (!X509_STORE_load_locations(store, ME_GOAHEAD_SSL_REVOKE, 0)) {
- error("Cannot load certificate revoke list: %s", ME_GOAHEAD_SSL_REVOKE);
- sslClose();
- return -1;
- }
- }
- /*
- Configure DH parameters
- */
- dhKey = getDhKey();
- SSL_CTX_set_tmp_dh_callback(sslctx, dhcallback);
- /*
- Configure cipher suite
- */
- if (ME_GOAHEAD_SSL_CIPHERS && *ME_GOAHEAD_SSL_CIPHERS) {
- ciphers = ME_GOAHEAD_SSL_CIPHERS;
- } else {
- ciphers = OPENSSL_DEFAULT_CIPHERS;
- }
- ciphers = mapCipherNames(ciphers);
- trace(5, "Using OpenSSL ciphers: %s", ciphers);
- if (SSL_CTX_set_cipher_list(sslctx, ciphers) != 1) {
- error("Unable to set cipher list \"%s\"", ciphers);
- sslClose();
- wfree(ciphers);
- return -1;
- }
- wfree(ciphers);
- /*
- Define default OpenSSL options
- */
- SSL_CTX_set_options(sslctx, SSL_OP_ALL);
- /*
- Ensure we generate a new private key for each connection
- */
- SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE);
- /*
- Define a session reuse context
- */
- RAND_bytes(resume, sizeof(resume));
- SSL_CTX_set_session_id_context(sslctx, resume, sizeof(resume));
- /*
- Elliptic Curve initialization
- */
- #if SSL_OP_SINGLE_ECDH_USE
- #ifdef SSL_CTX_set_ecdh_auto
- SSL_CTX_set_ecdh_auto(sslctx, 1);
- #else
- {
- EC_KEY *ecdh;
- cchar *name;
- int nid;
- name = ME_GOAHEAD_SSL_CURVE;
- if ((nid = OBJ_sn2nid(name)) == 0) {
- error("Unknown curve name \"%s\"", name);
- sslClose();
- return -1;
- }
- if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0) {
- error("Unable to create curve \"%s\"", name);
- sslClose();
- return -1;
- }
- SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_ECDH_USE);
- SSL_CTX_set_tmp_ecdh(sslctx, ecdh);
- EC_KEY_free(ecdh);
- }
- #endif
- #endif
- SSL_CTX_set_mode(sslctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
- #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
- SSL_CTX_set_options(sslctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
- #endif
- #ifdef SSL_MODE_RELEASE_BUFFERS
- SSL_CTX_set_mode(sslctx, SSL_MODE_RELEASE_BUFFERS);
- #endif
- #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
- SSL_CTX_set_mode(sslctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
- #endif
- /*
- Select the required protocols
- Disable both SSLv2 and SSLv3 by default - they are insecure
- */
- SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2);
- SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv3);
- #if defined(SSL_OP_NO_TLSv1) && ME_GOAHEAD_SSL_NO_V1
- SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1);
- #endif
- #if defined(SSL_OP_NO_TLSv1_1) && ME_GOAHEAD_SSL_NO_V1_1
- SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_1);
- #endif
- #if defined(SSL_OP_NO_TLSv1_2) && ME_GOAHEAD_SSL_NO_V1_2
- SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_2);
- #endif
- #if defined(SSL_OP_NO_TICKET)
- /*
- Ticket based session reuse is enabled by default
- */
- #if defined(ME_GOAHEAD_SSL_TICKET)
- if (ME_GOAHEAD_SSL_TICKET) {
- SSL_CTX_clear_options(sslctx, SSL_OP_NO_TICKET);
- } else {
- SSL_CTX_set_options(sslctx, SSL_OP_NO_TICKET);
- }
- #else
- SSL_CTX_clear_options(sslctx, SSL_OP_NO_TICKET);
- #endif
- #endif
- #if defined(SSL_OP_NO_COMPRESSION)
- /*
- CRIME attack targets compression
- */
- SSL_CTX_clear_options(sslctx, SSL_OP_NO_COMPRESSION);
- #endif
- #if defined(ME_GOAHEAD_SSL_HANDSHAKES)
- maxHandshakes = ME_GOAHEAD_SSL_HANDSHAKES;
- #endif
- #if defined(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)
- /*
- Disables a countermeasure against a SSL 3.0/TLS 1.0 protocol vulnerability affecting CBC ciphers.
- Defaults to true.
- */
- #if defined(ME_GOAHEAD_SSL_EMPTY_FRAGMENTS)
- if (ME_GOAHEAD_SSL_EMPTY_FRAGMENTS) {
- /* SSL_OP_ALL disables empty fragments. Only needed for ancient browsers like IE-6 on SSL-3.0/TLS-1.0 */
- SSL_CTX_clear_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
- } else {
- SSL_CTX_set_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
- }
- #else
- SSL_CTX_set_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
- #endif
- #endif
- #if defined(ME_GOAHEAD_SSL_CACHE)
- /*
- Set the number of sessions supported. Default in OpenSSL is 20K.
- */
- SSL_CTX_sess_set_cache_size(sslctx, ME_GOAHEAD_SSL_CACHE);
- #else
- SSL_CTX_sess_set_cache_size(sslctx, 256);
- #endif
- return 0;
- }
- /*
- Close the SSL module
- */
- PUBLIC void sslClose()
- {
- if (sslctx != NULL) {
- SSL_CTX_free(sslctx);
- sslctx = NULL;
- if (dhKey) {
- DH_free(dhKey);
- dhKey = NULL;
- }
- }
- }
- /*
- Upgrade a socket to use SSL
- */
- PUBLIC int sslUpgrade(Webs *wp)
- {
- WebsSocket *sptr;
- BIO *bio;
- assert(wp);
- sptr = socketPtr(wp->sid);
- if ((wp->ssl = SSL_new(sslctx)) == 0) {
- return -1;
- }
- /*
- Create a socket bio. We don't use the BIO except as storage for the fd.
- */
- if ((bio = BIO_new_socket((int) sptr->sock, BIO_NOCLOSE)) == 0) {
- return -1;
- }
- SSL_set_bio(wp->ssl, bio, bio);
- SSL_set_accept_state(wp->ssl);
- SSL_set_app_data(wp->ssl, (void*) wp);
- if (ME_GOAHEAD_SSL_HANDSHAKES) {
- SSL_CTX_set_info_callback(sslctx, infoCallback);
- }
- return 0;
- }
- static void infoCallback(const SSL *ssl, int where, int rc)
- {
- Webs *wp;
- WebsSocket *sp;
- if (where & SSL_CB_HANDSHAKE_START) {
- if ((wp = (Webs*) SSL_get_app_data(ssl)) == 0) {
- return;
- }
- if ((sp = socketPtr(wp->sid)) != 0) {
- sp->handshakes++;
- }
- }
- }
- PUBLIC void sslFree(Webs *wp)
- {
- if (wp->ssl) {
- SSL_set_shutdown(wp->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
- SSL_free(wp->ssl);
- wp->ssl = 0;
- }
- }
- /*
- Return the number of bytes read. Return -1 on errors and EOF. Distinguish EOF via mprIsSocketEof.
- If non-blocking, may return zero if no data or still handshaking.
- */
- PUBLIC ssize sslRead(Webs *wp, void *buf, ssize len)
- {
- WebsSocket *sp;
- char ebuf[ME_GOAHEAD_LIMIT_STRING];
- ulong serror;
- int rc, err, retries, i;
- if (wp->ssl == 0 || len <= 0) {
- return -1;
- }
- /*
- Limit retries on WANT_READ. If non-blocking and no data, then this can spin forever.
- */
- sp = socketPtr(wp->sid);
- retries = 5;
- for (i = 0; i < retries; i++) {
- rc = SSL_read(wp->ssl, buf, (int) len);
- if (rc < 0) {
- err = SSL_get_error(wp->ssl, rc);
- if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_CONNECT || err == SSL_ERROR_WANT_ACCEPT) {
- continue;
- }
- serror = ERR_get_error();
- ERR_error_string_n(serror, ebuf, sizeof(ebuf) - 1);
- trace(5, "SSL_read %s", ebuf);
- }
- break;
- }
- if (maxHandshakes && sp->handshakes > maxHandshakes) {
- error("TLS renegotiation attack");
- rc = -1;
- sp->flags |= SOCKET_EOF;
- return -1;
- }
- if (rc <= 0) {
- err = SSL_get_error(wp->ssl, rc);
- if (err == SSL_ERROR_WANT_READ) {
- rc = 0;
- } else if (err == SSL_ERROR_WANT_WRITE) {
- rc = 0;
- } else if (err == SSL_ERROR_ZERO_RETURN) {
- sp->flags |= SOCKET_EOF;
- rc = -1;
- } else if (err == SSL_ERROR_SYSCALL) {
- sp->flags |= SOCKET_EOF;
- rc = -1;
- } else if (err != SSL_ERROR_ZERO_RETURN) {
- serror = ERR_get_error();
- ERR_error_string_n(serror, ebuf, sizeof(ebuf) - 1);
- trace(4, "OpenSSL: connection with protocol error: %s", ebuf);
- rc = -1;
- sp->flags |= SOCKET_EOF;
- }
- } else if (SSL_pending(wp->ssl) > 0) {
- socketHiddenData(sp, SSL_pending(wp->ssl), SOCKET_READABLE);
- }
- return rc;
- }
- PUBLIC ssize sslWrite(Webs *wp, void *buf, ssize len)
- {
- WebsSocket *sp;
- ssize totalWritten;
- int err, rc;
- if (wp->ssl == 0 || len <= 0) {
- return -1;
- }
- sp = socketPtr(wp->sid);
- totalWritten = 0;
- err = 0;
- ERR_clear_error();
- do {
- rc = SSL_write(wp->ssl, buf, (int) len);
- trace(7, "OpenSSL: written %d, requested len %d", rc, len);
- if (rc <= 0) {
- err = SSL_get_error(wp->ssl, rc);
- if (err == SSL_ERROR_NONE || err == SSL_ERROR_WANT_WRITE) {
- break;
- }
- trace(7, "OpenSSL: error %d", err);
- return -1;
- } else if (maxHandshakes && sp->handshakes > maxHandshakes) {
- error("TLS renegotiation attack");
- rc = -1;
- sp->flags |= SOCKET_EOF;
- return -1;
- }
- totalWritten += rc;
- buf = (void*) ((char*) buf + rc);
- len -= rc;
- trace(7, "OpenSSL: write: len %d, written %d, total %d", len, rc, totalWritten);
- } while (len > 0);
- if (totalWritten == 0 && err == SSL_ERROR_WANT_WRITE) {
- socketSetError(EAGAIN);
- return -1;
- }
- return totalWritten;
- }
- /*
- Set certificate file for SSL context
- */
- static int sslSetCertFile(char *certFile)
- {
- X509 *cert;
- BIO *bio;
- char *buf;
- int rc;
- assert(sslctx);
- assert(certFile);
- rc = -1;
- bio = 0;
- buf = 0;
- cert = 0;
- if (sslctx == NULL) {
- return rc;
- }
- if ((buf = websReadWholeFile(certFile)) == 0) {
- error("Unable to read certificate %s", certFile);
- } else if ((bio = BIO_new_mem_buf(buf, -1)) == 0) {
- error("Unable to allocate memory for certificate %s", certFile);
- } else if ((cert = PEM_read_bio_X509(bio, NULL, 0, NULL)) == 0) {
- error("Unable to parse certificate %s", certFile);
- } else if (SSL_CTX_use_certificate(sslctx, cert) != 1) {
- error("Unable to use certificate %s", certFile);
-
- } else if (!SSL_CTX_check_private_key(sslctx)) {
- error("Unable to check certificate key %s", certFile);
- } else {
- rc = 0;
- }
- wfree(buf);
- if (bio) {
- BIO_free(bio);
- }
- if (cert) {
- X509_free(cert);
- }
- return rc;
- }
- /*
- Set key file for SSL context
- */
- static int sslSetKeyFile(char *keyFile)
- {
- RSA *key;
- BIO *bio;
- char *buf;
- int rc;
- assert(sslctx);
- assert(keyFile);
- key = 0;
- bio = 0;
- buf = 0;
- rc = -1;
- if (sslctx == NULL) {
- ;
- } else if ((buf = websReadWholeFile(keyFile)) == 0) {
- error("Unable to read certificate %s", keyFile);
- } else if ((bio = BIO_new_mem_buf(buf, -1)) == 0) {
- error("Unable to allocate memory for key %s", keyFile);
- } else if ((key = PEM_read_bio_RSAPrivateKey(bio, NULL, 0, NULL)) == 0) {
- error("Unable to parse key %s", keyFile);
- } else if (SSL_CTX_use_RSAPrivateKey(sslctx, key) != 1) {
- error("Unable to use key %s", keyFile);
- } else {
- rc = 0;
- }
- wfree(buf);
- if (bio) {
- BIO_free(bio);
- }
- if (key) {
- RSA_free(key);
- }
- return rc;
- }
- static int verifyClientCertificate(int ok, X509_STORE_CTX *xContext)
- {
- X509 *cert;
- char subject[260], issuer[260], peer[260];
- int error, depth;
- subject[0] = issuer[0] = '\0';
- cert = X509_STORE_CTX_get_current_cert(xContext);
- error = X509_STORE_CTX_get_error(xContext);
- depth = X509_STORE_CTX_get_error_depth(xContext);
- ok = 1;
- if (X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject) - 1) < 0) {
- ok = 0;
- }
- if (X509_NAME_oneline(X509_get_issuer_name(xContext->current_cert), issuer, sizeof(issuer) - 1) < 0) {
- ok = 0;
- }
- if (X509_NAME_get_text_by_NID(X509_get_subject_name(xContext->current_cert), NID_commonName, peer,
- sizeof(peer) - 1) < 0) {
- ok = 0;
- }
- if (ok && VERIFY_DEPTH < depth) {
- if (error == 0) {
- error = X509_V_ERR_CERT_CHAIN_TOO_LONG;
- }
- }
- switch (error) {
- case X509_V_OK:
- break;
- case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
- case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
- if (ME_GOAHEAD_SSL_VERIFY_ISSUER) {
- logmsg(3, "Self-signed certificate");
- ok = 0;
- }
- case X509_V_ERR_CERT_UNTRUSTED:
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
- if (ME_GOAHEAD_SSL_VERIFY_ISSUER) {
- logmsg(3, "Certificate not trusted");
- ok = 0;
- }
- break;
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
- case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
- if (ME_GOAHEAD_SSL_VERIFY_ISSUER) {
- logmsg(3, "Certificate not trusted");
- ok = 0;
- }
- break;
- case X509_V_ERR_CERT_CHAIN_TOO_LONG:
- case X509_V_ERR_CERT_HAS_EXPIRED:
- case X509_V_ERR_CERT_NOT_YET_VALID:
- case X509_V_ERR_CERT_REJECTED:
- case X509_V_ERR_CERT_SIGNATURE_FAILURE:
- case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
- case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
- case X509_V_ERR_INVALID_CA:
- default:
- logmsg(3, "Certificate verification error %d", error);
- ok = 0;
- break;
- }
- if (ok) {
- trace(3, "OpenSSL: Certificate verified: subject %s", subject);
- } else {
- trace(1, "OpenSSL: Certification failed: subject %s (more trace at level 4)", subject);
- trace(4, "OpenSSL: Error: %d: %s", error, X509_verify_cert_error_string(error));
- }
- trace(4, "OpenSSL: Issuer: %s", issuer);
- trace(4, "OpenSSL: Peer: %s", peer);
- return ok;
- }
- /*
- Map iana names to OpenSSL names so users can provide IANA names as well as OpenSSL cipher names
- */
- static char *mapCipherNames(char *ciphers)
- {
- WebsBuf buf;
- CipherMap *cp;
- char *cipher, *next, *str;
- if (!ciphers || *ciphers == 0) {
- return 0;
- }
- bufCreate(&buf, 0, 0);
- ciphers = sclone(ciphers);
- for (next = ciphers; (cipher = stok(next, ":, \t", &next)) != 0; ) {
- for (cp = cipherMap; cp->name; cp++) {
- if (smatch(cp->name, cipher)) {
- bufPut(&buf, "%s:", cp->ossName);
- break;
- }
- }
- if (cp->name == 0) {
- bufPut(&buf, "%s:", cipher);
- }
- }
- wfree(ciphers);
- str = sclone(bufStart(&buf));
- bufFree(&buf);
- return str;
- }
- /*
- Get the DH parameters
- */
- static DH *getDhKey()
- {
- static unsigned char dh2048_p[] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
- 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
- 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
- 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
- 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
- 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
- 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
- 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
- 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
- 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
- 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
- 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
- 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
- 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
- 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
- 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- };
- static unsigned char dh2048_g[] = {
- 0x02,
- };
- DH *dh;
- if ((dh = DH_new()) == 0) {
- return 0;
- }
- dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
- dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
- if ((dh->p == 0) || (dh->g == 0)) {
- DH_free(dh);
- return 0;
- }
- return dh;
- }
- /*
- Set the ephemeral DH key
- */
- static DH *dhcallback(SSL *handle, int isExport, int keyLength)
- {
- return dhKey;
- }
- void opensslDummy() {}
- #endif
- /*
- Copyright (c) Embedthis Software. All Rights Reserved.
- This software is distributed under commercial and open source licenses.
- You may use the Embedthis GoAhead open source license or you may acquire
- a commercial license from Embedthis Software. You agree to be fully bound
- by the terms of either license. Consult the LICENSE.md distributed with
- this software for full details and other copyrights.
- */
|