/* Copyright (c) 2005, 2014, 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; 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 header defines SSL supporting types not specified in the * draft along with type conversion functions and openssl compatibility */ #ifndef yaSSL_INT_HPP #define yaSSL_INT_HPP #include "yassl_imp.hpp" #include "yassl_error.hpp" #include "crypto_wrapper.hpp" #include "cert_wrapper.hpp" #include "log.hpp" #include "lock.hpp" #include "openssl/ssl.h" // ASN1_STRING and DH // Check if _POSIX_THREADS should be forced #if !defined(_POSIX_THREADS) && defined(__hpux) // HPUX does not define _POSIX_THREADS as it's not _fully_ implemented #define _POSIX_THREADS #endif #ifdef _POSIX_THREADS #include #endif namespace STL = STL_NAMESPACE; namespace yaSSL { // State Machine for Record Layer Protocol enum RecordLayerState { recordNotReady = 0, // fatal error, no more processing recordReady }; // State Machine for HandShake Protocol enum HandShakeState { handShakeNotReady = 0, // fatal error, no more processing preHandshake, // initial state inHandshake, // handshake started handShakeReady // handshake done }; // client input HandShake state, use if HandShakeState == inHandShake enum ClientState { serverNull = 0, serverHelloComplete, serverCertComplete, serverKeyExchangeComplete, serverHelloDoneComplete, serverFinishedComplete }; // server input HandShake state, use if HandShakeState == inHandShake enum ServerState { clientNull = 0, clientHelloComplete, clientKeyExchangeComplete, clientFinishedComplete }; // client connect state for nonblocking restart enum ConnectState { CONNECT_BEGIN = 0, CLIENT_HELLO_SENT, FIRST_REPLY_DONE, FINISHED_DONE, SECOND_REPLY_DONE }; // server accpet state for nonblocking restart enum AcceptState { ACCEPT_BEGIN = 0, ACCEPT_FIRST_REPLY_DONE, SERVER_HELLO_DONE, ACCEPT_SECOND_REPLY_DONE, ACCEPT_FINISHED_DONE, ACCEPT_THIRD_REPLY_DONE }; // track received messages to explicitly disallow duplicate messages struct RecvdMessages { uint8 gotClientHello_; uint8 gotServerHello_; uint8 gotCert_; uint8 gotServerKeyExchange_; uint8 gotCertRequest_; uint8 gotServerHelloDone_; uint8 gotCertVerify_; uint8 gotClientKeyExchange_; uint8 gotFinished_; RecvdMessages() : gotClientHello_(0), gotServerHello_(0), gotCert_(0), gotServerKeyExchange_(0), gotCertRequest_(0), gotServerHelloDone_(0), gotCertVerify_(0), gotClientKeyExchange_(0), gotFinished_(0) {} }; // combines all states class States { RecordLayerState recordLayer_; HandShakeState handshakeLayer_; ClientState clientState_; ServerState serverState_; ConnectState connectState_; AcceptState acceptState_; RecvdMessages recvdMessages_; char errorString_[MAX_ERROR_SZ]; YasslError what_; public: States(); const RecordLayerState& getRecord() const; const HandShakeState& getHandShake() const; const ClientState& getClient() const; const ServerState& getServer() const; const ConnectState& GetConnect() const; const AcceptState& GetAccept() const; const char* getString() const; YasslError What() const; RecordLayerState& useRecord(); HandShakeState& useHandShake(); ClientState& useClient(); ServerState& useServer(); ConnectState& UseConnect(); AcceptState& UseAccept(); char* useString(); void SetError(YasslError); int SetMessageRecvd(HandShakeType); private: States(const States&); // hide copy States& operator=(const States&); // and assign }; // holds all factories class sslFactory { MessageFactory messageFactory_; // creates new messages by type HandShakeFactory handShakeFactory_; // creates new handshake types ServerKeyFactory serverKeyFactory_; // creates new server key types ClientKeyFactory clientKeyFactory_; // creates new client key types sslFactory(); // only GetSSL_Factory creates public: const MessageFactory& getMessage() const; const HandShakeFactory& getHandShake() const; const ServerKeyFactory& getServerKey() const; const ClientKeyFactory& getClientKey() const; friend sslFactory& GetSSL_Factory(); // singleton creator private: sslFactory(const sslFactory&); // hide copy sslFactory& operator=(const sslFactory&); // and assign }; #undef X509_NAME // wincrypt.h clash // openSSL X509 names class X509_NAME { char* name_; size_t sz_; int cnPosition_; // start of common name, -1 is none int cnLen_; // length of above ASN1_STRING entry_; public: X509_NAME(const char*, size_t sz, int pos, int len); ~X509_NAME(); const char* GetName() const; ASN1_STRING* GetEntry(int i); size_t GetLength() const; int GetCnPosition() const { return cnPosition_; } int GetCnLength() const { return cnLen_; } private: X509_NAME(const X509_NAME&); // hide copy X509_NAME& operator=(const X509_NAME&); // and assign }; class StringHolder { ASN1_STRING asnString_; public: StringHolder(const char* str, int sz, byte type= 0); ~StringHolder(); ASN1_STRING* GetString(); private: StringHolder(const StringHolder&); // hide copy StringHolder& operator=(const StringHolder&); // and assign }; // openSSL X509 class X509 { X509_NAME issuer_; X509_NAME subject_; StringHolder beforeDate_; // not valid before StringHolder afterDate_; // not valid after public: X509(const char* i, size_t, const char* s, size_t, ASN1_STRING *b, ASN1_STRING *a, int, int, int, int); ~X509() {} X509_NAME* GetIssuer(); X509_NAME* GetSubject(); ASN1_STRING* GetBefore(); ASN1_STRING* GetAfter(); private: X509(const X509&); // hide copy X509& operator=(const X509&); // and assign }; // openSSL bignum struct BIGNUM { /* gcc 2.96 fix: because of two Integer classes (yaSSL::Integer and TaoCrypt::Integer), we need to explicitly state the namespace here to let gcc 2.96 deduce the correct type. */ yaSSL::Integer int_; void assign(const byte* b, uint s) { int_.assign(b,s); } }; // openSSL session class SSL_SESSION { opaque sessionID_[ID_LEN]; opaque master_secret_[SECRET_LEN]; Cipher suite_[SUITE_LEN]; uint bornOn_; // create time in seconds uint timeout_; // timeout in seconds RandomPool& random_; // will clean master secret X509* peerX509_; public: explicit SSL_SESSION(RandomPool&); SSL_SESSION(const SSL&, RandomPool&); ~SSL_SESSION(); const opaque* GetID() const; const opaque* GetSecret() const; const Cipher* GetSuite() const; uint GetBornOn() const; uint GetTimeOut() const; X509* GetPeerX509() const; void SetTimeOut(uint); SSL_SESSION& operator=(const SSL_SESSION&); // allow assign for resumption private: SSL_SESSION(const SSL_SESSION&); // hide copy void CopyX509(X509*); }; // holds all sessions class Sessions { STL::list list_; RandomPool random_; // for session cleaning Mutex mutex_; // no-op for single threaded int count_; // flush counter Sessions() : count_(0) {} // only GetSessions can create public: SSL_SESSION* lookup(const opaque*, SSL_SESSION* copy = 0); void add(const SSL&); void remove(const opaque*); void Flush(); ~Sessions(); friend void Session_initialize(); friend Sessions& GetSessions(); // singleton creator private: Sessions(const Sessions&); // hide copy Sessions& operator=(const Sessions&); // and assign }; #ifdef _POSIX_THREADS typedef pthread_t THREAD_ID_T; #else typedef DWORD THREAD_ID_T; #endif // thread error data struct ThreadError { THREAD_ID_T threadID_; int errorID_; }; // holds all errors class Errors { STL::list list_; Mutex mutex_; Errors() {} // only GetErrors can create public: int Lookup(bool peek); // self lookup void Add(int); void Remove(); // remove self ~Errors() {} friend Errors& GetErrors(); // singleton creator private: Errors(const Errors&); // hide copy Errors& operator=(const Errors); // and assign }; Sessions& GetSessions(); // forward singletons sslFactory& GetSSL_Factory(); Errors& GetErrors(); // openSSL method and context types class SSL_METHOD { ProtocolVersion version_; ConnectionEnd side_; bool verifyPeer_; // request or send certificate bool verifyNone_; // whether to verify certificate bool failNoCert_; bool multipleProtocol_; // for SSLv23 compatibility public: SSL_METHOD(ConnectionEnd ce, ProtocolVersion pv, bool multipleProtocol = false); ProtocolVersion getVersion() const; ConnectionEnd getSide() const; void setVerifyPeer(); void setVerifyNone(); void setFailNoCert(); bool verifyPeer() const; bool verifyNone() const; bool failNoCert() const; bool multipleProtocol() const; private: SSL_METHOD(const SSL_METHOD&); // hide copy SSL_METHOD& operator=(const SSL_METHOD&); // and assign }; struct Ciphers { bool setSuites_; // user set suites from default byte suites_[MAX_SUITE_SZ]; // new suites int suiteSz_; // suite length in bytes Ciphers() : setSuites_(false), suiteSz_(0) {} }; struct DH; // forward // save for SSL construction struct DH_Parms { Integer p_; Integer g_; bool set_; // if set by user DH_Parms() : set_(false) {} }; enum StatsField { Accept, Connect, AcceptGood, ConnectGood, AcceptRenegotiate, ConnectRenegotiate, Hits, CbHits, CacheFull, Misses, Timeouts, Number, GetCacheSize, VerifyMode, VerifyDepth }; // SSL stats struct Stats { long accept_; long connect_; long acceptGood_; long connectGood_; long acceptRenegotiate_; long connectRenegotiate_; long hits_; long cbHits_; long cacheFull_; long misses_; long timeouts_; long number_; long getCacheSize_; int verifyMode_; int verifyDepth_; public: Stats() : accept_(0), connect_(0), acceptGood_(0), connectGood_(0), acceptRenegotiate_(0), connectRenegotiate_(0), hits_(0), cbHits_(0), cacheFull_(0), misses_(0), timeouts_(0), number_(0), getCacheSize_(0), verifyMode_(0), verifyDepth_(0) {} private: Stats(const Stats&); // hide copy Stats& operator=(const Stats&); // and assign }; // the SSL context class SSL_CTX { public: typedef STL::list CertList; private: SSL_METHOD* method_; x509* certificate_; x509* privateKey_; CertList caList_; Ciphers ciphers_; DH_Parms dhParms_; pem_password_cb passwordCb_; void* userData_; bool sessionCacheOff_; bool sessionCacheFlushOff_; Stats stats_; Mutex mutex_; // for Stats VerifyCallback verifyCallback_; public: explicit SSL_CTX(SSL_METHOD* meth); ~SSL_CTX(); const x509* getCert() const; const x509* getKey() const; const SSL_METHOD* getMethod() const; const Ciphers& GetCiphers() const; const DH_Parms& GetDH_Parms() const; const Stats& GetStats() const; VerifyCallback getVerifyCallback() const; pem_password_cb GetPasswordCb() const; void* GetUserData() const; bool GetSessionCacheOff() const; bool GetSessionCacheFlushOff() const; void setVerifyPeer(); void setVerifyNone(); void setFailNoCert(); void setVerifyCallback(VerifyCallback); bool SetCipherList(const char*); bool SetDH(const DH&); void SetPasswordCb(pem_password_cb cb); void SetUserData(void*); void SetSessionCacheOff(); void SetSessionCacheFlushOff(); void SetMethod(SSL_METHOD* meth); void IncrementStats(StatsField); void AddCA(x509* ca); const CertList& GetCA_List() const; friend int read_file(SSL_CTX*, const char*, int, CertType); private: SSL_CTX(const SSL_CTX&); // hide copy SSL_CTX& operator=(const SSL_CTX&); // and assign }; // holds all cryptographic types class Crypto { Digest* digest_; // agreed upon digest BulkCipher* cipher_; // agreed upon cipher DiffieHellman* dh_; // dh parms RandomPool random_; // random number generator CertManager cert_; // manages certificates public: explicit Crypto(); ~Crypto(); const Digest& get_digest() const; const BulkCipher& get_cipher() const; const DiffieHellman& get_dh() const; const RandomPool& get_random() const; const CertManager& get_certManager() const; Digest& use_digest(); BulkCipher& use_cipher(); DiffieHellman& use_dh(); RandomPool& use_random(); CertManager& use_certManager(); void SetDH(DiffieHellman*); void SetDH(const DH_Parms&); void setDigest(Digest*); void setCipher(BulkCipher*); bool DhSet(); private: Crypto(const Crypto&); // hide copy Crypto& operator=(const Crypto&); // and assign }; // holds all handshake and verify hashes class sslHashes { MD5 md5HandShake_; // md5 handshake hash SHA shaHandShake_; // sha handshake hash Finished verify_; // peer's verify hash Hashes certVerify_; // peer's cert verify hash public: sslHashes() {} const MD5& get_MD5() const; const SHA& get_SHA() const; const Finished& get_verify() const; const Hashes& get_certVerify() const; MD5& use_MD5(); SHA& use_SHA(); Finished& use_verify(); Hashes& use_certVerify(); private: sslHashes(const sslHashes&); // hide copy sslHashes& operator=(const sslHashes&); // and assign }; // holds input and output buffers class Buffers { public: typedef STL::list inputList; typedef STL::list outputList; int prevSent; // previous plain text bytes sent when got WANT_WRITE int plainSz; // plain text bytes in buffer to send when got WANT_WRITE private: inputList dataList_; // list of users app data / handshake outputList handShakeList_; // buffered handshake msgs input_buffer* rawInput_; // buffered raw input yet to process output_buffer* output_; // WANT_WRITE buffered output public: Buffers(); ~Buffers(); const inputList& getData() const; const outputList& getHandShake() const; inputList& useData(); outputList& useHandShake(); void SetRawInput(input_buffer*); // takes ownership input_buffer* TakeRawInput(); // takes ownership void SetOutput(output_buffer*); // takes ownership output_buffer* TakeOutput(); // takes ownership private: Buffers(const Buffers&); // hide copy Buffers& operator=(const Buffers&); // and assign }; // wraps security parameters class Security { Connection conn_; // connection information Parameters parms_; // may be pending SSL_SESSION resumeSession_; // if resuming SSL_CTX* ctx_; // context used to init bool resuming_; // trying to resume public: Security(ProtocolVersion, RandomPool&, ConnectionEnd, const Ciphers&, SSL_CTX*, bool); const SSL_CTX* GetContext() const; const Connection& get_connection() const; const Parameters& get_parms() const; const SSL_SESSION& get_resume() const; bool get_resuming() const; Connection& use_connection(); Parameters& use_parms(); SSL_SESSION& use_resume(); void set_resuming(bool b); private: Security(const Security&); // hide copy Security& operator=(const Security&); // and assign }; // THE SSL type class SSL { Crypto crypto_; // agreed crypto agents Security secure_; // Connection and Session parms States states_; // Record and HandShake states sslHashes hashes_; // handshake, finished hashes Socket socket_; // socket wrapper Buffers buffers_; // buffered handshakes and data Log log_; // logger bool quietShutdown_; // optimization variables bool has_data_; // buffered data ready? public: SSL(SSL_CTX* ctx); // gets and uses const Crypto& getCrypto() const; const Security& getSecurity() const; const States& getStates() const; const sslHashes& getHashes() const; const sslFactory& getFactory() const; const Socket& getSocket() const; YasslError GetError() const; bool GetMultiProtocol() const; bool CompressionOn() const; Crypto& useCrypto(); Security& useSecurity(); States& useStates(); sslHashes& useHashes(); Socket& useSocket(); Log& useLog(); Buffers& useBuffers(); bool HasData() const; bool GetQuietShutdown() const; // sets void set_pending(Cipher suite); void set_random(const opaque*, ConnectionEnd); void set_sessionID(const opaque*); void set_session(SSL_SESSION*); void set_preMaster(const opaque*, uint); void set_masterSecret(const opaque*); void SetError(YasslError); int SetCompression(); void UnSetCompression(); void SetQuietShutdown(bool mode); // helpers bool isTLS() const; bool isTLSv1_1() const; void order_error(); void makeMasterSecret(); void makeTLSMasterSecret(); void addData(input_buffer* data); void fillData(Data&); void PeekData(Data&); void addBuffer(output_buffer* b); void flushBuffer(); void verifyState(const RecordLayerHeader&); void verifyState(const HandShakeHeader&); void verifyState(ClientState); void verifyState(ServerState); void verfiyHandShakeComplete(); void matchSuite(const opaque*, uint length); void deriveKeys(); void deriveTLSKeys(); void Send(const byte*, uint); void SendWriteBuffered(); uint bufferedData(); uint get_SEQIncrement(bool); const byte* get_macSecret(bool); private: void storeKeys(const opaque*); void setKeys(); void verifyClientState(HandShakeType); void verifyServerState(HandShakeType); SSL(const SSL&); // hide copy const SSL& operator=(const SSL&); // and assign }; // compression int Compress(const byte*, int, input_buffer&); int DeCompress(input_buffer&, int, input_buffer&); // conversion functions void c32to24(uint32, uint24&); void c24to32(const uint24, uint32&); uint32 c24to32(const uint24); void ato16(const opaque*, uint16&); void ato24(const opaque*, uint24&); void c16toa(uint16, opaque*); void c24toa(const uint24, opaque*); void c32toa(uint32 u32, opaque*); } // naemspace #endif // yaSSL_INT_HPP