mirror of https://github.com/MariaDB/server
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							2709 lines
						
					
					
						
							62 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							2709 lines
						
					
					
						
							62 KiB
						
					
					
				| /* | |
|    Copyright (c) 2005, 2014, Oracle and/or its affiliates | |
|  | |
|    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; see the file COPYING. If not, write to the | |
|    Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | |
|    MA  02110-1301  USA. | |
| */ | |
| 
 | |
| 
 | |
| /* yaSSL internal source implements SSL supporting types not specified in the | |
|  * draft along with type conversion functions. | |
|  */ | |
| 
 | |
| #include "runtime.hpp" | |
| #include "yassl_int.hpp" | |
| #include "handshake.hpp" | |
| #include "timer.hpp" | |
|  | |
| #ifdef _POSIX_THREADS | |
|     #include "pthread.h" | |
| #endif | |
|  | |
| 
 | |
| #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 | |
|  | |
| 
 | |
| 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_ == 0) { | |
|             // remove RSA or DSA suites depending on cert key type | |
|             // but don't override user sets | |
|             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); | |
|     } | |
| } | |
| 
 | |
| 
 | |
| // 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<output_buffer> 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 = 1; j < length; j+= 2) | |
|             if (secure_.use_parms().suites_[i] == peer[j]) { | |
|                 secure_.use_parms().suite_[0] = 0x00; | |
|                 secure_.use_parms().suite_[1] = peer[j]; | |
|                 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_STRING* before = x->GetBefore(); | |
|     ASN1_STRING* after  = x->GetAfter(); | |
| 
 | |
|     peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(), | |
|         subject->GetName(), subject->GetLength(), (const char*) before->data, | |
|         before->length, (const char*) after->data, after->length, | |
|         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; | |
| 
 | |
| Sessions& GetSessions() | |
| { | |
|     if (!sessionsInstance) | |
|         sessionsInstance = NEW_YS Sessions; | |
|     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<SSL_SESSION*>::iterator sess_iterator; | |
| typedef STL::list<ThreadError>::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_; | |
| } | |
| 
 | |
| 
 | |
| SSL_CTX::SSL_CTX(SSL_METHOD* meth)  | |
|     : method_(meth), certificate_(0), privateKey_(0), passwordCb_(0), | |
|       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::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<char*>(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, | |
|            const char* b, int bSz, const char* a, int aSz, int issPos, | |
|            int issLen, int subPos, int subLen) | |
|     : issuer_(i, iSz, issPos, issLen), subject_(s, sSz, subPos, subLen), | |
|       beforeDate_(b, bSz), afterDate_(a, aSz) | |
| {} | |
| 
 | |
| 
 | |
| X509_NAME* X509::GetIssuer() | |
| { | |
|     return &issuer_; | |
| } | |
| 
 | |
| 
 | |
| X509_NAME* X509::GetSubject() | |
| { | |
|     return &subject_; | |
| } | |
| 
 | |
| 
 | |
| ASN1_STRING* X509::GetBefore() | |
| { | |
|     return beforeDate_.GetString(); | |
| } | |
| 
 | |
| 
 | |
| ASN1_STRING* 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) | |
| { | |
|     asnString_.length = sz; | |
|     asnString_.data = NEW_YS byte[sz + 1]; | |
|     memcpy(asnString_.data, str, sz); | |
|     asnString_.type = 0;  // not used for now | |
| } | |
| 
 | |
| 
 | |
| 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<unsigned char*>(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<byte*>(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<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData); | |
| template yaSSL::yassl_int_cpp_local1::SumBuffer for_each<mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer>(mySTL::list<yaSSL::output_buffer*>::iterator, mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer); | |
| template mySTL::list<yaSSL::SSL_SESSION*>::iterator find_if<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match); | |
| template mySTL::list<yaSSL::ThreadError>::iterator find_if<mySTL::list<yaSSL::ThreadError>::iterator, yaSSL::yassl_int_cpp_local2::thr_match>(mySTL::list<yaSSL::ThreadError>::iterator, mySTL::list<yaSSL::ThreadError>::iterator, yaSSL::yassl_int_cpp_local2::thr_match); | |
| } | |
| #endif | |
| 
 |