/* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* yaSSL internal source implements SSL supporting types not specified in the * draft along with type conversion functions. */ // First include (the generated) my_config.h, to get correct platform defines. #include "my_config.h" #ifdef _WIN32 #include #else #include #endif #include "runtime.hpp" #include "yassl_int.hpp" #include "handshake.hpp" #include "timer.hpp" #ifdef HAVE_LIBZ #include "zlib.h" #endif #ifdef YASSL_PURE_C void* operator new(size_t sz, yaSSL::new_t) { void* ptr = malloc(sz ? sz : 1); if (!ptr) abort(); return ptr; } void operator delete(void* ptr, yaSSL::new_t) { if (ptr) free(ptr); } void* operator new[](size_t sz, yaSSL::new_t nt) { return ::operator new(sz, nt); } void operator delete[](void* ptr, yaSSL::new_t nt) { ::operator delete(ptr, nt); } namespace yaSSL { new_t ys; // for yaSSL library new } #endif // YASSL_PURE_C /* for the definition of get_tty_password() */ #include namespace yaSSL { // convert a 32 bit integer into a 24 bit one void c32to24(uint32 u32, uint24& u24) { u24[0] = (u32 >> 16) & 0xff; u24[1] = (u32 >> 8) & 0xff; u24[2] = u32 & 0xff; } // convert a 24 bit integer into a 32 bit one void c24to32(const uint24 u24, uint32& u32) { u32 = 0; u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2]; } // convert with return for ease of use uint32 c24to32(const uint24 u24) { uint32 ret; c24to32(u24, ret); return ret; } // using a for opaque since underlying type is unsgined char and o is not a // good leading identifier // convert opaque to 16 bit integer void ato16(const opaque* c, uint16& u16) { u16 = 0; u16 = (c[0] << 8) | (c[1]); } // convert (copy) opaque to 24 bit integer void ato24(const opaque* c, uint24& u24) { u24[0] = c[0]; u24[1] = c[1]; u24[2] = c[2]; } // convert 16 bit integer to opaque void c16toa(uint16 u16, opaque* c) { c[0] = (u16 >> 8) & 0xff; c[1] = u16 & 0xff; } // convert 24 bit integer to opaque void c24toa(const uint24 u24, opaque* c) { c[0] = u24[0]; c[1] = u24[1]; c[2] = u24[2]; } // convert 32 bit integer to opaque void c32toa(uint32 u32, opaque* c) { c[0] = (u32 >> 24) & 0xff; c[1] = (u32 >> 16) & 0xff; c[2] = (u32 >> 8) & 0xff; c[3] = u32 & 0xff; } States::States() : recordLayer_(recordReady), handshakeLayer_(preHandshake), clientState_(serverNull), serverState_(clientNull), connectState_(CONNECT_BEGIN), acceptState_(ACCEPT_BEGIN), what_(no_error) {} const RecordLayerState& States::getRecord() const { return recordLayer_; } const HandShakeState& States::getHandShake() const { return handshakeLayer_; } const ClientState& States::getClient() const { return clientState_; } const ServerState& States::getServer() const { return serverState_; } const ConnectState& States::GetConnect() const { return connectState_; } const AcceptState& States::GetAccept() const { return acceptState_; } const char* States::getString() const { return errorString_; } YasslError States::What() const { return what_; } RecordLayerState& States::useRecord() { return recordLayer_; } HandShakeState& States::useHandShake() { return handshakeLayer_; } ClientState& States::useClient() { return clientState_; } ServerState& States::useServer() { return serverState_; } ConnectState& States::UseConnect() { return connectState_; } AcceptState& States::UseAccept() { return acceptState_; } char* States::useString() { return errorString_; } void States::SetError(YasslError ye) { what_ = ye; } // mark message recvd, check for duplicates, return 0 on success int States::SetMessageRecvd(HandShakeType hst) { switch (hst) { case hello_request: break; // could send more than one case client_hello: if (recvdMessages_.gotClientHello_) return -1; recvdMessages_.gotClientHello_ = 1; break; case server_hello: if (recvdMessages_.gotServerHello_) return -1; recvdMessages_.gotServerHello_ = 1; break; case certificate: if (recvdMessages_.gotCert_) return -1; recvdMessages_.gotCert_ = 1; break; case server_key_exchange: if (recvdMessages_.gotServerKeyExchange_) return -1; recvdMessages_.gotServerKeyExchange_ = 1; break; case certificate_request: if (recvdMessages_.gotCertRequest_) return -1; recvdMessages_.gotCertRequest_ = 1; break; case server_hello_done: if (recvdMessages_.gotServerHelloDone_) return -1; recvdMessages_.gotServerHelloDone_ = 1; break; case certificate_verify: if (recvdMessages_.gotCertVerify_) return -1; recvdMessages_.gotCertVerify_ = 1; break; case client_key_exchange: if (recvdMessages_.gotClientKeyExchange_) return -1; recvdMessages_.gotClientKeyExchange_ = 1; break; case finished: if (recvdMessages_.gotFinished_) return -1; recvdMessages_.gotFinished_ = 1; break; default: return -1; } return 0; } sslFactory::sslFactory() : messageFactory_(InitMessageFactory), handShakeFactory_(InitHandShakeFactory), serverKeyFactory_(InitServerKeyFactory), clientKeyFactory_(InitClientKeyFactory) {} const MessageFactory& sslFactory::getMessage() const { return messageFactory_; } const HandShakeFactory& sslFactory::getHandShake() const { return handShakeFactory_; } const ServerKeyFactory& sslFactory::getServerKey() const { return serverKeyFactory_; } const ClientKeyFactory& sslFactory::getClientKey() const { return clientKeyFactory_; } // extract context parameters and store SSL::SSL(SSL_CTX* ctx) : secure_(ctx->getMethod()->getVersion(), crypto_.use_random(), ctx->getMethod()->getSide(), ctx->GetCiphers(), ctx, ctx->GetDH_Parms().set_), quietShutdown_(false), has_data_(false) { if (int err = crypto_.get_random().GetError()) { SetError(YasslError(err)); return; } CertManager& cm = crypto_.use_certManager(); cm.CopySelfCert(ctx->getCert()); bool serverSide = secure_.use_parms().entity_ == server_end; if (ctx->getKey()) { if (int err = cm.SetPrivateKey(*ctx->getKey())) { SetError(YasslError(err)); return; } else if (serverSide && !(ctx->GetCiphers().setSuites_)) { // remove RSA or DSA suites depending on cert key type ProtocolVersion pv = secure_.get_connection().version_; bool removeDH = secure_.use_parms().removeDH_; bool removeRSA = false; bool removeDSA = false; if (cm.get_keyType() == rsa_sa_algo) removeDSA = true; else removeRSA = true; secure_.use_parms().SetSuites(pv, removeDH, removeRSA, removeDSA); } } else if (serverSide) { SetError(no_key_file); return; } if (ctx->getMethod()->verifyPeer()) cm.setVerifyPeer(); if (ctx->getMethod()->verifyNone()) cm.setVerifyNone(); if (ctx->getMethod()->failNoCert()) cm.setFailNoCert(); cm.setVerifyCallback(ctx->getVerifyCallback()); if (serverSide) crypto_.SetDH(ctx->GetDH_Parms()); const SSL_CTX::CertList& ca = ctx->GetCA_List(); SSL_CTX::CertList::const_iterator first(ca.begin()); SSL_CTX::CertList::const_iterator last(ca.end()); while (first != last) { if (int err = cm.CopyCaCert(*first)) { SetError(YasslError(err)); return; } ++first; } } // store pending security parameters from Server Hello void SSL::set_pending(Cipher suite) { Parameters& parms = secure_.use_parms(); switch (suite) { case TLS_RSA_WITH_AES_256_CBC_SHA: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = sha; parms.kea_ = rsa_kea; parms.hash_size_ = SHA_LEN; parms.key_size_ = AES_256_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); strncpy(parms.cipher_name_, cipher_names[TLS_RSA_WITH_AES_256_CBC_SHA], MAX_SUITE_NAME); break; case TLS_RSA_WITH_AES_128_CBC_SHA: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = sha; parms.kea_ = rsa_kea; parms.hash_size_ = SHA_LEN; parms.key_size_ = AES_128_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS AES); strncpy(parms.cipher_name_, cipher_names[TLS_RSA_WITH_AES_128_CBC_SHA], MAX_SUITE_NAME); break; case SSL_RSA_WITH_3DES_EDE_CBC_SHA: parms.bulk_cipher_algorithm_ = triple_des; parms.mac_algorithm_ = sha; parms.kea_ = rsa_kea; parms.hash_size_ = SHA_LEN; parms.key_size_ = DES_EDE_KEY_SZ; parms.iv_size_ = DES_IV_SZ; parms.cipher_type_ = block; crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS DES_EDE); strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_3DES_EDE_CBC_SHA] , MAX_SUITE_NAME); break; case SSL_RSA_WITH_DES_CBC_SHA: parms.bulk_cipher_algorithm_ = des; parms.mac_algorithm_ = sha; parms.kea_ = rsa_kea; parms.hash_size_ = SHA_LEN; parms.key_size_ = DES_KEY_SZ; parms.iv_size_ = DES_IV_SZ; parms.cipher_type_ = block; crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS DES); strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_DES_CBC_SHA], MAX_SUITE_NAME); break; case SSL_RSA_WITH_RC4_128_SHA: parms.bulk_cipher_algorithm_ = rc4; parms.mac_algorithm_ = sha; parms.kea_ = rsa_kea; parms.hash_size_ = SHA_LEN; parms.key_size_ = RC4_KEY_SZ; parms.iv_size_ = 0; parms.cipher_type_ = stream; crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS RC4); strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_RC4_128_SHA], MAX_SUITE_NAME); break; case SSL_RSA_WITH_RC4_128_MD5: parms.bulk_cipher_algorithm_ = rc4; parms.mac_algorithm_ = md5; parms.kea_ = rsa_kea; parms.hash_size_ = MD5_LEN; parms.key_size_ = RC4_KEY_SZ; parms.iv_size_ = 0; parms.cipher_type_ = stream; crypto_.setDigest(NEW_YS MD5); crypto_.setCipher(NEW_YS RC4); strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_RC4_128_MD5], MAX_SUITE_NAME); break; case SSL_DHE_RSA_WITH_DES_CBC_SHA: parms.bulk_cipher_algorithm_ = des; parms.mac_algorithm_ = sha; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = rsa_sa_algo; parms.hash_size_ = SHA_LEN; parms.key_size_ = DES_KEY_SZ; parms.iv_size_ = DES_IV_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS DES); strncpy(parms.cipher_name_, cipher_names[SSL_DHE_RSA_WITH_DES_CBC_SHA], MAX_SUITE_NAME); break; case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA: parms.bulk_cipher_algorithm_ = triple_des; parms.mac_algorithm_ = sha; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = rsa_sa_algo; parms.hash_size_ = SHA_LEN; parms.key_size_ = DES_EDE_KEY_SZ; parms.iv_size_ = DES_IV_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS DES_EDE); strncpy(parms.cipher_name_, cipher_names[SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA], MAX_SUITE_NAME); break; case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = sha; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = rsa_sa_algo; parms.hash_size_ = SHA_LEN; parms.key_size_ = AES_256_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); strncpy(parms.cipher_name_, cipher_names[TLS_DHE_RSA_WITH_AES_256_CBC_SHA], MAX_SUITE_NAME); break; case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = sha; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = rsa_sa_algo; parms.hash_size_ = SHA_LEN; parms.key_size_ = AES_128_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS AES); strncpy(parms.cipher_name_, cipher_names[TLS_DHE_RSA_WITH_AES_128_CBC_SHA], MAX_SUITE_NAME); break; case SSL_DHE_DSS_WITH_DES_CBC_SHA: parms.bulk_cipher_algorithm_ = des; parms.mac_algorithm_ = sha; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = dsa_sa_algo; parms.hash_size_ = SHA_LEN; parms.key_size_ = DES_KEY_SZ; parms.iv_size_ = DES_IV_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS DES); strncpy(parms.cipher_name_, cipher_names[SSL_DHE_DSS_WITH_DES_CBC_SHA], MAX_SUITE_NAME); break; case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA: parms.bulk_cipher_algorithm_ = triple_des; parms.mac_algorithm_ = sha; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = dsa_sa_algo; parms.hash_size_ = SHA_LEN; parms.key_size_ = DES_EDE_KEY_SZ; parms.iv_size_ = DES_IV_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS DES_EDE); strncpy(parms.cipher_name_, cipher_names[SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA], MAX_SUITE_NAME); break; case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = sha; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = dsa_sa_algo; parms.hash_size_ = SHA_LEN; parms.key_size_ = AES_256_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); strncpy(parms.cipher_name_, cipher_names[TLS_DHE_DSS_WITH_AES_256_CBC_SHA], MAX_SUITE_NAME); break; case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = sha; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = dsa_sa_algo; parms.hash_size_ = SHA_LEN; parms.key_size_ = AES_128_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS SHA); crypto_.setCipher(NEW_YS AES); strncpy(parms.cipher_name_, cipher_names[TLS_DHE_DSS_WITH_AES_128_CBC_SHA], MAX_SUITE_NAME); break; case TLS_RSA_WITH_AES_256_CBC_RMD160: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = rmd; parms.kea_ = rsa_kea; parms.hash_size_ = RMD_LEN; parms.key_size_ = AES_256_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; crypto_.setDigest(NEW_YS RMD); crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); strncpy(parms.cipher_name_, cipher_names[TLS_RSA_WITH_AES_256_CBC_RMD160], MAX_SUITE_NAME); break; case TLS_RSA_WITH_AES_128_CBC_RMD160: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = rmd; parms.kea_ = rsa_kea; parms.hash_size_ = RMD_LEN; parms.key_size_ = AES_128_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; crypto_.setDigest(NEW_YS RMD); crypto_.setCipher(NEW_YS AES); strncpy(parms.cipher_name_, cipher_names[TLS_RSA_WITH_AES_128_CBC_RMD160], MAX_SUITE_NAME); break; case TLS_RSA_WITH_3DES_EDE_CBC_RMD160: parms.bulk_cipher_algorithm_ = triple_des; parms.mac_algorithm_ = rmd; parms.kea_ = rsa_kea; parms.hash_size_ = RMD_LEN; parms.key_size_ = DES_EDE_KEY_SZ; parms.iv_size_ = DES_IV_SZ; parms.cipher_type_ = block; crypto_.setDigest(NEW_YS RMD); crypto_.setCipher(NEW_YS DES_EDE); strncpy(parms.cipher_name_, cipher_names[TLS_RSA_WITH_3DES_EDE_CBC_RMD160], MAX_SUITE_NAME); break; case TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD160: parms.bulk_cipher_algorithm_ = triple_des; parms.mac_algorithm_ = rmd; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = rsa_sa_algo; parms.hash_size_ = RMD_LEN; parms.key_size_ = DES_EDE_KEY_SZ; parms.iv_size_ = DES_IV_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS RMD); crypto_.setCipher(NEW_YS DES_EDE); strncpy(parms.cipher_name_, cipher_names[TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD160], MAX_SUITE_NAME); break; case TLS_DHE_RSA_WITH_AES_256_CBC_RMD160: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = rmd; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = rsa_sa_algo; parms.hash_size_ = RMD_LEN; parms.key_size_ = AES_256_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS RMD); crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); strncpy(parms.cipher_name_, cipher_names[TLS_DHE_RSA_WITH_AES_256_CBC_RMD160], MAX_SUITE_NAME); break; case TLS_DHE_RSA_WITH_AES_128_CBC_RMD160: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = rmd; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = rsa_sa_algo; parms.hash_size_ = RMD_LEN; parms.key_size_ = AES_128_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS RMD); crypto_.setCipher(NEW_YS AES); strncpy(parms.cipher_name_, cipher_names[TLS_DHE_RSA_WITH_AES_128_CBC_RMD160], MAX_SUITE_NAME); break; case TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD160: parms.bulk_cipher_algorithm_ = triple_des; parms.mac_algorithm_ = rmd; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = dsa_sa_algo; parms.hash_size_ = RMD_LEN; parms.key_size_ = DES_EDE_KEY_SZ; parms.iv_size_ = DES_IV_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS RMD); crypto_.setCipher(NEW_YS DES_EDE); strncpy(parms.cipher_name_, cipher_names[TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD160], MAX_SUITE_NAME); break; case TLS_DHE_DSS_WITH_AES_256_CBC_RMD160: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = rmd; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = dsa_sa_algo; parms.hash_size_ = RMD_LEN; parms.key_size_ = AES_256_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS RMD); crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); strncpy(parms.cipher_name_, cipher_names[TLS_DHE_DSS_WITH_AES_256_CBC_RMD160], MAX_SUITE_NAME); break; case TLS_DHE_DSS_WITH_AES_128_CBC_RMD160: parms.bulk_cipher_algorithm_ = aes; parms.mac_algorithm_ = rmd; parms.kea_ = diffie_hellman_kea; parms.sig_algo_ = dsa_sa_algo; parms.hash_size_ = RMD_LEN; parms.key_size_ = AES_128_KEY_SZ; parms.iv_size_ = AES_BLOCK_SZ; parms.cipher_type_ = block; secure_.use_connection().send_server_key_ = true; // eph crypto_.setDigest(NEW_YS RMD); crypto_.setCipher(NEW_YS AES); strncpy(parms.cipher_name_, cipher_names[TLS_DHE_DSS_WITH_AES_128_CBC_RMD160], MAX_SUITE_NAME); break; default: SetError(unknown_cipher); } } #ifdef _WIN32 typedef volatile LONG yassl_pthread_once_t; #define YASSL_PTHREAD_ONCE_INIT 0 #define YASSL_PTHREAD_ONCE_INPROGRESS 1 #define YASSL_PTHREAD_ONCE_DONE 2 int yassl_pthread_once(yassl_pthread_once_t *once_control, void (*init_routine)(void)) { LONG state; /* Do "dirty" read to find out if initialization is already done, to save an interlocked operation in common case. Memory barriers are ensured by Visual C++ volatile implementation. */ if (*once_control == YASSL_PTHREAD_ONCE_DONE) return 0; state= InterlockedCompareExchange(once_control, YASSL_PTHREAD_ONCE_INPROGRESS, YASSL_PTHREAD_ONCE_INIT); switch(state) { case YASSL_PTHREAD_ONCE_INIT: /* This is initializer thread */ (*init_routine)(); *once_control= YASSL_PTHREAD_ONCE_DONE; break; case YASSL_PTHREAD_ONCE_INPROGRESS: /* init_routine in progress. Wait for its completion */ while(*once_control == YASSL_PTHREAD_ONCE_INPROGRESS) { Sleep(1); } break; case YASSL_PTHREAD_ONCE_DONE: /* Nothing to do */ break; } return 0; } #else #define yassl_pthread_once_t pthread_once_t #if defined(PTHREAD_ONCE_INITIALIZER) #define YASSL_PTHREAD_ONCE_INIT PTHREAD_ONCE_INITIALIZER #else #define YASSL_PTHREAD_ONCE_INIT PTHREAD_ONCE_INIT #endif #define yassl_pthread_once(C,F) pthread_once(C,F) #endif // _WIN32 // store peer's random void SSL::set_random(const opaque* random, ConnectionEnd sender) { if (sender == client_end) memcpy(secure_.use_connection().client_random_, random, RAN_LEN); else memcpy(secure_.use_connection().server_random_, random, RAN_LEN); } // store client pre master secret void SSL::set_preMaster(const opaque* pre, uint sz) { uint i(0); // trim leading zeros uint fullSz(sz); while (i++ < fullSz && *pre == 0) { sz--; pre++; } if (sz == 0) { SetError(bad_input); return; } secure_.use_connection().AllocPreSecret(sz); memcpy(secure_.use_connection().pre_master_secret_, pre, sz); } // set yaSSL zlib type compression int SSL::SetCompression() { #ifdef HAVE_LIBZ secure_.use_connection().compression_ = true; return 0; #else return -1; // not built in #endif } // unset yaSSL zlib type compression void SSL::UnSetCompression() { secure_.use_connection().compression_ = false; } // is yaSSL zlib compression on bool SSL::CompressionOn() const { return secure_.get_connection().compression_; } // store master secret void SSL::set_masterSecret(const opaque* sec) { memcpy(secure_.use_connection().master_secret_, sec, SECRET_LEN); } // store server issued id void SSL::set_sessionID(const opaque* sessionID) { memcpy(secure_.use_connection().sessionID_, sessionID, ID_LEN); secure_.use_connection().sessionID_Set_ = true; } // store error void SSL::SetError(YasslError ye) { states_.SetError(ye); //strncpy(states_.useString(), e.what(), mySTL::named_exception::NAME_SIZE); // TODO: add string here } // set the quiet shutdown mode (close_nofiy not sent or received on shutdown) void SSL::SetQuietShutdown(bool mode) { quietShutdown_ = mode; } Buffers& SSL::useBuffers() { return buffers_; } // locals namespace { // DeriveKeys and MasterSecret helper sets prefix letters static bool setPrefix(opaque* sha_input, int i) { switch (i) { case 0: memcpy(sha_input, "A", 1); break; case 1: memcpy(sha_input, "BB", 2); break; case 2: memcpy(sha_input, "CCC", 3); break; case 3: memcpy(sha_input, "DDDD", 4); break; case 4: memcpy(sha_input, "EEEEE", 5); break; case 5: memcpy(sha_input, "FFFFFF", 6); break; case 6: memcpy(sha_input, "GGGGGGG", 7); break; default: return false; // prefix_error } return true; } const char handshake_order[] = "Out of order HandShake Message!"; } // namespcae for locals void SSL::order_error() { SetError(out_of_order); } // Create and store the master secret see page 32, 6.1 void SSL::makeMasterSecret() { if (GetError()) return; if (isTLS()) makeTLSMasterSecret(); else { opaque sha_output[SHA_LEN]; const uint& preSz = secure_.get_connection().pre_secret_len_; output_buffer md5_input(preSz + SHA_LEN); output_buffer sha_input(PREFIX + preSz + 2 * RAN_LEN); MD5 md5; SHA sha; md5_input.write(secure_.get_connection().pre_master_secret_, preSz); for (int i = 0; i < MASTER_ROUNDS; ++i) { opaque prefix[PREFIX]; if (!setPrefix(prefix, i)) { SetError(prefix_error); return; } sha_input.set_current(0); sha_input.write(prefix, i + 1); sha_input.write(secure_.get_connection().pre_master_secret_,preSz); sha_input.write(secure_.get_connection().client_random_, RAN_LEN); sha_input.write(secure_.get_connection().server_random_, RAN_LEN); sha.get_digest(sha_output, sha_input.get_buffer(), sha_input.get_size()); md5_input.set_current(preSz); md5_input.write(sha_output, SHA_LEN); md5.get_digest(&secure_.use_connection().master_secret_[i*MD5_LEN], md5_input.get_buffer(), md5_input.get_size()); } deriveKeys(); } secure_.use_connection().CleanPreMaster(); } // create TLSv1 master secret void SSL::makeTLSMasterSecret() { opaque seed[SEED_LEN]; memcpy(seed, secure_.get_connection().client_random_, RAN_LEN); memcpy(&seed[RAN_LEN], secure_.get_connection().server_random_, RAN_LEN); PRF(secure_.use_connection().master_secret_, SECRET_LEN, secure_.get_connection().pre_master_secret_, secure_.get_connection().pre_secret_len_, master_label, MASTER_LABEL_SZ, seed, SEED_LEN); deriveTLSKeys(); } // derive mac, write, and iv keys for server and client, see page 34, 6.2.2 void SSL::deriveKeys() { int length = 2 * secure_.get_parms().hash_size_ + 2 * secure_.get_parms().key_size_ + 2 * secure_.get_parms().iv_size_; int rounds = (length + MD5_LEN - 1 ) / MD5_LEN; input_buffer key_data(rounds * MD5_LEN); opaque sha_output[SHA_LEN]; opaque md5_input[SECRET_LEN + SHA_LEN]; opaque sha_input[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN]; MD5 md5; SHA sha; memcpy(md5_input, secure_.get_connection().master_secret_, SECRET_LEN); for (int i = 0; i < rounds; ++i) { int j = i + 1; if (!setPrefix(sha_input, i)) { SetError(prefix_error); return; } memcpy(&sha_input[j], secure_.get_connection().master_secret_, SECRET_LEN); memcpy(&sha_input[j+SECRET_LEN], secure_.get_connection().server_random_, RAN_LEN); memcpy(&sha_input[j + SECRET_LEN + RAN_LEN], secure_.get_connection().client_random_, RAN_LEN); sha.get_digest(sha_output, sha_input, sizeof(sha_input) - KEY_PREFIX + j); memcpy(&md5_input[SECRET_LEN], sha_output, SHA_LEN); md5.get_digest(key_data.get_buffer() + i * MD5_LEN, md5_input, sizeof(md5_input)); } storeKeys(key_data.get_buffer()); } // derive mac, write, and iv keys for server and client void SSL::deriveTLSKeys() { int length = 2 * secure_.get_parms().hash_size_ + 2 * secure_.get_parms().key_size_ + 2 * secure_.get_parms().iv_size_; opaque seed[SEED_LEN]; input_buffer key_data(length); memcpy(seed, secure_.get_connection().server_random_, RAN_LEN); memcpy(&seed[RAN_LEN], secure_.get_connection().client_random_, RAN_LEN); PRF(key_data.get_buffer(), length, secure_.get_connection().master_secret_, SECRET_LEN, key_label, KEY_LABEL_SZ, seed, SEED_LEN); storeKeys(key_data.get_buffer()); } // store mac, write, and iv keys for client and server void SSL::storeKeys(const opaque* key_data) { int sz = secure_.get_parms().hash_size_; memcpy(secure_.use_connection().client_write_MAC_secret_, key_data, sz); int i = sz; memcpy(secure_.use_connection().server_write_MAC_secret_,&key_data[i], sz); i += sz; sz = secure_.get_parms().key_size_; memcpy(secure_.use_connection().client_write_key_, &key_data[i], sz); i += sz; memcpy(secure_.use_connection().server_write_key_, &key_data[i], sz); i += sz; sz = secure_.get_parms().iv_size_; memcpy(secure_.use_connection().client_write_IV_, &key_data[i], sz); i += sz; memcpy(secure_.use_connection().server_write_IV_, &key_data[i], sz); setKeys(); } // set encrypt/decrypt keys and ivs void SSL::setKeys() { Connection& conn = secure_.use_connection(); if (secure_.get_parms().entity_ == client_end) { crypto_.use_cipher().set_encryptKey(conn.client_write_key_, conn.client_write_IV_); crypto_.use_cipher().set_decryptKey(conn.server_write_key_, conn.server_write_IV_); } else { crypto_.use_cipher().set_encryptKey(conn.server_write_key_, conn.server_write_IV_); crypto_.use_cipher().set_decryptKey(conn.client_write_key_, conn.client_write_IV_); } } // local functors namespace yassl_int_cpp_local1 { // for explicit templates struct SumData { uint total_; SumData() : total_(0) {} void operator()(input_buffer* data) { total_ += data->get_remaining(); } }; struct SumBuffer { uint total_; SumBuffer() : total_(0) {} void operator()(output_buffer* buffer) { total_ += buffer->get_size(); } }; } // namespace for locals using namespace yassl_int_cpp_local1; uint SSL::bufferedData() { return STL::for_each(buffers_.getData().begin(),buffers_.getData().end(), SumData()).total_; } // use input buffer to fill data void SSL::fillData(Data& data) { if (GetError()) return; uint dataSz = data.get_length(); // input, data size to fill size_t elements = buffers_.getData().size(); data.set_length(0); // output, actual data filled dataSz = min(dataSz, bufferedData()); for (size_t i = 0; i < elements; i++) { input_buffer* front = buffers_.getData().front(); uint frontSz = front->get_remaining(); uint readSz = min(dataSz - data.get_length(), frontSz); front->read(data.set_buffer() + data.get_length(), readSz); data.set_length(data.get_length() + readSz); if (readSz == frontSz) { buffers_.useData().pop_front(); ysDelete(front); } if (data.get_length() == dataSz) break; } if (buffers_.getData().size() == 0) has_data_ = false; // none left } // like Fill but keep data in buffer void SSL::PeekData(Data& data) { if (GetError()) return; uint dataSz = data.get_length(); // input, data size to fill size_t elements = buffers_.getData().size(); data.set_length(0); // output, actual data filled dataSz = min(dataSz, bufferedData()); Buffers::inputList::iterator front = buffers_.useData().begin(); while (elements) { uint frontSz = (*front)->get_remaining(); uint readSz = min(dataSz - data.get_length(), frontSz); uint before = (*front)->get_current(); (*front)->read(data.set_buffer() + data.get_length(), readSz); data.set_length(data.get_length() + readSz); (*front)->set_current(before); if (data.get_length() == dataSz) break; elements--; front++; } } // flush output buffer void SSL::flushBuffer() { if (GetError()) return; uint sz = STL::for_each(buffers_.getHandShake().begin(), buffers_.getHandShake().end(), SumBuffer()).total_; output_buffer out(sz); size_t elements = buffers_.getHandShake().size(); for (size_t i = 0; i < elements; i++) { output_buffer* front = buffers_.getHandShake().front(); out.write(front->get_buffer(), front->get_size()); buffers_.useHandShake().pop_front(); ysDelete(front); } Send(out.get_buffer(), out.get_size()); } void SSL::Send(const byte* buffer, uint sz) { unsigned int sent = 0; if (socket_.send(buffer, sz, sent) != sz) { if (socket_.WouldBlock()) { buffers_.SetOutput(NEW_YS output_buffer(sz - sent, buffer + sent, sz - sent)); SetError(YasslError(SSL_ERROR_WANT_WRITE)); } else SetError(send_error); } } void SSL::SendWriteBuffered() { output_buffer* out = buffers_.TakeOutput(); if (out) { mySTL::auto_ptr tmp(out); Send(out->get_buffer(), out->get_size()); } } // get sequence number, if verify get peer's uint SSL::get_SEQIncrement(bool verify) { if (verify) return secure_.use_connection().peer_sequence_number_++; else return secure_.use_connection().sequence_number_++; } const byte* SSL::get_macSecret(bool verify) { if ( (secure_.get_parms().entity_ == client_end && !verify) || (secure_.get_parms().entity_ == server_end && verify) ) return secure_.get_connection().client_write_MAC_secret_; else return secure_.get_connection().server_write_MAC_secret_; } void SSL::verifyState(const RecordLayerHeader& rlHeader) { if (GetError()) return; if (rlHeader.version_.major_ != 3 || rlHeader.version_.minor_ > 2) { SetError(badVersion_error); return; } if (states_.getRecord() == recordNotReady || (rlHeader.type_ == application_data && // data and handshake states_.getHandShake() != handShakeReady) ) // isn't complete yet SetError(record_layer); } void SSL::verifyState(const HandShakeHeader& hsHeader) { if (GetError()) return; if (states_.getHandShake() == handShakeNotReady) { SetError(handshake_layer); return; } if (states_.SetMessageRecvd(hsHeader.get_handshakeType()) != 0) { order_error(); return; } if (secure_.get_parms().entity_ == client_end) verifyClientState(hsHeader.get_handshakeType()); else verifyServerState(hsHeader.get_handshakeType()); } void SSL::verifyState(ClientState cs) { if (GetError()) return; if (states_.getClient() != cs) order_error(); } void SSL::verifyState(ServerState ss) { if (GetError()) return; if (states_.getServer() != ss) order_error(); } void SSL::verfiyHandShakeComplete() { if (GetError()) return; if (states_.getHandShake() != handShakeReady) order_error(); } void SSL::verifyClientState(HandShakeType hsType) { if (GetError()) return; switch(hsType) { case server_hello : if (states_.getClient() != serverNull) order_error(); break; case certificate : if (states_.getClient() != serverHelloComplete) order_error(); break; case server_key_exchange : if (states_.getClient() != serverCertComplete) order_error(); break; case certificate_request : if (states_.getClient() != serverCertComplete && states_.getClient() != serverKeyExchangeComplete) order_error(); break; case server_hello_done : if (states_.getClient() != serverCertComplete && states_.getClient() != serverKeyExchangeComplete) order_error(); break; case finished : if (states_.getClient() != serverHelloDoneComplete || secure_.get_parms().pending_) // no change order_error(); // cipher yet break; default : order_error(); }; } void SSL::verifyServerState(HandShakeType hsType) { if (GetError()) return; switch(hsType) { case client_hello : if (states_.getServer() != clientNull) order_error(); break; case certificate : if (states_.getServer() != clientHelloComplete) order_error(); break; case client_key_exchange : if (states_.getServer() != clientHelloComplete) order_error(); break; case certificate_verify : if (states_.getServer() != clientKeyExchangeComplete) order_error(); break; case finished : if (states_.getServer() != clientKeyExchangeComplete || secure_.get_parms().pending_) // no change order_error(); // cipher yet break; default : order_error(); }; } // try to find a suite match void SSL::matchSuite(const opaque* peer, uint length) { if (length == 0 || (length % 2) != 0) { SetError(bad_input); return; } // start with best, if a match we are good, Ciphers are at odd index // since all SSL and TLS ciphers have 0x00 first byte for (uint i = 1; i < secure_.get_parms().suites_size_; i += 2) for (uint j = 0; (j + 1) < length; j+= 2) { if (peer[j] != 0x00) { continue; // only 0x00 first byte supported } if (secure_.use_parms().suites_[i] == peer[j + 1]) { secure_.use_parms().suite_[0] = 0x00; secure_.use_parms().suite_[1] = peer[j + 1]; return; } } SetError(match_error); } void SSL::set_session(SSL_SESSION* s) { if (getSecurity().GetContext()->GetSessionCacheOff()) return; if (s && GetSessions().lookup(s->GetID(), &secure_.use_resume())) { secure_.set_resuming(true); crypto_.use_certManager().setPeerX509(s->GetPeerX509()); } } const Crypto& SSL::getCrypto() const { return crypto_; } const Security& SSL::getSecurity() const { return secure_; } const States& SSL::getStates() const { return states_; } const sslHashes& SSL::getHashes() const { return hashes_; } const sslFactory& SSL::getFactory() const { return GetSSL_Factory(); } const Socket& SSL::getSocket() const { return socket_; } YasslError SSL::GetError() const { return states_.What(); } bool SSL::GetQuietShutdown() const { return quietShutdown_; } bool SSL::GetMultiProtocol() const { return secure_.GetContext()->getMethod()->multipleProtocol(); } Crypto& SSL::useCrypto() { return crypto_; } Security& SSL::useSecurity() { return secure_; } States& SSL::useStates() { return states_; } sslHashes& SSL::useHashes() { return hashes_; } Socket& SSL::useSocket() { return socket_; } Log& SSL::useLog() { return log_; } bool SSL::isTLS() const { return secure_.get_connection().TLS_; } bool SSL::isTLSv1_1() const { return secure_.get_connection().TLSv1_1_; } // is there buffered data available, optimization to remove iteration on buffer bool SSL::HasData() const { return has_data_; } void SSL::addData(input_buffer* data) { buffers_.useData().push_back(data); if (!has_data_) has_data_ = true; } void SSL::addBuffer(output_buffer* b) { buffers_.useHandShake().push_back(b); } void SSL_SESSION::CopyX509(X509* x) { if (x == 0) return; X509_NAME* issuer = x->GetIssuer(); X509_NAME* subject = x->GetSubject(); ASN1_TIME* before = x->GetBefore(); ASN1_TIME* after = x->GetAfter(); peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(), subject->GetName(), subject->GetLength(), before, after, issuer->GetCnPosition(), issuer->GetCnLength(), subject->GetCnPosition(), subject->GetCnLength()); } // store connection parameters SSL_SESSION::SSL_SESSION(const SSL& ssl, RandomPool& ran) : timeout_(DEFAULT_TIMEOUT), random_(ran), peerX509_(0) { const Connection& conn = ssl.getSecurity().get_connection(); memcpy(sessionID_, conn.sessionID_, ID_LEN); memcpy(master_secret_, conn.master_secret_, SECRET_LEN); memcpy(suite_, ssl.getSecurity().get_parms().suite_, SUITE_LEN); bornOn_ = lowResTimer(); CopyX509(ssl.getCrypto().get_certManager().get_peerX509()); } // for resumption copy in ssl::parameters SSL_SESSION::SSL_SESSION(RandomPool& ran) : bornOn_(0), timeout_(0), random_(ran), peerX509_(0) { memset(sessionID_, 0, ID_LEN); memset(master_secret_, 0, SECRET_LEN); memset(suite_, 0, SUITE_LEN); } SSL_SESSION& SSL_SESSION::operator=(const SSL_SESSION& that) { memcpy(sessionID_, that.sessionID_, ID_LEN); memcpy(master_secret_, that.master_secret_, SECRET_LEN); memcpy(suite_, that.suite_, SUITE_LEN); bornOn_ = that.bornOn_; timeout_ = that.timeout_; if (peerX509_) { ysDelete(peerX509_); peerX509_ = 0; } CopyX509(that.peerX509_); return *this; } const opaque* SSL_SESSION::GetID() const { return sessionID_; } const opaque* SSL_SESSION::GetSecret() const { return master_secret_; } const Cipher* SSL_SESSION::GetSuite() const { return suite_; } X509* SSL_SESSION::GetPeerX509() const { return peerX509_; } uint SSL_SESSION::GetBornOn() const { return bornOn_; } uint SSL_SESSION::GetTimeOut() const { return timeout_; } void SSL_SESSION::SetTimeOut(uint t) { timeout_ = t; } extern void clean(volatile opaque*, uint, RandomPool&); // clean up secret data SSL_SESSION::~SSL_SESSION() { volatile opaque* p = master_secret_; clean(p, SECRET_LEN, random_); ysDelete(peerX509_); } static Sessions* sessionsInstance = 0; static yassl_pthread_once_t session_created= YASSL_PTHREAD_ONCE_INIT; void Session_initialize() { sessionsInstance = NEW_YS Sessions; } extern "C" { static void c_session_initialize() { Session_initialize(); } } Sessions& GetSessions() { yassl_pthread_once(&session_created, c_session_initialize); return *sessionsInstance; } static sslFactory* sslFactoryInstance = 0; sslFactory& GetSSL_Factory() { if (!sslFactoryInstance) sslFactoryInstance = NEW_YS sslFactory; return *sslFactoryInstance; } static Errors* errorsInstance = 0; Errors& GetErrors() { if (!errorsInstance) errorsInstance = NEW_YS Errors; return *errorsInstance; } typedef Mutex::Lock Lock; void Sessions::add(const SSL& ssl) { if (ssl.getSecurity().get_connection().sessionID_Set_) { Lock guard(mutex_); list_.push_back(NEW_YS SSL_SESSION(ssl, random_)); count_++; } if (count_ > SESSION_FLUSH_COUNT) if (!ssl.getSecurity().GetContext()->GetSessionCacheFlushOff()) Flush(); } Sessions::~Sessions() { STL::for_each(list_.begin(), list_.end(), del_ptr_zero()); } // locals namespace yassl_int_cpp_local2 { // for explicit templates typedef STL::list::iterator sess_iterator; typedef STL::list::iterator thr_iterator; struct sess_match { const opaque* id_; explicit sess_match(const opaque* p) : id_(p) {} bool operator()(SSL_SESSION* sess) { if ( memcmp(sess->GetID(), id_, ID_LEN) == 0) return true; return false; } }; THREAD_ID_T GetSelf() { #ifndef _POSIX_THREADS return GetCurrentThreadId(); #else return pthread_self(); #endif } struct thr_match { THREAD_ID_T id_; explicit thr_match() : id_(GetSelf()) {} bool operator()(ThreadError thr) { if (thr.threadID_ == id_) return true; return false; } }; } // local namespace using namespace yassl_int_cpp_local2; // lookup session by id, return a copy if space provided SSL_SESSION* Sessions::lookup(const opaque* id, SSL_SESSION* copy) { Lock guard(mutex_); sess_iterator find = STL::find_if(list_.begin(), list_.end(), sess_match(id)); if (find != list_.end()) { uint current = lowResTimer(); if ( ((*find)->GetBornOn() + (*find)->GetTimeOut()) < current) { del_ptr_zero()(*find); list_.erase(find); return 0; } if (copy) *copy = *(*find); return *find; } return 0; } // remove a session by id void Sessions::remove(const opaque* id) { Lock guard(mutex_); sess_iterator find = STL::find_if(list_.begin(), list_.end(), sess_match(id)); if (find != list_.end()) { del_ptr_zero()(*find); list_.erase(find); } } // flush expired sessions from cache void Sessions::Flush() { Lock guard(mutex_); sess_iterator next = list_.begin(); uint current = lowResTimer(); while (next != list_.end()) { sess_iterator si = next; ++next; if ( ((*si)->GetBornOn() + (*si)->GetTimeOut()) < current) { del_ptr_zero()(*si); list_.erase(si); } } count_ = 0; // reset flush counter } // remove a self thread error void Errors::Remove() { Lock guard(mutex_); thr_iterator find = STL::find_if(list_.begin(), list_.end(), thr_match()); if (find != list_.end()) list_.erase(find); } // lookup self error code int Errors::Lookup(bool peek) { Lock guard(mutex_); thr_iterator find = STL::find_if(list_.begin(), list_.end(), thr_match()); if (find != list_.end()) { int ret = find->errorID_; if (!peek) list_.erase(find); return ret; } else return 0; } // add a new error code for self void Errors::Add(int error) { ThreadError add; add.errorID_ = error; add.threadID_ = GetSelf(); Remove(); // may have old error Lock guard(mutex_); list_.push_back(add); } SSL_METHOD::SSL_METHOD(ConnectionEnd ce, ProtocolVersion pv, bool multiProto) : version_(pv), side_(ce), verifyPeer_(false), verifyNone_(false), failNoCert_(false), multipleProtocol_(multiProto) {} ProtocolVersion SSL_METHOD::getVersion() const { return version_; } ConnectionEnd SSL_METHOD::getSide() const { return side_; } void SSL_METHOD::setVerifyPeer() { verifyPeer_ = true; } void SSL_METHOD::setVerifyNone() { verifyNone_ = true; } void SSL_METHOD::setFailNoCert() { failNoCert_ = true; } bool SSL_METHOD::verifyPeer() const { return verifyPeer_; } bool SSL_METHOD::verifyNone() const { return verifyNone_; } bool SSL_METHOD::failNoCert() const { return failNoCert_; } bool SSL_METHOD::multipleProtocol() const { return multipleProtocol_; } /** Implement a my_strdup replacement, so we can reuse get_password() */ extern "C" char *yassl_mysql_strdup(const char *from, int) { return from ? strdup(from) : NULL; } extern "C" { int default_password_callback(char * buffer, int size_arg, int rwflag, void * /* unused: callback_data */) { char *passwd; size_t passwd_len, size= (size_t) size_arg; passwd= ::yassl_mysql_get_tty_password_ext("Enter PEM pass phrase:", yassl_mysql_strdup); if (!passwd) return 0; passwd_len= strlen(passwd); if (!passwd_len) return 0; if (size > 0) { size_t result_len= size - 1 > passwd_len ? passwd_len : size - 1; memcpy(buffer, passwd, result_len); buffer[result_len]= 0; } free(passwd); return passwd_len; } } SSL_CTX::SSL_CTX(SSL_METHOD* meth) : method_(meth), certificate_(0), privateKey_(0), passwordCb_(default_password_callback), userData_(0), sessionCacheOff_(false), sessionCacheFlushOff_(false), verifyCallback_(0) {} SSL_CTX::~SSL_CTX() { ysDelete(method_); ysDelete(certificate_); ysDelete(privateKey_); STL::for_each(caList_.begin(), caList_.end(), del_ptr_zero()); } void SSL_CTX::AddCA(x509* ca) { caList_.push_back(ca); } const SSL_CTX::CertList& SSL_CTX::GetCA_List() const { return caList_; } VerifyCallback SSL_CTX::getVerifyCallback() const { return verifyCallback_; } const x509* SSL_CTX::getCert() const { return certificate_; } const x509* SSL_CTX::getKey() const { return privateKey_; } const SSL_METHOD* SSL_CTX::getMethod() const { return method_; } const Ciphers& SSL_CTX::GetCiphers() const { return ciphers_; } const DH_Parms& SSL_CTX::GetDH_Parms() const { return dhParms_; } const Stats& SSL_CTX::GetStats() const { return stats_; } pem_password_cb SSL_CTX::GetPasswordCb() const { return passwordCb_; } void SSL_CTX::SetPasswordCb(pem_password_cb cb) { passwordCb_ = cb; } void* SSL_CTX::GetUserData() const { return userData_; } bool SSL_CTX::GetSessionCacheOff() const { return sessionCacheOff_; } bool SSL_CTX::GetSessionCacheFlushOff() const { return sessionCacheFlushOff_; } void SSL_CTX::SetUserData(void* data) { userData_ = data; } void SSL_CTX::SetSessionCacheOff() { sessionCacheOff_ = true; } void SSL_CTX::SetMethod(SSL_METHOD* meth) { if(method_) ysDelete(method_); method_= meth; } void SSL_CTX::SetSessionCacheFlushOff() { sessionCacheFlushOff_ = true; } void SSL_CTX::setVerifyPeer() { method_->setVerifyPeer(); } void SSL_CTX::setVerifyNone() { method_->setVerifyNone(); } void SSL_CTX::setFailNoCert() { method_->setFailNoCert(); } void SSL_CTX::setVerifyCallback(VerifyCallback vc) { verifyCallback_ = vc; } bool SSL_CTX::SetDH(const DH& dh) { dhParms_.p_ = dh.p->int_; dhParms_.g_ = dh.g->int_; return dhParms_.set_ = true; } bool SSL_CTX::SetCipherList(const char* list) { if (!list) return false; bool ret = false; char name[MAX_SUITE_NAME]; char needle[] = ":"; char* haystack = const_cast(list); char* prev; const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]); int idx = 0; for(;;) { size_t len; prev = haystack; haystack = strstr(haystack, needle); if (!haystack) // last cipher len = min(sizeof(name), strlen(prev)); else len = min(sizeof(name), (size_t)(haystack - prev)); strncpy(name, prev, len); name[(len == sizeof(name)) ? len - 1 : len] = 0; for (int i = 0; i < suiteSz; i++) if (strncmp(name, cipher_names[i], sizeof(name)) == 0) { ciphers_.suites_[idx++] = 0x00; // first byte always zero ciphers_.suites_[idx++] = i; if (!ret) ret = true; // found at least one break; } if (!haystack) break; haystack++; } if (ret) { ciphers_.setSuites_ = true; ciphers_.suiteSz_ = idx; } return ret; } void SSL_CTX::IncrementStats(StatsField fd) { Lock guard(mutex_); switch (fd) { case Accept: ++stats_.accept_; break; case Connect: ++stats_.connect_; break; case AcceptGood: ++stats_.acceptGood_; break; case ConnectGood: ++stats_.connectGood_; break; case AcceptRenegotiate: ++stats_.acceptRenegotiate_; break; case ConnectRenegotiate: ++stats_.connectRenegotiate_; break; case Hits: ++stats_.hits_; break; case CbHits: ++stats_.cbHits_; break; case CacheFull: ++stats_.cacheFull_; break; case Misses: ++stats_.misses_; break; case Timeouts: ++stats_.timeouts_; break; case Number: ++stats_.number_; break; case GetCacheSize: ++stats_.getCacheSize_; break; case VerifyMode: ++stats_.verifyMode_; break; case VerifyDepth: ++stats_.verifyDepth_; break; default: break; } } Crypto::Crypto() : digest_(0), cipher_(0), dh_(0) {} Crypto::~Crypto() { ysDelete(dh_); ysDelete(cipher_); ysDelete(digest_); } const Digest& Crypto::get_digest() const { return *digest_; } const BulkCipher& Crypto::get_cipher() const { return *cipher_; } const DiffieHellman& Crypto::get_dh() const { return *dh_; } const RandomPool& Crypto::get_random() const { return random_; } const CertManager& Crypto::get_certManager() const { return cert_; } Digest& Crypto::use_digest() { return *digest_; } BulkCipher& Crypto::use_cipher() { return *cipher_; } DiffieHellman& Crypto::use_dh() { return *dh_; } RandomPool& Crypto::use_random() { return random_; } CertManager& Crypto::use_certManager() { return cert_; } void Crypto::SetDH(DiffieHellman* dh) { dh_ = dh; } void Crypto::SetDH(const DH_Parms& dh) { if (dh.set_) dh_ = NEW_YS DiffieHellman(dh.p_, dh.g_, random_); } bool Crypto::DhSet() { return dh_ != 0; } void Crypto::setDigest(Digest* digest) { digest_ = digest; } void Crypto::setCipher(BulkCipher* c) { cipher_ = c; } const MD5& sslHashes::get_MD5() const { return md5HandShake_; } const SHA& sslHashes::get_SHA() const { return shaHandShake_; } const Finished& sslHashes::get_verify() const { return verify_; } const Hashes& sslHashes::get_certVerify() const { return certVerify_; } MD5& sslHashes::use_MD5(){ return md5HandShake_; } SHA& sslHashes::use_SHA() { return shaHandShake_; } Finished& sslHashes::use_verify() { return verify_; } Hashes& sslHashes::use_certVerify() { return certVerify_; } Buffers::Buffers() : prevSent(0), plainSz(0), rawInput_(0), output_(0) {} Buffers::~Buffers() { STL::for_each(handShakeList_.begin(), handShakeList_.end(), del_ptr_zero()) ; STL::for_each(dataList_.begin(), dataList_.end(), del_ptr_zero()) ; ysDelete(rawInput_); ysDelete(output_); } void Buffers::SetOutput(output_buffer* ob) { output_ = ob; } void Buffers::SetRawInput(input_buffer* ib) { rawInput_ = ib; } input_buffer* Buffers::TakeRawInput() { input_buffer* ret = rawInput_; rawInput_ = 0; return ret; } output_buffer* Buffers::TakeOutput() { output_buffer* ret = output_; output_ = 0; return ret; } const Buffers::inputList& Buffers::getData() const { return dataList_; } const Buffers::outputList& Buffers::getHandShake() const { return handShakeList_; } Buffers::inputList& Buffers::useData() { return dataList_; } Buffers::outputList& Buffers::useHandShake() { return handShakeList_; } Security::Security(ProtocolVersion pv, RandomPool& ran, ConnectionEnd ce, const Ciphers& ciphers, SSL_CTX* ctx, bool haveDH) : conn_(pv, ran), parms_(ce, ciphers, pv, haveDH), resumeSession_(ran), ctx_(ctx), resuming_(false) {} const Connection& Security::get_connection() const { return conn_; } const SSL_CTX* Security::GetContext() const { return ctx_; } const Parameters& Security::get_parms() const { return parms_; } const SSL_SESSION& Security::get_resume() const { return resumeSession_; } bool Security::get_resuming() const { return resuming_; } Connection& Security::use_connection() { return conn_; } Parameters& Security::use_parms() { return parms_; } SSL_SESSION& Security::use_resume() { return resumeSession_; } void Security::set_resuming(bool b) { resuming_ = b; } X509_NAME::X509_NAME(const char* n, size_t sz, int pos, int len) : name_(0), sz_(sz), cnPosition_(pos), cnLen_(len) { if (sz) { name_ = NEW_YS char[sz]; memcpy(name_, n, sz); } entry_.data = 0; } X509_NAME::~X509_NAME() { ysArrayDelete(name_); ysArrayDelete(entry_.data); } const char* X509_NAME::GetName() const { return name_; } size_t X509_NAME::GetLength() const { return sz_; } X509::X509(const char* i, size_t iSz, const char* s, size_t sSz, ASN1_STRING *b, ASN1_STRING *a, int issPos, int issLen, int subPos, int subLen) : issuer_(i, iSz, issPos, issLen), subject_(s, sSz, subPos, subLen), beforeDate_((char *) b->data, b->length, b->type), afterDate_((char *) a->data, a->length, a->type) {} X509_NAME* X509::GetIssuer() { return &issuer_; } X509_NAME* X509::GetSubject() { return &subject_; } ASN1_TIME* X509::GetBefore() { return beforeDate_.GetString(); } ASN1_TIME* X509::GetAfter() { return afterDate_.GetString(); } ASN1_STRING* X509_NAME::GetEntry(int i) { if (i < 0 || i >= int(sz_)) return 0; if (i != cnPosition_ || cnLen_ <= 0) // only entry currently supported return 0; if (cnLen_ > int(sz_-i)) // make sure there's room in read buffer return 0; if (entry_.data) ysArrayDelete(entry_.data); entry_.data = NEW_YS byte[cnLen_+1]; // max size; memcpy(entry_.data, &name_[i], cnLen_); entry_.data[cnLen_] = 0; entry_.length = cnLen_; entry_.type = 0; return &entry_; } StringHolder::StringHolder(const char* str, int sz, byte type) { asnString_.length = sz; asnString_.data = NEW_YS byte[sz + 1]; memcpy(asnString_.data, str, sz); asnString_.type = type; } StringHolder::~StringHolder() { ysArrayDelete(asnString_.data); } ASN1_STRING* StringHolder::GetString() { return &asnString_; } #ifdef HAVE_LIBZ void* myAlloc(void* /* opaque */, unsigned int item, unsigned int size) { return NEW_YS unsigned char[item * size]; } void myFree(void* /* opaque */, void* memory) { unsigned char* ptr = static_cast(memory); yaSSL::ysArrayDelete(ptr); } // put size in front of compressed data int Compress(const byte* in, int sz, input_buffer& buffer) { byte tmp[LENGTH_SZ]; z_stream c_stream; /* compression stream */ buffer.allocate(sz + sizeof(uint16) + COMPRESS_EXTRA); c_stream.zalloc = myAlloc; c_stream.zfree = myFree; c_stream.opaque = (voidpf)0; c_stream.next_in = const_cast(in); c_stream.avail_in = sz; c_stream.next_out = buffer.get_buffer() + sizeof(tmp); c_stream.avail_out = buffer.get_capacity() - sizeof(tmp); if (deflateInit(&c_stream, 8) != Z_OK) return -1; int err = deflate(&c_stream, Z_FINISH); deflateEnd(&c_stream); if (err != Z_OK && err != Z_STREAM_END) return -1; c16toa(sz, tmp); memcpy(buffer.get_buffer(), tmp, sizeof(tmp)); buffer.add_size(c_stream.total_out + sizeof(tmp)); return 0; } // get uncompressed size in front int DeCompress(input_buffer& in, int sz, input_buffer& out) { byte tmp[LENGTH_SZ]; tmp[0] = in[AUTO]; tmp[1] = in[AUTO]; uint16 len; ato16(tmp, len); out.allocate(len); z_stream d_stream; /* decompression stream */ d_stream.zalloc = myAlloc; d_stream.zfree = myFree; d_stream.opaque = (voidpf)0; d_stream.next_in = in.get_buffer() + in.get_current(); d_stream.avail_in = sz - sizeof(tmp); d_stream.next_out = out.get_buffer(); d_stream.avail_out = out.get_capacity(); if (inflateInit(&d_stream) != Z_OK) return -1; int err = inflate(&d_stream, Z_FINISH); inflateEnd(&d_stream); if (err != Z_OK && err != Z_STREAM_END) return -1; out.add_size(d_stream.total_out); in.set_current(in.get_current() + sz - sizeof(tmp)); return 0; } #else // LIBZ // these versions should never get called int Compress(const byte* in, int sz, input_buffer& buffer) { return -1; } int DeCompress(input_buffer& in, int sz, input_buffer& out) { return -1; } #endif // LIBZ } // namespace extern "C" void yaSSL_CleanUp() { TaoCrypt::CleanUp(); yaSSL::ysDelete(yaSSL::sslFactoryInstance); yaSSL::ysDelete(yaSSL::sessionsInstance); yaSSL::ysDelete(yaSSL::errorsInstance); // In case user calls more than once, prevent seg fault yaSSL::sslFactoryInstance = 0; yaSSL::sessionsInstance = 0; yaSSL::errorsInstance = 0; } #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION namespace mySTL { template yaSSL::yassl_int_cpp_local1::SumData for_each::iterator, yaSSL::yassl_int_cpp_local1::SumData>(mySTL::list::iterator, mySTL::list::iterator, yaSSL::yassl_int_cpp_local1::SumData); template yaSSL::yassl_int_cpp_local1::SumBuffer for_each::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer>(mySTL::list::iterator, mySTL::list::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer); template mySTL::list::iterator find_if::iterator, yaSSL::yassl_int_cpp_local2::sess_match>(mySTL::list::iterator, mySTL::list::iterator, yaSSL::yassl_int_cpp_local2::sess_match); template mySTL::list::iterator find_if::iterator, yaSSL::yassl_int_cpp_local2::thr_match>(mySTL::list::iterator, mySTL::list::iterator, yaSSL::yassl_int_cpp_local2::thr_match); } #endif