From 354bb40e75d94466e91fe6960523612c9d17ccfb Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 2 Nov 2017 23:11:29 +0300 Subject: Add implementation --- mysql/extra/yassl/src/buffer.cpp | 330 ++++ mysql/extra/yassl/src/cert_wrapper.cpp | 408 +++++ mysql/extra/yassl/src/crypto_wrapper.cpp | 1016 +++++++++++ mysql/extra/yassl/src/get_password.c | 218 +++ mysql/extra/yassl/src/handshake.cpp | 1190 +++++++++++++ mysql/extra/yassl/src/lock.cpp | 87 + mysql/extra/yassl/src/log.cpp | 147 ++ mysql/extra/yassl/src/socket_wrapper.cpp | 238 +++ mysql/extra/yassl/src/ssl.cpp | 1883 ++++++++++++++++++++ mysql/extra/yassl/src/timer.cpp | 80 + mysql/extra/yassl/src/yassl_error.cpp | 288 +++ mysql/extra/yassl/src/yassl_imp.cpp | 2642 ++++++++++++++++++++++++++++ mysql/extra/yassl/src/yassl_int.cpp | 2826 ++++++++++++++++++++++++++++++ 13 files changed, 11353 insertions(+) create mode 100644 mysql/extra/yassl/src/buffer.cpp create mode 100644 mysql/extra/yassl/src/cert_wrapper.cpp create mode 100644 mysql/extra/yassl/src/crypto_wrapper.cpp create mode 100644 mysql/extra/yassl/src/get_password.c create mode 100644 mysql/extra/yassl/src/handshake.cpp create mode 100644 mysql/extra/yassl/src/lock.cpp create mode 100644 mysql/extra/yassl/src/log.cpp create mode 100644 mysql/extra/yassl/src/socket_wrapper.cpp create mode 100644 mysql/extra/yassl/src/ssl.cpp create mode 100644 mysql/extra/yassl/src/timer.cpp create mode 100644 mysql/extra/yassl/src/yassl_error.cpp create mode 100644 mysql/extra/yassl/src/yassl_imp.cpp create mode 100644 mysql/extra/yassl/src/yassl_int.cpp (limited to 'mysql/extra/yassl/src') diff --git a/mysql/extra/yassl/src/buffer.cpp b/mysql/extra/yassl/src/buffer.cpp new file mode 100644 index 0000000..954fdb5 --- /dev/null +++ b/mysql/extra/yassl/src/buffer.cpp @@ -0,0 +1,330 @@ +/* + 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 buffer header implements input/output buffers to simulate streaming + * with SSL types and sockets + */ + + +// First include (the generated) my_config.h, to get correct platform defines. +#include "my_config.h" +#include // memcpy +#include "runtime.hpp" +#include "buffer.hpp" +#include "yassl_types.hpp" + +namespace yaSSL { + + + + +/* return 0 on check success, always true for NoCheck policy */ +int NoCheck::check(uint, uint) +{ + return 0; +} + +/* return 0 on check success */ +int Check::check(uint i, uint max) +{ + if (i < max) + return 0; + + return -1; +} + + +/* input_buffer operates like a smart c style array with a checking option, + * meant to be read from through [] with AUTO index or read(). + * Should only write to at/near construction with assign() or raw (e.g., recv) + * followed by add_size with the number of elements added by raw write. + * + * Not using vector because need checked []access, offset, and the ability to + * write to the buffer bulk wise and have the correct size + */ + + +input_buffer::input_buffer() + : size_(0), current_(0), buffer_(0), end_(0), error_(0), zero_(0) +{} + + +input_buffer::input_buffer(uint s) + : size_(0), current_(0), buffer_(NEW_YS byte[s]), end_(buffer_ + s), + error_(0), zero_(0) +{} + + +// with assign +input_buffer::input_buffer(uint s, const byte* t, uint len) + : size_(0), current_(0), buffer_(NEW_YS byte[s]), end_(buffer_ + s), + error_(0), zero_(0) +{ + assign(t, len); +} + + +input_buffer::~input_buffer() +{ + ysArrayDelete(buffer_); +} + + +// users can pass defualt zero length buffer and then allocate +void input_buffer::allocate(uint s) +{ + if (error_ == 0) { + buffer_ = NEW_YS byte[s]; + end_ = buffer_ + s; + } +} + + +// for passing to raw writing functions at beginning, then use add_size +byte* input_buffer::get_buffer() const +{ + return buffer_; +} + + +// after a raw write user can set NEW_YS size +// if you know the size before the write use assign() +void input_buffer::add_size(uint i) +{ + if (error_ == 0 && check(size_ + i-1, get_capacity()) == 0) + size_ += i; + else + error_ = -1; +} + + +uint input_buffer::get_capacity() const +{ + if (error_ == 0) + return end_ - buffer_; + + return 0; +} + + +uint input_buffer::get_current() const +{ + if (error_ == 0) + return current_; + + return 0; +} + + +uint input_buffer::get_size() const +{ + if (error_ == 0) + return size_; + + return 0; +} + + +uint input_buffer::get_remaining() const +{ + if (error_ == 0) + return size_ - current_; + + return 0; +} + + +int input_buffer::get_error() const +{ + return error_; +} + + +void input_buffer::set_error() +{ + error_ = -1; +} + + +void input_buffer::set_current(uint i) +{ + if (error_ == 0 && check(i ? i - 1 : 0, size_) == 0) + current_ = i; + else + error_ = -1; +} + + +// read only access through [], advance current +// user passes in AUTO index for ease of use +const byte& input_buffer::operator[](uint i) +{ + if (error_ == 0 && check(current_, size_) == 0) + return buffer_[current_++]; + + error_ = -1; + return zero_; +} + + +// end of input test +bool input_buffer::eof() +{ + if (error_ != 0) + return true; + + return current_ >= size_; +} + + +// peek ahead +byte input_buffer::peek() +{ + if (error_ == 0 && check(current_, size_) == 0) + return buffer_[current_]; + + error_ = -1; + return 0; +} + + +// write function, should use at/near construction +void input_buffer::assign(const byte* t, uint s) +{ + if (t && error_ == 0 && check(current_, get_capacity()) == 0) { + add_size(s); + if (error_ == 0) { + memcpy(&buffer_[current_], t, s); + return; // success + } + } + + error_ = -1; +} + + +// use read to query input, adjusts current +void input_buffer::read(byte* dst, uint length) +{ + if (dst && error_ == 0 && check(current_ + length - 1, size_) == 0) { + memcpy(dst, &buffer_[current_], length); + current_ += length; + } else { + error_ = -1; + } +} + + + +/* output_buffer operates like a smart c style array with a checking option. + * Meant to be written to through [] with AUTO index or write(). + * Size (current) counter increases when written to. Can be constructed with + * zero length buffer but be sure to allocate before first use. + * Don't use add write for a couple bytes, use [] instead, way less overhead. + * + * Not using vector because need checked []access and the ability to + * write to the buffer bulk wise and retain correct size + */ + + +output_buffer::output_buffer() + : current_(0), buffer_(0), end_(0) +{} + + +// with allocate +output_buffer::output_buffer(uint s) + : current_(0), buffer_(NEW_YS byte[s]), end_(buffer_ + s) +{} + + +// with assign +output_buffer::output_buffer(uint s, const byte* t, uint len) + : current_(0), buffer_(NEW_YS byte[s]), end_(buffer_+ s) +{ + write(t, len); +} + + +output_buffer::~output_buffer() +{ + ysArrayDelete(buffer_); +} + + +uint output_buffer::get_size() const +{ + return current_; +} + + +uint output_buffer::get_capacity() const +{ + return (uint) (end_ - buffer_); +} + + +void output_buffer::set_current(uint c) +{ + check(c, get_capacity()); + current_ = c; +} + + +// users can pass defualt zero length buffer and then allocate +void output_buffer::allocate(uint s) +{ + buffer_ = NEW_YS byte[s]; end_ = buffer_ + s; +} + + +// for passing to reading functions when finished +const byte* output_buffer::get_buffer() const +{ + return buffer_; +} + + +// allow write access through [], update current +// user passes in AUTO as index for ease of use +byte& output_buffer::operator[](uint i) +{ + check(current_, get_capacity()); + return buffer_[current_++]; +} + + +// end of output test +bool output_buffer::eof() +{ + return current_ >= get_capacity(); +} + + +void output_buffer::write(const byte* t, uint s) +{ + check(current_ + s - 1, get_capacity()); + memcpy(&buffer_[current_], t, s); + current_ += s; +} + + + +} // naemspace + diff --git a/mysql/extra/yassl/src/cert_wrapper.cpp b/mysql/extra/yassl/src/cert_wrapper.cpp new file mode 100644 index 0000000..1092e42 --- /dev/null +++ b/mysql/extra/yassl/src/cert_wrapper.cpp @@ -0,0 +1,408 @@ +/* + 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. +*/ + + +/* The certificate wrapper source implements certificate management functions + * + */ + +#include "runtime.hpp" +#include "cert_wrapper.hpp" +#include "yassl_int.hpp" +#include "error.hpp" + +#if defined(USE_CML_LIB) + #include "cmapi_cpp.h" +#else + #include "asn.hpp" + #include "file.hpp" +#endif // USE_CML_LIB + + +namespace yaSSL { + + +x509::x509(uint sz) : length_(sz), buffer_(NEW_YS opaque[sz]) +{ +} + + +x509::~x509() +{ + ysArrayDelete(buffer_); +} + + +x509::x509(const x509& that) : length_(that.length_), + buffer_(NEW_YS opaque[length_]) +{ + memcpy(buffer_, that.buffer_, length_); +} + + +void x509::Swap(x509& that) +{ + STL::swap(length_, that.length_); + STL::swap(buffer_, that.buffer_); +} + + +x509& x509::operator=(const x509& that) +{ + x509 temp(that); + Swap(temp); + return *this; +} + + +uint x509::get_length() const +{ + return length_; +} + + +const opaque* x509::get_buffer() const +{ + return buffer_; +} + + +opaque* x509::use_buffer() +{ + return buffer_; +} + + +//CertManager +CertManager::CertManager() + : peerX509_(0), selfX509_(0), verifyPeer_(false), verifyNone_(false), failNoCert_(false), + sendVerify_(false), sendBlankCert_(false), verifyCallback_(0) +{} + + +CertManager::~CertManager() +{ + ysDelete(peerX509_); + ysDelete(selfX509_); + + STL::for_each(signers_.begin(), signers_.end(), del_ptr_zero()) ; + + STL::for_each(peerList_.begin(), peerList_.end(), del_ptr_zero()) ; + + STL::for_each(list_.begin(), list_.end(), del_ptr_zero()) ; +} + + +bool CertManager::verifyPeer() const +{ + return verifyPeer_; +} + + +bool CertManager::verifyNone() const +{ + return verifyNone_; +} + + +bool CertManager::failNoCert() const +{ + return failNoCert_; +} + + +bool CertManager::sendVerify() const +{ + return sendVerify_; +} + + +void CertManager::setVerifyPeer() +{ + verifyPeer_ = true; +} + + +void CertManager::setVerifyNone() +{ + verifyNone_ = true; +} + +bool CertManager::sendBlankCert() const +{ + return sendBlankCert_; +} + + +void CertManager::setFailNoCert() +{ + failNoCert_ = true; +} + + +void CertManager::setSendVerify() +{ + sendVerify_ = true; +} + +void CertManager::setSendBlankCert() +{ + sendBlankCert_ = true; +} + + +void CertManager::setVerifyCallback(VerifyCallback vc) +{ + verifyCallback_ = vc; +} + + +void CertManager::AddPeerCert(x509* x) +{ + peerList_.push_back(x); // take ownership +} + + +void CertManager::CopySelfCert(const x509* x) +{ + if (x) + list_.push_back(NEW_YS x509(*x)); +} + + +// add to signers +int CertManager::CopyCaCert(const x509* x) +{ + TaoCrypt::Source source(x->get_buffer(), x->get_length()); + TaoCrypt::CertDecoder cert(source, true, &signers_, verifyNone_, + TaoCrypt::CertDecoder::CA); + + if (!cert.GetError().What()) { + const TaoCrypt::PublicKey& key = cert.GetPublicKey(); + signers_.push_back(NEW_YS TaoCrypt::Signer(key.GetKey(), key.size(), + cert.GetCommonName(), cert.GetHash())); + } + // just don't add, not an error return cert.GetError().What(); + return 0; +} + + +const x509* CertManager::get_cert() const +{ + return list_.front(); +} + + +const opaque* CertManager::get_peerKey() const +{ + return peerPublicKey_.get_buffer(); +} + + +X509* CertManager::get_peerX509() const +{ + return peerX509_; +} + + +X509* CertManager::get_selfX509() const +{ + return selfX509_; +} + + +SignatureAlgorithm CertManager::get_peerKeyType() const +{ + return peerKeyType_; +} + + +SignatureAlgorithm CertManager::get_keyType() const +{ + return keyType_; +} + + +uint CertManager::get_peerKeyLength() const +{ + return peerPublicKey_.get_size(); +} + + +const opaque* CertManager::get_privateKey() const +{ + return privateKey_.get_buffer(); +} + + +uint CertManager::get_privateKeyLength() const +{ + return privateKey_.get_size(); +} + + +// Validate the peer's certificate list, from root to peer (last to first) +int CertManager::Validate() +{ + CertList::reverse_iterator last = peerList_.rbegin(); + size_t count = peerList_.size(); + + while ( count > 1 ) { + TaoCrypt::Source source((*last)->get_buffer(), (*last)->get_length()); + TaoCrypt::CertDecoder cert(source, true, &signers_, verifyNone_); + + if (int err = cert.GetError().What()) + return err; + + const TaoCrypt::PublicKey& key = cert.GetPublicKey(); + signers_.push_back(NEW_YS TaoCrypt::Signer(key.GetKey(), key.size(), + cert.GetCommonName(), cert.GetHash())); + ++last; + --count; + } + + if (count) { + // peer's is at the front + TaoCrypt::Source source((*last)->get_buffer(), (*last)->get_length()); + TaoCrypt::CertDecoder cert(source, true, &signers_, verifyNone_); + + int err = cert.GetError().What(); + if ( err && err != TaoCrypt::SIG_OTHER_E) + return err; + + uint sz = cert.GetPublicKey().size(); + peerPublicKey_.allocate(sz); + peerPublicKey_.assign(cert.GetPublicKey().GetKey(), sz); + + if (cert.GetKeyType() == TaoCrypt::RSAk) + peerKeyType_ = rsa_sa_algo; + else + peerKeyType_ = dsa_sa_algo; + + size_t iSz = strlen(cert.GetIssuer()) + 1; + size_t sSz = strlen(cert.GetCommonName()) + 1; + ASN1_STRING beforeDate, afterDate; + beforeDate.data= (unsigned char *) cert.GetBeforeDate(); + beforeDate.type= cert.GetBeforeDateType(); + beforeDate.length= strlen((char *) beforeDate.data) + 1; + afterDate.data= (unsigned char *) cert.GetAfterDate(); + afterDate.type= cert.GetAfterDateType(); + afterDate.length= strlen((char *) afterDate.data) + 1; + peerX509_ = NEW_YS X509(cert.GetIssuer(), iSz, cert.GetCommonName(), + sSz, &beforeDate, &afterDate, + cert.GetIssuerCnStart(), cert.GetIssuerCnLength(), + cert.GetSubjectCnStart(), cert.GetSubjectCnLength() + ); + + if (err == TaoCrypt::SIG_OTHER_E && verifyCallback_) { + X509_STORE_CTX store; + store.error = err; + store.error_depth = static_cast(count) - 1; + store.current_cert = peerX509_; + + int ok = verifyCallback_(0, &store); + if (ok) return 0; + } + + if (err == TaoCrypt::SIG_OTHER_E) return err; + } + return 0; +} + + +// Set the private key +int CertManager::SetPrivateKey(const x509& key) +{ + privateKey_.allocate(key.get_length()); + privateKey_.assign(key.get_buffer(), key.get_length()); + + // set key type + if (x509* cert = list_.front()) { + TaoCrypt::Source source(cert->get_buffer(), cert->get_length()); + TaoCrypt::CertDecoder cd(source, false); + cd.DecodeToKey(); + if (int err = cd.GetError().What()) + return err; + if (cd.GetKeyType() == TaoCrypt::RSAk) + keyType_ = rsa_sa_algo; + else + keyType_ = dsa_sa_algo; + + size_t iSz = strlen(cd.GetIssuer()) + 1; + size_t sSz = strlen(cd.GetCommonName()) + 1; + ASN1_STRING beforeDate, afterDate; + beforeDate.data= (unsigned char *) cd.GetBeforeDate(); + beforeDate.type= cd.GetBeforeDateType(); + beforeDate.length= strlen((char *) beforeDate.data) + 1; + afterDate.data= (unsigned char *) cd.GetAfterDate(); + afterDate.type= cd.GetAfterDateType(); + afterDate.length= strlen((char *) afterDate.data) + 1; + selfX509_ = NEW_YS X509(cd.GetIssuer(), iSz, cd.GetCommonName(), + sSz, &beforeDate, &afterDate, + cd.GetIssuerCnStart(), cd.GetIssuerCnLength(), + cd.GetSubjectCnStart(), cd.GetSubjectCnLength()); + } + return 0; +} + + +// Store OpenSSL type peer's cert +void CertManager::setPeerX509(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(), before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); +} + + +#if defined(USE_CML_LIB) + +// Get the peer's certificate, extract and save public key +void CertManager::SetPeerKey() +{ + // first cert is the peer's + x509* main = peerList_.front(); + + Bytes_struct cert; + cert.num = main->get_length(); + cert.data = main->set_buffer(); + + CML::Certificate cm(cert); + const CML::ASN::Cert& raw = cm.base(); + CTIL::CSM_Buffer key = raw.pubKeyInfo.key; + + uint sz; + opaque* key_buffer = reinterpret_cast(key.Get(sz)); + peerPublicKey_.allocate(sz); + peerPublicKey_.assign(key_buffer, sz); +} + + +#endif // USE_CML_LIB + + + +} // namespace diff --git a/mysql/extra/yassl/src/crypto_wrapper.cpp b/mysql/extra/yassl/src/crypto_wrapper.cpp new file mode 100644 index 0000000..12f956e --- /dev/null +++ b/mysql/extra/yassl/src/crypto_wrapper.cpp @@ -0,0 +1,1016 @@ +/* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + +/* The crypto wrapper source implements the policies for the cipher + * components used by SSL. + * + * The implementation relies on a specfic library, taoCrypt. + */ + +#if !defined(USE_CRYPTOPP_LIB) + +#include "runtime.hpp" +#include "crypto_wrapper.hpp" +#include "cert_wrapper.hpp" + +#include "md5.hpp" +#include "sha.hpp" +#include "ripemd.hpp" +#include "hmac.hpp" +#include "modes.hpp" +#include "des.hpp" +#include "arc4.hpp" +#include "aes.hpp" +#include "rsa.hpp" +#include "dsa.hpp" +#include "dh.hpp" +#include "random.hpp" +#include "file.hpp" +#include "coding.hpp" + + +namespace yaSSL { + + +// MD5 Implementation +struct MD5::MD5Impl { + TaoCrypt::MD5 md5_; + MD5Impl() {} + explicit MD5Impl(const TaoCrypt::MD5& md5) : md5_(md5) {} +}; + + +MD5::MD5() : pimpl_(NEW_YS MD5Impl) {} + + +MD5::~MD5() { ysDelete(pimpl_); } + + +MD5::MD5(const MD5& that) : Digest(), pimpl_(NEW_YS + MD5Impl(that.pimpl_->md5_)) {} + + +MD5& MD5::operator=(const MD5& that) +{ + pimpl_->md5_ = that.pimpl_->md5_; + return *this; +} + + +uint MD5::get_digestSize() const +{ + return MD5_LEN; +} + + +uint MD5::get_padSize() const +{ + return PAD_MD5; +} + + +// Fill out with MD5 digest from in that is sz bytes, out must be >= digest sz +void MD5::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->md5_.Update(in, sz); + pimpl_->md5_.Final(out); +} + +// Fill out with MD5 digest from previous updates +void MD5::get_digest(byte* out) +{ + pimpl_->md5_.Final(out); +} + + +// Update the current digest +void MD5::update(const byte* in, unsigned int sz) +{ + pimpl_->md5_.Update(in, sz); +} + + +// SHA Implementation +struct SHA::SHAImpl { + TaoCrypt::SHA sha_; + SHAImpl() {} + explicit SHAImpl(const TaoCrypt::SHA& sha) : sha_(sha) {} +}; + + +SHA::SHA() : pimpl_(NEW_YS SHAImpl) {} + + +SHA::~SHA() { ysDelete(pimpl_); } + + +SHA::SHA(const SHA& that) : Digest(), pimpl_(NEW_YS SHAImpl(that.pimpl_->sha_)) {} + +SHA& SHA::operator=(const SHA& that) +{ + pimpl_->sha_ = that.pimpl_->sha_; + return *this; +} + + +uint SHA::get_digestSize() const +{ + return SHA_LEN; +} + + +uint SHA::get_padSize() const +{ + return PAD_SHA; +} + + +// Fill out with SHA digest from in that is sz bytes, out must be >= digest sz +void SHA::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->sha_.Update(in, sz); + pimpl_->sha_.Final(out); +} + + +// Fill out with SHA digest from previous updates +void SHA::get_digest(byte* out) +{ + pimpl_->sha_.Final(out); +} + + +// Update the current digest +void SHA::update(const byte* in, unsigned int sz) +{ + pimpl_->sha_.Update(in, sz); +} + + +// RMD-160 Implementation +struct RMD::RMDImpl { + TaoCrypt::RIPEMD160 rmd_; + RMDImpl() {} + explicit RMDImpl(const TaoCrypt::RIPEMD160& rmd) : rmd_(rmd) {} +}; + + +RMD::RMD() : pimpl_(NEW_YS RMDImpl) {} + + +RMD::~RMD() { ysDelete(pimpl_); } + + +RMD::RMD(const RMD& that) : Digest(), pimpl_(NEW_YS RMDImpl(that.pimpl_->rmd_)) {} + +RMD& RMD::operator=(const RMD& that) +{ + pimpl_->rmd_ = that.pimpl_->rmd_; + return *this; +} + + +uint RMD::get_digestSize() const +{ + return RMD_LEN; +} + + +uint RMD::get_padSize() const +{ + return PAD_RMD; +} + + +// Fill out with RMD digest from in that is sz bytes, out must be >= digest sz +void RMD::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->rmd_.Update(in, sz); + pimpl_->rmd_.Final(out); +} + + +// Fill out with RMD digest from previous updates +void RMD::get_digest(byte* out) +{ + pimpl_->rmd_.Final(out); +} + + +// Update the current digest +void RMD::update(const byte* in, unsigned int sz) +{ + pimpl_->rmd_.Update(in, sz); +} + + +// HMAC_MD5 Implementation +struct HMAC_MD5::HMAC_MD5Impl { + TaoCrypt::HMAC mac_; + HMAC_MD5Impl() {} +}; + + +HMAC_MD5::HMAC_MD5(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_MD5Impl) +{ + pimpl_->mac_.SetKey(secret, len); +} + + +HMAC_MD5::~HMAC_MD5() { ysDelete(pimpl_); } + + +uint HMAC_MD5::get_digestSize() const +{ + return MD5_LEN; +} + + +uint HMAC_MD5::get_padSize() const +{ + return PAD_MD5; +} + + +// Fill out with MD5 digest from in that is sz bytes, out must be >= digest sz +void HMAC_MD5::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); + pimpl_->mac_.Final(out); +} + +// Fill out with MD5 digest from previous updates +void HMAC_MD5::get_digest(byte* out) +{ + pimpl_->mac_.Final(out); +} + + +// Update the current digest +void HMAC_MD5::update(const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); +} + + +// HMAC_SHA Implementation +struct HMAC_SHA::HMAC_SHAImpl { + TaoCrypt::HMAC mac_; + HMAC_SHAImpl() {} +}; + + +HMAC_SHA::HMAC_SHA(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_SHAImpl) +{ + pimpl_->mac_.SetKey(secret, len); +} + + +HMAC_SHA::~HMAC_SHA() { ysDelete(pimpl_); } + + +uint HMAC_SHA::get_digestSize() const +{ + return SHA_LEN; +} + + +uint HMAC_SHA::get_padSize() const +{ + return PAD_SHA; +} + + +// Fill out with SHA digest from in that is sz bytes, out must be >= digest sz +void HMAC_SHA::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); + pimpl_->mac_.Final(out); +} + +// Fill out with SHA digest from previous updates +void HMAC_SHA::get_digest(byte* out) +{ + pimpl_->mac_.Final(out); +} + + +// Update the current digest +void HMAC_SHA::update(const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); +} + + + +// HMAC_RMD Implementation +struct HMAC_RMD::HMAC_RMDImpl { + TaoCrypt::HMAC mac_; + HMAC_RMDImpl() {} +}; + + +HMAC_RMD::HMAC_RMD(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_RMDImpl) +{ + pimpl_->mac_.SetKey(secret, len); +} + + +HMAC_RMD::~HMAC_RMD() { ysDelete(pimpl_); } + + +uint HMAC_RMD::get_digestSize() const +{ + return RMD_LEN; +} + + +uint HMAC_RMD::get_padSize() const +{ + return PAD_RMD; +} + + +// Fill out with RMD digest from in that is sz bytes, out must be >= digest sz +void HMAC_RMD::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); + pimpl_->mac_.Final(out); +} + +// Fill out with RMD digest from previous updates +void HMAC_RMD::get_digest(byte* out) +{ + pimpl_->mac_.Final(out); +} + + +// Update the current digest +void HMAC_RMD::update(const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); +} + + +struct DES::DESImpl { + TaoCrypt::DES_CBC_Encryption encryption; + TaoCrypt::DES_CBC_Decryption decryption; +}; + + +DES::DES() : pimpl_(NEW_YS DESImpl) {} + +DES::~DES() { ysDelete(pimpl_); } + + +void DES::set_encryptKey(const byte* k, const byte* iv) +{ + pimpl_->encryption.SetKey(k, DES_KEY_SZ, iv); +} + + +void DES::set_decryptKey(const byte* k, const byte* iv) +{ + pimpl_->decryption.SetKey(k, DES_KEY_SZ, iv); +} + +// DES encrypt plain of length sz into cipher +void DES::encrypt(byte* cipher, const byte* plain, unsigned int sz) +{ + pimpl_->encryption.Process(cipher, plain, sz); +} + + +// DES decrypt cipher of length sz into plain +void DES::decrypt(byte* plain, const byte* cipher, unsigned int sz) +{ + pimpl_->decryption.Process(plain, cipher, sz); +} + + +struct DES_EDE::DES_EDEImpl { + TaoCrypt::DES_EDE3_CBC_Encryption encryption; + TaoCrypt::DES_EDE3_CBC_Decryption decryption; +}; + + +DES_EDE::DES_EDE() : pimpl_(NEW_YS DES_EDEImpl) {} + +DES_EDE::~DES_EDE() { ysDelete(pimpl_); } + + +void DES_EDE::set_encryptKey(const byte* k, const byte* iv) +{ + pimpl_->encryption.SetKey(k, DES_EDE_KEY_SZ, iv); +} + + +void DES_EDE::set_decryptKey(const byte* k, const byte* iv) +{ + pimpl_->decryption.SetKey(k, DES_EDE_KEY_SZ, iv); +} + + +// 3DES encrypt plain of length sz into cipher +void DES_EDE::encrypt(byte* cipher, const byte* plain, unsigned int sz) +{ + pimpl_->encryption.Process(cipher, plain, sz); +} + + +// 3DES decrypt cipher of length sz into plain +void DES_EDE::decrypt(byte* plain, const byte* cipher, unsigned int sz) +{ + pimpl_->decryption.Process(plain, cipher, sz); +} + + +// Implementation of alledged RC4 +struct RC4::RC4Impl { + TaoCrypt::ARC4::Encryption encryption; + TaoCrypt::ARC4::Decryption decryption; +}; + + +RC4::RC4() : pimpl_(NEW_YS RC4Impl) {} + +RC4::~RC4() { ysDelete(pimpl_); } + + +void RC4::set_encryptKey(const byte* k, const byte*) +{ + pimpl_->encryption.SetKey(k, RC4_KEY_SZ); +} + + +void RC4::set_decryptKey(const byte* k, const byte*) +{ + pimpl_->decryption.SetKey(k, RC4_KEY_SZ); +} + + +// RC4 encrypt plain of length sz into cipher +void RC4::encrypt(byte* cipher, const byte* plain, unsigned int sz) +{ + pimpl_->encryption.Process(cipher, plain, sz); +} + + +// RC4 decrypt cipher of length sz into plain +void RC4::decrypt(byte* plain, const byte* cipher, unsigned int sz) +{ + pimpl_->decryption.Process(plain, cipher, sz); +} + + + +// Implementation of AES +struct AES::AESImpl { + TaoCrypt::AES_CBC_Encryption encryption; + TaoCrypt::AES_CBC_Decryption decryption; + unsigned int keySz_; + + AESImpl(unsigned int ks) : keySz_(ks) {} +}; + + +AES::AES(unsigned int ks) : pimpl_(NEW_YS AESImpl(ks)) {} + +AES::~AES() { ysDelete(pimpl_); } + + +int AES::get_keySize() const +{ + return pimpl_->keySz_; +} + + +void AES::set_encryptKey(const byte* k, const byte* iv) +{ + pimpl_->encryption.SetKey(k, pimpl_->keySz_, iv); +} + + +void AES::set_decryptKey(const byte* k, const byte* iv) +{ + pimpl_->decryption.SetKey(k, pimpl_->keySz_, iv); +} + + +// AES encrypt plain of length sz into cipher +void AES::encrypt(byte* cipher, const byte* plain, unsigned int sz) +{ + pimpl_->encryption.Process(cipher, plain, sz); +} + + +// AES decrypt cipher of length sz into plain +void AES::decrypt(byte* plain, const byte* cipher, unsigned int sz) +{ + pimpl_->decryption.Process(plain, cipher, sz); +} + + +struct RandomPool::RandomImpl { + TaoCrypt::RandomNumberGenerator RNG_; +}; + +RandomPool::RandomPool() : pimpl_(NEW_YS RandomImpl) {} + +RandomPool::~RandomPool() { ysDelete(pimpl_); } + +int RandomPool::GetError() const +{ + return pimpl_->RNG_.GetError(); +} + +void RandomPool::Fill(opaque* dst, uint sz) const +{ + pimpl_->RNG_.GenerateBlock(dst, sz); +} + + +// Implementation of DSS Authentication +struct DSS::DSSImpl { + void SetPublic (const byte*, unsigned int); + void SetPrivate(const byte*, unsigned int); + TaoCrypt::DSA_PublicKey publicKey_; + TaoCrypt::DSA_PrivateKey privateKey_; +}; + + +// Decode and store the public key +void DSS::DSSImpl::SetPublic(const byte* key, unsigned int sz) +{ + TaoCrypt::Source source(key, sz); + publicKey_.Initialize(source); +} + + +// Decode and store the public key +void DSS::DSSImpl::SetPrivate(const byte* key, unsigned int sz) +{ + TaoCrypt::Source source(key, sz); + privateKey_.Initialize(source); + publicKey_ = TaoCrypt::DSA_PublicKey(privateKey_); + +} + + +// Set public or private key +DSS::DSS(const byte* key, unsigned int sz, bool publicKey) + : pimpl_(NEW_YS DSSImpl) +{ + if (publicKey) + pimpl_->SetPublic(key, sz); + else + pimpl_->SetPrivate(key, sz); +} + + +DSS::~DSS() +{ + ysDelete(pimpl_); +} + + +uint DSS::get_signatureLength() const +{ + return pimpl_->publicKey_.SignatureLength(); +} + + +// DSS Sign message of length sz into sig +void DSS::sign(byte* sig, const byte* sha_digest, unsigned int /* shaSz */, + const RandomPool& random) +{ + using namespace TaoCrypt; + + DSA_Signer signer(pimpl_->privateKey_); + signer.Sign(sha_digest, sig, random.pimpl_->RNG_); +} + + +// DSS Verify message of length sz against sig, is it correct? +bool DSS::verify(const byte* sha_digest, unsigned int /* shaSz */, + const byte* sig, unsigned int /* sigSz */) +{ + using namespace TaoCrypt; + + DSA_Verifier ver(pimpl_->publicKey_); + return ver.Verify(sha_digest, sig); +} + + +// Implementation of RSA key interface +struct RSA::RSAImpl { + void SetPublic (const byte*, unsigned int); + void SetPrivate(const byte*, unsigned int); + TaoCrypt::RSA_PublicKey publicKey_; + TaoCrypt::RSA_PrivateKey privateKey_; +}; + + +// Decode and store the public key +void RSA::RSAImpl::SetPublic(const byte* key, unsigned int sz) +{ + TaoCrypt::Source source(key, sz); + publicKey_.Initialize(source); +} + + +// Decode and store the private key +void RSA::RSAImpl::SetPrivate(const byte* key, unsigned int sz) +{ + TaoCrypt::Source source(key, sz); + privateKey_.Initialize(source); + publicKey_ = TaoCrypt::RSA_PublicKey(privateKey_); +} + + +// Set public or private key +RSA::RSA(const byte* key, unsigned int sz, bool publicKey) + : pimpl_(NEW_YS RSAImpl) +{ + if (publicKey) + pimpl_->SetPublic(key, sz); + else + pimpl_->SetPrivate(key, sz); +} + +RSA::~RSA() +{ + ysDelete(pimpl_); +} + + +// get cipher text length, varies on key size +unsigned int RSA::get_cipherLength() const +{ + return pimpl_->publicKey_.FixedCiphertextLength(); +} + + +// get signautre length, varies on key size +unsigned int RSA::get_signatureLength() const +{ + return get_cipherLength(); +} + + +// RSA Sign message of length sz into sig +void RSA::sign(byte* sig, const byte* message, unsigned int sz, + const RandomPool& random) +{ + TaoCrypt::RSAES_Decryptor dec(pimpl_->privateKey_); + dec.SSL_Sign(message, sz, sig, random.pimpl_->RNG_); +} + + +// RSA Verify message of length sz against sig +bool RSA::verify(const byte* message, unsigned int sz, const byte* sig, + unsigned int) +{ + TaoCrypt::RSAES_Encryptor enc(pimpl_->publicKey_); + return enc.SSL_Verify(message, sz, sig); +} + + +// RSA public encrypt plain of length sz into cipher +void RSA::encrypt(byte* cipher, const byte* plain, unsigned int sz, + const RandomPool& random) +{ + + TaoCrypt::RSAES_Encryptor enc(pimpl_->publicKey_); + enc.Encrypt(plain, sz, cipher, random.pimpl_->RNG_); +} + + +// RSA private decrypt cipher of length sz into plain +void RSA::decrypt(byte* plain, const byte* cipher, unsigned int sz, + const RandomPool& random) +{ + TaoCrypt::RSAES_Decryptor dec(pimpl_->privateKey_); + dec.Decrypt(cipher, sz, plain, random.pimpl_->RNG_); +} + + +struct Integer::IntegerImpl { + TaoCrypt::Integer int_; + + IntegerImpl() {} + explicit IntegerImpl(const TaoCrypt::Integer& i) : int_(i) {} +}; + +Integer::Integer() : pimpl_(NEW_YS IntegerImpl) {} + +Integer::~Integer() { ysDelete(pimpl_); } + + + +Integer::Integer(const Integer& other) : pimpl_(NEW_YS + IntegerImpl(other.pimpl_->int_)) +{} + + +Integer& Integer::operator=(const Integer& that) +{ + pimpl_->int_ = that.pimpl_->int_; + + return *this; +} + + +void Integer::assign(const byte* num, unsigned int sz) +{ + pimpl_->int_ = TaoCrypt::Integer(num, sz); +} + + +struct DiffieHellman::DHImpl { + TaoCrypt::DH dh_; + TaoCrypt::RandomNumberGenerator& ranPool_; + byte* publicKey_; + byte* privateKey_; + byte* agreedKey_; + uint pubKeyLength_; + + DHImpl(TaoCrypt::RandomNumberGenerator& r) : ranPool_(r), publicKey_(0), + privateKey_(0), agreedKey_(0), pubKeyLength_(0) {} + ~DHImpl() + { + ysArrayDelete(agreedKey_); + ysArrayDelete(privateKey_); + ysArrayDelete(publicKey_); + } + + DHImpl(const DHImpl& that) : dh_(that.dh_), ranPool_(that.ranPool_), + publicKey_(0), privateKey_(0), agreedKey_(0), pubKeyLength_(0) + { + uint length = dh_.GetByteLength(); + AllocKeys(length, length, length); + } + + void AllocKeys(unsigned int pubSz, unsigned int privSz, unsigned int agrSz) + { + publicKey_ = NEW_YS byte[pubSz]; + privateKey_ = NEW_YS byte[privSz]; + agreedKey_ = NEW_YS byte[agrSz]; + } +}; + + + +/* +// server Side DH, server's view +DiffieHellman::DiffieHellman(const char* file, const RandomPool& random) + : pimpl_(NEW_YS DHImpl(random.pimpl_->RNG_)) +{ + using namespace TaoCrypt; + Source source; + FileSource(file, source); + if (source.size() == 0) + return; // TODO add error state, and force check + HexDecoder hd(source); + + pimpl_->dh_.Initialize(source); + + uint length = pimpl_->dh_.GetByteLength(); + + pimpl_->AllocKeys(length, length, length); + pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, + pimpl_->publicKey_); +} +*/ + + +// server Side DH, client's view +DiffieHellman::DiffieHellman(const byte* p, unsigned int pSz, const byte* g, + unsigned int gSz, const byte* pub, + unsigned int pubSz, const RandomPool& random) + : pimpl_(NEW_YS DHImpl(random.pimpl_->RNG_)) +{ + using TaoCrypt::Integer; + + pimpl_->dh_.Initialize(Integer(p, pSz).Ref(), Integer(g, gSz).Ref()); + pimpl_->publicKey_ = NEW_YS opaque[pimpl_->pubKeyLength_ = pubSz]; + memcpy(pimpl_->publicKey_, pub, pubSz); +} + + +// Server Side DH, server's view +DiffieHellman::DiffieHellman(const Integer& p, const Integer& g, + const RandomPool& random) +: pimpl_(NEW_YS DHImpl(random.pimpl_->RNG_)) +{ + using TaoCrypt::Integer; + + pimpl_->dh_.Initialize(p.pimpl_->int_, g.pimpl_->int_); + + uint length = pimpl_->dh_.GetByteLength(); + + pimpl_->AllocKeys(length, length, length); + pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, + pimpl_->publicKey_); +} + +DiffieHellman::~DiffieHellman() { ysDelete(pimpl_); } + + +// Client side and view, use server that for p and g +DiffieHellman::DiffieHellman(const DiffieHellman& that) + : pimpl_(NEW_YS DHImpl(*that.pimpl_)) +{ + pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, + pimpl_->publicKey_); +} + + +DiffieHellman& DiffieHellman::operator=(const DiffieHellman& that) +{ + pimpl_->dh_ = that.pimpl_->dh_; + pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, + pimpl_->publicKey_); + return *this; +} + + +void DiffieHellman::makeAgreement(const byte* other, unsigned int otherSz) +{ + pimpl_->dh_.Agree(pimpl_->agreedKey_, pimpl_->privateKey_, other, otherSz); +} + + +uint DiffieHellman::get_agreedKeyLength() const +{ + return pimpl_->dh_.GetByteLength(); +} + + +const byte* DiffieHellman::get_agreedKey() const +{ + return pimpl_->agreedKey_; +} + +uint DiffieHellman::get_publicKeyLength() const +{ + return pimpl_->pubKeyLength_; +} + +const byte* DiffieHellman::get_publicKey() const +{ + return pimpl_->publicKey_; +} + + +void DiffieHellman::set_sizes(int& pSz, int& gSz, int& pubSz) const +{ + using TaoCrypt::Integer; + Integer p = pimpl_->dh_.GetP(); + Integer g = pimpl_->dh_.GetG(); + + pSz = p.ByteCount(); + gSz = g.ByteCount(); + pubSz = pimpl_->dh_.GetByteLength(); +} + + +void DiffieHellman::get_parms(byte* bp, byte* bg, byte* bpub) const +{ + using TaoCrypt::Integer; + Integer p = pimpl_->dh_.GetP(); + Integer g = pimpl_->dh_.GetG(); + + p.Encode(bp, p.ByteCount()); + g.Encode(bg, g.ByteCount()); + memcpy(bpub, pimpl_->publicKey_, pimpl_->dh_.GetByteLength()); +} + + +// convert PEM file to DER x509 type +x509* PemToDer(FILE* file, CertType type, EncryptedInfo* info) +{ + using namespace TaoCrypt; + + char header[80]; + char footer[80]; + + if (type == Cert) { + strncpy(header, "-----BEGIN CERTIFICATE-----", sizeof(header)); + strncpy(footer, "-----END CERTIFICATE-----", sizeof(footer)); + } else { + strncpy(header, "-----BEGIN RSA PRIVATE KEY-----", sizeof(header)); + strncpy(footer, "-----END RSA PRIVATE KEY-----", sizeof(header)); + } + + long begin = -1; + long end = 0; + bool foundEnd = false; + + char line[80]; + + while(fgets(line, sizeof(line), file)) + if (strncmp(header, line, strlen(header)) == 0) { + begin = ftell(file); + break; + } + + // remove encrypted header if there + if (fgets(line, sizeof(line), file)) { + char encHeader[] = "Proc-Type"; + if (strncmp(encHeader, line, strlen(encHeader)) == 0 && + fgets(line,sizeof(line), file)) { + + char* start = strstr(line, "DES"); + char* finish = strstr(line, ","); + if (!start) + start = strstr(line, "AES"); + + if (!info) return 0; + + if ( start && finish && (start < finish)) { + memcpy(info->name, start, finish - start); + info->name[finish - start] = 0; + memcpy(info->iv, finish + 1, sizeof(info->iv)); + + char* newline = strstr(line, "\r"); + if (!newline) newline = strstr(line, "\n"); + if (newline && (newline > finish)) { + info->ivSz = newline - (finish + 1); + info->set = true; + } + } + begin = ftell(file); + if (fgets(line,sizeof(line), file)) // get blank line + begin = ftell(file); + } + + } + + while(fgets(line, sizeof(line), file)) + if (strncmp(footer, line, strlen(footer)) == 0) { + foundEnd = true; + break; + } + else + end = ftell(file); + + if (begin == -1 || !foundEnd) + return 0; + + input_buffer tmp(end - begin); + fseek(file, begin, SEEK_SET); + size_t bytes = fread(tmp.get_buffer(), end - begin, 1, file); + if (bytes != 1) + return 0; + + Source der(tmp.get_buffer(), end - begin); + Base64Decoder b64Dec(der); + + uint sz = der.size(); + mySTL::auto_ptr x(NEW_YS x509(sz)); + memcpy(x->use_buffer(), der.get_buffer(), sz); + + return x.release(); +} + + +} // namespace + + +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION +namespace yaSSL { +template void ysDelete(DiffieHellman::DHImpl*); +template void ysDelete(Integer::IntegerImpl*); +template void ysDelete(RSA::RSAImpl*); +template void ysDelete(DSS::DSSImpl*); +template void ysDelete(RandomPool::RandomImpl*); +template void ysDelete(AES::AESImpl*); +template void ysDelete(RC4::RC4Impl*); +template void ysDelete(DES_EDE::DES_EDEImpl*); +template void ysDelete(DES::DESImpl*); +template void ysDelete(HMAC_RMD::HMAC_RMDImpl*); +template void ysDelete(HMAC_SHA::HMAC_SHAImpl*); +template void ysDelete(HMAC_MD5::HMAC_MD5Impl*); +template void ysDelete(RMD::RMDImpl*); +template void ysDelete(SHA::SHAImpl*); +template void ysDelete(MD5::MD5Impl*); +} +#endif // HAVE_EXPLICIT_TEMPLATE_INSTANTIATION + +#endif // !USE_CRYPTOPP_LIB diff --git a/mysql/extra/yassl/src/get_password.c b/mysql/extra/yassl/src/get_password.c new file mode 100644 index 0000000..65e5763 --- /dev/null +++ b/mysql/extra/yassl/src/get_password.c @@ -0,0 +1,218 @@ +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/* +** Ask for a password from tty +** This is an own file to avoid conflicts with curses +*/ +#include +#include +#include "mysql.h" +#include +#include +#include + +#ifdef HAVE_GETPASS +#ifdef HAVE_PWD_H +#include +#endif /* HAVE_PWD_H */ +#else /* ! HAVE_GETPASS */ +#ifndef _WIN32 +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_TERMIOS_H /* For tty-password */ +#include +#define TERMIO struct termios +#else +#ifdef HAVE_TERMIO_H /* For tty-password */ +#include +#define TERMIO struct termio +#else +#include +#define TERMIO struct sgttyb +#endif +#endif +#else +#include +#endif /* _WIN32 */ +#endif /* HAVE_GETPASS */ + +#ifdef HAVE_GETPASSPHRASE /* For Solaris */ +#define getpass(A) getpassphrase(A) +#endif + +#ifdef _WIN32 +/* were just going to fake it here and get input from + the keyboard */ + +char *get_tty_password_ext(const char *opt_message, + strdup_handler_t strdup_function) +{ + char to[80]; + char *pos=to,*end=to+sizeof(to)-1; + int i=0; + DBUG_ENTER("get_tty_password_ext"); + _cputs(opt_message ? opt_message : "Enter password: "); + for (;;) + { + char tmp; + tmp=_getch(); + if (tmp == '\b' || (int) tmp == 127) + { + if (pos != to) + { + _cputs("\b \b"); + pos--; + continue; + } + } + if (tmp == '\n' || tmp == '\r' || tmp == 3) + break; + if (iscntrl(tmp) || pos == end) + continue; + _cputs("*"); + *(pos++) = tmp; + } + while (pos != to && isspace(pos[-1]) == ' ') + pos--; /* Allow dummy space at end */ + *pos=0; + _cputs("\n"); + DBUG_RETURN(strdup_function(to,MYF(MY_FAE))); +} + +#else + + +#ifndef HAVE_GETPASS +/* +** Can't use fgets, because readline will get confused +** length is max number of chars in to, not counting \0 +* to will not include the eol characters. +*/ + +static void get_password(char *to,uint length,int fd, my_bool echo) +{ + char *pos=to,*end=to+length; + + for (;;) + { + char tmp; + if (my_read(fd,&tmp,1,MYF(0)) != 1) + break; + if (tmp == '\b' || (int) tmp == 127) + { + if (pos != to) + { + if (echo) + { + fputs("\b \b",stderr); + fflush(stderr); + } + pos--; + continue; + } + } + if (tmp == '\n' || tmp == '\r' || tmp == 3) + break; + if (iscntrl(tmp) || pos == end) + continue; + if (echo) + { + fputc('*',stderr); + fflush(stderr); + } + *(pos++) = tmp; + } + while (pos != to && isspace(pos[-1]) == ' ') + pos--; /* Allow dummy space at end */ + *pos=0; + return; +} + +#endif /* ! HAVE_GETPASS */ + + +char *get_tty_password_ext(const char *opt_message, + strdup_handler_t strdup_function) +{ +#ifdef HAVE_GETPASS + char *passbuff; +#else /* ! HAVE_GETPASS */ + TERMIO org,tmp; +#endif /* HAVE_GETPASS */ + char buff[80]; + + DBUG_ENTER("get_tty_password_ext"); + +#ifdef HAVE_GETPASS + passbuff = getpass(opt_message ? opt_message : "Enter password: "); + + /* copy the password to buff and clear original (static) buffer */ + my_stpnmov(buff, passbuff, sizeof(buff) - 1); +#ifdef _PASSWORD_LEN + memset(passbuff, 0, _PASSWORD_LEN); +#endif +#else + if (isatty(fileno(stderr))) + { + fputs(opt_message ? opt_message : "Enter password: ",stderr); + fflush(stderr); + } +#if defined(HAVE_TERMIOS_H) + tcgetattr(fileno(stdin), &org); + tmp = org; + tmp.c_lflag &= ~(ECHO | ISIG | ICANON); + tmp.c_cc[VMIN] = 1; + tmp.c_cc[VTIME] = 0; + tcsetattr(fileno(stdin), TCSADRAIN, &tmp); + get_password(buff, sizeof(buff)-1, fileno(stdin), isatty(fileno(stderr))); + tcsetattr(fileno(stdin), TCSADRAIN, &org); +#elif defined(HAVE_TERMIO_H) + ioctl(fileno(stdin), (int) TCGETA, &org); + tmp=org; + tmp.c_lflag &= ~(ECHO | ISIG | ICANON); + tmp.c_cc[VMIN] = 1; + tmp.c_cc[VTIME]= 0; + ioctl(fileno(stdin),(int) TCSETA, &tmp); + get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stderr))); + ioctl(fileno(stdin),(int) TCSETA, &org); +#else + gtty(fileno(stdin), &org); + tmp=org; + tmp.sg_flags &= ~ECHO; + tmp.sg_flags |= RAW; + stty(fileno(stdin), &tmp); + get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stderr))); + stty(fileno(stdin), &org); +#endif + if (isatty(fileno(stderr))) + fputc('\n',stderr); +#endif /* HAVE_GETPASS */ + + DBUG_RETURN(strdup_function(buff,MYF(MY_FAE))); +} + +#endif /* _WIN32 */ + +static char * my_strdup_fct(const char *str, myf flags) +{ + return my_strdup(PSI_NOT_INSTRUMENTED, str, flags); +} + +char *get_tty_password(const char *opt_message) +{ + return get_tty_password_ext(opt_message, my_strdup_fct); +} diff --git a/mysql/extra/yassl/src/handshake.cpp b/mysql/extra/yassl/src/handshake.cpp new file mode 100644 index 0000000..91cc407 --- /dev/null +++ b/mysql/extra/yassl/src/handshake.cpp @@ -0,0 +1,1190 @@ +/* + 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. +*/ + + +/* The handshake source implements functions for creating and reading + * the various handshake messages. + */ + + + +#include "runtime.hpp" +#include "handshake.hpp" +#include "yassl_int.hpp" + + +namespace yaSSL { + + + +// Build a client hello message from cipher suites and compression method +void buildClientHello(SSL& ssl, ClientHello& hello) +{ + // store for pre master secret + ssl.useSecurity().use_connection().chVersion_ = hello.client_version_; + + ssl.getCrypto().get_random().Fill(hello.random_, RAN_LEN); + if (ssl.getSecurity().get_resuming()) { + hello.id_len_ = ID_LEN; + memcpy(hello.session_id_, ssl.getSecurity().get_resume().GetID(), + ID_LEN); + } + else + hello.id_len_ = 0; + hello.suite_len_ = ssl.getSecurity().get_parms().suites_size_; + memcpy(hello.cipher_suites_, ssl.getSecurity().get_parms().suites_, + hello.suite_len_); + hello.comp_len_ = 1; + + hello.set_length(sizeof(ProtocolVersion) + + RAN_LEN + + hello.id_len_ + sizeof(hello.id_len_) + + hello.suite_len_ + sizeof(hello.suite_len_) + + hello.comp_len_ + sizeof(hello.comp_len_)); +} + + +// Build a server hello message +void buildServerHello(SSL& ssl, ServerHello& hello) +{ + if (ssl.getSecurity().get_resuming()) { + memcpy(hello.random_,ssl.getSecurity().get_connection().server_random_, + RAN_LEN); + memcpy(hello.session_id_, ssl.getSecurity().get_resume().GetID(), + ID_LEN); + } + else { + ssl.getCrypto().get_random().Fill(hello.random_, RAN_LEN); + ssl.getCrypto().get_random().Fill(hello.session_id_, ID_LEN); + } + hello.id_len_ = ID_LEN; + ssl.set_sessionID(hello.session_id_); + + hello.cipher_suite_[0] = ssl.getSecurity().get_parms().suite_[0]; + hello.cipher_suite_[1] = ssl.getSecurity().get_parms().suite_[1]; + hello.compression_method_ = hello.compression_method_; + + hello.set_length(sizeof(ProtocolVersion) + RAN_LEN + ID_LEN + + sizeof(hello.id_len_) + SUITE_LEN + SIZEOF_ENUM); +} + + +// add handshake from buffer into md5 and sha hashes, use handshake header +void hashHandShake(SSL& ssl, const input_buffer& input, uint sz) +{ + const opaque* buffer = input.get_buffer() + input.get_current() - + HANDSHAKE_HEADER; + sz += HANDSHAKE_HEADER; + ssl.useHashes().use_MD5().update(buffer, sz); + ssl.useHashes().use_SHA().update(buffer, sz); +} + + +// locals +namespace { + +// Write a plaintext record to buffer +void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, + const Message& msg) +{ + buffer.allocate(RECORD_HEADER + rlHdr.length_); + buffer << rlHdr << msg; +} + + +// Write a plaintext record to buffer +void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, + const HandShakeHeader& hsHdr, const HandShakeBase& shake) +{ + buffer.allocate(RECORD_HEADER + rlHdr.length_); + buffer << rlHdr << hsHdr << shake; +} + + +// Build Record Layer header for Message without handshake header +void buildHeader(SSL& ssl, RecordLayerHeader& rlHeader, const Message& msg) +{ + ProtocolVersion pv = ssl.getSecurity().get_connection().version_; + rlHeader.type_ = msg.get_type(); + rlHeader.version_.major_ = pv.major_; + rlHeader.version_.minor_ = pv.minor_; + rlHeader.length_ = msg.get_length(); +} + + +// Build HandShake and RecordLayer Headers for handshake output +void buildHeaders(SSL& ssl, HandShakeHeader& hsHeader, + RecordLayerHeader& rlHeader, const HandShakeBase& shake) +{ + int sz = shake.get_length(); + + hsHeader.set_type(shake.get_type()); + hsHeader.set_length(sz); + + ProtocolVersion pv = ssl.getSecurity().get_connection().version_; + rlHeader.type_ = handshake; + rlHeader.version_.major_ = pv.major_; + rlHeader.version_.minor_ = pv.minor_; + rlHeader.length_ = sz + HANDSHAKE_HEADER; +} + + +// add handshake from buffer into md5 and sha hashes, exclude record header +void hashHandShake(SSL& ssl, const output_buffer& output, bool removeIV = false) +{ + uint sz = output.get_size() - RECORD_HEADER; + + const opaque* buffer = output.get_buffer() + RECORD_HEADER; + + if (removeIV) { // TLSv1_1 IV + uint blockSz = ssl.getCrypto().get_cipher().get_blockSize(); + sz -= blockSz; + buffer += blockSz; + } + + ssl.useHashes().use_MD5().update(buffer, sz); + ssl.useHashes().use_SHA().update(buffer, sz); +} + + +// calculate MD5 hash for finished +void buildMD5(SSL& ssl, Finished& fin, const opaque* sender) +{ + + opaque md5_result[MD5_LEN]; + opaque md5_inner[SIZEOF_SENDER + SECRET_LEN + PAD_MD5]; + opaque md5_outer[SECRET_LEN + PAD_MD5 + MD5_LEN]; + + const opaque* master_secret = + ssl.getSecurity().get_connection().master_secret_; + + // make md5 inner + memcpy(md5_inner, sender, SIZEOF_SENDER); + memcpy(&md5_inner[SIZEOF_SENDER], master_secret, SECRET_LEN); + memcpy(&md5_inner[SIZEOF_SENDER + SECRET_LEN], PAD1, PAD_MD5); + + ssl.useHashes().use_MD5().get_digest(md5_result, md5_inner, + sizeof(md5_inner)); + + // make md5 outer + memcpy(md5_outer, master_secret, SECRET_LEN); + memcpy(&md5_outer[SECRET_LEN], PAD2, PAD_MD5); + memcpy(&md5_outer[SECRET_LEN + PAD_MD5], md5_result, MD5_LEN); + + ssl.useHashes().use_MD5().get_digest(fin.set_md5(), md5_outer, + sizeof(md5_outer)); +} + + +// calculate SHA hash for finished +void buildSHA(SSL& ssl, Finished& fin, const opaque* sender) +{ + + opaque sha_result[SHA_LEN]; + opaque sha_inner[SIZEOF_SENDER + SECRET_LEN + PAD_SHA]; + opaque sha_outer[SECRET_LEN + PAD_SHA + SHA_LEN]; + + const opaque* master_secret = + ssl.getSecurity().get_connection().master_secret_; + + // make sha inner + memcpy(sha_inner, sender, SIZEOF_SENDER); + memcpy(&sha_inner[SIZEOF_SENDER], master_secret, SECRET_LEN); + memcpy(&sha_inner[SIZEOF_SENDER + SECRET_LEN], PAD1, PAD_SHA); + + ssl.useHashes().use_SHA().get_digest(sha_result, sha_inner, + sizeof(sha_inner)); + + // make sha outer + memcpy(sha_outer, master_secret, SECRET_LEN); + memcpy(&sha_outer[SECRET_LEN], PAD2, PAD_SHA); + memcpy(&sha_outer[SECRET_LEN + PAD_SHA], sha_result, SHA_LEN); + + ssl.useHashes().use_SHA().get_digest(fin.set_sha(), sha_outer, + sizeof(sha_outer)); +} + + +// sanity checks on encrypted message size +static int sanity_check_message(SSL& ssl, uint msgSz) +{ + uint minSz = 0; + + if (ssl.getSecurity().get_parms().cipher_type_ == block) { + uint blockSz = ssl.getCrypto().get_cipher().get_blockSize(); + if (msgSz % blockSz) + return -1; + + minSz = ssl.getSecurity().get_parms().hash_size_ + 1; // pad byte too + if (blockSz > minSz) + minSz = blockSz; + + if (ssl.isTLSv1_1()) + minSz += blockSz; // explicit IV + } + else { // stream + minSz = ssl.getSecurity().get_parms().hash_size_; + } + + if (msgSz < minSz) + return -1; + + return 0; +} + + +// decrypt input message in place, store size in case needed later +void decrypt_message(SSL& ssl, input_buffer& input, uint sz) +{ + input_buffer plain(sz); + opaque* cipher = input.get_buffer() + input.get_current(); + + if (sanity_check_message(ssl, sz) != 0) { + ssl.SetError(sanityCipher_error); + return; + } + + ssl.useCrypto().use_cipher().decrypt(plain.get_buffer(), cipher, sz); + memcpy(cipher, plain.get_buffer(), sz); + ssl.useSecurity().use_parms().encrypt_size_ = sz; + + if (ssl.isTLSv1_1()) // IV + input.set_current(input.get_current() + + ssl.getCrypto().get_cipher().get_blockSize()); +} + + +// output operator for input_buffer +output_buffer& operator<<(output_buffer& output, const input_buffer& input) +{ + output.write(input.get_buffer(), input.get_size()); + return output; +} + + +// write headers, handshake hash, mac, pad, and encrypt +void cipherFinished(SSL& ssl, Finished& fin, output_buffer& output) +{ + uint digestSz = ssl.getCrypto().get_digest().get_digestSize(); + uint finishedSz = ssl.isTLS() ? TLS_FINISHED_SZ : FINISHED_SZ; + uint sz = RECORD_HEADER + HANDSHAKE_HEADER + finishedSz + digestSz; + uint pad = 0; + uint blockSz = ssl.getCrypto().get_cipher().get_blockSize(); + + if (ssl.getSecurity().get_parms().cipher_type_ == block) { + if (ssl.isTLSv1_1()) + sz += blockSz; // IV + sz += 1; // pad byte + pad = (sz - RECORD_HEADER) % blockSz; + pad = blockSz - pad; + sz += pad; + } + + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + buildHeaders(ssl, hsHeader, rlHeader, fin); + rlHeader.length_ = sz - RECORD_HEADER; // record header includes mac + // and pad, hanshake doesn't + input_buffer iv; + if (ssl.isTLSv1_1() && ssl.getSecurity().get_parms().cipher_type_== block){ + iv.allocate(blockSz); + ssl.getCrypto().get_random().Fill(iv.get_buffer(), blockSz); + iv.add_size(blockSz); + } + uint ivSz = iv.get_size(); + output.allocate(sz); + output << rlHeader << iv << hsHeader << fin; + + hashHandShake(ssl, output, ssl.isTLSv1_1() ? true : false); + opaque digest[SHA_LEN]; // max size + if (ssl.isTLS()) + TLS_hmac(ssl, digest, output.get_buffer() + RECORD_HEADER + ivSz, + output.get_size() - RECORD_HEADER - ivSz, handshake); + else + hmac(ssl, digest, output.get_buffer() + RECORD_HEADER, + output.get_size() - RECORD_HEADER, handshake); + output.write(digest, digestSz); + + if (ssl.getSecurity().get_parms().cipher_type_ == block) + for (uint i = 0; i <= pad; i++) output[AUTO] = pad; // pad byte gets + // pad value too + input_buffer cipher(rlHeader.length_); + ssl.useCrypto().use_cipher().encrypt(cipher.get_buffer(), + output.get_buffer() + RECORD_HEADER, output.get_size() - RECORD_HEADER); + output.set_current(RECORD_HEADER); + output.write(cipher.get_buffer(), cipher.get_capacity()); +} + + +// build an encrypted data or alert message for output +void buildMessage(SSL& ssl, output_buffer& output, const Message& msg) +{ + uint digestSz = ssl.getCrypto().get_digest().get_digestSize(); + uint sz = RECORD_HEADER + msg.get_length() + digestSz; + uint pad = 0; + uint blockSz = ssl.getCrypto().get_cipher().get_blockSize(); + + if (ssl.getSecurity().get_parms().cipher_type_ == block) { + if (ssl.isTLSv1_1()) // IV + sz += blockSz; + sz += 1; // pad byte + pad = (sz - RECORD_HEADER) % blockSz; + pad = blockSz - pad; + sz += pad; + } + + RecordLayerHeader rlHeader; + buildHeader(ssl, rlHeader, msg); + rlHeader.length_ = sz - RECORD_HEADER; // record header includes mac + // and pad, hanshake doesn't + input_buffer iv; + if (ssl.isTLSv1_1() && ssl.getSecurity().get_parms().cipher_type_== block){ + iv.allocate(blockSz); + ssl.getCrypto().get_random().Fill(iv.get_buffer(), blockSz); + iv.add_size(blockSz); + } + + uint ivSz = iv.get_size(); + output.allocate(sz); + output << rlHeader << iv << msg; + + opaque digest[SHA_LEN]; // max size + if (ssl.isTLS()) + TLS_hmac(ssl, digest, output.get_buffer() + RECORD_HEADER + ivSz, + output.get_size() - RECORD_HEADER - ivSz, msg.get_type()); + else + hmac(ssl, digest, output.get_buffer() + RECORD_HEADER, + output.get_size() - RECORD_HEADER, msg.get_type()); + output.write(digest, digestSz); + + if (ssl.getSecurity().get_parms().cipher_type_ == block) + for (uint i = 0; i <= pad; i++) output[AUTO] = pad; // pad byte gets + // pad value too + input_buffer cipher(rlHeader.length_); + ssl.useCrypto().use_cipher().encrypt(cipher.get_buffer(), + output.get_buffer() + RECORD_HEADER, output.get_size() - RECORD_HEADER); + output.set_current(RECORD_HEADER); + output.write(cipher.get_buffer(), cipher.get_capacity()); +} + + +// build alert message +void buildAlert(SSL& ssl, output_buffer& output, const Alert& alert) +{ + if (ssl.getSecurity().get_parms().pending_ == false) // encrypted + buildMessage(ssl, output, alert); + else { + RecordLayerHeader rlHeader; + buildHeader(ssl, rlHeader, alert); + buildOutput(output, rlHeader, alert); + } +} + + +// build TLS finished message +void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) +{ + opaque handshake_hash[FINISHED_SZ]; + + ssl.useHashes().use_MD5().get_digest(handshake_hash); + ssl.useHashes().use_SHA().get_digest(&handshake_hash[MD5_LEN]); + + const opaque* side; + if ( strncmp((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0) + side = tls_client; + else + side = tls_server; + + PRF(fin.set_md5(), TLS_FINISHED_SZ, + ssl.getSecurity().get_connection().master_secret_, SECRET_LEN, + side, FINISHED_LABEL_SZ, + handshake_hash, FINISHED_SZ); + + fin.set_length(TLS_FINISHED_SZ); // shorter length for TLS +} + + +// compute p_hash for MD5 or SHA-1 for TLSv1 PRF +void p_hash(output_buffer& result, const output_buffer& secret, + const output_buffer& seed, MACAlgorithm hash) +{ + uint len = hash == md5 ? MD5_LEN : SHA_LEN; + uint times = result.get_capacity() / len; + uint lastLen = result.get_capacity() % len; + opaque previous[SHA_LEN]; // max size + opaque current[SHA_LEN]; // max size + mySTL::auto_ptr hmac; + + if (lastLen) times += 1; + + if (hash == md5) + hmac.reset(NEW_YS HMAC_MD5(secret.get_buffer(), secret.get_size())); + else + hmac.reset(NEW_YS HMAC_SHA(secret.get_buffer(), secret.get_size())); + // A0 = seed + hmac->get_digest(previous, seed.get_buffer(), seed.get_size());// A1 + uint lastTime = times - 1; + + for (uint i = 0; i < times; i++) { + hmac->update(previous, len); + hmac->get_digest(current, seed.get_buffer(), seed.get_size()); + + if (lastLen && (i == lastTime)) + result.write(current, lastLen); + else { + result.write(current, len); + //memcpy(previous, current, len); + hmac->get_digest(previous, previous, len); + } + } +} + + +// calculate XOR for TLSv1 PRF +void get_xor(byte *digest, uint digLen, output_buffer& md5, + output_buffer& sha) +{ + for (uint i = 0; i < digLen; i++) + digest[i] = md5[AUTO] ^ sha[AUTO]; +} + + +// build MD5 part of certificate verify +void buildMD5_CertVerify(SSL& ssl, byte* digest) +{ + opaque md5_result[MD5_LEN]; + opaque md5_inner[SECRET_LEN + PAD_MD5]; + opaque md5_outer[SECRET_LEN + PAD_MD5 + MD5_LEN]; + + const opaque* master_secret = + ssl.getSecurity().get_connection().master_secret_; + + // make md5 inner + memcpy(md5_inner, master_secret, SECRET_LEN); + memcpy(&md5_inner[SECRET_LEN], PAD1, PAD_MD5); + + ssl.useHashes().use_MD5().get_digest(md5_result, md5_inner, + sizeof(md5_inner)); + + // make md5 outer + memcpy(md5_outer, master_secret, SECRET_LEN); + memcpy(&md5_outer[SECRET_LEN], PAD2, PAD_MD5); + memcpy(&md5_outer[SECRET_LEN + PAD_MD5], md5_result, MD5_LEN); + + ssl.useHashes().use_MD5().get_digest(digest, md5_outer, sizeof(md5_outer)); +} + + +// build SHA part of certificate verify +void buildSHA_CertVerify(SSL& ssl, byte* digest) +{ + opaque sha_result[SHA_LEN]; + opaque sha_inner[SECRET_LEN + PAD_SHA]; + opaque sha_outer[SECRET_LEN + PAD_SHA + SHA_LEN]; + + const opaque* master_secret = + ssl.getSecurity().get_connection().master_secret_; + + // make sha inner + memcpy(sha_inner, master_secret, SECRET_LEN); + memcpy(&sha_inner[SECRET_LEN], PAD1, PAD_SHA); + + ssl.useHashes().use_SHA().get_digest(sha_result, sha_inner, + sizeof(sha_inner)); + + // make sha outer + memcpy(sha_outer, master_secret, SECRET_LEN); + memcpy(&sha_outer[SECRET_LEN], PAD2, PAD_SHA); + memcpy(&sha_outer[SECRET_LEN + PAD_SHA], sha_result, SHA_LEN); + + ssl.useHashes().use_SHA().get_digest(digest, sha_outer, sizeof(sha_outer)); +} + + +} // namespace for locals + + +// some clients still send sslv2 client hello +void ProcessOldClientHello(input_buffer& input, SSL& ssl) +{ + if (input.get_error() || input.get_remaining() < 2) { + ssl.SetError(bad_input); + return; + } + byte b0 = input[AUTO]; + byte b1 = input[AUTO]; + + uint16 sz = ((b0 & 0x7f) << 8) | b1; + + if (sz > input.get_remaining()) { + ssl.SetError(bad_input); + return; + } + + // hashHandShake manually + const opaque* buffer = input.get_buffer() + input.get_current(); + ssl.useHashes().use_MD5().update(buffer, sz); + ssl.useHashes().use_SHA().update(buffer, sz); + + b1 = input[AUTO]; // does this value mean client_hello? + + ClientHello ch; + ch.client_version_.major_ = input[AUTO]; + ch.client_version_.minor_ = input[AUTO]; + + byte len[2]; + + len[0] = input[AUTO]; + len[1] = input[AUTO]; + ato16(len, ch.suite_len_); + + len[0] = input[AUTO]; + len[1] = input[AUTO]; + uint16 sessionLen; + ato16(len, sessionLen); + ch.id_len_ = sessionLen; + + len[0] = input[AUTO]; + len[1] = input[AUTO]; + uint16 randomLen; + ato16(len, randomLen); + + if (input.get_error() || ch.suite_len_ > MAX_SUITE_SZ || + ch.suite_len_ > input.get_remaining() || + sessionLen > ID_LEN || randomLen > RAN_LEN) { + ssl.SetError(bad_input); + return; + } + + int j = 0; + for (uint16 i = 0; i < ch.suite_len_; i += 3) { + byte first = input[AUTO]; + if (first) // sslv2 type + input.read(len, SUITE_LEN); // skip + else { + input.read(&ch.cipher_suites_[j], SUITE_LEN); + j += SUITE_LEN; + } + } + ch.suite_len_ = j; + + if (ch.id_len_) + input.read(ch.session_id_, ch.id_len_); // id_len_ from sessionLen + + if (randomLen < RAN_LEN) + memset(ch.random_, 0, RAN_LEN - randomLen); + input.read(&ch.random_[RAN_LEN - randomLen], randomLen); + + ch.Process(input, ssl); +} + + +// Build a finished message, see 7.6.9 +void buildFinished(SSL& ssl, Finished& fin, const opaque* sender) +{ + // store current states, building requires get_digest which resets state + MD5 md5(ssl.getHashes().get_MD5()); + SHA sha(ssl.getHashes().get_SHA()); + + if (ssl.isTLS()) + buildFinishedTLS(ssl, fin, sender); + else { + buildMD5(ssl, fin, sender); + buildSHA(ssl, fin, sender); + } + + // restore + ssl.useHashes().use_MD5() = md5; + ssl.useHashes().use_SHA() = sha; +} + + +/* compute SSLv3 HMAC into digest see + * buffer is of sz size and includes HandShake Header but not a Record Header + * verify means to check peers hmac +*/ +void hmac(SSL& ssl, byte* digest, const byte* buffer, uint sz, + ContentType content, bool verify) +{ + Digest& mac = ssl.useCrypto().use_digest(); + opaque inner[SHA_LEN + PAD_MD5 + SEQ_SZ + SIZEOF_ENUM + LENGTH_SZ]; + opaque outer[SHA_LEN + PAD_MD5 + SHA_LEN]; + opaque result[SHA_LEN]; // max possible sizes + uint digestSz = mac.get_digestSize(); // actual sizes + uint padSz = mac.get_padSize(); + uint innerSz = digestSz + padSz + SEQ_SZ + SIZEOF_ENUM + LENGTH_SZ; + uint outerSz = digestSz + padSz + digestSz; + + // data + const opaque* mac_secret = ssl.get_macSecret(verify); + opaque seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 }; + opaque length[LENGTH_SZ]; + c16toa(sz, length); + c32toa(ssl.get_SEQIncrement(verify), &seq[sizeof(uint32)]); + + // make inner + memcpy(inner, mac_secret, digestSz); + memcpy(&inner[digestSz], PAD1, padSz); + memcpy(&inner[digestSz + padSz], seq, SEQ_SZ); + inner[digestSz + padSz + SEQ_SZ] = content; + memcpy(&inner[digestSz + padSz + SEQ_SZ + SIZEOF_ENUM], length, LENGTH_SZ); + + mac.update(inner, innerSz); + mac.get_digest(result, buffer, sz); // append content buffer + + // make outer + memcpy(outer, mac_secret, digestSz); + memcpy(&outer[digestSz], PAD2, padSz); + memcpy(&outer[digestSz + padSz], result, digestSz); + + mac.get_digest(digest, outer, outerSz); +} + + +// TLS type HAMC +void TLS_hmac(SSL& ssl, byte* digest, const byte* buffer, uint sz, + ContentType content, bool verify) +{ + mySTL::auto_ptr hmac; + opaque seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 }; + opaque length[LENGTH_SZ]; + opaque inner[SIZEOF_ENUM + VERSION_SZ + LENGTH_SZ]; // type + version + len + + c16toa(sz, length); + c32toa(ssl.get_SEQIncrement(verify), &seq[sizeof(uint32)]); + + MACAlgorithm algo = ssl.getSecurity().get_parms().mac_algorithm_; + + if (algo == sha) + hmac.reset(NEW_YS HMAC_SHA(ssl.get_macSecret(verify), SHA_LEN)); + else if (algo == rmd) + hmac.reset(NEW_YS HMAC_RMD(ssl.get_macSecret(verify), RMD_LEN)); + else + hmac.reset(NEW_YS HMAC_MD5(ssl.get_macSecret(verify), MD5_LEN)); + + hmac->update(seq, SEQ_SZ); // seq_num + inner[0] = content; // type + inner[SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.major_; + inner[SIZEOF_ENUM + SIZEOF_ENUM] = + ssl.getSecurity().get_connection().version_.minor_; // version + memcpy(&inner[SIZEOF_ENUM + VERSION_SZ], length, LENGTH_SZ); // length + hmac->update(inner, sizeof(inner)); + hmac->get_digest(digest, buffer, sz); // content +} + + +// compute TLSv1 PRF (pseudo random function using HMAC) +void PRF(byte* digest, uint digLen, const byte* secret, uint secLen, + const byte* label, uint labLen, const byte* seed, uint seedLen) +{ + uint half = (secLen + 1) / 2; + + output_buffer md5_half(half); + output_buffer sha_half(half); + output_buffer labelSeed(labLen + seedLen); + + md5_half.write(secret, half); + sha_half.write(secret + half - secLen % 2, half); + labelSeed.write(label, labLen); + labelSeed.write(seed, seedLen); + + output_buffer md5_result(digLen); + output_buffer sha_result(digLen); + + p_hash(md5_result, md5_half, labelSeed, md5); + p_hash(sha_result, sha_half, labelSeed, sha); + + md5_result.set_current(0); + sha_result.set_current(0); + get_xor(digest, digLen, md5_result, sha_result); +} + + +// build certificate hashes +void build_certHashes(SSL& ssl, Hashes& hashes) +{ + // store current states, building requires get_digest which resets state + MD5 md5(ssl.getHashes().get_MD5()); + SHA sha(ssl.getHashes().get_SHA()); + + if (ssl.isTLS()) { + ssl.useHashes().use_MD5().get_digest(hashes.md5_); + ssl.useHashes().use_SHA().get_digest(hashes.sha_); + } + else { + buildMD5_CertVerify(ssl, hashes.md5_); + buildSHA_CertVerify(ssl, hashes.sha_); + } + + // restore + ssl.useHashes().use_MD5() = md5; + ssl.useHashes().use_SHA() = sha; +} + + + +// do process input requests, return 0 is done, 1 is call again to complete +int DoProcessReply(SSL& ssl) +{ + uint ready = ssl.getSocket().get_ready(); + if (!ready) + ready= 64; + + // add buffered data if its there + input_buffer* buffered = ssl.useBuffers().TakeRawInput(); + uint buffSz = buffered ? buffered->get_size() : 0; + input_buffer buffer(buffSz + ready); + if (buffSz) { + buffer.assign(buffered->get_buffer(), buffSz); + ysDelete(buffered); + buffered = 0; + } + + // add new data + uint read = ssl.useSocket().receive(buffer.get_buffer() + buffSz, ready); + if (read == static_cast(-1)) { + ssl.SetError(receive_error); + return 0; + } else if (read == 0) + return 1; + + buffer.add_size(read); + uint offset = 0; + const MessageFactory& mf = ssl.getFactory().getMessage(); + + // old style sslv2 client hello? + if (ssl.getSecurity().get_parms().entity_ == server_end && + ssl.getStates().getServer() == clientNull) + if (buffer.peek() != handshake) { + ProcessOldClientHello(buffer, ssl); + if (ssl.GetError()) + return 0; + } + + while(!buffer.eof()) { + // each record + RecordLayerHeader hdr; + bool needHdr = false; + + if (static_cast(RECORD_HEADER) > buffer.get_remaining()) + needHdr = true; + else { + buffer >> hdr; + ssl.verifyState(hdr); + } + + if (ssl.GetError()) + return 0; + + // make sure we have enough input in buffer to process this record + if (needHdr || hdr.length_ > buffer.get_remaining()) { + // put header in front for next time processing + uint extra = needHdr ? 0 : RECORD_HEADER; + uint sz = buffer.get_remaining() + extra; + ssl.useBuffers().SetRawInput(NEW_YS input_buffer(sz, + buffer.get_buffer() + buffer.get_current() - extra, sz)); + return 1; + } + + while (buffer.get_current() < hdr.length_ + RECORD_HEADER + offset) { + // each message in record, can be more than 1 if not encrypted + if (ssl.GetError()) + return 0; + + if (ssl.getSecurity().get_parms().pending_ == false) { // cipher on + // sanity check for malicious/corrupted/illegal input + if (buffer.get_remaining() < hdr.length_) { + ssl.SetError(bad_input); + return 0; + } + decrypt_message(ssl, buffer, hdr.length_); + if (ssl.GetError()) + return 0; + } + + mySTL::auto_ptr msg(mf.CreateObject(hdr.type_)); + if (!msg.get()) { + ssl.SetError(factory_error); + return 0; + } + buffer >> *msg; + msg->Process(buffer, ssl); + if (ssl.GetError()) + return 0; + } + offset += hdr.length_ + RECORD_HEADER; + } + return 0; +} + + +// process input requests +void processReply(SSL& ssl) +{ + if (ssl.GetError()) return; + + if (DoProcessReply(ssl)) { + // didn't complete process + if (!ssl.getSocket().IsNonBlocking()) { + // keep trying now, blocking ok + while (!ssl.GetError()) + if (DoProcessReply(ssl) == 0) break; + } + else + // user will have try again later, non blocking + ssl.SetError(YasslError(SSL_ERROR_WANT_READ)); + } +} + + +// send client_hello, no buffering +void sendClientHello(SSL& ssl) +{ + ssl.verifyState(serverNull); + if (ssl.GetError()) return; + + ClientHello ch(ssl.getSecurity().get_connection().version_, + ssl.getSecurity().get_connection().compression_); + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + output_buffer out; + + buildClientHello(ssl, ch); + ssl.set_random(ch.get_random(), client_end); + buildHeaders(ssl, hsHeader, rlHeader, ch); + buildOutput(out, rlHeader, hsHeader, ch); + hashHandShake(ssl, out); + + ssl.Send(out.get_buffer(), out.get_size()); +} + + +// send client key exchange +void sendClientKeyExchange(SSL& ssl, BufferOutput buffer) +{ + ssl.verifyState(serverHelloDoneComplete); + if (ssl.GetError()) return; + + ClientKeyExchange ck(ssl); + ck.build(ssl); + ssl.makeMasterSecret(); + + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr out(NEW_YS output_buffer); + buildHeaders(ssl, hsHeader, rlHeader, ck); + buildOutput(*out.get(), rlHeader, hsHeader, ck); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send server key exchange +void sendServerKeyExchange(SSL& ssl, BufferOutput buffer) +{ + if (ssl.GetError()) return; + ServerKeyExchange sk(ssl); + sk.build(ssl); + if (ssl.GetError()) return; + + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr out(NEW_YS output_buffer); + buildHeaders(ssl, hsHeader, rlHeader, sk); + buildOutput(*out.get(), rlHeader, hsHeader, sk); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send change cipher +void sendChangeCipher(SSL& ssl, BufferOutput buffer) +{ + if (ssl.getSecurity().get_parms().entity_ == server_end) { + if (ssl.getSecurity().get_resuming()) + ssl.verifyState(clientKeyExchangeComplete); + else + ssl.verifyState(clientFinishedComplete); + } + if (ssl.GetError()) return; + + ChangeCipherSpec ccs; + RecordLayerHeader rlHeader; + buildHeader(ssl, rlHeader, ccs); + mySTL::auto_ptr out(NEW_YS output_buffer); + buildOutput(*out.get(), rlHeader, ccs); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send finished +void sendFinished(SSL& ssl, ConnectionEnd side, BufferOutput buffer) +{ + if (ssl.GetError()) return; + + Finished fin; + buildFinished(ssl, fin, side == client_end ? client : server); + mySTL::auto_ptr out(NEW_YS output_buffer); + cipherFinished(ssl, fin, *out.get()); // hashes handshake + + if (ssl.getSecurity().get_resuming()) { + if (side == server_end) + buildFinished(ssl, ssl.useHashes().use_verify(), client); // client + } + else { + if (!ssl.getSecurity().GetContext()->GetSessionCacheOff()) + GetSessions().add(ssl); // store session + if (side == client_end) + buildFinished(ssl, ssl.useHashes().use_verify(), server); // server + } + ssl.useSecurity().use_connection().CleanMaster(); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send data +int sendData(SSL& ssl, const void* buffer, int sz) +{ + int sent = 0; + + if (ssl.GetError() == YasslError(SSL_ERROR_WANT_READ)) + ssl.SetError(no_error); + + if (ssl.GetError() == YasslError(SSL_ERROR_WANT_WRITE)) { + ssl.SetError(no_error); + ssl.SendWriteBuffered(); + if (!ssl.GetError()) { + // advance sent to prvevious sent + plain size just sent + sent = ssl.useBuffers().prevSent + ssl.useBuffers().plainSz; + } + } + + ssl.verfiyHandShakeComplete(); + if (ssl.GetError()) return -1; + + for (;;) { + int len = min(sz - sent, MAX_RECORD_SIZE); + output_buffer out; + input_buffer tmp; + + Data data; + + if (sent == sz) break; + + if (ssl.CompressionOn()) { + if (Compress(static_cast(buffer) + sent, len, + tmp) == -1) { + ssl.SetError(compress_error); + return -1; + } + data.SetData(tmp.get_size(), tmp.get_buffer()); + } + else + data.SetData(len, static_cast(buffer) + sent); + + buildMessage(ssl, out, data); + ssl.Send(out.get_buffer(), out.get_size()); + + if (ssl.GetError()) { + if (ssl.GetError() == YasslError(SSL_ERROR_WANT_WRITE)) { + ssl.useBuffers().plainSz = len; + ssl.useBuffers().prevSent = sent; + } + return -1; + } + sent += len; + } + ssl.useLog().ShowData(sent, true); + return sent; +} + + +// send alert +int sendAlert(SSL& ssl, const Alert& alert) +{ + output_buffer out; + buildAlert(ssl, out, alert); + ssl.Send(out.get_buffer(), out.get_size()); + + return alert.get_length(); +} + + +// process input data +int receiveData(SSL& ssl, Data& data, bool peek) +{ + if (ssl.GetError() == YasslError(SSL_ERROR_WANT_READ)) + ssl.SetError(no_error); + + ssl.verfiyHandShakeComplete(); + if (ssl.GetError()) return -1; + + if (!ssl.HasData()) + processReply(ssl); + + if (peek) + ssl.PeekData(data); + else + ssl.fillData(data); + + ssl.useLog().ShowData(data.get_length()); + if (ssl.GetError()) return -1; + + if (data.get_length() == 0 && ssl.getSocket().WouldBlock()) { + ssl.SetError(YasslError(SSL_ERROR_WANT_READ)); + return SSL_WOULD_BLOCK; + } + return data.get_length(); +} + + +// send server hello +void sendServerHello(SSL& ssl, BufferOutput buffer) +{ + if (ssl.getSecurity().get_resuming()) + ssl.verifyState(clientKeyExchangeComplete); + else + ssl.verifyState(clientHelloComplete); + if (ssl.GetError()) return; + + ServerHello sh(ssl.getSecurity().get_connection().version_, + ssl.getSecurity().get_connection().compression_); + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr out(NEW_YS output_buffer); + + buildServerHello(ssl, sh); + ssl.set_random(sh.get_random(), server_end); + buildHeaders(ssl, hsHeader, rlHeader, sh); + buildOutput(*out.get(), rlHeader, hsHeader, sh); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send server hello done +void sendServerHelloDone(SSL& ssl, BufferOutput buffer) +{ + if (ssl.GetError()) return; + + ServerHelloDone shd; + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr out(NEW_YS output_buffer); + + buildHeaders(ssl, hsHeader, rlHeader, shd); + buildOutput(*out.get(), rlHeader, hsHeader, shd); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send certificate +void sendCertificate(SSL& ssl, BufferOutput buffer) +{ + if (ssl.GetError()) return; + + Certificate cert(ssl.getCrypto().get_certManager().get_cert()); + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr out(NEW_YS output_buffer); + + buildHeaders(ssl, hsHeader, rlHeader, cert); + buildOutput(*out.get(), rlHeader, hsHeader, cert); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send certificate request +void sendCertificateRequest(SSL& ssl, BufferOutput buffer) +{ + if (ssl.GetError()) return; + + CertificateRequest request; + request.Build(); + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr out(NEW_YS output_buffer); + + buildHeaders(ssl, hsHeader, rlHeader, request); + buildOutput(*out.get(), rlHeader, hsHeader, request); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send certificate verify +void sendCertificateVerify(SSL& ssl, BufferOutput buffer) +{ + if (ssl.GetError()) return; + + if(ssl.getCrypto().get_certManager().sendBlankCert()) return; + + CertificateVerify verify; + verify.Build(ssl); + if (ssl.GetError()) return; + + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr out(NEW_YS output_buffer); + + buildHeaders(ssl, hsHeader, rlHeader, verify); + buildOutput(*out.get(), rlHeader, hsHeader, verify); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +} // namespace diff --git a/mysql/extra/yassl/src/lock.cpp b/mysql/extra/yassl/src/lock.cpp new file mode 100644 index 0000000..c74ea1c --- /dev/null +++ b/mysql/extra/yassl/src/lock.cpp @@ -0,0 +1,87 @@ +/* + Copyright (c) 2005, 2012, 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. +*/ + +/* Locking functions + */ + +#include "runtime.hpp" +#include "lock.hpp" + + +namespace yaSSL { + + +#ifdef MULTI_THREADED + #ifdef _WIN32 + + Mutex::Mutex() + { + InitializeCriticalSection(&cs_); + } + + + Mutex::~Mutex() + { + DeleteCriticalSection(&cs_); + } + + + Mutex::Lock::Lock(Mutex& lm) : mutex_(lm) + { + EnterCriticalSection(&mutex_.cs_); + } + + + Mutex::Lock::~Lock() + { + LeaveCriticalSection(&mutex_.cs_); + } + + #else // _WIN32 + + Mutex::Mutex() + { + pthread_mutex_init(&mutex_, 0); + } + + + Mutex::~Mutex() + { + pthread_mutex_destroy(&mutex_); + } + + + Mutex::Lock::Lock(Mutex& lm) : mutex_(lm) + { + pthread_mutex_lock(&mutex_.mutex_); + } + + + Mutex::Lock::~Lock() + { + pthread_mutex_unlock(&mutex_.mutex_); + } + + + #endif // _WIN32 +#endif // MULTI_THREADED + + + +} // namespace yaSSL + diff --git a/mysql/extra/yassl/src/log.cpp b/mysql/extra/yassl/src/log.cpp new file mode 100644 index 0000000..2f112ac --- /dev/null +++ b/mysql/extra/yassl/src/log.cpp @@ -0,0 +1,147 @@ +/* + Copyright (c) 2000, 2016, 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. +*/ + +/* Debug logging functions + */ + + +#include "runtime.hpp" +#include "log.hpp" + +#ifdef YASSL_LOG + #include + #include + #include +#endif + + + +namespace yaSSL { + + +#ifdef YASSL_LOG + + enum { MAX_MSG = 81 }; + + Log::Log(const char* str) + { + log_ = fopen(str, "w"); + Trace("********** Logger Attached **********"); + } + + + Log::~Log() + { + Trace("********** Logger Detached **********"); + fclose(log_); + } + + + // Trace a message + void Log::Trace(const char* str) + { + if (!log_) return; + + time_t clicks = time(0); + char timeStr[32]; + + memset(timeStr, 0, sizeof(timeStr)); + // get rid of newline + strncpy(timeStr, ctime(&clicks), sizeof(timeStr)); + unsigned int len = strlen(timeStr); + timeStr[len - 1] = 0; + + char msg[MAX_MSG]; + + strncpy(msg, timeStr, sizeof(timeStr)); + strncat(msg, ":", 1); + strncat(msg, str, MAX_MSG - sizeof(timeStr) - 2); + strncat(msg, "\n", 1); + msg[MAX_MSG - 1] = 0; + + fputs(msg, log_); + } + + + #if defined(_WIN32) || defined(__MACH__) || defined(__hpux__) + typedef int socklen_t; + #endif + + + // write tcp address + void Log::ShowTCP(socket_t fd, bool ended) + { + sockaddr_in peeraddr; + socklen_t len = sizeof(peeraddr); + if (getpeername(fd, (sockaddr*)&peeraddr, &len) != 0) + return; + + const char* p = reinterpret_cast(&peeraddr.sin_addr); + char msg[MAX_MSG]; + char number[16]; + + if (ended) + strncpy(msg, "yaSSL conn DONE w/ peer ", 26); + else + strncpy(msg, "yaSSL conn BEGUN w/ peer ", 26); + for (int i = 0; i < 4; ++i) { + sprintf(number, "%u", static_cast(p[i])); + strncat(msg, number, 8); + if (i < 3) + strncat(msg, ".", 1); + } + strncat(msg, " port ", 8); + sprintf(number, "%d", htons(peeraddr.sin_port)); + strncat(msg, number, 8); + + msg[MAX_MSG - 1] = 0; + Trace(msg); + } + + + // log processed data + void Log::ShowData(uint bytes, bool sent) + { + char msg[MAX_MSG]; + char number[16]; + + if (sent) + strncpy(msg, "Sent ", 10); + else + strncpy(msg, "Received ", 10); + sprintf(number, "%u", bytes); + strncat(msg, number, 8); + strncat(msg, " bytes of application data", 27); + + msg[MAX_MSG - 1] = 0; + Trace(msg); + } + + +#else // no YASSL_LOG + + + Log::Log(const char*) {} + Log::~Log() {} + void Log::Trace(const char*) {} + void Log::ShowTCP(socket_t, bool) {} + void Log::ShowData(uint, bool) {} + + +#endif // YASSL_LOG +} // namespace diff --git a/mysql/extra/yassl/src/socket_wrapper.cpp b/mysql/extra/yassl/src/socket_wrapper.cpp new file mode 100644 index 0000000..a23c1c1 --- /dev/null +++ b/mysql/extra/yassl/src/socket_wrapper.cpp @@ -0,0 +1,238 @@ +/* + Copyright (c) 2005, 2012, 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. +*/ + + +/* The socket wrapper source implements a Socket class that hides the + * differences between Berkely style sockets and Windows sockets, allowing + * transparent TCP access. + */ + + +#include "runtime.hpp" +#include "socket_wrapper.hpp" + +#ifndef _WIN32 + #include + #include + #include + #include + #include + #include + #include + #include +#endif // _WIN32 + +#if defined(__sun) || defined(__SCO_VERSION__) + #include +#endif + +#ifdef _WIN32 + const int SOCKET_EINVAL = WSAEINVAL; + const int SOCKET_EWOULDBLOCK = WSAEWOULDBLOCK; + const int SOCKET_EAGAIN = WSAEWOULDBLOCK; +#else + const int SOCKET_EINVAL = EINVAL; + const int SOCKET_EWOULDBLOCK = EWOULDBLOCK; + const int SOCKET_EAGAIN = EAGAIN; +#endif // _WIN32 + + +namespace { + + +extern "C" long system_recv(void *ptr, void *buf, size_t count) +{ + yaSSL::socket_t *socket = (yaSSL::socket_t *) ptr; + return ::recv(*socket, reinterpret_cast(buf), count, 0); +} + + +extern "C" long system_send(void *ptr, const void *buf, size_t count) +{ + yaSSL::socket_t *socket = (yaSSL::socket_t *) ptr; + return ::send(*socket, reinterpret_cast(buf), count, 0); +} + + +} + + +namespace yaSSL { + + +Socket::Socket(socket_t s) + : socket_(s), wouldBlock_(false), nonBlocking_(false), + ptr_(&socket_), send_func_(system_send), recv_func_(system_recv) +{} + + +void Socket::set_fd(socket_t s) +{ + socket_ = s; +} + + +socket_t Socket::get_fd() const +{ + return socket_; +} + + +Socket::~Socket() +{ + // don't close automatically now +} + + +void Socket::closeSocket() +{ + if (socket_ != INVALID_SOCKET) { +#ifdef _WIN32 + closesocket(socket_); +#else + close(socket_); +#endif + socket_ = INVALID_SOCKET; + } +} + + +uint Socket::get_ready() const +{ +#ifdef _WIN32 + unsigned long ready = 0; + ioctlsocket(socket_, FIONREAD, &ready); +#else + /* + 64-bit Solaris requires the variable passed to + FIONREAD be a 32-bit value. + */ + unsigned int ready = 0; + ioctl(socket_, FIONREAD, &ready); +#endif + + return ready; +} + + +void Socket::set_transport_ptr(void *ptr) +{ + ptr_ = ptr; +} + + +void Socket::set_transport_recv_function(yaSSL_recv_func_t recv_func) +{ + recv_func_ = recv_func; +} + + +void Socket::set_transport_send_function(yaSSL_send_func_t send_func) +{ + send_func_ = send_func; +} + + +uint Socket::send(const byte* buf, unsigned int sz, unsigned int& written) +{ + const byte* pos = buf; + const byte* end = pos + sz; + + wouldBlock_ = false; + + /* Remove send()/recv() hooks once non-blocking send is implemented. */ + while (pos != end) { + int sent = send_func_(ptr_, pos, static_cast(end - pos)); + if (sent == -1) { + if (get_lastError() == SOCKET_EWOULDBLOCK || + get_lastError() == SOCKET_EAGAIN) { + wouldBlock_ = true; // would have blocked this time only + nonBlocking_ = true; // nonblocking, win32 only way to tell + return 0; + } + return static_cast(-1); + } + pos += sent; + written += sent; + } + + return sz; +} + + +uint Socket::receive(byte* buf, unsigned int sz) +{ + wouldBlock_ = false; + + int recvd = recv_func_(ptr_, buf, sz); + + // idea to seperate error from would block by arnetheduck@gmail.com + if (recvd == -1) { + if (get_lastError() == SOCKET_EWOULDBLOCK || + get_lastError() == SOCKET_EAGAIN) { + wouldBlock_ = true; // would have blocked this time only + nonBlocking_ = true; // socket nonblocking, win32 only way to tell + return 0; + } + } + else if (recvd == 0) + return static_cast(-1); + + return recvd; +} + + +void Socket::shutDown(int how) +{ + shutdown(socket_, how); +} + + +int Socket::get_lastError() +{ +#ifdef _WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + + +bool Socket::WouldBlock() const +{ + return wouldBlock_; +} + + +bool Socket::IsNonBlocking() const +{ + return nonBlocking_; +} + + +void Socket::set_lastError(int errorCode) +{ +#ifdef _WIN32 + WSASetLastError(errorCode); +#else + errno = errorCode; +#endif +} + + +} // namespace diff --git a/mysql/extra/yassl/src/ssl.cpp b/mysql/extra/yassl/src/ssl.cpp new file mode 100644 index 0000000..39244a0 --- /dev/null +++ b/mysql/extra/yassl/src/ssl.cpp @@ -0,0 +1,1883 @@ +/* + 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. +*/ + +/* SSL source implements all openssl compatibility API functions + * + * TODO: notes are mostly api additions to allow compilation with mysql + * they don't affect normal modes but should be provided for completeness + + * stunnel functions at end of file + */ + + + +/* see man pages for function descriptions */ + +#include "runtime.hpp" +#include "openssl/ssl.h" +#include "handshake.hpp" +#include "yassl_int.hpp" +#include "md5.hpp" // for TaoCrypt MD5 size assert +#include "md4.hpp" // for TaoCrypt MD4 size assert +#include "file.hpp" // for TaoCrypt Source +#include "coding.hpp" // HexDecoder +#include "helpers.hpp" // for placement new hack +#include "rsa.hpp" // for TaoCrypt RSA key decode +#include "dsa.hpp" // for TaoCrypt DSA key decode +#include + +#ifdef _WIN32 + #include // FindFirstFile etc.. +#else + #include // file helper + #include // stat + #include // opendir +#endif + + +namespace yaSSL { + + + +int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) +{ + int ret = SSL_SUCCESS; + + if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM) + return SSL_BAD_FILETYPE; + + if (file == NULL || !file[0]) + return SSL_BAD_FILE; + + FILE* input = fopen(file, "rb"); + if (!input) + return SSL_BAD_FILE; + + if (type == CA) { + // may have a bunch of CAs + x509* ptr; + while ( (ptr = PemToDer(input, Cert)) ) + ctx->AddCA(ptr); + + if (!feof(input)) { + fclose(input); + return SSL_BAD_FILE; + } + } + else { + x509*& x = (type == Cert) ? ctx->certificate_ : ctx->privateKey_; + + if (format == SSL_FILETYPE_ASN1) { + fseek(input, 0, SEEK_END); + long sz = ftell(input); + rewind(input); + x = NEW_YS x509(sz); // takes ownership + size_t bytes = fread(x->use_buffer(), sz, 1, input); + if (bytes != 1) { + fclose(input); + return SSL_BAD_FILE; + } + } + else { + EncryptedInfo info; + x = PemToDer(input, type, &info); + if (!x) { + fclose(input); + return SSL_BAD_FILE; + } + if (info.set) { + // decrypt + char password[80]; + pem_password_cb cb = ctx->GetPasswordCb(); + if (!cb) { + fclose(input); + return SSL_BAD_FILE; + } + int passwordSz = cb(password, sizeof(password), 0, + ctx->GetUserData()); + byte key[AES_256_KEY_SZ]; // max sizes + byte iv[AES_IV_SZ]; + + // use file's salt for key derivation, but not real iv + TaoCrypt::Source source(info.iv, info.ivSz); + TaoCrypt::HexDecoder dec(source); + memcpy(info.iv, source.get_buffer(), min((uint)sizeof(info.iv), + source.size())); + EVP_BytesToKey(info.name, "MD5", info.iv, (byte*)password, + passwordSz, 1, key, iv); + + mySTL::auto_ptr cipher; + if (strncmp(info.name, "DES-CBC", 7) == 0) + cipher.reset(NEW_YS DES); + else if (strncmp(info.name, "DES-EDE3-CBC", 13) == 0) + cipher.reset(NEW_YS DES_EDE); + else if (strncmp(info.name, "AES-128-CBC", 13) == 0) + cipher.reset(NEW_YS AES(AES_128_KEY_SZ)); + else if (strncmp(info.name, "AES-192-CBC", 13) == 0) + cipher.reset(NEW_YS AES(AES_192_KEY_SZ)); + else if (strncmp(info.name, "AES-256-CBC", 13) == 0) + cipher.reset(NEW_YS AES(AES_256_KEY_SZ)); + else { + fclose(input); + return SSL_BAD_FILE; + } + cipher->set_decryptKey(key, info.iv); + mySTL::auto_ptr newx(NEW_YS x509(x->get_length())); + cipher->decrypt(newx->use_buffer(), x->get_buffer(), + x->get_length()); + ysDelete(x); + x = newx.release(); + } + } + } + + if (type == PrivateKey && ctx->privateKey_) { + // see if key is valid early + TaoCrypt::Source rsaSource(ctx->privateKey_->get_buffer(), + ctx->privateKey_->get_length()); + TaoCrypt::RSA_PrivateKey rsaKey; + rsaKey.Initialize(rsaSource); + + if (rsaSource.GetError().What()) { + // rsa failed see if DSA works + + TaoCrypt::Source dsaSource(ctx->privateKey_->get_buffer(), + ctx->privateKey_->get_length()); + TaoCrypt::DSA_PrivateKey dsaKey; + dsaKey.Initialize(dsaSource); + + if (dsaSource.GetError().What()) { + // neither worked + ret = SSL_FAILURE; + } + } + } + + fclose(input); + return ret; +} + + +extern "C" { + + +SSL_METHOD* SSLv3_method() +{ + return SSLv3_client_method(); +} + + +SSL_METHOD* SSLv3_server_method() +{ + return NEW_YS SSL_METHOD(server_end, ProtocolVersion(3,0)); +} + + +SSL_METHOD* SSLv3_client_method() +{ + return NEW_YS SSL_METHOD(client_end, ProtocolVersion(3,0)); +} + + +SSL_METHOD* TLSv1_server_method() +{ + return NEW_YS SSL_METHOD(server_end, ProtocolVersion(3,1)); +} + + +SSL_METHOD* TLSv1_client_method() +{ + return NEW_YS SSL_METHOD(client_end, ProtocolVersion(3,1)); +} + + +SSL_METHOD* TLSv1_1_server_method() +{ + return NEW_YS SSL_METHOD(server_end, ProtocolVersion(3,2)); +} + + +SSL_METHOD* TLSv1_1_client_method() +{ + return NEW_YS SSL_METHOD(client_end, ProtocolVersion(3,2)); +} + + +SSL_METHOD* SSLv23_server_method() +{ + // compatibility only, no version 2 support, but does SSL 3 and TLS 1 + return NEW_YS SSL_METHOD(server_end, ProtocolVersion(3,2), true); +} + + +SSL_METHOD* SSLv23_client_method() +{ + // compatibility only, no version 2 support, but does SSL 3 and TLS 1 + // though it sends TLS1 hello not SSLv2 so SSLv3 only servers will decline + // TODO: maybe add support to send SSLv2 hello ??? + return NEW_YS SSL_METHOD(client_end, ProtocolVersion(3,2), true); +} + + +SSL_CTX* SSL_CTX_new(SSL_METHOD* method) +{ + return NEW_YS SSL_CTX(method); +} + + +void SSL_CTX_free(SSL_CTX* ctx) +{ + ysDelete(ctx); +} + + +SSL* SSL_new(SSL_CTX* ctx) +{ + return NEW_YS SSL(ctx); +} + + +void SSL_free(SSL* ssl) +{ + ysDelete(ssl); +} + + +int SSL_set_fd(SSL* ssl, YASSL_SOCKET_T fd) +{ + ssl->useSocket().set_fd(fd); + return SSL_SUCCESS; +} + + +YASSL_SOCKET_T SSL_get_fd(const SSL* ssl) +{ + return ssl->getSocket().get_fd(); +} + + +// if you get an error from connect see note at top of README +int SSL_connect(SSL* ssl) +{ + if (ssl->GetError() == YasslError(SSL_ERROR_WANT_READ)) + ssl->SetError(no_error); + + if (ssl->GetError() == YasslError(SSL_ERROR_WANT_WRITE)) { + + ssl->SetError(no_error); + ssl->SendWriteBuffered(); + if (!ssl->GetError()) + ssl->useStates().UseConnect() = + ConnectState(ssl->getStates().GetConnect() + 1); + } + + ClientState neededState; + + switch (ssl->getStates().GetConnect()) { + + case CONNECT_BEGIN : + sendClientHello(*ssl); + if (!ssl->GetError()) + ssl->useStates().UseConnect() = CLIENT_HELLO_SENT; + + case CLIENT_HELLO_SENT : + neededState = ssl->getSecurity().get_resuming() ? + serverFinishedComplete : serverHelloDoneComplete; + while (ssl->getStates().getClient() < neededState) { + if (ssl->GetError()) break; + processReply(*ssl); + // if resumption failed, reset needed state + if (neededState == serverFinishedComplete) + if (!ssl->getSecurity().get_resuming()) + neededState = serverHelloDoneComplete; + } + if (!ssl->GetError()) + ssl->useStates().UseConnect() = FIRST_REPLY_DONE; + + case FIRST_REPLY_DONE : + if(ssl->getCrypto().get_certManager().sendVerify()) + sendCertificate(*ssl); + + if (!ssl->getSecurity().get_resuming()) + sendClientKeyExchange(*ssl); + + if(ssl->getCrypto().get_certManager().sendVerify()) + sendCertificateVerify(*ssl); + + sendChangeCipher(*ssl); + sendFinished(*ssl, client_end); + ssl->flushBuffer(); + + if (!ssl->GetError()) + ssl->useStates().UseConnect() = FINISHED_DONE; + + case FINISHED_DONE : + if (!ssl->getSecurity().get_resuming()) + while (ssl->getStates().getClient() < serverFinishedComplete) { + if (ssl->GetError()) break; + processReply(*ssl); + } + if (!ssl->GetError()) + ssl->useStates().UseConnect() = SECOND_REPLY_DONE; + + case SECOND_REPLY_DONE : + ssl->verifyState(serverFinishedComplete); + ssl->useLog().ShowTCP(ssl->getSocket().get_fd()); + + if (ssl->GetError()) { + GetErrors().Add(ssl->GetError()); + return SSL_FATAL_ERROR; + } + return SSL_SUCCESS; + + default : + return SSL_FATAL_ERROR; // unkown state + } +} + + +int SSL_write(SSL* ssl, const void* buffer, int sz) +{ + return sendData(*ssl, buffer, sz); +} + + +int SSL_read(SSL* ssl, void* buffer, int sz) +{ + Data data(min(sz, MAX_RECORD_SIZE), static_cast(buffer)); + return receiveData(*ssl, data); +} + + +int SSL_accept(SSL* ssl) +{ + if (ssl->GetError() == YasslError(SSL_ERROR_WANT_READ)) + ssl->SetError(no_error); + + if (ssl->GetError() == YasslError(SSL_ERROR_WANT_WRITE)) { + + ssl->SetError(no_error); + ssl->SendWriteBuffered(); + if (!ssl->GetError()) + ssl->useStates().UseAccept() = + AcceptState(ssl->getStates().GetAccept() + 1); + } + + switch (ssl->getStates().GetAccept()) { + + case ACCEPT_BEGIN : + processReply(*ssl); + if (!ssl->GetError()) + ssl->useStates().UseAccept() = ACCEPT_FIRST_REPLY_DONE; + + case ACCEPT_FIRST_REPLY_DONE : + sendServerHello(*ssl); + + if (!ssl->getSecurity().get_resuming()) { + sendCertificate(*ssl); + + if (ssl->getSecurity().get_connection().send_server_key_) + sendServerKeyExchange(*ssl); + + if(ssl->getCrypto().get_certManager().verifyPeer()) + sendCertificateRequest(*ssl); + + sendServerHelloDone(*ssl); + ssl->flushBuffer(); + } + + if (!ssl->GetError()) + ssl->useStates().UseAccept() = SERVER_HELLO_DONE; + + case SERVER_HELLO_DONE : + if (!ssl->getSecurity().get_resuming()) { + while (ssl->getStates().getServer() < clientFinishedComplete) { + if (ssl->GetError()) break; + processReply(*ssl); + } + } + if (!ssl->GetError()) + ssl->useStates().UseAccept() = ACCEPT_SECOND_REPLY_DONE; + + case ACCEPT_SECOND_REPLY_DONE : + sendChangeCipher(*ssl); + sendFinished(*ssl, server_end); + ssl->flushBuffer(); + + if (!ssl->GetError()) + ssl->useStates().UseAccept() = ACCEPT_FINISHED_DONE; + + case ACCEPT_FINISHED_DONE : + if (ssl->getSecurity().get_resuming()) { + while (ssl->getStates().getServer() < clientFinishedComplete) { + if (ssl->GetError()) break; + processReply(*ssl); + } + } + if (!ssl->GetError()) + ssl->useStates().UseAccept() = ACCEPT_THIRD_REPLY_DONE; + + case ACCEPT_THIRD_REPLY_DONE : + ssl->useLog().ShowTCP(ssl->getSocket().get_fd()); + + if (ssl->GetError()) { + GetErrors().Add(ssl->GetError()); + return SSL_FATAL_ERROR; + } + return SSL_SUCCESS; + + default: + return SSL_FATAL_ERROR; // unknown state + } +} + + +int SSL_do_handshake(SSL* ssl) +{ + if (ssl->getSecurity().get_parms().entity_ == client_end) + return SSL_connect(ssl); + else + return SSL_accept(ssl); +} + + +int SSL_clear(SSL* ssl) +{ + GetErrors().Remove(); + + return SSL_SUCCESS; +} + + +int SSL_shutdown(SSL* ssl) +{ + if (!ssl->GetQuietShutdown()) { + Alert alert(warning, close_notify); + sendAlert(*ssl, alert); + } + ssl->useLog().ShowTCP(ssl->getSocket().get_fd(), true); + + GetErrors().Remove(); + + return SSL_SUCCESS; +} + + +void SSL_set_quiet_shutdown(SSL *ssl,int mode) +{ + ssl->SetQuietShutdown(mode != 0); +} + + +int SSL_get_quiet_shutdown(SSL *ssl) +{ + return ssl->GetQuietShutdown(); +} + + +/* on by default but allow user to turn off */ +long SSL_CTX_set_session_cache_mode(SSL_CTX* ctx, long mode) +{ + if (mode == SSL_SESS_CACHE_OFF) + ctx->SetSessionCacheOff(); + + if (mode == SSL_SESS_CACHE_NO_AUTO_CLEAR) + ctx->SetSessionCacheFlushOff(); + + return SSL_SUCCESS; +} + + +SSL_SESSION* SSL_get_session(SSL* ssl) +{ + if (ssl->getSecurity().GetContext()->GetSessionCacheOff()) + return 0; + + return GetSessions().lookup( + ssl->getSecurity().get_connection().sessionID_); +} + + +int SSL_set_session(SSL* ssl, SSL_SESSION* session) +{ + if (ssl->getSecurity().GetContext()->GetSessionCacheOff()) + return SSL_FAILURE; + + ssl->set_session(session); + return SSL_SUCCESS; +} + + +int SSL_session_reused(SSL* ssl) +{ + return ssl->getSecurity().get_resuming(); +} + + +long SSL_SESSION_set_timeout(SSL_SESSION* sess, long t) +{ + if (!sess) + return SSL_ERROR_NONE; + + sess->SetTimeOut(t); + return SSL_SUCCESS; +} + + +long SSL_get_default_timeout(SSL* /*ssl*/) +{ + return DEFAULT_TIMEOUT; +} + + +void SSL_flush_sessions(SSL_CTX *ctx, long /* tm */) +{ + if (ctx->GetSessionCacheOff()) + return; + + GetSessions().Flush(); +} + + +const char* SSL_get_cipher_name(SSL* ssl) +{ + return SSL_get_cipher(ssl); +} + + +const char* SSL_get_cipher(SSL* ssl) +{ + return ssl->getSecurity().get_parms().cipher_name_; +} + + +// SSLv2 only, not implemented +char* SSL_get_shared_ciphers(SSL* /*ssl*/, char* buf, int len) +{ + return strncpy(buf, "Not Implemented, SSLv2 only", len); +} + + +const char* SSL_get_cipher_list(SSL* ssl, int priority) +{ + if (priority < 0 || priority >= MAX_CIPHERS) + return 0; + + if (ssl->getSecurity().get_parms().cipher_list_[priority][0]) + return ssl->getSecurity().get_parms().cipher_list_[priority]; + + return 0; +} + + +int SSL_CTX_set_cipher_list(SSL_CTX* ctx, const char* list) +{ + if (ctx->SetCipherList(list)) + return SSL_SUCCESS; + else + return SSL_FAILURE; +} + + +const char* SSL_get_version(SSL* ssl) +{ + static const char* version3 = "SSLv3"; + static const char* version31 = "TLSv1"; + static const char* version32 = "TLSv1.1"; + + if (ssl->isTLSv1_1()) + return version32; + else if(ssl->isTLS()) + return version31; + else + return version3; +} + +const char* SSLeay_version(int) +{ + static const char* version = "SSLeay yaSSL compatibility"; + return version; +} + + +int SSL_get_error(SSL* ssl, int /*previous*/) +{ + return ssl->getStates().What(); +} + + + +/* turn on yaSSL zlib compression + returns 0 for success, else error (not built in) + only need to turn on for client, becuase server on by default if built in + but calling for server will tell you whether it's available or not +*/ +int SSL_set_compression(SSL* ssl) /* Chad didn't rename to ya~ because it is prob. bug. */ +{ + return ssl->SetCompression(); +} + + + +X509* X509_Copy(X509 *x) +{ + if (x == 0) return NULL; + + X509_NAME* issuer = x->GetIssuer(); + X509_NAME* subject = x->GetSubject(); + ASN1_TIME* before = x->GetBefore(); + ASN1_TIME* after = x->GetAfter(); + + X509 *newX509 = NEW_YS X509(issuer->GetName(), issuer->GetLength(), + subject->GetName(), subject->GetLength(), + before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); + + return newX509; +} + +X509* SSL_get_peer_certificate(SSL* ssl) +{ + return X509_Copy(ssl->getCrypto().get_certManager().get_peerX509()); +} + + +void X509_free(X509* x) +{ + ysDelete(x); +} + + +X509* X509_STORE_CTX_get_current_cert(X509_STORE_CTX* ctx) +{ + return ctx->current_cert; +} + + +int X509_STORE_CTX_get_error(X509_STORE_CTX* ctx) +{ + return ctx->error; +} + + +int X509_STORE_CTX_get_error_depth(X509_STORE_CTX* ctx) +{ + return ctx->error_depth; +} + +X509* PEM_read_X509(FILE *fp, X509 *x, + pem_password_cb cb, + void *u) +{ + if (fp == NULL) + return NULL; + + // Get x509 handle and encryption information + x509* ptr = PemToDer(fp, Cert); + if (!ptr) + return NULL; + + // Now decode x509 object. + TaoCrypt::SignerList signers; + TaoCrypt::Source source(ptr->get_buffer(), ptr->get_length()); + TaoCrypt::CertDecoder cert(source, true, &signers, true, TaoCrypt::CertDecoder::CA); + + if (cert.GetError().What()) { + ysDelete(ptr); + return NULL; + } + + // Ok. Now create X509 object. + size_t iSz = strlen(cert.GetIssuer()) + 1; + size_t sSz = strlen(cert.GetCommonName()) + 1; + ASN1_STRING beforeDate, afterDate; + beforeDate.data = (unsigned char *) cert.GetBeforeDate(); + beforeDate.type = cert.GetBeforeDateType(); + beforeDate.length = strlen((char *) beforeDate.data) + 1; + afterDate.data = (unsigned char *) cert.GetAfterDate(); + afterDate.type = cert.GetAfterDateType(); + afterDate.length = strlen((char *) afterDate.data) + 1; + + X509 *thisX509 = NEW_YS X509(cert.GetIssuer(), iSz, cert.GetCommonName(), + sSz, &beforeDate, &afterDate, + cert.GetIssuerCnStart(), cert.GetIssuerCnLength(), + cert.GetSubjectCnStart(), cert.GetSubjectCnLength()); + + + ysDelete(ptr); + return thisX509; +} + +// copy name into buffer, at most sz bytes, if buffer is null +// will malloc buffer, caller responsible for freeing +char* X509_NAME_oneline(X509_NAME* name, char* buffer, int sz) +{ + if (!name->GetName()) return buffer; + + int len = (int)strlen(name->GetName()) + 1; + int copySz = min(len, sz); + + if (!buffer) { + buffer = (char*)malloc(len); + if (!buffer) return buffer; + copySz = len; + } + + if (copySz == 0) + return buffer; + + memcpy(buffer, name->GetName(), copySz - 1); + buffer[copySz - 1] = 0; + + return buffer; +} + + +X509_NAME* X509_get_issuer_name(X509* x) +{ + return x->GetIssuer(); +} + + +X509_NAME* X509_get_subject_name(X509* x) +{ + return x->GetSubject(); +} + + +void SSL_load_error_strings() // compatibility only +{} + + +void SSL_set_connect_state(SSL*) +{ + // already a client by default +} + + +void SSL_set_accept_state(SSL* ssl) +{ + ssl->useSecurity().use_parms().entity_ = server_end; +} + + +long SSL_get_verify_result(SSL*) +{ + // won't get here if not OK + return X509_V_OK; +} + + +long SSL_CTX_sess_set_cache_size(SSL_CTX* /*ctx*/, long /*sz*/) +{ + // unlimited size, can't set for now + return 0; +} + + +long SSL_CTX_get_session_cache_mode(SSL_CTX*) +{ + // always 0, unlimited size for now + return 0; +} + + +long SSL_CTX_set_tmp_dh(SSL_CTX* ctx, DH* dh) +{ + if (ctx->SetDH(*dh)) + return SSL_SUCCESS; + else + return SSL_FAILURE; +} + + +int SSL_CTX_use_certificate_file(SSL_CTX* ctx, const char* file, int format) +{ + return read_file(ctx, file, format, Cert); +} + + +int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx, const char* file, int format) +{ + return read_file(ctx, file, format, PrivateKey); +} + + +void SSL_CTX_set_verify(SSL_CTX* ctx, int mode, VerifyCallback vc) +{ + if (mode & SSL_VERIFY_PEER) + ctx->setVerifyPeer(); + + if (mode == SSL_VERIFY_NONE) + ctx->setVerifyNone(); + + if (mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + ctx->setFailNoCert(); + + ctx->setVerifyCallback(vc); +} + + +int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, + const char* path) +{ + int ret = SSL_FAILURE; + const int HALF_PATH = 128; + + if (file) ret = read_file(ctx, file, SSL_FILETYPE_PEM, CA); + + if (ret == SSL_SUCCESS && path) { + // call read_file for each reqular file in path +#ifdef _WIN32 + + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + + const int DELIMITER_SZ = 2; + const int DELIMITER_STAR_SZ = 3; + int pathSz = (int)strlen(path); + int nameSz = pathSz + DELIMITER_STAR_SZ + 1; // plus 1 for terminator + char* name = NEW_YS char[nameSz]; // directory specification + memset(name, 0, nameSz); + strncpy(name, path, nameSz - DELIMITER_STAR_SZ - 1); + strncat(name, "\\*", DELIMITER_STAR_SZ); + + hFind = FindFirstFile(name, &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) { + ysArrayDelete(name); + return SSL_BAD_PATH; + } + + do { + if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + int curSz = (int)strlen(FindFileData.cFileName); + if (pathSz + curSz + DELIMITER_SZ + 1 > nameSz) { + ysArrayDelete(name); + // plus 1 for terminator + nameSz = pathSz + curSz + DELIMITER_SZ + 1; + name = NEW_YS char[nameSz]; + } + memset(name, 0, nameSz); + strncpy(name, path, nameSz - curSz - DELIMITER_SZ - 1); + strncat(name, "\\", DELIMITER_SZ); + strncat(name, FindFileData.cFileName, + nameSz - pathSz - DELIMITER_SZ - 1); + ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); + } + } while (ret == SSL_SUCCESS && FindNextFile(hFind, &FindFileData)); + + ysArrayDelete(name); + FindClose(hFind); + +#else // _WIN32 + DIR* dir = opendir(path); + if (!dir) return SSL_BAD_PATH; + + struct dirent* entry; + struct stat buf; + const int DELIMITER_SZ = 1; + int pathSz = (int)strlen(path); + int nameSz = pathSz + DELIMITER_SZ + 1; //plus 1 for null terminator + char* name = NEW_YS char[nameSz]; // directory specification + + while (ret == SSL_SUCCESS && (entry = readdir(dir))) { + int curSz = (int)strlen(entry->d_name); + if (pathSz + curSz + DELIMITER_SZ + 1 > nameSz) { + ysArrayDelete(name); + nameSz = pathSz + DELIMITER_SZ + curSz + 1; + name = NEW_YS char[nameSz]; + } + memset(name, 0, nameSz); + strncpy(name, path, nameSz - curSz - 1); + strncat(name, "/", DELIMITER_SZ); + strncat(name, entry->d_name, nameSz - pathSz - DELIMITER_SZ - 1); + + if (stat(name, &buf) < 0) { + ysArrayDelete(name); + closedir(dir); + return SSL_BAD_STAT; + } + + if (S_ISREG(buf.st_mode)) + ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); + } + + ysArrayDelete(name); + closedir(dir); + +#endif + } + + return ret; +} + + +int SSL_CTX_set_default_verify_paths(SSL_CTX* /*ctx*/) +{ + // TODO: figure out way to set/store default path, then call load_verify + return SSL_NOT_IMPLEMENTED; +} + + +int SSL_CTX_set_session_id_context(SSL_CTX*, const unsigned char*, + unsigned int) +{ + // No application specific context needed for yaSSL + return SSL_SUCCESS; +} + + +int SSL_CTX_check_private_key(SSL_CTX* /*ctx*/) +{ + // TODO: check private against public for RSA match + return SSL_NOT_IMPLEMENTED; +} + + +// TODO: all session stats +long SSL_CTX_sess_accept(SSL_CTX* ctx) +{ + return ctx->GetStats().accept_; +} + + +long SSL_CTX_sess_connect(SSL_CTX* ctx) +{ + return ctx->GetStats().connect_; +} + + +long SSL_CTX_sess_accept_good(SSL_CTX* ctx) +{ + return ctx->GetStats().acceptGood_; +} + + +long SSL_CTX_sess_connect_good(SSL_CTX* ctx) +{ + return ctx->GetStats().connectGood_; +} + + +long SSL_CTX_sess_accept_renegotiate(SSL_CTX* ctx) +{ + return ctx->GetStats().acceptRenegotiate_; +} + + +long SSL_CTX_sess_connect_renegotiate(SSL_CTX* ctx) +{ + return ctx->GetStats().connectRenegotiate_; +} + + +long SSL_CTX_sess_hits(SSL_CTX* ctx) +{ + return ctx->GetStats().hits_; +} + + +long SSL_CTX_sess_cb_hits(SSL_CTX* ctx) +{ + return ctx->GetStats().cbHits_; +} + + +long SSL_CTX_sess_cache_full(SSL_CTX* ctx) +{ + return ctx->GetStats().cacheFull_; +} + + +long SSL_CTX_sess_misses(SSL_CTX* ctx) +{ + return ctx->GetStats().misses_; +} + + +long SSL_CTX_sess_timeouts(SSL_CTX* ctx) +{ + return ctx->GetStats().timeouts_; +} + + +long SSL_CTX_sess_number(SSL_CTX* ctx) +{ + return ctx->GetStats().number_; +} + + +long SSL_CTX_sess_get_cache_size(SSL_CTX* ctx) +{ + return ctx->GetStats().getCacheSize_; +} +// end session stats TODO: + + +int SSL_CTX_get_verify_mode(SSL_CTX* ctx) +{ + return ctx->GetStats().verifyMode_; +} + + +int SSL_get_verify_mode(SSL* ssl) +{ + return ssl->getSecurity().GetContext()->GetStats().verifyMode_; +} + + +int SSL_CTX_get_verify_depth(SSL_CTX* ctx) +{ + return ctx->GetStats().verifyDepth_; +} + + +int SSL_get_verify_depth(SSL* ssl) +{ + return ssl->getSecurity().GetContext()->GetStats().verifyDepth_; +} + + +long SSL_CTX_set_options(SSL_CTX* ctx, long options) +{ + ProtocolVersion pv= ctx->getMethod()->getVersion(); + bool multi_proto= ctx->getMethod()->multipleProtocol(); + unsigned long ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1; + + do + { + if (options == 0) + break; + // only TLSv1.1 + if ((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 2; + multi_proto= false; + break; + } + // only TLSv1 + ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1; + if((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 1; + multi_proto= false; + break; + } + // TLSv1.1 and TLSv1 + ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + if((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 2; + multi_proto= true; + break; + } + }while(0); + + SSL_METHOD *meth= NEW_YS SSL_METHOD(ctx->getMethod()->getSide(), ProtocolVersion(3,pv.minor_), multi_proto); + ctx->SetMethod(meth); + return SSL_SUCCESS; +} + + +void SSL_CTX_set_info_callback(SSL_CTX*, void (*)()) +{ + // TDOD: +} + + +void OpenSSL_add_all_algorithms() // compatibility only +{} + + +int SSL_library_init() // compatiblity only +{ + return 1; +} + + +DH* DH_new(void) +{ + DH* dh = NEW_YS DH; + if (dh) + dh->p = dh->g = 0; + return dh; +} + + +void DH_free(DH* dh) +{ + ysDelete(dh->g); + ysDelete(dh->p); + ysDelete(dh); +} + + +// convert positive big-endian num of length sz into retVal, which may need to +// be created +BIGNUM* BN_bin2bn(const unsigned char* num, int sz, BIGNUM* retVal) +{ + bool created = false; + mySTL::auto_ptr bn; + + if (!retVal) { + created = true; + bn.reset(NEW_YS BIGNUM); + retVal = bn.get(); + } + + retVal->assign(num, sz); + + if (created) + return bn.release(); + else + return retVal; +} + + +unsigned long ERR_get_error_line_data(const char**, int*, const char**, int *) +{ + //return SSL_NOT_IMPLEMENTED; + return 0; +} + + +void ERR_print_errors_fp(FILE* /*fp*/) +{ + // need ssl access to implement TODO: + //fprintf(fp, "%s", ssl.get_states().errorString_.c_str()); +} + + +char* ERR_error_string(unsigned long errNumber, char* buffer) +{ + static char* msg = (char*)"Please supply a buffer for error string"; + + if (buffer) { + SetErrorString(YasslError(errNumber), buffer); + return buffer; + } + + return msg; +} + + +const char* X509_verify_cert_error_string(long /* error */) +{ + // TODO: + static const char* msg = "Not Implemented"; + return msg; +} + + +const EVP_MD* EVP_md5(void) +{ + static const char* type = "MD5"; + return type; +} + + +const EVP_CIPHER* EVP_des_ede3_cbc(void) +{ + static const char* type = "DES-EDE3-CBC"; + return type; +} + + +int EVP_BytesToKey(const EVP_CIPHER* type, const EVP_MD* md, const byte* salt, + const byte* data, int sz, int count, byte* key, byte* iv) +{ + // only support MD5 for now + if (strncmp(md, "MD5", 3)) return 0; + + int keyLen = 0; + int ivLen = 0; + + // only support CBC DES and AES for now + if (strncmp(type, "DES-CBC", 7) == 0) { + keyLen = DES_KEY_SZ; + ivLen = DES_IV_SZ; + } + else if (strncmp(type, "DES-EDE3-CBC", 12) == 0) { + keyLen = DES_EDE_KEY_SZ; + ivLen = DES_IV_SZ; + } + else if (strncmp(type, "AES-128-CBC", 11) == 0) { + keyLen = AES_128_KEY_SZ; + ivLen = AES_IV_SZ; + } + else if (strncmp(type, "AES-192-CBC", 11) == 0) { + keyLen = AES_192_KEY_SZ; + ivLen = AES_IV_SZ; + } + else if (strncmp(type, "AES-256-CBC", 11) == 0) { + keyLen = AES_256_KEY_SZ; + ivLen = AES_IV_SZ; + } + else + return 0; + + yaSSL::MD5 myMD; + uint digestSz = myMD.get_digestSize(); + byte digest[SHA_LEN]; // max size + + int keyLeft = keyLen; + int ivLeft = ivLen; + int keyOutput = 0; + + while (keyOutput < (keyLen + ivLen)) { + int digestLeft = digestSz; + // D_(i - 1) + if (keyOutput) // first time D_0 is empty + myMD.update(digest, digestSz); + // data + myMD.update(data, sz); + // salt + if (salt) + myMD.update(salt, EVP_SALT_SZ); + myMD.get_digest(digest); + // count + for (int j = 1; j < count; j++) { + myMD.update(digest, digestSz); + myMD.get_digest(digest); + } + + if (keyLeft) { + int store = min(keyLeft, static_cast(digestSz)); + memcpy(&key[keyLen - keyLeft], digest, store); + + keyOutput += store; + keyLeft -= store; + digestLeft -= store; + } + + if (ivLeft && digestLeft) { + int store = min(ivLeft, digestLeft); + memcpy(&iv[ivLen - ivLeft], &digest[digestSz - digestLeft], store); + + keyOutput += store; + ivLeft -= store; + } + } + return keyOutput; +} + + + +void DES_set_key_unchecked(const_DES_cblock* key, DES_key_schedule* schedule) +{ + memcpy(schedule, key, sizeof(const_DES_cblock)); +} + + +void DES_ede3_cbc_encrypt(const byte* input, byte* output, long sz, + DES_key_schedule* ks1, DES_key_schedule* ks2, + DES_key_schedule* ks3, DES_cblock* ivec, int enc) +{ + DES_EDE des; + byte key[DES_EDE_KEY_SZ]; + + memcpy(key, *ks1, DES_BLOCK); + memcpy(&key[DES_BLOCK], *ks2, DES_BLOCK); + memcpy(&key[DES_BLOCK * 2], *ks3, DES_BLOCK); + + if (enc) { + des.set_encryptKey(key, *ivec); + des.encrypt(output, input, sz); + } + else { + des.set_decryptKey(key, *ivec); + des.decrypt(output, input, sz); + } +} + + +// functions for libcurl +int RAND_status() +{ + return 1; /* TaoCrypt provides enough seed */ +} + + +int DES_set_key(const_DES_cblock* key, DES_key_schedule* schedule) +{ + memcpy(schedule, key, sizeof(const_DES_cblock)); + return 1; +} + + +void DES_set_odd_parity(DES_cblock* key) +{ + // not needed now for TaoCrypt +} + + +void DES_ecb_encrypt(DES_cblock* input, DES_cblock* output, + DES_key_schedule* key, int enc) +{ + DES des; + + if (enc) { + des.set_encryptKey(*key, 0); + des.encrypt(*output, *input, DES_BLOCK); + } + else { + des.set_decryptKey(*key, 0); + des.decrypt(*output, *input, DES_BLOCK); + } +} + + +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX* ctx, void* userdata) +{ + ctx->SetUserData(userdata); +} + + +X509* SSL_get_certificate(SSL* ssl) +{ + return ssl->getCrypto().get_certManager().get_selfX509(); +} + + +EVP_PKEY* SSL_get_privatekey(SSL* ssl) +{ + // only called, not used + return 0; +} + + +void SSL_SESSION_free(SSL_SESSION* session) +{ + // managed by singleton +} + + + +EVP_PKEY* X509_get_pubkey(X509* x) +{ + // called, not used though + return 0; +} + + +int EVP_PKEY_copy_parameters(EVP_PKEY* to, const EVP_PKEY* from) +{ + // called, not used though + return 0; +} + + +void EVP_PKEY_free(EVP_PKEY* pkey) +{ + // never allocated from above +} + + +void ERR_error_string_n(unsigned long e, char *buf, size_t len) +{ + if (len) ERR_error_string(e, buf); +} + + +void ERR_free_strings(void) +{ + // handled internally +} + + +void EVP_cleanup(void) +{ + // nothing to do yet +} + + +ASN1_TIME* X509_get_notBefore(X509* x) +{ + if (x) return x->GetBefore(); + return 0; +} + + +ASN1_TIME* X509_get_notAfter(X509* x) +{ + if (x) return x->GetAfter(); + return 0; +} + + +SSL_METHOD* SSLv2_client_method(void) /* will never work, no v 2 */ +{ + return 0; +} + + +SSL_SESSION* SSL_get1_session(SSL* ssl) /* what's ref count */ +{ + return SSL_get_session(ssl); +} + + +void GENERAL_NAMES_free(STACK_OF(GENERAL_NAME) *x) +{ + // no extension names supported yet +} + + +int sk_GENERAL_NAME_num(STACK_OF(GENERAL_NAME) *x) +{ + // no extension names supported yet + return 0; +} + + +GENERAL_NAME* sk_GENERAL_NAME_value(STACK_OF(GENERAL_NAME) *x, int i) +{ + // no extension names supported yet + return 0; +} + + +unsigned char* ASN1_STRING_data(ASN1_STRING* x) +{ + if (x) return x->data; + return 0; +} + + +int ASN1_STRING_length(ASN1_STRING* x) +{ + if (x) return x->length; + return 0; +} + + +int ASN1_STRING_type(ASN1_STRING *x) +{ + if (x) return x->type; + return 0; +} + + +int X509_NAME_get_index_by_NID(X509_NAME* name,int nid, int lastpos) +{ + int idx = -1; // not found + int cnPos = -1; + + switch (nid) { + case NID_commonName: + cnPos = name->GetCnPosition(); + if (lastpos < cnPos) + idx = cnPos; + break; + } + + return idx; +} + + +ASN1_STRING* X509_NAME_ENTRY_get_data(X509_NAME_ENTRY* ne) +{ + // the same in yaSSL + return ne; +} + + +X509_NAME_ENTRY* X509_NAME_get_entry(X509_NAME* name, int loc) +{ + return name->GetEntry(loc); +} + + +// already formatted, caller responsible for freeing *out +int ASN1_STRING_to_UTF8(unsigned char** out, ASN1_STRING* in) +{ + if (!in) return 0; + + *out = (unsigned char*)malloc(in->length + 1); + if (*out) { + memcpy(*out, in->data, in->length); + (*out)[in->length] = 0; + } + return in->length; +} + + +void* X509_get_ext_d2i(X509* x, int nid, int* crit, int* idx) +{ + // no extensions supported yet + return 0; +} + + +void MD4_Init(MD4_CTX* md4) +{ + // make sure we have a big enough buffer + typedef char ok[sizeof(md4->buffer) >= sizeof(TaoCrypt::MD4) ? 1 : -1]; + (void) sizeof(ok); + + // using TaoCrypt since no dynamic memory allocated + // and no destructor will be called + new (reinterpret_cast(md4->buffer)) TaoCrypt::MD4(); +} + + +void MD4_Update(MD4_CTX* md4, const void* data, unsigned long sz) +{ + reinterpret_cast(md4->buffer)->Update( + static_cast(data), static_cast(sz)); +} + + +void MD4_Final(unsigned char* hash, MD4_CTX* md4) +{ + reinterpret_cast(md4->buffer)->Final(hash); +} + + +void MD5_Init(MD5_CTX* md5) +{ + // make sure we have a big enough buffer + typedef char ok[sizeof(md5->buffer) >= sizeof(TaoCrypt::MD5) ? 1 : -1]; + (void) sizeof(ok); + + // using TaoCrypt since no dynamic memory allocated + // and no destructor will be called + new (reinterpret_cast(md5->buffer)) TaoCrypt::MD5(); +} + + +void MD5_Update(MD5_CTX* md5, const void* data, unsigned long sz) +{ + reinterpret_cast(md5->buffer)->Update( + static_cast(data), static_cast(sz)); +} + + +void MD5_Final(unsigned char* hash, MD5_CTX* md5) +{ + reinterpret_cast(md5->buffer)->Final(hash); +} + + +int RAND_bytes(unsigned char* buf, int num) +{ + RandomPool ran; + + if (ran.GetError()) return 0; + + ran.Fill(buf, num); + return 1; +} + + +int SSL_peek(SSL* ssl, void* buffer, int sz) +{ + Data data(min(sz, MAX_RECORD_SIZE), static_cast(buffer)); + return receiveData(*ssl, data, true); +} + + +int SSL_pending(SSL* ssl) +{ + // Just in case there's pending data that hasn't been processed yet... + char c; + SSL_peek(ssl, &c, 1); + + return ssl->bufferedData(); +} + + +void SSL_CTX_set_default_passwd_cb(SSL_CTX* ctx, pem_password_cb cb) +{ + ctx->SetPasswordCb(cb); +} + + +int SSLeay_add_ssl_algorithms() // compatibility only +{ + return 1; +} + + +void ERR_remove_state(unsigned long) +{ + GetErrors().Remove(); +} + + +int ERR_GET_REASON(int l) +{ + return l & 0xfff; +} + + +unsigned long err_helper(bool peek = false) +{ + int ysError = GetErrors().Lookup(peek); + + // translate cert error for libcurl, it uses OpenSSL hex code + switch (ysError) { + case TaoCrypt::SIG_OTHER_E: + return CERTFICATE_ERROR; + break; + default : + return 0; + } + + return 0; // shut up compiler +} + + +unsigned long ERR_peek_error() +{ + return err_helper(true); +} + + +unsigned long ERR_get_error() +{ + return err_helper(); +} + + + // functions for stunnel + + void RAND_screen() + { + // TODO: + } + + + const char* RAND_file_name(char*, size_t) + { + // TODO: + return 0; + } + + + int RAND_write_file(const char*) + { + // TODO: + return 0; + } + + + int RAND_load_file(const char*, long) + { + // TODO: + return 0; + } + + + void RSA_free(RSA*) + { + // TODO: + } + + + RSA* RSA_generate_key(int, unsigned long, void(*)(int, int, void*), void*) + { + // TODO: + return 0; + } + + + int X509_LOOKUP_add_dir(X509_LOOKUP*, const char*, long) + { + // TODO: + return SSL_SUCCESS; + } + + + int X509_LOOKUP_load_file(X509_LOOKUP*, const char*, long) + { + // TODO: + return SSL_SUCCESS; + } + + + X509_LOOKUP_METHOD* X509_LOOKUP_hash_dir(void) + { + // TODO: + return 0; + } + + + X509_LOOKUP_METHOD* X509_LOOKUP_file(void) + { + // TODO: + return 0; + } + + + X509_LOOKUP* X509_STORE_add_lookup(X509_STORE*, X509_LOOKUP_METHOD*) + { + // TODO: + return 0; + } + + + int X509_STORE_get_by_subject(X509_STORE_CTX*, int, X509_NAME*, X509_OBJECT*) + { + // TODO: + return SSL_SUCCESS; + } + + + X509_STORE* X509_STORE_new(void) + { + // TODO: + return 0; + } + + char* SSL_alert_type_string_long(int) + { + // TODO: + return 0; + } + + + char* SSL_alert_desc_string_long(int) + { + // TODO: + return 0; + } + + + char* SSL_state_string_long(SSL*) + { + // TODO: + return 0; + } + + + void SSL_CTX_set_tmp_rsa_callback(SSL_CTX*, RSA*(*)(SSL*, int, int)) + { + // TDOD: + } + + + long SSL_CTX_set_timeout(SSL_CTX*, long) + { + // TDOD: + return SSL_SUCCESS; + } + + + int SSL_CTX_use_certificate_chain_file(SSL_CTX*, const char*) + { + // TDOD: + return SSL_SUCCESS; + } + + + int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX*, const char*, int) + { + // TDOD: + return SSL_SUCCESS; + } + + + int SSL_set_rfd(SSL*, int) + { + return SSL_SUCCESS; // TODO: + } + + + int SSL_set_wfd(SSL*, int) + { + return SSL_SUCCESS; // TODO: + } + + + int SSL_want_read(SSL*) + { + return 0; // TODO: + } + + + int SSL_want_write(SSL*) + { + return 0; // TODO: + } + + + void SSL_set_shutdown(SSL*, int) + { + // TODO: + } + + + SSL_CIPHER* SSL_get_current_cipher(SSL*) + { + // TODO: + return 0; + } + + + char* SSL_CIPHER_description(SSL_CIPHER*, char*, int) + { + // TODO: + return 0; + } + + + + // end stunnel needs + + char *yaSSL_ASN1_TIME_to_string(ASN1_TIME *time, char *buf, size_t len) + { + tm t; + static const char *month_names[12]= + { + "Jan","Feb","Mar","Apr","May","Jun", + "Jul","Aug","Sep","Oct","Nov","Dec" + }; + + TaoCrypt::ASN1_TIME_extract(time->data, time->type, &t); +#ifdef _WIN32 + _snprintf(buf, len, "%s %2d %02d:%02d:%02d %d GMT", +#else + snprintf(buf, len, "%s %2d %02d:%02d:%02d %d GMT", +#endif + month_names[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min, + t.tm_sec, t.tm_year + 1900); + return buf; + } + + + void yaSSL_transport_set_ptr(SSL *ssl, void *ptr) + { + ssl->useSocket().set_transport_ptr(ptr); + } + + + void yaSSL_transport_set_recv_function(SSL *ssl, yaSSL_recv_func_t func) + { + ssl->useSocket().set_transport_recv_function(func); + } + + + void yaSSL_transport_set_send_function(SSL *ssl, yaSSL_send_func_t func) + { + ssl->useSocket().set_transport_send_function(func); + } + +} // extern "C" +} // namespace diff --git a/mysql/extra/yassl/src/timer.cpp b/mysql/extra/yassl/src/timer.cpp new file mode 100644 index 0000000..a1b9063 --- /dev/null +++ b/mysql/extra/yassl/src/timer.cpp @@ -0,0 +1,80 @@ +/* + Copyright (c) 2000, 2012, 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. +*/ + +/* timer.cpp implements a high res and low res timer + * +*/ + +#include "runtime.hpp" +#include "timer.hpp" + +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace yaSSL { + +#ifdef _WIN32 + + timer_d timer() + { + static bool init(false); + static LARGE_INTEGER freq; + + if (!init) { + QueryPerformanceFrequency(&freq); + init = true; + } + + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + + return static_cast(count.QuadPart) / freq.QuadPart; + } + + + uint lowResTimer() + { + return static_cast(timer()); + } + +#else // _WIN32 + + timer_d timer() + { + struct timeval tv; + gettimeofday(&tv, 0); + + return static_cast(tv.tv_sec) + + static_cast(tv.tv_usec) / 1000000; + } + + + uint lowResTimer() + { + struct timeval tv; + gettimeofday(&tv, 0); + + return tv.tv_sec; + } + + +#endif // _WIN32 +} // namespace yaSSL diff --git a/mysql/extra/yassl/src/yassl_error.cpp b/mysql/extra/yassl/src/yassl_error.cpp new file mode 100644 index 0000000..5169b7d --- /dev/null +++ b/mysql/extra/yassl/src/yassl_error.cpp @@ -0,0 +1,288 @@ +/* + Copyright (c) 2005, 2013, 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 error implements and an exception class + */ + +#include "runtime.hpp" +#include "yassl_error.hpp" +#include "error.hpp" // TaoCrypt error numbers +#include "openssl/ssl.h" // SSL_ERROR_WANT_READ +#include // strncpy + +#ifdef _MSC_VER + // 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy + #pragma warning(disable: 4996) +#endif + +namespace yaSSL { + + +/* may bring back in future +Error::Error(const char* s, YasslError e, Library l) + : mySTL::runtime_error(s), error_(e), lib_(l) +{ +} + + +YasslError Error::get_number() const +{ + return error_; +} + + +Library Error::get_lib() const +{ + + return lib_; +} +*/ + + +void SetErrorString(YasslError error, char* buffer) +{ + using namespace TaoCrypt; + const int max = MAX_ERROR_SZ; // shorthand + int localError = error; // errors from a few enums + + switch (localError) { + + // yaSSL proper errors + case range_error : + strncpy(buffer, "buffer index error, out of range", max); + break; + + case realloc_error : + strncpy(buffer, "trying to realloc a fixed buffer", max); + break; + + case factory_error : + strncpy(buffer, "unknown factory create request", max); + break; + + case unknown_cipher : + strncpy(buffer, "trying to use an unknown cipher", max); + break; + + case prefix_error : + strncpy(buffer, "bad master secret derivation, prefix too big", max); + break; + + case record_layer : + strncpy(buffer, "record layer not ready yet", max); + break; + + case handshake_layer : + strncpy(buffer, "handshake layer not ready yet", max); + break; + + case out_of_order : + strncpy(buffer, "handshake message received in wrong order", max); + break; + + case bad_input : + strncpy(buffer, "bad cipher suite input", max); + break; + + case match_error : + strncpy(buffer, "unable to match a supported cipher suite", max); + break; + + case no_key_file : + strncpy(buffer, "the server needs a private key file", max); + break; + + case verify_error : + strncpy(buffer, "unable to verify peer checksum", max); + break; + + case send_error : + strncpy(buffer, "socket layer send error", max); + break; + + case receive_error : + strncpy(buffer, "socket layer receive error", max); + break; + + case certificate_error : + strncpy(buffer, "unable to proccess cerificate", max); + break; + + case privateKey_error : + strncpy(buffer, "unable to proccess private key, bad format", max); + break; + + case badVersion_error : + strncpy(buffer, "protocol version mismatch", max); + break; + + case compress_error : + strncpy(buffer, "compression error", max); + break; + + case decompress_error : + strncpy(buffer, "decompression error", max); + break; + + case pms_version_error : + strncpy(buffer, "bad PreMasterSecret version error", max); + break; + + case sanityCipher_error : + strncpy(buffer, "sanity check on cipher text size error", max); + break; + + case rsaSignFault_error: + strncpy(buffer, "rsa signature fault error", max); + break; + + // openssl errors + case SSL_ERROR_WANT_READ : + strncpy(buffer, "the read operation would block", max); + break; + + case SSL_ERROR_WANT_WRITE : + strncpy(buffer, "the write operation would block", max); + break; + + case CERTFICATE_ERROR : + strncpy(buffer, "Unable to verify certificate", max); + break; + + // TaoCrypt errors + case NO_ERROR_E : + strncpy(buffer, "not in error state", max); + break; + + case WINCRYPT_E : + strncpy(buffer, "bad wincrypt acquire", max); + break; + + case CRYPTGEN_E : + strncpy(buffer, "CryptGenRandom error", max); + break; + + case OPEN_RAN_E : + strncpy(buffer, "unable to use random device", max); + break; + + case READ_RAN_E : + strncpy(buffer, "unable to use random device", max); + break; + + case INTEGER_E : + strncpy(buffer, "ASN: bad DER Integer Header", max); + break; + + case SEQUENCE_E : + strncpy(buffer, "ASN: bad Sequence Header", max); + break; + + case SET_E : + strncpy(buffer, "ASN: bad Set Header", max); + break; + + case VERSION_E : + strncpy(buffer, "ASN: version length not 1", max); + break; + + case SIG_OID_E : + strncpy(buffer, "ASN: signature OID mismatch", max); + break; + + case BIT_STR_E : + strncpy(buffer, "ASN: bad BitString Header", max); + break; + + case UNKNOWN_OID_E : + strncpy(buffer, "ASN: unknown key OID type", max); + break; + + case OBJECT_ID_E : + strncpy(buffer, "ASN: bad Ojbect ID Header", max); + break; + + case TAG_NULL_E : + strncpy(buffer, "ASN: expected TAG NULL", max); + break; + + case EXPECT_0_E : + strncpy(buffer, "ASN: expected 0", max); + break; + + case OCTET_STR_E : + strncpy(buffer, "ASN: bad Octet String Header", max); + break; + + case TIME_E : + strncpy(buffer, "ASN: bad TIME", max); + break; + + case DATE_SZ_E : + strncpy(buffer, "ASN: bad Date Size", max); + break; + + case SIG_LEN_E : + strncpy(buffer, "ASN: bad Signature Length", max); + break; + + case UNKOWN_SIG_E : + strncpy(buffer, "ASN: unknown signature OID", max); + break; + + case UNKOWN_HASH_E : + strncpy(buffer, "ASN: unknown hash OID", max); + break; + + case DSA_SZ_E : + strncpy(buffer, "ASN: bad DSA r or s size", max); + break; + + case BEFORE_DATE_E : + strncpy(buffer, "ASN: before date in the future", max); + break; + + case AFTER_DATE_E : + strncpy(buffer, "ASN: after date in the past", max); + break; + + case SIG_CONFIRM_E : + strncpy(buffer, "ASN: bad self signature confirmation", max); + break; + + case SIG_OTHER_E : + strncpy(buffer, "ASN: bad other signature confirmation", max); + break; + + case CONTENT_E : + strncpy(buffer, "bad content processing", max); + break; + + case PEM_E : + strncpy(buffer, "bad PEM format processing", max); + break; + + default : + strncpy(buffer, "unknown error number", max); + } +} + + + +} // namespace yaSSL diff --git a/mysql/extra/yassl/src/yassl_imp.cpp b/mysql/extra/yassl/src/yassl_imp.cpp new file mode 100644 index 0000000..ea09777 --- /dev/null +++ b/mysql/extra/yassl/src/yassl_imp.cpp @@ -0,0 +1,2642 @@ +/* + Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301 USA. +*/ + +/* yaSSL source implements all SSL.v3 secification structures. + */ + +#include "runtime.hpp" +#include "yassl_int.hpp" +#include "handshake.hpp" + +#include "asn.hpp" // provide crypto wrapper?? + + + +namespace yaSSL { + + +namespace { // locals + +bool isTLS(ProtocolVersion pv) +{ + if (pv.major_ >= 3 && pv.minor_ >= 1) + return true; + + return false; +} + + +} // namespace (locals) + + +void hashHandShake(SSL&, const input_buffer&, uint); + + +ProtocolVersion::ProtocolVersion(uint8 maj, uint8 min) + : major_(maj), minor_(min) +{} + + +// construct key exchange with known ssl parms +void ClientKeyExchange::createKey(SSL& ssl) +{ + const ClientKeyFactory& ckf = ssl.getFactory().getClientKey(); + client_key_ = ckf.CreateObject(ssl.getSecurity().get_parms().kea_); + + if (!client_key_) + ssl.SetError(factory_error); +} + + +// construct key exchange with known ssl parms +void ServerKeyExchange::createKey(SSL& ssl) +{ + const ServerKeyFactory& skf = ssl.getFactory().getServerKey(); + server_key_ = skf.CreateObject(ssl.getSecurity().get_parms().kea_); + + if (!server_key_) + ssl.SetError(factory_error); +} + + +// build/set PreMaster secret and encrypt, client side +void EncryptedPreMasterSecret::build(SSL& ssl) +{ + opaque tmp[SECRET_LEN]; + memset(tmp, 0, sizeof(tmp)); + ssl.getCrypto().get_random().Fill(tmp, SECRET_LEN); + ProtocolVersion pv = ssl.getSecurity().get_connection().chVersion_; + tmp[0] = pv.major_; + tmp[1] = pv.minor_; + ssl.set_preMaster(tmp, SECRET_LEN); + + const CertManager& cert = ssl.getCrypto().get_certManager(); + RSA rsa(cert.get_peerKey(), cert.get_peerKeyLength()); + bool tls = ssl.isTLS(); // if TLS, put length for encrypted data + alloc(rsa.get_cipherLength() + (tls ? 2 : 0)); + byte* holder = secret_; + if (tls) { + byte len[2]; + c16toa(rsa.get_cipherLength(), len); + memcpy(secret_, len, sizeof(len)); + holder += 2; + } + rsa.encrypt(holder, tmp, SECRET_LEN, ssl.getCrypto().get_random()); +} + + +// build/set premaster and Client Public key, client side +void ClientDiffieHellmanPublic::build(SSL& ssl) +{ + DiffieHellman& dhServer = ssl.useCrypto().use_dh(); + DiffieHellman dhClient(dhServer); + + uint keyLength = dhClient.get_agreedKeyLength(); // pub and agree same + + alloc(keyLength, true); + dhClient.makeAgreement(dhServer.get_publicKey(), + dhServer.get_publicKeyLength()); + c16toa(keyLength, Yc_); + memcpy(Yc_ + KEY_OFFSET, dhClient.get_publicKey(), keyLength); + + ssl.set_preMaster(dhClient.get_agreedKey(), keyLength); +} + + +// build server exhange, server side +void DH_Server::build(SSL& ssl) +{ + DiffieHellman& dhServer = ssl.useCrypto().use_dh(); + + int pSz, gSz, pubSz; + dhServer.set_sizes(pSz, gSz, pubSz); + dhServer.get_parms(parms_.alloc_p(pSz), parms_.alloc_g(gSz), + parms_.alloc_pub(pubSz)); + + short sigSz = 0; + mySTL::auto_ptr auth; + const CertManager& cert = ssl.getCrypto().get_certManager(); + + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { + if (cert.get_keyType() != rsa_sa_algo) { + ssl.SetError(privateKey_error); + return; + } + auth.reset(NEW_YS RSA(cert.get_privateKey(), + cert.get_privateKeyLength(), false)); + } + else { + if (cert.get_keyType() != dsa_sa_algo) { + ssl.SetError(privateKey_error); + return; + } + auth.reset(NEW_YS DSS(cert.get_privateKey(), + cert.get_privateKeyLength(), false)); + sigSz += DSS_ENCODED_EXTRA; + } + + sigSz += auth->get_signatureLength(); + if (!sigSz) { + ssl.SetError(privateKey_error); + return; + } + + length_ = 8; // pLen + gLen + YsLen + SigLen + length_ += pSz + gSz + pubSz + sigSz; + + output_buffer tmp(length_); + byte len[2]; + // P + c16toa(pSz, len); + tmp.write(len, sizeof(len)); + tmp.write(parms_.get_p(), pSz); + // G + c16toa(gSz, len); + tmp.write(len, sizeof(len)); + tmp.write(parms_.get_g(), gSz); + // Ys + c16toa(pubSz, len); + tmp.write(len, sizeof(len)); + tmp.write(parms_.get_pub(), pubSz); + + // Sig + byte hash[FINISHED_SZ]; + MD5 md5; + SHA sha; + signature_ = NEW_YS byte[sigSz]; + + const Connection& conn = ssl.getSecurity().get_connection(); + // md5 + md5.update(conn.client_random_, RAN_LEN); + md5.update(conn.server_random_, RAN_LEN); + md5.update(tmp.get_buffer(), tmp.get_size()); + md5.get_digest(hash); + + // sha + sha.update(conn.client_random_, RAN_LEN); + sha.update(conn.server_random_, RAN_LEN); + sha.update(tmp.get_buffer(), tmp.get_size()); + sha.get_digest(&hash[MD5_LEN]); + + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { + auth->sign(signature_, hash, sizeof(hash), + ssl.getCrypto().get_random()); + // check for rsa signautre fault + if (!auth->verify(hash, sizeof(hash), signature_, + auth->get_signatureLength())) { + ssl.SetError(rsaSignFault_error); + return; + } + } + else { + auth->sign(signature_, &hash[MD5_LEN], SHA_LEN, + ssl.getCrypto().get_random()); + byte encoded[DSS_SIG_SZ + DSS_ENCODED_EXTRA]; + TaoCrypt::EncodeDSA_Signature(signature_, encoded); + memcpy(signature_, encoded, sizeof(encoded)); + } + + c16toa(sigSz, len); + tmp.write(len, sizeof(len)); + tmp.write(signature_, sigSz); + + // key message + keyMessage_ = NEW_YS opaque[length_]; + memcpy(keyMessage_, tmp.get_buffer(), tmp.get_size()); +} + + +// read PreMaster secret and decrypt, server side +void EncryptedPreMasterSecret::read(SSL& ssl, input_buffer& input) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + const CertManager& cert = ssl.getCrypto().get_certManager(); + RSA rsa(cert.get_privateKey(), cert.get_privateKeyLength(), false); + uint16 cipherLen = rsa.get_cipherLength(); + if (ssl.isTLS()) { + byte len[2]; + len[0] = input[AUTO]; + len[1] = input[AUTO]; + ato16(len, cipherLen); + } + alloc(cipherLen); + input.read(secret_, length_); + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + opaque preMasterSecret[SECRET_LEN]; + memset(preMasterSecret, 0, sizeof(preMasterSecret)); + rsa.decrypt(preMasterSecret, secret_, length_, + ssl.getCrypto().get_random()); + + ProtocolVersion pv = ssl.getSecurity().get_connection().chVersion_; + if (pv.major_ != preMasterSecret[0] || pv.minor_ != preMasterSecret[1]) + ssl.SetError(pms_version_error); // continue deriving for timing attack + + ssl.set_preMaster(preMasterSecret, SECRET_LEN); + ssl.makeMasterSecret(); +} + + +EncryptedPreMasterSecret::EncryptedPreMasterSecret() + : secret_(0), length_(0) +{} + + +EncryptedPreMasterSecret::~EncryptedPreMasterSecret() +{ + ysArrayDelete(secret_); +} + + +int EncryptedPreMasterSecret::get_length() const +{ + return length_; +} + + +opaque* EncryptedPreMasterSecret::get_clientKey() const +{ + return secret_; +} + + +void EncryptedPreMasterSecret::alloc(int sz) +{ + length_ = sz; + secret_ = NEW_YS opaque[sz]; +} + + +// read client's public key, server side +void ClientDiffieHellmanPublic::read(SSL& ssl, input_buffer& input) +{ + if (input.get_error() || input.get_remaining() < (uint)LENGTH_SZ) { + ssl.SetError(bad_input); + return; + } + + DiffieHellman& dh = ssl.useCrypto().use_dh(); + + uint16 keyLength; + byte tmp[2]; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, keyLength); + + if (keyLength < dh.get_agreedKeyLength()/2) { + ssl.SetError(bad_input); + return; + } + + alloc(keyLength); + input.read(Yc_, keyLength); + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + dh.makeAgreement(Yc_, keyLength); + + ssl.set_preMaster(dh.get_agreedKey(), dh.get_agreedKeyLength()); + ssl.makeMasterSecret(); +} + + +ClientDiffieHellmanPublic::ClientDiffieHellmanPublic() + : length_(0), Yc_(0) +{} + + +ClientDiffieHellmanPublic::~ClientDiffieHellmanPublic() +{ + ysArrayDelete(Yc_); +} + + +int ClientDiffieHellmanPublic::get_length() const +{ + return length_; +} + + +opaque* ClientDiffieHellmanPublic::get_clientKey() const +{ + return Yc_; +} + + +void ClientDiffieHellmanPublic::alloc(int sz, bool offset) +{ + length_ = sz + (offset ? KEY_OFFSET : 0); + Yc_ = NEW_YS opaque[length_]; +} + + +// read server's p, g, public key and sig, client side +void DH_Server::read(SSL& ssl, input_buffer& input) +{ + if (input.get_error() || input.get_remaining() < (uint)LENGTH_SZ) { + ssl.SetError(bad_input); + return; + } + uint16 length, messageTotal = 6; // pSz + gSz + pubSz + byte tmp[2]; + + // p + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, length); + messageTotal += length; + + input.read(parms_.alloc_p(length), length); + if (input.get_error() || input.get_remaining() < (uint)LENGTH_SZ) { + ssl.SetError(bad_input); + return; + } + + // g + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, length); + messageTotal += length; + + input.read(parms_.alloc_g(length), length); + if (input.get_error() || input.get_remaining() < (uint)LENGTH_SZ) { + ssl.SetError(bad_input); + return; + } + + // pub + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, length); + messageTotal += length; + + input.read(parms_.alloc_pub(length), length); + if (input.get_error() || input.get_remaining() < (uint)LENGTH_SZ) { + ssl.SetError(bad_input); + return; + } + + // save message for hash verify + input_buffer message(messageTotal); + input.set_current(input.get_current() - messageTotal); + input.read(message.get_buffer(), messageTotal); + message.add_size(messageTotal); + if (input.get_error() || input.get_remaining() < (uint)LENGTH_SZ) { + ssl.SetError(bad_input); + return; + } + + // signature + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, length); + + if (length == 0) { + ssl.SetError(bad_input); + return; + } + signature_ = NEW_YS byte[length]; + input.read(signature_, length); + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + // verify signature + byte hash[FINISHED_SZ]; + MD5 md5; + SHA sha; + + const Connection& conn = ssl.getSecurity().get_connection(); + // md5 + md5.update(conn.client_random_, RAN_LEN); + md5.update(conn.server_random_, RAN_LEN); + md5.update(message.get_buffer(), message.get_size()); + md5.get_digest(hash); + + // sha + sha.update(conn.client_random_, RAN_LEN); + sha.update(conn.server_random_, RAN_LEN); + sha.update(message.get_buffer(), message.get_size()); + sha.get_digest(&hash[MD5_LEN]); + + const CertManager& cert = ssl.getCrypto().get_certManager(); + + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { + RSA rsa(cert.get_peerKey(), cert.get_peerKeyLength()); + if (!rsa.verify(hash, sizeof(hash), signature_, length)) + ssl.SetError(verify_error); + } + else { + byte decodedSig[DSS_SIG_SZ]; + length = TaoCrypt::DecodeDSA_Signature(decodedSig, signature_, length); + + DSS dss(cert.get_peerKey(), cert.get_peerKeyLength()); + if (!dss.verify(&hash[MD5_LEN], SHA_LEN, decodedSig, length)) + ssl.SetError(verify_error); + } + + // save input + ssl.useCrypto().SetDH(NEW_YS DiffieHellman(parms_.get_p(), + parms_.get_pSize(), parms_.get_g(), parms_.get_gSize(), + parms_.get_pub(), parms_.get_pubSize(), + ssl.getCrypto().get_random())); +} + + +DH_Server::DH_Server() + : signature_(0), length_(0), keyMessage_(0) +{} + + +DH_Server::~DH_Server() +{ + ysArrayDelete(keyMessage_); + ysArrayDelete(signature_); +} + + +int DH_Server::get_length() const +{ + return length_; +} + + +opaque* DH_Server::get_serverKey() const +{ + return keyMessage_; +} + + +// set available suites +Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, + ProtocolVersion pv, bool haveDH) : entity_(ce) +{ + pending_ = true; // suite not set yet + strncpy(cipher_name_, "NONE", 5); + + removeDH_ = !haveDH; // only use on server side for set suites + + if (ciphers.setSuites_) { // use user set list + suites_size_ = ciphers.suiteSz_; + memcpy(suites_, ciphers.suites_, ciphers.suiteSz_); + SetCipherNames(); + } + else + SetSuites(pv, ce == server_end && removeDH_); // defaults + +} + + +void Parameters::SetSuites(ProtocolVersion pv, bool removeDH, bool removeRSA, + bool removeDSA) +{ + int i = 0; + // available suites, best first + // when adding more, make sure cipher_names is updated and + // MAX_CIPHERS is big enough + + if (isTLS(pv)) { + if (!removeDH) { + if (!removeRSA) { + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA; + } + if (!removeDSA) { + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_DSS_WITH_AES_256_CBC_SHA; + } + } + if (!removeRSA) { + suites_[i++] = 0x00; + suites_[i++] = TLS_RSA_WITH_AES_256_CBC_SHA; + } + if (!removeDH) { + if (!removeRSA) { + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA; + } + if (!removeDSA) { + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_DSS_WITH_AES_128_CBC_SHA; + } + } + if (!removeRSA) { + suites_[i++] = 0x00; + suites_[i++] = TLS_RSA_WITH_AES_128_CBC_SHA; + suites_[i++] = 0x00; + suites_[i++] = TLS_RSA_WITH_AES_256_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_RSA_WITH_AES_128_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_RSA_WITH_3DES_EDE_CBC_RMD160; + } + if (!removeDH) { + if (!removeRSA) { + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_RSA_WITH_AES_256_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_RSA_WITH_AES_128_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD160; + } + if (!removeDSA) { + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_DSS_WITH_AES_256_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_DSS_WITH_AES_128_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD160; + } + } + } + + if (!removeRSA) { + suites_[i++] = 0x00; + suites_[i++] = SSL_RSA_WITH_RC4_128_SHA; + suites_[i++] = 0x00; + suites_[i++] = SSL_RSA_WITH_RC4_128_MD5; + + suites_[i++] = 0x00; + suites_[i++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA; + suites_[i++] = 0x00; + suites_[i++] = SSL_RSA_WITH_DES_CBC_SHA; + } + if (!removeDH) { + if (!removeRSA) { + suites_[i++] = 0x00; + suites_[i++] = SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA; + } + if (!removeDSA) { + suites_[i++] = 0x00; + suites_[i++] = SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA; + } + if (!removeRSA) { + suites_[i++] = 0x00; + suites_[i++] = SSL_DHE_RSA_WITH_DES_CBC_SHA; + } + if (!removeDSA) { + suites_[i++] = 0x00; + suites_[i++] = SSL_DHE_DSS_WITH_DES_CBC_SHA; + } + } + + suites_size_ = i; + + SetCipherNames(); +} + + +void Parameters::SetCipherNames() +{ + const int suites = suites_size_ / 2; + int pos = 0; + + for (int j = 0; j < suites; j++) { + int index = suites_[j*2 + 1]; // every other suite is suite id + size_t len = strlen(cipher_names[index]) + 1; + strncpy(cipher_list_[pos++], cipher_names[index], len); + } + cipher_list_[pos][0] = 0; +} + + +// input operator for RecordLayerHeader, adjust stream +input_buffer& operator>>(input_buffer& input, RecordLayerHeader& hdr) +{ + hdr.type_ = ContentType(input[AUTO]); + hdr.version_.major_ = input[AUTO]; + hdr.version_.minor_ = input[AUTO]; + + // length + byte tmp[2]; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, hdr.length_); + + return input; +} + + +// output operator for RecordLayerHeader +output_buffer& operator<<(output_buffer& output, const RecordLayerHeader& hdr) +{ + output[AUTO] = hdr.type_; + output[AUTO] = hdr.version_.major_; + output[AUTO] = hdr.version_.minor_; + + // length + byte tmp[2]; + c16toa(hdr.length_, tmp); + output[AUTO] = tmp[0]; + output[AUTO] = tmp[1]; + + return output; +} + + +// virtual input operator for Messages +input_buffer& operator>>(input_buffer& input, Message& msg) +{ + return msg.set(input); +} + +// virtual output operator for Messages +output_buffer& operator<<(output_buffer& output, const Message& msg) +{ + return msg.get(output); +} + + +// input operator for HandShakeHeader +input_buffer& operator>>(input_buffer& input, HandShakeHeader& hs) +{ + hs.type_ = HandShakeType(input[AUTO]); + + hs.length_[0] = input[AUTO]; + hs.length_[1] = input[AUTO]; + hs.length_[2] = input[AUTO]; + + return input; +} + + +// output operator for HandShakeHeader +output_buffer& operator<<(output_buffer& output, const HandShakeHeader& hdr) +{ + output[AUTO] = hdr.type_; + output.write(hdr.length_, sizeof(hdr.length_)); + return output; +} + + +// HandShake Header Processing function +void HandShakeHeader::Process(input_buffer& input, SSL& ssl) +{ + ssl.verifyState(*this); + if (ssl.GetError()) return; + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + const HandShakeFactory& hsf = ssl.getFactory().getHandShake(); + mySTL::auto_ptr hs(hsf.CreateObject(type_)); + if (!hs.get()) { + ssl.SetError(factory_error); + return; + } + + uint len = c24to32(length_); + if (len > input.get_remaining()) { + ssl.SetError(bad_input); + return; + } + hashHandShake(ssl, input, len); + + hs->set_length(len); + input >> *hs; + hs->Process(input, ssl); +} + + +ContentType HandShakeHeader::get_type() const +{ + return handshake; +} + + +uint16 HandShakeHeader::get_length() const +{ + return c24to32(length_); +} + + +HandShakeType HandShakeHeader::get_handshakeType() const +{ + return type_; +} + + +void HandShakeHeader::set_type(HandShakeType hst) +{ + type_ = hst; +} + + +void HandShakeHeader::set_length(uint32 u32) +{ + c32to24(u32, length_); +} + + +input_buffer& HandShakeHeader::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& HandShakeHeader::get(output_buffer& out) const +{ + return out << *this; +} + + + +int HandShakeBase::get_length() const +{ + return length_; +} + + +void HandShakeBase::set_length(int l) +{ + length_ = l; +} + + +// for building buffer's type field +HandShakeType HandShakeBase::get_type() const +{ + return no_shake; +} + + +input_buffer& HandShakeBase::set(input_buffer& in) +{ + return in; +} + + +output_buffer& HandShakeBase::get(output_buffer& out) const +{ + return out; +} + + +void HandShakeBase::Process(input_buffer&, SSL&) +{} + + +input_buffer& HelloRequest::set(input_buffer& in) +{ + return in; +} + + +output_buffer& HelloRequest::get(output_buffer& out) const +{ + return out; +} + + +void HelloRequest::Process(input_buffer&, SSL&) +{} + + +HandShakeType HelloRequest::get_type() const +{ + return hello_request; +} + + +// input operator for CipherSpec +input_buffer& operator>>(input_buffer& input, ChangeCipherSpec& cs) +{ + cs.type_ = CipherChoice(input[AUTO]); + return input; +} + +// output operator for CipherSpec +output_buffer& operator<<(output_buffer& output, const ChangeCipherSpec& cs) +{ + output[AUTO] = cs.type_; + return output; +} + + +ChangeCipherSpec::ChangeCipherSpec() + : type_(change_cipher_spec_choice) +{} + + +input_buffer& ChangeCipherSpec::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& ChangeCipherSpec::get(output_buffer& out) const +{ + return out << *this; +} + + +ContentType ChangeCipherSpec::get_type() const +{ + return change_cipher_spec; +} + + +uint16 ChangeCipherSpec::get_length() const +{ + return SIZEOF_ENUM; +} + + +// CipherSpec processing handler +void ChangeCipherSpec::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + // detect duplicate change_cipher + if (ssl.getSecurity().get_parms().pending_ == false) { + ssl.order_error(); + return; + } + + ssl.useSecurity().use_parms().pending_ = false; + if (ssl.getSecurity().get_resuming()) { + if (ssl.getSecurity().get_parms().entity_ == client_end) + buildFinished(ssl, ssl.useHashes().use_verify(), server); // server + } + else if (ssl.getSecurity().get_parms().entity_ == server_end) + buildFinished(ssl, ssl.useHashes().use_verify(), client); // client +} + + +Alert::Alert(AlertLevel al, AlertDescription ad) + : level_(al), description_(ad) +{} + + +ContentType Alert::get_type() const +{ + return alert; +} + + +uint16 Alert::get_length() const +{ + return SIZEOF_ENUM * 2; +} + + +input_buffer& Alert::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& Alert::get(output_buffer& out) const +{ + return out << *this; +} + + +// input operator for Alert +input_buffer& operator>>(input_buffer& input, Alert& a) +{ + a.level_ = AlertLevel(input[AUTO]); + a.description_ = AlertDescription(input[AUTO]); + + return input; +} + + +// output operator for Alert +output_buffer& operator<<(output_buffer& output, const Alert& a) +{ + output[AUTO] = a.level_; + output[AUTO] = a.description_; + return output; +} + + +// Alert processing handler +void Alert::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + if (ssl.getSecurity().get_parms().pending_ == false) { // encrypted alert + int aSz = get_length(); // alert size already read on input + opaque verify[SHA_LEN]; + const opaque* data = input.get_buffer() + input.get_current() - aSz; + + if (ssl.isTLS()) + TLS_hmac(ssl, verify, data, aSz, alert, true); + else + hmac(ssl, verify, data, aSz, alert, true); + + // read mac and skip fill + int digestSz = ssl.getCrypto().get_digest().get_digestSize(); + opaque mac[SHA_LEN]; + input.read(mac, digestSz); + + if (ssl.getSecurity().get_parms().cipher_type_ == block) { + int ivExtra = 0; + opaque fill; + + if (ssl.isTLSv1_1()) + ivExtra = ssl.getCrypto().get_cipher().get_blockSize(); + int padSz = ssl.getSecurity().get_parms().encrypt_size_ - ivExtra - + aSz - digestSz; + for (int i = 0; i < padSz; i++) + fill = input[AUTO]; + } + + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + // verify + if (memcmp(mac, verify, digestSz)) { + ssl.SetError(verify_error); + return; + } + } + if (level_ == fatal) { + ssl.useStates().useRecord() = recordNotReady; + ssl.useStates().useHandShake() = handShakeNotReady; + ssl.SetError(YasslError(description_)); + } +} + + +Data::Data() + : length_(0), buffer_(0), write_buffer_(0) +{} + + +Data::Data(uint16 len, opaque* b) + : length_(len), buffer_(b), write_buffer_(0) +{} + + +void Data::SetData(uint16 len, const opaque* buffer) +{ + length_ = len; + write_buffer_ = buffer; +} + +input_buffer& Data::set(input_buffer& in) +{ + return in; +} + + +output_buffer& Data::get(output_buffer& out) const +{ + return out << *this; +} + + +ContentType Data::get_type() const +{ + return application_data; +} + + +uint16 Data::get_length() const +{ + return length_; +} + + +void Data::set_length(uint16 l) +{ + length_ = l; +} + + +opaque* Data::set_buffer() +{ + return buffer_; +} + + +// output operator for Data +output_buffer& operator<<(output_buffer& output, const Data& data) +{ + output.write(data.write_buffer_, data.length_); + return output; +} + + +// check all bytes for equality +static int constant_compare(const byte* a, const byte* b, int len) +{ + int good = 0; + int bad = 0; + + for (int i = 0; i < len; i++) { + if (a[i] == b[i]) + good++; + else + bad++; + } + + if (good == len) + return 0; + else + return 0 - bad; // failure +} + + +// check bytes for pad value +static int pad_check(const byte* input, byte pad, int len) +{ + int good = 0; + int bad = 0; + + for (int i = 0; i < len; i++) { + if (input[i] == pad) + good++; + else + bad++; + } + + if (good == len) + return 0; + else + return 0 - bad; // failure +} + + +// get number of compression rounds +static inline int get_rounds(int pLen, int padLen, int t) +{ + int roundL1 = 1; // round ups + int roundL2 = 1; + + int L1 = COMPRESS_CONSTANT + pLen - t; + int L2 = COMPRESS_CONSTANT + pLen - padLen - 1 - t; + + L1 -= COMPRESS_UPPER; + L2 -= COMPRESS_UPPER; + + if ( (L1 % COMPRESS_LOWER) == 0) + roundL1 = 0; + if ( (L2 % COMPRESS_LOWER) == 0) + roundL2 = 0; + + L1 /= COMPRESS_LOWER; + L2 /= COMPRESS_LOWER; + + L1 += roundL1; + L2 += roundL2; + + return L1 - L2; +} + + +// do compression rounds on dummy data +static inline void compress_rounds(SSL& ssl, int rounds, const byte* dummy) +{ + if (rounds) { + Digest* digest = NULL; + + MACAlgorithm ma = ssl.getSecurity().get_parms().mac_algorithm_; + if (ma == sha) + digest = NEW_YS SHA; + else if (ma == md5) + digest = NEW_YS MD5; + else if (ma == rmd) + digest = NEW_YS RMD; + else + return; + + for (int i = 0; i < rounds; i++) + digest->update(dummy, COMPRESS_LOWER); + + ysDelete(digest); + } +} + + +// timing resistant pad verification +static int timing_verify(SSL& ssl, const byte* input, int padLen, int t, + int pLen) +{ + byte verify[SHA_LEN]; + byte dummy[MAX_PAD_SIZE]; + + memset(dummy, 1, sizeof(dummy)); + + if ( (t + padLen + 1) > pLen) { + pad_check(dummy, (byte)padLen, MAX_PAD_SIZE); + if (ssl.isTLS()) + TLS_hmac(ssl, verify, input, pLen - t, application_data, 1); + else + hmac(ssl, verify, input, pLen - t, application_data, 1); + constant_compare(verify, input + pLen - t, t); + + return -1; + } + + if (pad_check(input + pLen - (padLen + 1), (byte)padLen, padLen + 1) != 0) { + pad_check(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1); + if (ssl.isTLS()) + TLS_hmac(ssl, verify, input, pLen - t, application_data, 1); + else + hmac(ssl, verify, input, pLen - t, application_data, 1); + constant_compare(verify, input + pLen - t, t); + + return -1; + } + + pad_check(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1); + if (ssl.isTLS()) + TLS_hmac(ssl, verify, input, pLen - padLen - 1 - t, application_data,1); + else + hmac(ssl, verify, input, pLen - padLen - 1 - t, application_data, 1); + + compress_rounds(ssl, get_rounds(pLen, padLen, t), dummy); + + if (constant_compare(verify, input + (pLen - padLen - 1 - t), t) != 0) + return -1; + + return 0; +} + + +// Process handler for Data +void Data::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + int msgSz = ssl.getSecurity().get_parms().encrypt_size_; + int pad = 0, padSz = 0; + int ivExtra = 0; + int digestSz = ssl.getCrypto().get_digest().get_digestSize(); + const byte* rawData = input.get_buffer() + input.get_current(); + opaque verify[SHA_LEN]; + + if (ssl.getSecurity().get_parms().cipher_type_ == block) { + if (ssl.isTLSv1_1()) // IV + ivExtra = ssl.getCrypto().get_cipher().get_blockSize(); + pad = *(input.get_buffer() + input.get_current() + msgSz -ivExtra - 1); + padSz = 1; + + if (ssl.isTLS()) { + if (timing_verify(ssl, rawData, pad,digestSz, msgSz-ivExtra) != 0) { + ssl.SetError(verify_error); + return; + } + } + else { // SSLv3, some don't do this padding right + int sz3 = msgSz - digestSz - pad - 1; + hmac(ssl, verify, rawData, sz3, application_data, true); + if (constant_compare(verify, rawData + sz3, digestSz) != 0) { + ssl.SetError(verify_error); + return; + } + } + } + else { // stream + int streamSz = msgSz - digestSz; + if (ssl.isTLS()) + TLS_hmac(ssl, verify, rawData, streamSz, application_data, true); + else + hmac(ssl, verify, rawData, streamSz, application_data, true); + if (constant_compare(verify, rawData + streamSz, digestSz) != 0) { + ssl.SetError(verify_error); + return; + } + } + + int dataSz = msgSz - ivExtra - digestSz - pad - padSz; + + if (dataSz < 0 || dataSz > (MAX_RECORD_SIZE + COMPRESS_EXTRA)) { + ssl.SetError(bad_input); + return; + } + + // read data + if (dataSz) { // could be compressed + if (ssl.CompressionOn()) { + input_buffer tmp; + if (DeCompress(input, dataSz, tmp) == -1) { + ssl.SetError(decompress_error); + return; + } + ssl.addData(NEW_YS input_buffer(tmp.get_size(), + tmp.get_buffer(), tmp.get_size())); + } + else { + input_buffer* data; + ssl.addData(data = NEW_YS input_buffer(dataSz)); + input.read(data->get_buffer(), dataSz); + data->add_size(dataSz); + } + } + + // advance past mac and fill + input.set_current(input.get_current() + digestSz + pad + padSz); + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } +} + + +// virtual input operator for HandShakes +input_buffer& operator>>(input_buffer& input, HandShakeBase& hs) +{ + return hs.set(input); +} + + +// virtual output operator for HandShakes +output_buffer& operator<<(output_buffer& output, const HandShakeBase& hs) +{ + return hs.get(output); +} + + +Certificate::Certificate(const x509* cert) : cert_(cert) +{ + if (cert) + set_length(cert_->get_length() + 2 * CERT_HEADER); // list and cert size + else + set_length(CERT_HEADER); // total blank cert size, just list header +} + + +const opaque* Certificate::get_buffer() const +{ + if (cert_) + return cert_->get_buffer(); + + return NULL; +} + + +// output operator for Certificate +output_buffer& operator<<(output_buffer& output, const Certificate& cert) +{ + uint sz = cert.get_length(); + opaque tmp[CERT_HEADER]; + + if ((int)sz > CERT_HEADER) + sz -= 2 * CERT_HEADER; // actual cert, not including headers + else { + sz = 0; // blank cert case + c32to24(sz, tmp); + output.write(tmp, CERT_HEADER); + + return output; + } + + c32to24(sz + CERT_HEADER, tmp); + output.write(tmp, CERT_HEADER); + c32to24(sz, tmp); + output.write(tmp, CERT_HEADER); + output.write(cert.get_buffer(), sz); + + return output; +} + + +// certificate processing handler +void Certificate::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + CertManager& cm = ssl.useCrypto().use_certManager(); + + uint32 list_sz; + byte tmp[3]; + + if (input.get_remaining() < sizeof(tmp)) { + ssl.SetError(YasslError(bad_input)); + return; + } + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + tmp[2] = input[AUTO]; + c24to32(tmp, list_sz); + + if (list_sz > (uint)MAX_RECORD_SIZE) { // sanity check + ssl.SetError(YasslError(bad_input)); + return; + } + + while (list_sz) { + // cert size + uint32 cert_sz; + + if (input.get_remaining() < sizeof(tmp)) { + ssl.SetError(YasslError(bad_input)); + return; + } + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + tmp[2] = input[AUTO]; + c24to32(tmp, cert_sz); + + if (cert_sz > (uint)MAX_RECORD_SIZE || input.get_remaining() < cert_sz){ + ssl.SetError(YasslError(bad_input)); + return; + } + if (cert_sz) { + x509* myCert; + cm.AddPeerCert(myCert = NEW_YS x509(cert_sz)); + input.read(myCert->use_buffer(), myCert->get_length()); + } + + list_sz -= cert_sz + CERT_HEADER; + } + if (int err = cm.Validate()) + ssl.SetError(YasslError(err)); + else if (ssl.getSecurity().get_parms().entity_ == client_end) + ssl.useStates().useClient() = serverCertComplete; +} + + +Certificate::Certificate() + : cert_(0) +{} + + +input_buffer& Certificate::set(input_buffer& in) +{ + return in; +} + + +output_buffer& Certificate::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType Certificate::get_type() const +{ + return certificate; +} + + +ServerDHParams::ServerDHParams() + : pSz_(0), gSz_(0), pubSz_(0), p_(0), g_(0), Ys_(0) +{} + + +ServerDHParams::~ServerDHParams() +{ + ysArrayDelete(Ys_); + ysArrayDelete(g_); + ysArrayDelete(p_); +} + + +int ServerDHParams::get_pSize() const +{ + return pSz_; +} + + +int ServerDHParams::get_gSize() const +{ + return gSz_; +} + + +int ServerDHParams::get_pubSize() const +{ + return pubSz_; +} + + +const opaque* ServerDHParams::get_p() const +{ + return p_; +} + + +const opaque* ServerDHParams::get_g() const +{ + return g_; +} + + +const opaque* ServerDHParams::get_pub() const +{ + return Ys_; +} + + +opaque* ServerDHParams::alloc_p(int sz) +{ + p_ = NEW_YS opaque[pSz_ = sz]; + return p_; +} + + +opaque* ServerDHParams::alloc_g(int sz) +{ + g_ = NEW_YS opaque[gSz_ = sz]; + return g_; +} + + +opaque* ServerDHParams::alloc_pub(int sz) +{ + Ys_ = NEW_YS opaque[pubSz_ = sz]; + return Ys_; +} + + +int ServerKeyBase::get_length() const +{ + return 0; +} + + +opaque* ServerKeyBase::get_serverKey() const +{ + return 0; +} + + +// input operator for ServerHello +input_buffer& operator>>(input_buffer& input, ServerHello& hello) +{ + // Protocol + hello.server_version_.major_ = input[AUTO]; + hello.server_version_.minor_ = input[AUTO]; + + // Random + input.read(hello.random_, RAN_LEN); + + // Session + hello.id_len_ = input[AUTO]; + if (hello.id_len_ > ID_LEN) { + input.set_error(); + return input; + } + if (hello.id_len_) + input.read(hello.session_id_, hello.id_len_); + + // Suites + hello.cipher_suite_[0] = input[AUTO]; + hello.cipher_suite_[1] = input[AUTO]; + + // Compression + hello.compression_method_ = CompressionMethod(input[AUTO]); + + return input; +} + + +// output operator for ServerHello +output_buffer& operator<<(output_buffer& output, const ServerHello& hello) +{ + // Protocol + output[AUTO] = hello.server_version_.major_; + output[AUTO] = hello.server_version_.minor_; + + // Random + output.write(hello.random_, RAN_LEN); + + // Session + output[AUTO] = hello.id_len_; + output.write(hello.session_id_, ID_LEN); + + // Suites + output[AUTO] = hello.cipher_suite_[0]; + output[AUTO] = hello.cipher_suite_[1]; + + // Compression + output[AUTO] = hello.compression_method_; + + return output; +} + + +// Server Hello processing handler +void ServerHello::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + if (ssl.GetMultiProtocol()) { // SSLv23 support + if (ssl.isTLS() && server_version_.minor_ < 1) + // downgrade to SSLv3 + ssl.useSecurity().use_connection().TurnOffTLS(); + else if (ssl.isTLSv1_1() && server_version_.minor_ == 1) + // downdrage to TLSv1 + ssl.useSecurity().use_connection().TurnOffTLS1_1(); + } + else if (ssl.isTLSv1_1() && server_version_.minor_ < 2) { + ssl.SetError(badVersion_error); + return; + } + else if (ssl.isTLS() && server_version_.minor_ < 1) { + ssl.SetError(badVersion_error); + return; + } + else if (!ssl.isTLS() && (server_version_.major_ == 3 && + server_version_.minor_ >= 1)) { + ssl.SetError(badVersion_error); + return; + } + if (cipher_suite_[0] != 0x00) { + ssl.SetError(unknown_cipher); + return; + } + ssl.set_pending(cipher_suite_[1]); + ssl.set_random(random_, server_end); + if (id_len_) + ssl.set_sessionID(session_id_); + else + ssl.useSecurity().use_connection().sessionID_Set_ = false; + + if (ssl.getSecurity().get_resuming()) { + if (memcmp(session_id_, ssl.getSecurity().get_resume().GetID(), + ID_LEN) == 0) { + ssl.set_masterSecret(ssl.getSecurity().get_resume().GetSecret()); + if (ssl.isTLS()) + ssl.deriveTLSKeys(); + else + ssl.deriveKeys(); + ssl.useStates().useClient() = serverHelloDoneComplete; + return; + } + else { + ssl.useSecurity().set_resuming(false); + ssl.useLog().Trace("server denied resumption"); + } + } + + if (ssl.CompressionOn() && !compression_method_) + ssl.UnSetCompression(); // server isn't supporting yaSSL zlib request + + ssl.useStates().useClient() = serverHelloComplete; +} + + +ServerHello::ServerHello() +{ + memset(random_, 0, RAN_LEN); + memset(session_id_, 0, ID_LEN); +} + + +ServerHello::ServerHello(ProtocolVersion pv, bool useCompression) + : server_version_(pv), + compression_method_(useCompression ? zlib : no_compression) +{ + memset(random_, 0, RAN_LEN); + memset(session_id_, 0, ID_LEN); +} + + +input_buffer& ServerHello::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& ServerHello::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType ServerHello::get_type() const +{ + return server_hello; +} + + +const opaque* ServerHello::get_random() const +{ + return random_; +} + + +// Server Hello Done processing handler +void ServerHelloDone::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + ssl.useStates().useClient() = serverHelloDoneComplete; +} + + +ServerHelloDone::ServerHelloDone() +{ + set_length(0); +} + + +input_buffer& ServerHelloDone::set(input_buffer& in) +{ + return in; +} + + +output_buffer& ServerHelloDone::get(output_buffer& out) const +{ + return out; +} + + +HandShakeType ServerHelloDone::get_type() const +{ + return server_hello_done; +} + + +int ClientKeyBase::get_length() const +{ + return 0; +} + + +opaque* ClientKeyBase::get_clientKey() const +{ + return 0; +} + + +// input operator for Client Hello +input_buffer& operator>>(input_buffer& input, ClientHello& hello) +{ + uint begin = input.get_current(); // could have extensions at end + + // Protocol + hello.client_version_.major_ = input[AUTO]; + hello.client_version_.minor_ = input[AUTO]; + + // Random + input.read(hello.random_, RAN_LEN); + + // Session + hello.id_len_ = input[AUTO]; + if (hello.id_len_) input.read(hello.session_id_, ID_LEN); + + // Suites + byte tmp[2]; + uint16 len; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, len); + + hello.suite_len_ = min(len, static_cast(MAX_SUITE_SZ)); + input.read(hello.cipher_suites_, hello.suite_len_); + if (len > hello.suite_len_) // ignore extra suites + input.set_current(input.get_current() + len - hello.suite_len_); + + // Compression + hello.comp_len_ = input[AUTO]; + hello.compression_methods_ = no_compression; + while (hello.comp_len_--) { + CompressionMethod cm = CompressionMethod(input[AUTO]); + if (cm == zlib) + hello.compression_methods_ = zlib; + } + + uint read = input.get_current() - begin; + uint expected = hello.get_length(); + + // ignore client hello extensions for now + if (read < expected) + input.set_current(input.get_current() + expected - read); + + return input; +} + + +// output operaotr for Client Hello +output_buffer& operator<<(output_buffer& output, const ClientHello& hello) +{ + // Protocol + output[AUTO] = hello.client_version_.major_; + output[AUTO] = hello.client_version_.minor_; + + // Random + output.write(hello.random_, RAN_LEN); + + // Session + output[AUTO] = hello.id_len_; + if (hello.id_len_) output.write(hello.session_id_, ID_LEN); + + // Suites + byte tmp[2]; + c16toa(hello.suite_len_, tmp); + output[AUTO] = tmp[0]; + output[AUTO] = tmp[1]; + output.write(hello.cipher_suites_, hello.suite_len_); + + // Compression + output[AUTO] = hello.comp_len_; + output[AUTO] = hello.compression_methods_; + + return output; +} + + +// Client Hello processing handler +void ClientHello::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + // store version for pre master secret + ssl.useSecurity().use_connection().chVersion_ = client_version_; + + if (client_version_.major_ != 3) { + ssl.SetError(badVersion_error); + return; + } + if (ssl.GetMultiProtocol()) { // SSLv23 support + if (ssl.isTLS() && client_version_.minor_ < 1) { + // downgrade to SSLv3 + ssl.useSecurity().use_connection().TurnOffTLS(); + + ProtocolVersion pv = ssl.getSecurity().get_connection().version_; + bool removeDH = ssl.getSecurity().get_parms().removeDH_; + bool removeRSA = false; + bool removeDSA = false; + + const CertManager& cm = ssl.getCrypto().get_certManager(); + if (cm.get_keyType() == rsa_sa_algo) + removeDSA = true; + else + removeRSA = true; + + // reset w/ SSL suites + ssl.useSecurity().use_parms().SetSuites(pv, removeDH, removeRSA, + removeDSA); + } + else if (ssl.isTLSv1_1() && client_version_.minor_ == 1) + // downgrade to TLSv1, but use same suites + ssl.useSecurity().use_connection().TurnOffTLS1_1(); + } + else if (ssl.isTLSv1_1() && client_version_.minor_ < 2) { + ssl.SetError(badVersion_error); + return; + } + else if (ssl.isTLS() && client_version_.minor_ < 1) { + ssl.SetError(badVersion_error); + return; + } + else if (!ssl.isTLS() && client_version_.minor_ >= 1) { + ssl.SetError(badVersion_error); + return; + } + + ssl.set_random(random_, client_end); + + while (id_len_) { // trying to resume + SSL_SESSION* session = 0; + if (!ssl.getSecurity().GetContext()->GetSessionCacheOff()) + session = GetSessions().lookup(session_id_); + if (!session) { + ssl.useLog().Trace("session lookup failed"); + break; + } + ssl.set_session(session); + ssl.useSecurity().set_resuming(true); + ssl.matchSuite(session->GetSuite(), SUITE_LEN); + if (ssl.GetError()) return; + ssl.set_pending(ssl.getSecurity().get_parms().suite_[1]); + ssl.set_masterSecret(session->GetSecret()); + + opaque serverRandom[RAN_LEN]; + ssl.getCrypto().get_random().Fill(serverRandom, sizeof(serverRandom)); + ssl.set_random(serverRandom, server_end); + if (ssl.isTLS()) + ssl.deriveTLSKeys(); + else + ssl.deriveKeys(); + ssl.useStates().useServer() = clientKeyExchangeComplete; + return; + } + ssl.matchSuite(cipher_suites_, suite_len_); + if (ssl.GetError()) return; + ssl.set_pending(ssl.getSecurity().get_parms().suite_[1]); + + if (compression_methods_ == zlib) + ssl.SetCompression(); + + ssl.useStates().useServer() = clientHelloComplete; +} + + +input_buffer& ClientHello::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& ClientHello::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType ClientHello::get_type() const +{ + return client_hello; +} + + +const opaque* ClientHello::get_random() const +{ + return random_; +} + + +ClientHello::ClientHello() +{ + memset(random_, 0, RAN_LEN); +} + + +ClientHello::ClientHello(ProtocolVersion pv, bool useCompression) + : client_version_(pv), + compression_methods_(useCompression ? zlib : no_compression) +{ + memset(random_, 0, RAN_LEN); +} + + +// output operator for ServerKeyExchange +output_buffer& operator<<(output_buffer& output, const ServerKeyExchange& sk) +{ + output.write(sk.getKey(), sk.getKeyLength()); + return output; +} + + +// Server Key Exchange processing handler +void ServerKeyExchange::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + createKey(ssl); + if (ssl.GetError()) return; + server_key_->read(ssl, input); + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + ssl.useStates().useClient() = serverKeyExchangeComplete; +} + + +ServerKeyExchange::ServerKeyExchange(SSL& ssl) +{ + createKey(ssl); +} + + +ServerKeyExchange::ServerKeyExchange() + : server_key_(0) +{} + + +ServerKeyExchange::~ServerKeyExchange() +{ + ysDelete(server_key_); +} + + +void ServerKeyExchange::build(SSL& ssl) +{ + server_key_->build(ssl); + set_length(server_key_->get_length()); +} + + +const opaque* ServerKeyExchange::getKey() const +{ + return server_key_->get_serverKey(); +} + + +int ServerKeyExchange::getKeyLength() const +{ + return server_key_->get_length(); +} + + +input_buffer& ServerKeyExchange::set(input_buffer& in) +{ + return in; // process does +} + + +output_buffer& ServerKeyExchange::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType ServerKeyExchange::get_type() const +{ + return server_key_exchange; +} + + +// CertificateRequest +CertificateRequest::CertificateRequest() + : typeTotal_(0) +{ + memset(certificate_types_, 0, sizeof(certificate_types_)); +} + + +CertificateRequest::~CertificateRequest() +{ + + STL::for_each(certificate_authorities_.begin(), + certificate_authorities_.end(), + del_ptr_zero()) ; +} + + +void CertificateRequest::Build() +{ + certificate_types_[0] = rsa_sign; + certificate_types_[1] = dss_sign; + + typeTotal_ = 2; + + uint16 authCount = 0; + uint16 authSz = 0; + + for (int j = 0; j < authCount; j++) { + int sz = REQUEST_HEADER + MIN_DIS_SIZE; + DistinguishedName dn; + certificate_authorities_.push_back(dn = NEW_YS byte[sz]); + + opaque tmp[REQUEST_HEADER]; + c16toa(MIN_DIS_SIZE, tmp); + memcpy(dn, tmp, sizeof(tmp)); + + // fill w/ junk for now + memcpy(dn, tmp, MIN_DIS_SIZE); + authSz += sz; + } + + set_length(SIZEOF_ENUM + typeTotal_ + REQUEST_HEADER + authSz); +} + + +input_buffer& CertificateRequest::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& CertificateRequest::get(output_buffer& out) const +{ + return out << *this; +} + + +// input operator for CertificateRequest +input_buffer& operator>>(input_buffer& input, CertificateRequest& request) +{ + // types + request.typeTotal_ = input[AUTO]; + if (request.typeTotal_ > CERT_TYPES) { + input.set_error(); + return input; + } + for (int i = 0; i < request.typeTotal_; i++) + request.certificate_types_[i] = ClientCertificateType(input[AUTO]); + + byte tmp[2]; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + uint16 sz; + ato16(tmp, sz); + + // authorities + while (sz) { + uint16 dnSz; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, dnSz); + + input.set_current(input.get_current() + dnSz); + + sz -= dnSz + REQUEST_HEADER; + + if (input.get_error()) + break; + } + + return input; +} + + +// output operator for CertificateRequest +output_buffer& operator<<(output_buffer& output, + const CertificateRequest& request) +{ + // types + output[AUTO] = request.typeTotal_; + for (int i = 0; i < request.typeTotal_; i++) + output[AUTO] = request.certificate_types_[i]; + + // authorities + opaque tmp[REQUEST_HEADER]; + c16toa(request.get_length() - SIZEOF_ENUM - + request.typeTotal_ - REQUEST_HEADER, tmp); + output.write(tmp, sizeof(tmp)); + + STL::list::const_iterator first = + request.certificate_authorities_.begin(); + STL::list::const_iterator last = + request.certificate_authorities_.end(); + while (first != last) { + uint16 sz; + ato16(*first, sz); + output.write(*first, sz + REQUEST_HEADER); + + ++first; + } + + return output; +} + + +// CertificateRequest processing handler +void CertificateRequest::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + CertManager& cm = ssl.useCrypto().use_certManager(); + + cm.setSendVerify(); + if (cm.get_cert() == NULL || cm.get_privateKey() == NULL) + cm.setSendBlankCert(); // send blank cert, OpenSSL requires now +} + + +HandShakeType CertificateRequest::get_type() const +{ + return certificate_request; +} + + +// CertificateVerify +CertificateVerify::CertificateVerify() : signature_(0) +{} + + +CertificateVerify::~CertificateVerify() +{ + ysArrayDelete(signature_); +} + + +void CertificateVerify::Build(SSL& ssl) +{ + build_certHashes(ssl, hashes_); + + uint16 sz = 0; + byte len[VERIFY_HEADER]; + mySTL::auto_array sig; + + // sign + const CertManager& cert = ssl.getCrypto().get_certManager(); + if (cert.get_keyType() == rsa_sa_algo) { + RSA rsa(cert.get_privateKey(), cert.get_privateKeyLength(), false); + + sz = rsa.get_cipherLength() + VERIFY_HEADER; + sig.reset(NEW_YS byte[sz]); + + c16toa(sz - VERIFY_HEADER, len); + memcpy(sig.get(), len, VERIFY_HEADER); + rsa.sign(sig.get() + VERIFY_HEADER, hashes_.md5_, sizeof(Hashes), + ssl.getCrypto().get_random()); + // check for rsa signautre fault + if (!rsa.verify(hashes_.md5_, sizeof(Hashes), sig.get() + VERIFY_HEADER, + rsa.get_cipherLength())) { + ssl.SetError(rsaSignFault_error); + return; + } + } + else { // DSA + DSS dss(cert.get_privateKey(), cert.get_privateKeyLength(), false); + + sz = DSS_SIG_SZ + DSS_ENCODED_EXTRA + VERIFY_HEADER; + sig.reset(NEW_YS byte[sz]); + + c16toa(sz - VERIFY_HEADER, len); + memcpy(sig.get(), len, VERIFY_HEADER); + dss.sign(sig.get() + VERIFY_HEADER, hashes_.sha_, SHA_LEN, + ssl.getCrypto().get_random()); + + byte encoded[DSS_SIG_SZ + DSS_ENCODED_EXTRA]; + TaoCrypt::EncodeDSA_Signature(sig.get() + VERIFY_HEADER, encoded); + memcpy(sig.get() + VERIFY_HEADER, encoded, sizeof(encoded)); + } + set_length(sz); + signature_ = sig.release(); +} + + +input_buffer& CertificateVerify::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& CertificateVerify::get(output_buffer& out) const +{ + return out << *this; +} + + +// input operator for CertificateVerify +input_buffer& operator>>(input_buffer& input, CertificateVerify& request) +{ + byte tmp[VERIFY_HEADER]; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + + uint16 sz = 0; + ato16(tmp, sz); + request.set_length(sz); + + if (sz == 0) { + input.set_error(); + return input; + } + + request.signature_ = NEW_YS byte[sz]; + input.read(request.signature_, sz); + + return input; +} + + +// output operator for CertificateVerify +output_buffer& operator<<(output_buffer& output, + const CertificateVerify& verify) +{ + output.write(verify.signature_, verify.get_length()); + + return output; +} + + +// CertificateVerify processing handler +void CertificateVerify::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + const Hashes& hashVerify = ssl.getHashes().get_certVerify(); + const CertManager& cert = ssl.getCrypto().get_certManager(); + + if (cert.get_peerKeyType() == rsa_sa_algo) { + RSA rsa(cert.get_peerKey(), cert.get_peerKeyLength()); + + if (!rsa.verify(hashVerify.md5_, sizeof(hashVerify), signature_, + get_length())) + ssl.SetError(verify_error); + } + else { // DSA + byte decodedSig[DSS_SIG_SZ]; + TaoCrypt::DecodeDSA_Signature(decodedSig, signature_, get_length()); + + DSS dss(cert.get_peerKey(), cert.get_peerKeyLength()); + if (!dss.verify(hashVerify.sha_, SHA_LEN, decodedSig, get_length())) + ssl.SetError(verify_error); + } +} + + +HandShakeType CertificateVerify::get_type() const +{ + return certificate_verify; +} + + +// output operator for ClientKeyExchange +output_buffer& operator<<(output_buffer& output, const ClientKeyExchange& ck) +{ + output.write(ck.getKey(), ck.getKeyLength()); + return output; +} + + +// Client Key Exchange processing handler +void ClientKeyExchange::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + createKey(ssl); + if (ssl.GetError()) return; + client_key_->read(ssl, input); + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + if (ssl.getCrypto().get_certManager().verifyPeer()) + build_certHashes(ssl, ssl.useHashes().use_certVerify()); + + ssl.useStates().useServer() = clientKeyExchangeComplete; +} + + +ClientKeyExchange::ClientKeyExchange(SSL& ssl) +{ + createKey(ssl); +} + + +ClientKeyExchange::ClientKeyExchange() + : client_key_(0) +{} + + +ClientKeyExchange::~ClientKeyExchange() +{ + ysDelete(client_key_); +} + + +void ClientKeyExchange::build(SSL& ssl) +{ + client_key_->build(ssl); + set_length(client_key_->get_length()); +} + +const opaque* ClientKeyExchange::getKey() const +{ + return client_key_->get_clientKey(); +} + + +int ClientKeyExchange::getKeyLength() const +{ + return client_key_->get_length(); +} + + +input_buffer& ClientKeyExchange::set(input_buffer& in) +{ + return in; +} + + +output_buffer& ClientKeyExchange::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType ClientKeyExchange::get_type() const +{ + return client_key_exchange; +} + + +// input operator for Finished +input_buffer& operator>>(input_buffer& input, Finished&) +{ + /* do in process */ + + return input; +} + +// output operator for Finished +output_buffer& operator<<(output_buffer& output, const Finished& fin) +{ + if (fin.get_length() == FINISHED_SZ) { + output.write(fin.hashes_.md5_, MD5_LEN); + output.write(fin.hashes_.sha_, SHA_LEN); + } + else // TLS_FINISHED_SZ + output.write(fin.hashes_.md5_, TLS_FINISHED_SZ); + + return output; +} + + +// Finished processing handler +void Finished::Process(input_buffer& input, SSL& ssl) +{ + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + // verify hashes + const Finished& verify = ssl.getHashes().get_verify(); + uint finishedSz = ssl.isTLS() ? TLS_FINISHED_SZ : FINISHED_SZ; + + input.read(hashes_.md5_, finishedSz); + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + if (memcmp(&hashes_, &verify.hashes_, finishedSz)) { + ssl.SetError(verify_error); + return; + } + + // read verify mac + opaque verifyMAC[SHA_LEN]; + uint macSz = finishedSz + HANDSHAKE_HEADER; + + if (ssl.isTLS()) + TLS_hmac(ssl, verifyMAC, input.get_buffer() + input.get_current() + - macSz, macSz, handshake, true); + else + hmac(ssl, verifyMAC, input.get_buffer() + input.get_current() - macSz, + macSz, handshake, true); + + // read mac and fill + opaque mac[SHA_LEN]; // max size + int digestSz = ssl.getCrypto().get_digest().get_digestSize(); + input.read(mac, digestSz); + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + uint ivExtra = 0; + if (ssl.getSecurity().get_parms().cipher_type_ == block) + if (ssl.isTLSv1_1()) + ivExtra = ssl.getCrypto().get_cipher().get_blockSize(); + + opaque fill; + int padSz = ssl.getSecurity().get_parms().encrypt_size_ - ivExtra - + HANDSHAKE_HEADER - finishedSz - digestSz; + for (int i = 0; i < padSz; i++) + fill = input[AUTO]; + if (input.get_error()) { + ssl.SetError(bad_input); + return; + } + + // verify mac + if (memcmp(mac, verifyMAC, digestSz)) { + ssl.SetError(verify_error); + return; + } + + // update states + ssl.useStates().useHandShake() = handShakeReady; + if (ssl.getSecurity().get_parms().entity_ == client_end) + ssl.useStates().useClient() = serverFinishedComplete; + else + ssl.useStates().useServer() = clientFinishedComplete; +} + + +Finished::Finished() +{ + set_length(FINISHED_SZ); +} + + +uint8* Finished::set_md5() +{ + return hashes_.md5_; +} + + +uint8* Finished::set_sha() +{ + return hashes_.sha_; +} + + +input_buffer& Finished::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& Finished::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType Finished::get_type() const +{ + return finished; +} + + +void clean(volatile opaque* p, uint sz, RandomPool& ran) +{ + uint i(0); + + for (i = 0; i < sz; ++i) + p[i] = 0; + + ran.Fill(const_cast(p), sz); + + for (i = 0; i < sz; ++i) + p[i] = 0; +} + + + +Connection::Connection(ProtocolVersion v, RandomPool& ran) + : pre_master_secret_(0), sequence_number_(0), peer_sequence_number_(0), + pre_secret_len_(0), send_server_key_(false), master_clean_(false), + TLS_(v.major_ >= 3 && v.minor_ >= 1), + TLSv1_1_(v.major_ >= 3 && v.minor_ >= 2), compression_(false), + version_(v), random_(ran) +{ + memset(sessionID_, 0, sizeof(sessionID_)); +} + + +Connection::~Connection() +{ + CleanMaster(); CleanPreMaster(); ysArrayDelete(pre_master_secret_); +} + + +void Connection::AllocPreSecret(uint sz) +{ + pre_master_secret_ = NEW_YS opaque[pre_secret_len_ = sz]; +} + + +void Connection::TurnOffTLS() +{ + TLS_ = false; + version_.minor_ = 0; +} + + +void Connection::TurnOffTLS1_1() +{ + TLSv1_1_ = false; + version_.minor_ = 1; +} + + +// wipeout master secret +void Connection::CleanMaster() +{ + if (!master_clean_) { + volatile opaque* p = master_secret_; + clean(p, SECRET_LEN, random_); + master_clean_ = true; + } +} + + +// wipeout pre master secret +void Connection::CleanPreMaster() +{ + if (pre_master_secret_) { + volatile opaque* p = pre_master_secret_; + clean(p, pre_secret_len_, random_); + + ysArrayDelete(pre_master_secret_); + pre_master_secret_ = 0; + } +} + + +// Create functions for message factory +Message* CreateCipherSpec() { return NEW_YS ChangeCipherSpec; } +Message* CreateAlert() { return NEW_YS Alert; } +Message* CreateHandShake() { return NEW_YS HandShakeHeader; } +Message* CreateData() { return NEW_YS Data; } + +// Create functions for handshake factory +HandShakeBase* CreateHelloRequest() { return NEW_YS HelloRequest; } +HandShakeBase* CreateClientHello() { return NEW_YS ClientHello; } +HandShakeBase* CreateServerHello() { return NEW_YS ServerHello; } +HandShakeBase* CreateCertificate() { return NEW_YS Certificate; } +HandShakeBase* CreateServerKeyExchange() { return NEW_YS ServerKeyExchange;} +HandShakeBase* CreateCertificateRequest() { return NEW_YS + CertificateRequest; } +HandShakeBase* CreateServerHelloDone() { return NEW_YS ServerHelloDone; } +HandShakeBase* CreateCertificateVerify() { return NEW_YS CertificateVerify;} +HandShakeBase* CreateClientKeyExchange() { return NEW_YS ClientKeyExchange;} +HandShakeBase* CreateFinished() { return NEW_YS Finished; } + +// Create functions for server key exchange factory +ServerKeyBase* CreateRSAServerKEA() { return NEW_YS RSA_Server; } +ServerKeyBase* CreateDHServerKEA() { return NEW_YS DH_Server; } +ServerKeyBase* CreateFortezzaServerKEA() { return NEW_YS Fortezza_Server; } + +// Create functions for client key exchange factory +ClientKeyBase* CreateRSAClient() { return NEW_YS + EncryptedPreMasterSecret; } +ClientKeyBase* CreateDHClient() { return NEW_YS + ClientDiffieHellmanPublic; } +ClientKeyBase* CreateFortezzaClient() { return NEW_YS FortezzaKeys; } + + +// Constructor calls this to Register compile time callbacks +void InitMessageFactory(MessageFactory& mf) +{ + mf.Reserve(4); + mf.Register(alert, CreateAlert); + mf.Register(change_cipher_spec, CreateCipherSpec); + mf.Register(handshake, CreateHandShake); + mf.Register(application_data, CreateData); +} + + +// Constructor calls this to Register compile time callbacks +void InitHandShakeFactory(HandShakeFactory& hsf) +{ + hsf.Reserve(10); + hsf.Register(hello_request, CreateHelloRequest); + hsf.Register(client_hello, CreateClientHello); + hsf.Register(server_hello, CreateServerHello); + hsf.Register(certificate, CreateCertificate); + hsf.Register(server_key_exchange, CreateServerKeyExchange); + hsf.Register(certificate_request, CreateCertificateRequest); + hsf.Register(server_hello_done, CreateServerHelloDone); + hsf.Register(certificate_verify, CreateCertificateVerify); + hsf.Register(client_key_exchange, CreateClientKeyExchange); + hsf.Register(finished, CreateFinished); +} + + +// Constructor calls this to Register compile time callbacks +void InitServerKeyFactory(ServerKeyFactory& skf) +{ + skf.Reserve(3); + skf.Register(rsa_kea, CreateRSAServerKEA); + skf.Register(diffie_hellman_kea, CreateDHServerKEA); + skf.Register(fortezza_kea, CreateFortezzaServerKEA); +} + + +// Constructor calls this to Register compile time callbacks +void InitClientKeyFactory(ClientKeyFactory& ckf) +{ + ckf.Reserve(3); + ckf.Register(rsa_kea, CreateRSAClient); + ckf.Register(diffie_hellman_kea, CreateDHClient); + ckf.Register(fortezza_kea, CreateFortezzaClient); +} + + +} // namespace diff --git a/mysql/extra/yassl/src/yassl_int.cpp b/mysql/extra/yassl/src/yassl_int.cpp new file mode 100644 index 0000000..a39965c --- /dev/null +++ b/mysql/extra/yassl/src/yassl_int.cpp @@ -0,0 +1,2826 @@ +/* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + +/* yaSSL internal source implements SSL supporting types not specified in the + * draft along with type conversion functions. + */ + +// First include (the generated) my_config.h, to get correct platform defines. +#include "my_config.h" +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "runtime.hpp" +#include "yassl_int.hpp" +#include "handshake.hpp" +#include "timer.hpp" + +#ifdef HAVE_LIBZ + #include "zlib.h" +#endif + + +#ifdef YASSL_PURE_C + + void* operator new(size_t sz, yaSSL::new_t) + { + void* ptr = malloc(sz ? sz : 1); + if (!ptr) abort(); + + return ptr; + } + + + void operator delete(void* ptr, yaSSL::new_t) + { + if (ptr) free(ptr); + } + + + void* operator new[](size_t sz, yaSSL::new_t nt) + { + return ::operator new(sz, nt); + } + + + void operator delete[](void* ptr, yaSSL::new_t nt) + { + ::operator delete(ptr, nt); + } + + namespace yaSSL { + + new_t ys; // for yaSSL library new + + } + +#endif // YASSL_PURE_C + +/* for the definition of get_tty_password() */ +#include + +namespace yaSSL { + + + + + + +// convert a 32 bit integer into a 24 bit one +void c32to24(uint32 u32, uint24& u24) +{ + u24[0] = (u32 >> 16) & 0xff; + u24[1] = (u32 >> 8) & 0xff; + u24[2] = u32 & 0xff; +} + + +// convert a 24 bit integer into a 32 bit one +void c24to32(const uint24 u24, uint32& u32) +{ + u32 = 0; + u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2]; +} + + +// convert with return for ease of use +uint32 c24to32(const uint24 u24) +{ + uint32 ret; + c24to32(u24, ret); + + return ret; +} + + +// using a for opaque since underlying type is unsgined char and o is not a +// good leading identifier + +// convert opaque to 16 bit integer +void ato16(const opaque* c, uint16& u16) +{ + u16 = 0; + u16 = (c[0] << 8) | (c[1]); +} + + +// convert (copy) opaque to 24 bit integer +void ato24(const opaque* c, uint24& u24) +{ + u24[0] = c[0]; + u24[1] = c[1]; + u24[2] = c[2]; +} + + +// convert 16 bit integer to opaque +void c16toa(uint16 u16, opaque* c) +{ + c[0] = (u16 >> 8) & 0xff; + c[1] = u16 & 0xff; +} + + +// convert 24 bit integer to opaque +void c24toa(const uint24 u24, opaque* c) +{ + c[0] = u24[0]; + c[1] = u24[1]; + c[2] = u24[2]; +} + + +// convert 32 bit integer to opaque +void c32toa(uint32 u32, opaque* c) +{ + c[0] = (u32 >> 24) & 0xff; + c[1] = (u32 >> 16) & 0xff; + c[2] = (u32 >> 8) & 0xff; + c[3] = u32 & 0xff; +} + + +States::States() : recordLayer_(recordReady), handshakeLayer_(preHandshake), + clientState_(serverNull), serverState_(clientNull), + connectState_(CONNECT_BEGIN), acceptState_(ACCEPT_BEGIN), + what_(no_error) {} + +const RecordLayerState& States::getRecord() const +{ + return recordLayer_; +} + + +const HandShakeState& States::getHandShake() const +{ + return handshakeLayer_; +} + + +const ClientState& States::getClient() const +{ + return clientState_; +} + + +const ServerState& States::getServer() const +{ + return serverState_; +} + + +const ConnectState& States::GetConnect() const +{ + return connectState_; +} + + +const AcceptState& States::GetAccept() const +{ + return acceptState_; +} + + +const char* States::getString() const +{ + return errorString_; +} + + +YasslError States::What() const +{ + return what_; +} + + +RecordLayerState& States::useRecord() +{ + return recordLayer_; +} + + +HandShakeState& States::useHandShake() +{ + return handshakeLayer_; +} + + +ClientState& States::useClient() +{ + return clientState_; +} + + +ServerState& States::useServer() +{ + return serverState_; +} + + +ConnectState& States::UseConnect() +{ + return connectState_; +} + + +AcceptState& States::UseAccept() +{ + return acceptState_; +} + + +char* States::useString() +{ + return errorString_; +} + + +void States::SetError(YasslError ye) +{ + what_ = ye; +} + + +// mark message recvd, check for duplicates, return 0 on success +int States::SetMessageRecvd(HandShakeType hst) +{ + switch (hst) { + case hello_request: + break; // could send more than one + + case client_hello: + if (recvdMessages_.gotClientHello_) + return -1; + recvdMessages_.gotClientHello_ = 1; + break; + + case server_hello: + if (recvdMessages_.gotServerHello_) + return -1; + recvdMessages_.gotServerHello_ = 1; + break; + + case certificate: + if (recvdMessages_.gotCert_) + return -1; + recvdMessages_.gotCert_ = 1; + break; + + case server_key_exchange: + if (recvdMessages_.gotServerKeyExchange_) + return -1; + recvdMessages_.gotServerKeyExchange_ = 1; + break; + + case certificate_request: + if (recvdMessages_.gotCertRequest_) + return -1; + recvdMessages_.gotCertRequest_ = 1; + break; + + case server_hello_done: + if (recvdMessages_.gotServerHelloDone_) + return -1; + recvdMessages_.gotServerHelloDone_ = 1; + break; + + case certificate_verify: + if (recvdMessages_.gotCertVerify_) + return -1; + recvdMessages_.gotCertVerify_ = 1; + break; + + case client_key_exchange: + if (recvdMessages_.gotClientKeyExchange_) + return -1; + recvdMessages_.gotClientKeyExchange_ = 1; + break; + + case finished: + if (recvdMessages_.gotFinished_) + return -1; + recvdMessages_.gotFinished_ = 1; + break; + + + default: + return -1; + + } + + return 0; +} + + +sslFactory::sslFactory() : + messageFactory_(InitMessageFactory), + handShakeFactory_(InitHandShakeFactory), + serverKeyFactory_(InitServerKeyFactory), + clientKeyFactory_(InitClientKeyFactory) +{} + + +const MessageFactory& sslFactory::getMessage() const +{ + return messageFactory_; +} + + +const HandShakeFactory& sslFactory::getHandShake() const +{ + return handShakeFactory_; +} + + +const ServerKeyFactory& sslFactory::getServerKey() const +{ + return serverKeyFactory_; +} + + +const ClientKeyFactory& sslFactory::getClientKey() const +{ + return clientKeyFactory_; +} + + +// extract context parameters and store +SSL::SSL(SSL_CTX* ctx) + : secure_(ctx->getMethod()->getVersion(), crypto_.use_random(), + ctx->getMethod()->getSide(), ctx->GetCiphers(), ctx, + ctx->GetDH_Parms().set_), quietShutdown_(false), has_data_(false) +{ + if (int err = crypto_.get_random().GetError()) { + SetError(YasslError(err)); + return; + } + + CertManager& cm = crypto_.use_certManager(); + cm.CopySelfCert(ctx->getCert()); + + bool serverSide = secure_.use_parms().entity_ == server_end; + + if (ctx->getKey()) { + if (int err = cm.SetPrivateKey(*ctx->getKey())) { + SetError(YasslError(err)); + return; + } + else if (serverSide && !(ctx->GetCiphers().setSuites_)) { + // remove RSA or DSA suites depending on cert key type + ProtocolVersion pv = secure_.get_connection().version_; + + bool removeDH = secure_.use_parms().removeDH_; + bool removeRSA = false; + bool removeDSA = false; + + if (cm.get_keyType() == rsa_sa_algo) + removeDSA = true; + else + removeRSA = true; + secure_.use_parms().SetSuites(pv, removeDH, removeRSA, removeDSA); + } + } + else if (serverSide) { + SetError(no_key_file); + return; + } + + if (ctx->getMethod()->verifyPeer()) + cm.setVerifyPeer(); + if (ctx->getMethod()->verifyNone()) + cm.setVerifyNone(); + if (ctx->getMethod()->failNoCert()) + cm.setFailNoCert(); + cm.setVerifyCallback(ctx->getVerifyCallback()); + + if (serverSide) + crypto_.SetDH(ctx->GetDH_Parms()); + + const SSL_CTX::CertList& ca = ctx->GetCA_List(); + SSL_CTX::CertList::const_iterator first(ca.begin()); + SSL_CTX::CertList::const_iterator last(ca.end()); + + while (first != last) { + if (int err = cm.CopyCaCert(*first)) { + SetError(YasslError(err)); + return; + } + ++first; + } +} + + +// store pending security parameters from Server Hello +void SSL::set_pending(Cipher suite) +{ + Parameters& parms = secure_.use_parms(); + + switch (suite) { + + case TLS_RSA_WITH_AES_256_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = rsa_kea; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, cipher_names[TLS_RSA_WITH_AES_256_CBC_SHA], + MAX_SUITE_NAME); + break; + + case TLS_RSA_WITH_AES_128_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = rsa_kea; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS AES); + strncpy(parms.cipher_name_, cipher_names[TLS_RSA_WITH_AES_128_CBC_SHA], + MAX_SUITE_NAME); + break; + + case SSL_RSA_WITH_3DES_EDE_CBC_SHA: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = sha; + parms.kea_ = rsa_kea; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS DES_EDE); + strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_3DES_EDE_CBC_SHA] + , MAX_SUITE_NAME); + break; + + case SSL_RSA_WITH_DES_CBC_SHA: + parms.bulk_cipher_algorithm_ = des; + parms.mac_algorithm_ = sha; + parms.kea_ = rsa_kea; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS DES); + strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_DES_CBC_SHA], + MAX_SUITE_NAME); + break; + + case SSL_RSA_WITH_RC4_128_SHA: + parms.bulk_cipher_algorithm_ = rc4; + parms.mac_algorithm_ = sha; + parms.kea_ = rsa_kea; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = RC4_KEY_SZ; + parms.iv_size_ = 0; + parms.cipher_type_ = stream; + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS RC4); + strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_RC4_128_SHA], + MAX_SUITE_NAME); + break; + + case SSL_RSA_WITH_RC4_128_MD5: + parms.bulk_cipher_algorithm_ = rc4; + parms.mac_algorithm_ = md5; + parms.kea_ = rsa_kea; + parms.hash_size_ = MD5_LEN; + parms.key_size_ = RC4_KEY_SZ; + parms.iv_size_ = 0; + parms.cipher_type_ = stream; + crypto_.setDigest(NEW_YS MD5); + crypto_.setCipher(NEW_YS RC4); + strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_RC4_128_MD5], + MAX_SUITE_NAME); + break; + + case SSL_DHE_RSA_WITH_DES_CBC_SHA: + parms.bulk_cipher_algorithm_ = des; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS DES); + strncpy(parms.cipher_name_, cipher_names[SSL_DHE_RSA_WITH_DES_CBC_SHA], + MAX_SUITE_NAME); + break; + + case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS DES_EDE); + strncpy(parms.cipher_name_, + cipher_names[SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA], MAX_SUITE_NAME); + break; + + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_RSA_WITH_AES_256_CBC_SHA], MAX_SUITE_NAME); + break; + + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS AES); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_RSA_WITH_AES_128_CBC_SHA], MAX_SUITE_NAME); + break; + + case SSL_DHE_DSS_WITH_DES_CBC_SHA: + parms.bulk_cipher_algorithm_ = des; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS DES); + strncpy(parms.cipher_name_, cipher_names[SSL_DHE_DSS_WITH_DES_CBC_SHA], + MAX_SUITE_NAME); + break; + + case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS DES_EDE); + strncpy(parms.cipher_name_, + cipher_names[SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA], MAX_SUITE_NAME); + break; + + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_DSS_WITH_AES_256_CBC_SHA], MAX_SUITE_NAME); + break; + + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS SHA); + crypto_.setCipher(NEW_YS AES); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_DSS_WITH_AES_128_CBC_SHA], MAX_SUITE_NAME); + break; + + case TLS_RSA_WITH_AES_256_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = rsa_kea; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(NEW_YS RMD); + crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, + cipher_names[TLS_RSA_WITH_AES_256_CBC_RMD160], MAX_SUITE_NAME); + break; + + case TLS_RSA_WITH_AES_128_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = rsa_kea; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(NEW_YS RMD); + crypto_.setCipher(NEW_YS AES); + strncpy(parms.cipher_name_, + cipher_names[TLS_RSA_WITH_AES_128_CBC_RMD160], MAX_SUITE_NAME); + break; + + case TLS_RSA_WITH_3DES_EDE_CBC_RMD160: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = rmd; + parms.kea_ = rsa_kea; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(NEW_YS RMD); + crypto_.setCipher(NEW_YS DES_EDE); + strncpy(parms.cipher_name_, + cipher_names[TLS_RSA_WITH_3DES_EDE_CBC_RMD160], MAX_SUITE_NAME); + break; + + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD160: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS RMD); + crypto_.setCipher(NEW_YS DES_EDE); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD160], + MAX_SUITE_NAME); + break; + + case TLS_DHE_RSA_WITH_AES_256_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS RMD); + crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_RSA_WITH_AES_256_CBC_RMD160], + MAX_SUITE_NAME); + break; + + case TLS_DHE_RSA_WITH_AES_128_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS RMD); + crypto_.setCipher(NEW_YS AES); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_RSA_WITH_AES_128_CBC_RMD160], + MAX_SUITE_NAME); + break; + + case TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD160: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS RMD); + crypto_.setCipher(NEW_YS DES_EDE); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD160], + MAX_SUITE_NAME); + break; + + case TLS_DHE_DSS_WITH_AES_256_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS RMD); + crypto_.setCipher(NEW_YS AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_DSS_WITH_AES_256_CBC_RMD160], + MAX_SUITE_NAME); + break; + + case TLS_DHE_DSS_WITH_AES_128_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(NEW_YS RMD); + crypto_.setCipher(NEW_YS AES); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_DSS_WITH_AES_128_CBC_RMD160], + MAX_SUITE_NAME); + break; + + default: + SetError(unknown_cipher); + } +} + +#ifdef _WIN32 +typedef volatile LONG yassl_pthread_once_t; +#define YASSL_PTHREAD_ONCE_INIT 0 +#define YASSL_PTHREAD_ONCE_INPROGRESS 1 +#define YASSL_PTHREAD_ONCE_DONE 2 + +int yassl_pthread_once(yassl_pthread_once_t *once_control, + void (*init_routine)(void)) +{ + LONG state; + + /* + Do "dirty" read to find out if initialization is already done, to + save an interlocked operation in common case. Memory barriers are ensured by + Visual C++ volatile implementation. + */ + if (*once_control == YASSL_PTHREAD_ONCE_DONE) + return 0; + + state= InterlockedCompareExchange(once_control, YASSL_PTHREAD_ONCE_INPROGRESS, + YASSL_PTHREAD_ONCE_INIT); + + switch(state) + { + case YASSL_PTHREAD_ONCE_INIT: + /* This is initializer thread */ + (*init_routine)(); + *once_control= YASSL_PTHREAD_ONCE_DONE; + break; + + case YASSL_PTHREAD_ONCE_INPROGRESS: + /* init_routine in progress. Wait for its completion */ + while(*once_control == YASSL_PTHREAD_ONCE_INPROGRESS) + { + Sleep(1); + } + break; + case YASSL_PTHREAD_ONCE_DONE: + /* Nothing to do */ + break; + } + return 0; +} +#else +#define yassl_pthread_once_t pthread_once_t +#if defined(PTHREAD_ONCE_INITIALIZER) +#define YASSL_PTHREAD_ONCE_INIT PTHREAD_ONCE_INITIALIZER +#else +#define YASSL_PTHREAD_ONCE_INIT PTHREAD_ONCE_INIT +#endif +#define yassl_pthread_once(C,F) pthread_once(C,F) +#endif // _WIN32 + +// store peer's random +void SSL::set_random(const opaque* random, ConnectionEnd sender) +{ + if (sender == client_end) + memcpy(secure_.use_connection().client_random_, random, RAN_LEN); + else + memcpy(secure_.use_connection().server_random_, random, RAN_LEN); +} + + +// store client pre master secret +void SSL::set_preMaster(const opaque* pre, uint sz) +{ + uint i(0); // trim leading zeros + uint fullSz(sz); + + while (i++ < fullSz && *pre == 0) { + sz--; + pre++; + } + + if (sz == 0) { + SetError(bad_input); + return; + } + + secure_.use_connection().AllocPreSecret(sz); + memcpy(secure_.use_connection().pre_master_secret_, pre, sz); +} + + +// set yaSSL zlib type compression +int SSL::SetCompression() +{ +#ifdef HAVE_LIBZ + secure_.use_connection().compression_ = true; + return 0; +#else + return -1; // not built in +#endif +} + + +// unset yaSSL zlib type compression +void SSL::UnSetCompression() +{ + secure_.use_connection().compression_ = false; +} + + +// is yaSSL zlib compression on +bool SSL::CompressionOn() const +{ + return secure_.get_connection().compression_; +} + + +// store master secret +void SSL::set_masterSecret(const opaque* sec) +{ + memcpy(secure_.use_connection().master_secret_, sec, SECRET_LEN); +} + +// store server issued id +void SSL::set_sessionID(const opaque* sessionID) +{ + memcpy(secure_.use_connection().sessionID_, sessionID, ID_LEN); + secure_.use_connection().sessionID_Set_ = true; +} + + +// store error +void SSL::SetError(YasslError ye) +{ + states_.SetError(ye); + //strncpy(states_.useString(), e.what(), mySTL::named_exception::NAME_SIZE); + // TODO: add string here +} + + +// set the quiet shutdown mode (close_nofiy not sent or received on shutdown) +void SSL::SetQuietShutdown(bool mode) +{ + quietShutdown_ = mode; +} + + +Buffers& SSL::useBuffers() +{ + return buffers_; +} + + +// locals +namespace { + +// DeriveKeys and MasterSecret helper sets prefix letters +static bool setPrefix(opaque* sha_input, int i) +{ + switch (i) { + case 0: + memcpy(sha_input, "A", 1); + break; + case 1: + memcpy(sha_input, "BB", 2); + break; + case 2: + memcpy(sha_input, "CCC", 3); + break; + case 3: + memcpy(sha_input, "DDDD", 4); + break; + case 4: + memcpy(sha_input, "EEEEE", 5); + break; + case 5: + memcpy(sha_input, "FFFFFF", 6); + break; + case 6: + memcpy(sha_input, "GGGGGGG", 7); + break; + default: + return false; // prefix_error + } + return true; +} + + +const char handshake_order[] = "Out of order HandShake Message!"; + + +} // namespcae for locals + + +void SSL::order_error() +{ + SetError(out_of_order); +} + + +// Create and store the master secret see page 32, 6.1 +void SSL::makeMasterSecret() +{ + if (GetError()) return; + + if (isTLS()) + makeTLSMasterSecret(); + else { + opaque sha_output[SHA_LEN]; + + const uint& preSz = secure_.get_connection().pre_secret_len_; + output_buffer md5_input(preSz + SHA_LEN); + output_buffer sha_input(PREFIX + preSz + 2 * RAN_LEN); + + MD5 md5; + SHA sha; + + md5_input.write(secure_.get_connection().pre_master_secret_, preSz); + + for (int i = 0; i < MASTER_ROUNDS; ++i) { + opaque prefix[PREFIX]; + if (!setPrefix(prefix, i)) { + SetError(prefix_error); + return; + } + + sha_input.set_current(0); + sha_input.write(prefix, i + 1); + + sha_input.write(secure_.get_connection().pre_master_secret_,preSz); + sha_input.write(secure_.get_connection().client_random_, RAN_LEN); + sha_input.write(secure_.get_connection().server_random_, RAN_LEN); + sha.get_digest(sha_output, sha_input.get_buffer(), + sha_input.get_size()); + + md5_input.set_current(preSz); + md5_input.write(sha_output, SHA_LEN); + md5.get_digest(&secure_.use_connection().master_secret_[i*MD5_LEN], + md5_input.get_buffer(), md5_input.get_size()); + } + deriveKeys(); + } + secure_.use_connection().CleanPreMaster(); +} + + +// create TLSv1 master secret +void SSL::makeTLSMasterSecret() +{ + opaque seed[SEED_LEN]; + + memcpy(seed, secure_.get_connection().client_random_, RAN_LEN); + memcpy(&seed[RAN_LEN], secure_.get_connection().server_random_, RAN_LEN); + + PRF(secure_.use_connection().master_secret_, SECRET_LEN, + secure_.get_connection().pre_master_secret_, + secure_.get_connection().pre_secret_len_, + master_label, MASTER_LABEL_SZ, + seed, SEED_LEN); + + deriveTLSKeys(); +} + + +// derive mac, write, and iv keys for server and client, see page 34, 6.2.2 +void SSL::deriveKeys() +{ + int length = 2 * secure_.get_parms().hash_size_ + + 2 * secure_.get_parms().key_size_ + + 2 * secure_.get_parms().iv_size_; + int rounds = (length + MD5_LEN - 1 ) / MD5_LEN; + input_buffer key_data(rounds * MD5_LEN); + + opaque sha_output[SHA_LEN]; + opaque md5_input[SECRET_LEN + SHA_LEN]; + opaque sha_input[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN]; + + MD5 md5; + SHA sha; + + memcpy(md5_input, secure_.get_connection().master_secret_, SECRET_LEN); + + for (int i = 0; i < rounds; ++i) { + int j = i + 1; + if (!setPrefix(sha_input, i)) { + SetError(prefix_error); + return; + } + + memcpy(&sha_input[j], secure_.get_connection().master_secret_, + SECRET_LEN); + memcpy(&sha_input[j+SECRET_LEN], + secure_.get_connection().server_random_, RAN_LEN); + memcpy(&sha_input[j + SECRET_LEN + RAN_LEN], + secure_.get_connection().client_random_, RAN_LEN); + sha.get_digest(sha_output, sha_input, + sizeof(sha_input) - KEY_PREFIX + j); + + memcpy(&md5_input[SECRET_LEN], sha_output, SHA_LEN); + md5.get_digest(key_data.get_buffer() + i * MD5_LEN, + md5_input, sizeof(md5_input)); + } + storeKeys(key_data.get_buffer()); +} + + +// derive mac, write, and iv keys for server and client +void SSL::deriveTLSKeys() +{ + int length = 2 * secure_.get_parms().hash_size_ + + 2 * secure_.get_parms().key_size_ + + 2 * secure_.get_parms().iv_size_; + opaque seed[SEED_LEN]; + input_buffer key_data(length); + + memcpy(seed, secure_.get_connection().server_random_, RAN_LEN); + memcpy(&seed[RAN_LEN], secure_.get_connection().client_random_, RAN_LEN); + + PRF(key_data.get_buffer(), length, secure_.get_connection().master_secret_, + SECRET_LEN, key_label, KEY_LABEL_SZ, seed, SEED_LEN); + + storeKeys(key_data.get_buffer()); +} + + +// store mac, write, and iv keys for client and server +void SSL::storeKeys(const opaque* key_data) +{ + int sz = secure_.get_parms().hash_size_; + memcpy(secure_.use_connection().client_write_MAC_secret_, key_data, sz); + int i = sz; + memcpy(secure_.use_connection().server_write_MAC_secret_,&key_data[i], sz); + i += sz; + + sz = secure_.get_parms().key_size_; + memcpy(secure_.use_connection().client_write_key_, &key_data[i], sz); + i += sz; + memcpy(secure_.use_connection().server_write_key_, &key_data[i], sz); + i += sz; + + sz = secure_.get_parms().iv_size_; + memcpy(secure_.use_connection().client_write_IV_, &key_data[i], sz); + i += sz; + memcpy(secure_.use_connection().server_write_IV_, &key_data[i], sz); + + setKeys(); +} + + +// set encrypt/decrypt keys and ivs +void SSL::setKeys() +{ + Connection& conn = secure_.use_connection(); + + if (secure_.get_parms().entity_ == client_end) { + crypto_.use_cipher().set_encryptKey(conn.client_write_key_, + conn.client_write_IV_); + crypto_.use_cipher().set_decryptKey(conn.server_write_key_, + conn.server_write_IV_); + } + else { + crypto_.use_cipher().set_encryptKey(conn.server_write_key_, + conn.server_write_IV_); + crypto_.use_cipher().set_decryptKey(conn.client_write_key_, + conn.client_write_IV_); + } +} + + + +// local functors +namespace yassl_int_cpp_local1 { // for explicit templates + +struct SumData { + uint total_; + SumData() : total_(0) {} + void operator()(input_buffer* data) { total_ += data->get_remaining(); } +}; + + +struct SumBuffer { + uint total_; + SumBuffer() : total_(0) {} + void operator()(output_buffer* buffer) { total_ += buffer->get_size(); } +}; + +} // namespace for locals +using namespace yassl_int_cpp_local1; + + +uint SSL::bufferedData() +{ + return STL::for_each(buffers_.getData().begin(),buffers_.getData().end(), + SumData()).total_; +} + + +// use input buffer to fill data +void SSL::fillData(Data& data) +{ + if (GetError()) return; + uint dataSz = data.get_length(); // input, data size to fill + size_t elements = buffers_.getData().size(); + + data.set_length(0); // output, actual data filled + dataSz = min(dataSz, bufferedData()); + + for (size_t i = 0; i < elements; i++) { + input_buffer* front = buffers_.getData().front(); + uint frontSz = front->get_remaining(); + uint readSz = min(dataSz - data.get_length(), frontSz); + + front->read(data.set_buffer() + data.get_length(), readSz); + data.set_length(data.get_length() + readSz); + + if (readSz == frontSz) { + buffers_.useData().pop_front(); + ysDelete(front); + } + if (data.get_length() == dataSz) + break; + } + + if (buffers_.getData().size() == 0) has_data_ = false; // none left +} + + +// like Fill but keep data in buffer +void SSL::PeekData(Data& data) +{ + if (GetError()) return; + uint dataSz = data.get_length(); // input, data size to fill + size_t elements = buffers_.getData().size(); + + data.set_length(0); // output, actual data filled + dataSz = min(dataSz, bufferedData()); + + Buffers::inputList::iterator front = buffers_.useData().begin(); + + while (elements) { + uint frontSz = (*front)->get_remaining(); + uint readSz = min(dataSz - data.get_length(), frontSz); + uint before = (*front)->get_current(); + + (*front)->read(data.set_buffer() + data.get_length(), readSz); + data.set_length(data.get_length() + readSz); + (*front)->set_current(before); + + if (data.get_length() == dataSz) + break; + + elements--; + front++; + } +} + + +// flush output buffer +void SSL::flushBuffer() +{ + if (GetError()) return; + + uint sz = STL::for_each(buffers_.getHandShake().begin(), + buffers_.getHandShake().end(), + SumBuffer()).total_; + output_buffer out(sz); + size_t elements = buffers_.getHandShake().size(); + + for (size_t i = 0; i < elements; i++) { + output_buffer* front = buffers_.getHandShake().front(); + out.write(front->get_buffer(), front->get_size()); + + buffers_.useHandShake().pop_front(); + ysDelete(front); + } + Send(out.get_buffer(), out.get_size()); +} + + +void SSL::Send(const byte* buffer, uint sz) +{ + unsigned int sent = 0; + + if (socket_.send(buffer, sz, sent) != sz) { + if (socket_.WouldBlock()) { + buffers_.SetOutput(NEW_YS output_buffer(sz - sent, buffer + sent, + sz - sent)); + SetError(YasslError(SSL_ERROR_WANT_WRITE)); + } + else + SetError(send_error); + } +} + + +void SSL::SendWriteBuffered() +{ + output_buffer* out = buffers_.TakeOutput(); + + if (out) { + mySTL::auto_ptr tmp(out); + Send(out->get_buffer(), out->get_size()); + } +} + + +// get sequence number, if verify get peer's +uint SSL::get_SEQIncrement(bool verify) +{ + if (verify) + return secure_.use_connection().peer_sequence_number_++; + else + return secure_.use_connection().sequence_number_++; +} + + +const byte* SSL::get_macSecret(bool verify) +{ + if ( (secure_.get_parms().entity_ == client_end && !verify) || + (secure_.get_parms().entity_ == server_end && verify) ) + return secure_.get_connection().client_write_MAC_secret_; + else + return secure_.get_connection().server_write_MAC_secret_; +} + + +void SSL::verifyState(const RecordLayerHeader& rlHeader) +{ + if (GetError()) return; + + if (rlHeader.version_.major_ != 3 || rlHeader.version_.minor_ > 2) { + SetError(badVersion_error); + return; + } + + if (states_.getRecord() == recordNotReady || + (rlHeader.type_ == application_data && // data and handshake + states_.getHandShake() != handShakeReady) ) // isn't complete yet + SetError(record_layer); +} + + +void SSL::verifyState(const HandShakeHeader& hsHeader) +{ + if (GetError()) return; + + if (states_.getHandShake() == handShakeNotReady) { + SetError(handshake_layer); + return; + } + + if (states_.SetMessageRecvd(hsHeader.get_handshakeType()) != 0) { + order_error(); + return; + } + + if (secure_.get_parms().entity_ == client_end) + verifyClientState(hsHeader.get_handshakeType()); + else + verifyServerState(hsHeader.get_handshakeType()); +} + + +void SSL::verifyState(ClientState cs) +{ + if (GetError()) return; + if (states_.getClient() != cs) order_error(); +} + + +void SSL::verifyState(ServerState ss) +{ + if (GetError()) return; + if (states_.getServer() != ss) order_error(); +} + + +void SSL::verfiyHandShakeComplete() +{ + if (GetError()) return; + if (states_.getHandShake() != handShakeReady) order_error(); +} + + +void SSL::verifyClientState(HandShakeType hsType) +{ + if (GetError()) return; + + switch(hsType) { + case server_hello : + if (states_.getClient() != serverNull) + order_error(); + break; + case certificate : + if (states_.getClient() != serverHelloComplete) + order_error(); + break; + case server_key_exchange : + if (states_.getClient() != serverCertComplete) + order_error(); + break; + case certificate_request : + if (states_.getClient() != serverCertComplete && + states_.getClient() != serverKeyExchangeComplete) + order_error(); + break; + case server_hello_done : + if (states_.getClient() != serverCertComplete && + states_.getClient() != serverKeyExchangeComplete) + order_error(); + break; + case finished : + if (states_.getClient() != serverHelloDoneComplete || + secure_.get_parms().pending_) // no change + order_error(); // cipher yet + break; + default : + order_error(); + }; +} + + +void SSL::verifyServerState(HandShakeType hsType) +{ + if (GetError()) return; + + switch(hsType) { + case client_hello : + if (states_.getServer() != clientNull) + order_error(); + break; + case certificate : + if (states_.getServer() != clientHelloComplete) + order_error(); + break; + case client_key_exchange : + if (states_.getServer() != clientHelloComplete) + order_error(); + break; + case certificate_verify : + if (states_.getServer() != clientKeyExchangeComplete) + order_error(); + break; + case finished : + if (states_.getServer() != clientKeyExchangeComplete || + secure_.get_parms().pending_) // no change + order_error(); // cipher yet + break; + default : + order_error(); + }; +} + + +// try to find a suite match +void SSL::matchSuite(const opaque* peer, uint length) +{ + if (length == 0 || (length % 2) != 0) { + SetError(bad_input); + return; + } + + // start with best, if a match we are good, Ciphers are at odd index + // since all SSL and TLS ciphers have 0x00 first byte + for (uint i = 1; i < secure_.get_parms().suites_size_; i += 2) + for (uint j = 0; (j + 1) < length; j+= 2) { + if (peer[j] != 0x00) { + continue; // only 0x00 first byte supported + } + + if (secure_.use_parms().suites_[i] == peer[j + 1]) { + secure_.use_parms().suite_[0] = 0x00; + secure_.use_parms().suite_[1] = peer[j + 1]; + return; + } + } + + SetError(match_error); +} + + +void SSL::set_session(SSL_SESSION* s) +{ + if (getSecurity().GetContext()->GetSessionCacheOff()) + return; + + if (s && GetSessions().lookup(s->GetID(), &secure_.use_resume())) { + secure_.set_resuming(true); + crypto_.use_certManager().setPeerX509(s->GetPeerX509()); + } +} + + +const Crypto& SSL::getCrypto() const +{ + return crypto_; +} + + +const Security& SSL::getSecurity() const +{ + return secure_; +} + + +const States& SSL::getStates() const +{ + return states_; +} + + +const sslHashes& SSL::getHashes() const +{ + return hashes_; +} + + +const sslFactory& SSL::getFactory() const +{ + return GetSSL_Factory(); +} + + +const Socket& SSL::getSocket() const +{ + return socket_; +} + + +YasslError SSL::GetError() const +{ + return states_.What(); +} + + +bool SSL::GetQuietShutdown() const +{ + return quietShutdown_; +} + + +bool SSL::GetMultiProtocol() const +{ + return secure_.GetContext()->getMethod()->multipleProtocol(); +} + + +Crypto& SSL::useCrypto() +{ + return crypto_; +} + + +Security& SSL::useSecurity() +{ + return secure_; +} + + +States& SSL::useStates() +{ + return states_; +} + + +sslHashes& SSL::useHashes() +{ + return hashes_; +} + + +Socket& SSL::useSocket() +{ + return socket_; +} + + +Log& SSL::useLog() +{ + return log_; +} + + +bool SSL::isTLS() const +{ + return secure_.get_connection().TLS_; +} + + +bool SSL::isTLSv1_1() const +{ + return secure_.get_connection().TLSv1_1_; +} + + +// is there buffered data available, optimization to remove iteration on buffer +bool SSL::HasData() const +{ + return has_data_; +} + + +void SSL::addData(input_buffer* data) +{ + buffers_.useData().push_back(data); + if (!has_data_) has_data_ = true; +} + + +void SSL::addBuffer(output_buffer* b) +{ + buffers_.useHandShake().push_back(b); +} + + +void SSL_SESSION::CopyX509(X509* x) +{ + if (x == 0) return; + + X509_NAME* issuer = x->GetIssuer(); + X509_NAME* subject = x->GetSubject(); + ASN1_TIME* before = x->GetBefore(); + ASN1_TIME* after = x->GetAfter(); + + peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(), + subject->GetName(), subject->GetLength(), + before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); +} + + +// store connection parameters +SSL_SESSION::SSL_SESSION(const SSL& ssl, RandomPool& ran) + : timeout_(DEFAULT_TIMEOUT), random_(ran), peerX509_(0) +{ + const Connection& conn = ssl.getSecurity().get_connection(); + + memcpy(sessionID_, conn.sessionID_, ID_LEN); + memcpy(master_secret_, conn.master_secret_, SECRET_LEN); + memcpy(suite_, ssl.getSecurity().get_parms().suite_, SUITE_LEN); + + bornOn_ = lowResTimer(); + + CopyX509(ssl.getCrypto().get_certManager().get_peerX509()); +} + + +// for resumption copy in ssl::parameters +SSL_SESSION::SSL_SESSION(RandomPool& ran) + : bornOn_(0), timeout_(0), random_(ran), peerX509_(0) +{ + memset(sessionID_, 0, ID_LEN); + memset(master_secret_, 0, SECRET_LEN); + memset(suite_, 0, SUITE_LEN); +} + + +SSL_SESSION& SSL_SESSION::operator=(const SSL_SESSION& that) +{ + memcpy(sessionID_, that.sessionID_, ID_LEN); + memcpy(master_secret_, that.master_secret_, SECRET_LEN); + memcpy(suite_, that.suite_, SUITE_LEN); + + bornOn_ = that.bornOn_; + timeout_ = that.timeout_; + + if (peerX509_) { + ysDelete(peerX509_); + peerX509_ = 0; + } + CopyX509(that.peerX509_); + + return *this; +} + + +const opaque* SSL_SESSION::GetID() const +{ + return sessionID_; +} + + +const opaque* SSL_SESSION::GetSecret() const +{ + return master_secret_; +} + + +const Cipher* SSL_SESSION::GetSuite() const +{ + return suite_; +} + + +X509* SSL_SESSION::GetPeerX509() const +{ + return peerX509_; +} + + +uint SSL_SESSION::GetBornOn() const +{ + return bornOn_; +} + + +uint SSL_SESSION::GetTimeOut() const +{ + return timeout_; +} + + +void SSL_SESSION::SetTimeOut(uint t) +{ + timeout_ = t; +} + + +extern void clean(volatile opaque*, uint, RandomPool&); + + +// clean up secret data +SSL_SESSION::~SSL_SESSION() +{ + volatile opaque* p = master_secret_; + clean(p, SECRET_LEN, random_); + + ysDelete(peerX509_); +} + + +static Sessions* sessionsInstance = 0; +static yassl_pthread_once_t session_created= YASSL_PTHREAD_ONCE_INIT; + +void Session_initialize() +{ + sessionsInstance = NEW_YS Sessions; +} + +extern "C" +{ + static void c_session_initialize() { Session_initialize(); } +} + + +Sessions& GetSessions() +{ + yassl_pthread_once(&session_created, c_session_initialize); + return *sessionsInstance; +} + + +static sslFactory* sslFactoryInstance = 0; + +sslFactory& GetSSL_Factory() +{ + if (!sslFactoryInstance) + sslFactoryInstance = NEW_YS sslFactory; + return *sslFactoryInstance; +} + + +static Errors* errorsInstance = 0; + +Errors& GetErrors() +{ + if (!errorsInstance) + errorsInstance = NEW_YS Errors; + return *errorsInstance; +} + + +typedef Mutex::Lock Lock; + + + +void Sessions::add(const SSL& ssl) +{ + if (ssl.getSecurity().get_connection().sessionID_Set_) { + Lock guard(mutex_); + list_.push_back(NEW_YS SSL_SESSION(ssl, random_)); + count_++; + } + + if (count_ > SESSION_FLUSH_COUNT) + if (!ssl.getSecurity().GetContext()->GetSessionCacheFlushOff()) + Flush(); +} + + +Sessions::~Sessions() +{ + STL::for_each(list_.begin(), list_.end(), del_ptr_zero()); +} + + +// locals +namespace yassl_int_cpp_local2 { // for explicit templates + +typedef STL::list::iterator sess_iterator; +typedef STL::list::iterator thr_iterator; + +struct sess_match { + const opaque* id_; + explicit sess_match(const opaque* p) : id_(p) {} + + bool operator()(SSL_SESSION* sess) + { + if ( memcmp(sess->GetID(), id_, ID_LEN) == 0) + return true; + return false; + } +}; + + +THREAD_ID_T GetSelf() +{ +#ifndef _POSIX_THREADS + return GetCurrentThreadId(); +#else + return pthread_self(); +#endif +} + +struct thr_match { + THREAD_ID_T id_; + explicit thr_match() : id_(GetSelf()) {} + + bool operator()(ThreadError thr) + { + if (thr.threadID_ == id_) + return true; + return false; + } +}; + + +} // local namespace +using namespace yassl_int_cpp_local2; + + +// lookup session by id, return a copy if space provided +SSL_SESSION* Sessions::lookup(const opaque* id, SSL_SESSION* copy) +{ + Lock guard(mutex_); + sess_iterator find = STL::find_if(list_.begin(), list_.end(), + sess_match(id)); + if (find != list_.end()) { + uint current = lowResTimer(); + if ( ((*find)->GetBornOn() + (*find)->GetTimeOut()) < current) { + del_ptr_zero()(*find); + list_.erase(find); + return 0; + } + if (copy) + *copy = *(*find); + return *find; + } + return 0; +} + + +// remove a session by id +void Sessions::remove(const opaque* id) +{ + Lock guard(mutex_); + sess_iterator find = STL::find_if(list_.begin(), list_.end(), + sess_match(id)); + if (find != list_.end()) { + del_ptr_zero()(*find); + list_.erase(find); + } +} + + +// flush expired sessions from cache +void Sessions::Flush() +{ + Lock guard(mutex_); + sess_iterator next = list_.begin(); + uint current = lowResTimer(); + + while (next != list_.end()) { + sess_iterator si = next; + ++next; + if ( ((*si)->GetBornOn() + (*si)->GetTimeOut()) < current) { + del_ptr_zero()(*si); + list_.erase(si); + } + } + count_ = 0; // reset flush counter +} + + +// remove a self thread error +void Errors::Remove() +{ + Lock guard(mutex_); + thr_iterator find = STL::find_if(list_.begin(), list_.end(), + thr_match()); + if (find != list_.end()) + list_.erase(find); +} + + +// lookup self error code +int Errors::Lookup(bool peek) +{ + Lock guard(mutex_); + thr_iterator find = STL::find_if(list_.begin(), list_.end(), + thr_match()); + if (find != list_.end()) { + int ret = find->errorID_; + if (!peek) + list_.erase(find); + return ret; + } + else + return 0; +} + + +// add a new error code for self +void Errors::Add(int error) +{ + ThreadError add; + add.errorID_ = error; + add.threadID_ = GetSelf(); + + Remove(); // may have old error + + Lock guard(mutex_); + list_.push_back(add); +} + + +SSL_METHOD::SSL_METHOD(ConnectionEnd ce, ProtocolVersion pv, bool multiProto) + : version_(pv), side_(ce), verifyPeer_(false), verifyNone_(false), + failNoCert_(false), multipleProtocol_(multiProto) +{} + + +ProtocolVersion SSL_METHOD::getVersion() const +{ + return version_; +} + + +ConnectionEnd SSL_METHOD::getSide() const +{ + return side_; +} + + +void SSL_METHOD::setVerifyPeer() +{ + verifyPeer_ = true; +} + + +void SSL_METHOD::setVerifyNone() +{ + verifyNone_ = true; +} + + +void SSL_METHOD::setFailNoCert() +{ + failNoCert_ = true; +} + + +bool SSL_METHOD::verifyPeer() const +{ + return verifyPeer_; +} + + +bool SSL_METHOD::verifyNone() const +{ + return verifyNone_; +} + + +bool SSL_METHOD::failNoCert() const +{ + return failNoCert_; +} + + +bool SSL_METHOD::multipleProtocol() const +{ + return multipleProtocol_; +} + + +/** Implement a my_strdup replacement, so we can reuse get_password() */ +extern "C" char *yassl_mysql_strdup(const char *from, int) +{ + return from ? strdup(from) : NULL; +} + + +extern "C" +{ +int +default_password_callback(char * buffer, int size_arg, int rwflag, + void * /* unused: callback_data */) +{ + char *passwd; + size_t passwd_len, size= (size_t) size_arg; + + passwd= ::yassl_mysql_get_tty_password_ext("Enter PEM pass phrase:", + yassl_mysql_strdup); + + if (!passwd) + return 0; + + passwd_len= strlen(passwd); + + if (!passwd_len) + return 0; + + if (size > 0) + { + size_t result_len= size - 1 > passwd_len ? + passwd_len : size - 1; + memcpy(buffer, passwd, result_len); + buffer[result_len]= 0; + } + free(passwd); + return passwd_len; +} +} + +SSL_CTX::SSL_CTX(SSL_METHOD* meth) + : method_(meth), certificate_(0), privateKey_(0), + passwordCb_(default_password_callback), + userData_(0), sessionCacheOff_(false), sessionCacheFlushOff_(false), + verifyCallback_(0) +{} + + +SSL_CTX::~SSL_CTX() +{ + ysDelete(method_); + ysDelete(certificate_); + ysDelete(privateKey_); + + STL::for_each(caList_.begin(), caList_.end(), del_ptr_zero()); +} + + +void SSL_CTX::AddCA(x509* ca) +{ + caList_.push_back(ca); +} + + +const SSL_CTX::CertList& +SSL_CTX::GetCA_List() const +{ + return caList_; +} + + +VerifyCallback SSL_CTX::getVerifyCallback() const +{ + return verifyCallback_; +} + + +const x509* SSL_CTX::getCert() const +{ + return certificate_; +} + + +const x509* SSL_CTX::getKey() const +{ + return privateKey_; +} + + +const SSL_METHOD* SSL_CTX::getMethod() const +{ + return method_; +} + + +const Ciphers& SSL_CTX::GetCiphers() const +{ + return ciphers_; +} + + +const DH_Parms& SSL_CTX::GetDH_Parms() const +{ + return dhParms_; +} + + +const Stats& SSL_CTX::GetStats() const +{ + return stats_; +} + + +pem_password_cb SSL_CTX::GetPasswordCb() const +{ + return passwordCb_; +} + + +void SSL_CTX::SetPasswordCb(pem_password_cb cb) +{ + passwordCb_ = cb; +} + + +void* SSL_CTX::GetUserData() const +{ + return userData_; +} + + +bool SSL_CTX::GetSessionCacheOff() const +{ + return sessionCacheOff_; +} + + +bool SSL_CTX::GetSessionCacheFlushOff() const +{ + return sessionCacheFlushOff_; +} + + +void SSL_CTX::SetUserData(void* data) +{ + userData_ = data; +} + + +void SSL_CTX::SetSessionCacheOff() +{ + sessionCacheOff_ = true; +} + + +void SSL_CTX::SetMethod(SSL_METHOD* meth) +{ + if(method_) + ysDelete(method_); + method_= meth; +} + + +void SSL_CTX::SetSessionCacheFlushOff() +{ + sessionCacheFlushOff_ = true; +} + + +void SSL_CTX::setVerifyPeer() +{ + method_->setVerifyPeer(); +} + + +void SSL_CTX::setVerifyNone() +{ + method_->setVerifyNone(); +} + + +void SSL_CTX::setFailNoCert() +{ + method_->setFailNoCert(); +} + + +void SSL_CTX::setVerifyCallback(VerifyCallback vc) +{ + verifyCallback_ = vc; +} + + +bool SSL_CTX::SetDH(const DH& dh) +{ + dhParms_.p_ = dh.p->int_; + dhParms_.g_ = dh.g->int_; + + return dhParms_.set_ = true; +} + + +bool SSL_CTX::SetCipherList(const char* list) +{ + if (!list) + return false; + + bool ret = false; + char name[MAX_SUITE_NAME]; + + char needle[] = ":"; + char* haystack = const_cast(list); + char* prev; + + const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]); + int idx = 0; + + for(;;) { + size_t len; + prev = haystack; + haystack = strstr(haystack, needle); + + if (!haystack) // last cipher + len = min(sizeof(name), strlen(prev)); + else + len = min(sizeof(name), (size_t)(haystack - prev)); + + strncpy(name, prev, len); + name[(len == sizeof(name)) ? len - 1 : len] = 0; + + for (int i = 0; i < suiteSz; i++) + if (strncmp(name, cipher_names[i], sizeof(name)) == 0) { + + ciphers_.suites_[idx++] = 0x00; // first byte always zero + ciphers_.suites_[idx++] = i; + + if (!ret) ret = true; // found at least one + break; + } + if (!haystack) break; + haystack++; + } + + if (ret) { + ciphers_.setSuites_ = true; + ciphers_.suiteSz_ = idx; + } + + return ret; +} + + +void SSL_CTX::IncrementStats(StatsField fd) +{ + + Lock guard(mutex_); + + switch (fd) { + + case Accept: + ++stats_.accept_; + break; + + case Connect: + ++stats_.connect_; + break; + + case AcceptGood: + ++stats_.acceptGood_; + break; + + case ConnectGood: + ++stats_.connectGood_; + break; + + case AcceptRenegotiate: + ++stats_.acceptRenegotiate_; + break; + + case ConnectRenegotiate: + ++stats_.connectRenegotiate_; + break; + + case Hits: + ++stats_.hits_; + break; + + case CbHits: + ++stats_.cbHits_; + break; + + case CacheFull: + ++stats_.cacheFull_; + break; + + case Misses: + ++stats_.misses_; + break; + + case Timeouts: + ++stats_.timeouts_; + break; + + case Number: + ++stats_.number_; + break; + + case GetCacheSize: + ++stats_.getCacheSize_; + break; + + case VerifyMode: + ++stats_.verifyMode_; + break; + + case VerifyDepth: + ++stats_.verifyDepth_; + break; + + default: + break; + } +} + + +Crypto::Crypto() + : digest_(0), cipher_(0), dh_(0) +{} + + +Crypto::~Crypto() +{ + ysDelete(dh_); + ysDelete(cipher_); + ysDelete(digest_); +} + + +const Digest& Crypto::get_digest() const +{ + return *digest_; +} + + +const BulkCipher& Crypto::get_cipher() const +{ + return *cipher_; +} + + +const DiffieHellman& Crypto::get_dh() const +{ + return *dh_; +} + + +const RandomPool& Crypto::get_random() const +{ + return random_; +} + + +const CertManager& Crypto::get_certManager() const +{ + return cert_; +} + + + +Digest& Crypto::use_digest() +{ + return *digest_; +} + + +BulkCipher& Crypto::use_cipher() +{ + return *cipher_; +} + + +DiffieHellman& Crypto::use_dh() +{ + return *dh_; +} + + +RandomPool& Crypto::use_random() +{ + return random_; +} + + +CertManager& Crypto::use_certManager() +{ + return cert_; +} + + + +void Crypto::SetDH(DiffieHellman* dh) +{ + dh_ = dh; +} + + +void Crypto::SetDH(const DH_Parms& dh) +{ + if (dh.set_) + dh_ = NEW_YS DiffieHellman(dh.p_, dh.g_, random_); +} + + +bool Crypto::DhSet() +{ + return dh_ != 0; +} + + +void Crypto::setDigest(Digest* digest) +{ + digest_ = digest; +} + + +void Crypto::setCipher(BulkCipher* c) +{ + cipher_ = c; +} + + +const MD5& sslHashes::get_MD5() const +{ + return md5HandShake_; +} + + +const SHA& sslHashes::get_SHA() const +{ + return shaHandShake_; +} + + +const Finished& sslHashes::get_verify() const +{ + return verify_; +} + + +const Hashes& sslHashes::get_certVerify() const +{ + return certVerify_; +} + + +MD5& sslHashes::use_MD5(){ + return md5HandShake_; +} + + +SHA& sslHashes::use_SHA() +{ + return shaHandShake_; +} + + +Finished& sslHashes::use_verify() +{ + return verify_; +} + + +Hashes& sslHashes::use_certVerify() +{ + return certVerify_; +} + + +Buffers::Buffers() : prevSent(0), plainSz(0), rawInput_(0), output_(0) +{} + + +Buffers::~Buffers() +{ + STL::for_each(handShakeList_.begin(), handShakeList_.end(), + del_ptr_zero()) ; + STL::for_each(dataList_.begin(), dataList_.end(), + del_ptr_zero()) ; + ysDelete(rawInput_); + ysDelete(output_); +} + + +void Buffers::SetOutput(output_buffer* ob) +{ + output_ = ob; +} + + +void Buffers::SetRawInput(input_buffer* ib) +{ + rawInput_ = ib; +} + + +input_buffer* Buffers::TakeRawInput() +{ + input_buffer* ret = rawInput_; + rawInput_ = 0; + + return ret; +} + + +output_buffer* Buffers::TakeOutput() +{ + output_buffer* ret = output_; + output_ = 0; + + return ret; +} + + +const Buffers::inputList& Buffers::getData() const +{ + return dataList_; +} + + +const Buffers::outputList& Buffers::getHandShake() const +{ + return handShakeList_; +} + + +Buffers::inputList& Buffers::useData() +{ + return dataList_; +} + + +Buffers::outputList& Buffers::useHandShake() +{ + return handShakeList_; +} + + +Security::Security(ProtocolVersion pv, RandomPool& ran, ConnectionEnd ce, + const Ciphers& ciphers, SSL_CTX* ctx, bool haveDH) + : conn_(pv, ran), parms_(ce, ciphers, pv, haveDH), resumeSession_(ran), + ctx_(ctx), resuming_(false) +{} + + +const Connection& Security::get_connection() const +{ + return conn_; +} + + +const SSL_CTX* Security::GetContext() const +{ + return ctx_; +} + + +const Parameters& Security::get_parms() const +{ + return parms_; +} + + +const SSL_SESSION& Security::get_resume() const +{ + return resumeSession_; +} + + +bool Security::get_resuming() const +{ + return resuming_; +} + + +Connection& Security::use_connection() +{ + return conn_; +} + + +Parameters& Security::use_parms() +{ + return parms_; +} + + +SSL_SESSION& Security::use_resume() +{ + return resumeSession_; +} + + +void Security::set_resuming(bool b) +{ + resuming_ = b; +} + + +X509_NAME::X509_NAME(const char* n, size_t sz, int pos, int len) + : name_(0), sz_(sz), cnPosition_(pos), cnLen_(len) +{ + if (sz) { + name_ = NEW_YS char[sz]; + memcpy(name_, n, sz); + } + entry_.data = 0; +} + + +X509_NAME::~X509_NAME() +{ + ysArrayDelete(name_); + ysArrayDelete(entry_.data); +} + + +const char* X509_NAME::GetName() const +{ + return name_; +} + + +size_t X509_NAME::GetLength() const +{ + return sz_; +} + + +X509::X509(const char* i, size_t iSz, const char* s, size_t sSz, + ASN1_STRING *b, ASN1_STRING *a, + int issPos, int issLen, + int subPos, int subLen) + : issuer_(i, iSz, issPos, issLen), subject_(s, sSz, subPos, subLen), + beforeDate_((char *) b->data, b->length, b->type), + afterDate_((char *) a->data, a->length, a->type) +{} + + +X509_NAME* X509::GetIssuer() +{ + return &issuer_; +} + + +X509_NAME* X509::GetSubject() +{ + return &subject_; +} + + +ASN1_TIME* X509::GetBefore() +{ + return beforeDate_.GetString(); +} + + +ASN1_TIME* X509::GetAfter() +{ + return afterDate_.GetString(); +} + + +ASN1_STRING* X509_NAME::GetEntry(int i) +{ + if (i < 0 || i >= int(sz_)) + return 0; + + if (i != cnPosition_ || cnLen_ <= 0) // only entry currently supported + return 0; + + if (cnLen_ > int(sz_-i)) // make sure there's room in read buffer + return 0; + + if (entry_.data) + ysArrayDelete(entry_.data); + entry_.data = NEW_YS byte[cnLen_+1]; // max size; + + memcpy(entry_.data, &name_[i], cnLen_); + entry_.data[cnLen_] = 0; + entry_.length = cnLen_; + entry_.type = 0; + return &entry_; +} + + +StringHolder::StringHolder(const char* str, int sz, byte type) +{ + asnString_.length = sz; + asnString_.data = NEW_YS byte[sz + 1]; + memcpy(asnString_.data, str, sz); + asnString_.type = type; +} + + +StringHolder::~StringHolder() +{ + ysArrayDelete(asnString_.data); +} + + +ASN1_STRING* StringHolder::GetString() +{ + return &asnString_; +} + + +#ifdef HAVE_LIBZ + + void* myAlloc(void* /* opaque */, unsigned int item, unsigned int size) + { + return NEW_YS unsigned char[item * size]; + } + + + void myFree(void* /* opaque */, void* memory) + { + unsigned char* ptr = static_cast(memory); + yaSSL::ysArrayDelete(ptr); + } + + + // put size in front of compressed data + int Compress(const byte* in, int sz, input_buffer& buffer) + { + byte tmp[LENGTH_SZ]; + z_stream c_stream; /* compression stream */ + + buffer.allocate(sz + sizeof(uint16) + COMPRESS_EXTRA); + + c_stream.zalloc = myAlloc; + c_stream.zfree = myFree; + c_stream.opaque = (voidpf)0; + + c_stream.next_in = const_cast(in); + c_stream.avail_in = sz; + c_stream.next_out = buffer.get_buffer() + sizeof(tmp); + c_stream.avail_out = buffer.get_capacity() - sizeof(tmp); + + if (deflateInit(&c_stream, 8) != Z_OK) return -1; + int err = deflate(&c_stream, Z_FINISH); + deflateEnd(&c_stream); + if (err != Z_OK && err != Z_STREAM_END) return -1; + + c16toa(sz, tmp); + memcpy(buffer.get_buffer(), tmp, sizeof(tmp)); + buffer.add_size(c_stream.total_out + sizeof(tmp)); + + return 0; + } + + + // get uncompressed size in front + int DeCompress(input_buffer& in, int sz, input_buffer& out) + { + byte tmp[LENGTH_SZ]; + + tmp[0] = in[AUTO]; + tmp[1] = in[AUTO]; + + uint16 len; + ato16(tmp, len); + + out.allocate(len); + + z_stream d_stream; /* decompression stream */ + + d_stream.zalloc = myAlloc; + d_stream.zfree = myFree; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = in.get_buffer() + in.get_current(); + d_stream.avail_in = sz - sizeof(tmp); + d_stream.next_out = out.get_buffer(); + d_stream.avail_out = out.get_capacity(); + + if (inflateInit(&d_stream) != Z_OK) return -1; + int err = inflate(&d_stream, Z_FINISH); + inflateEnd(&d_stream); + if (err != Z_OK && err != Z_STREAM_END) return -1; + + out.add_size(d_stream.total_out); + in.set_current(in.get_current() + sz - sizeof(tmp)); + + return 0; + } + + +#else // LIBZ + + // these versions should never get called + int Compress(const byte* in, int sz, input_buffer& buffer) + { + return -1; + } + + + int DeCompress(input_buffer& in, int sz, input_buffer& out) + { + return -1; + } + + +#endif // LIBZ + + +} // namespace + + + +extern "C" void yaSSL_CleanUp() +{ + TaoCrypt::CleanUp(); + yaSSL::ysDelete(yaSSL::sslFactoryInstance); + yaSSL::ysDelete(yaSSL::sessionsInstance); + yaSSL::ysDelete(yaSSL::errorsInstance); + + // In case user calls more than once, prevent seg fault + yaSSL::sslFactoryInstance = 0; + yaSSL::sessionsInstance = 0; + yaSSL::errorsInstance = 0; +} + + +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION +namespace mySTL { +template yaSSL::yassl_int_cpp_local1::SumData for_each::iterator, yaSSL::yassl_int_cpp_local1::SumData>(mySTL::list::iterator, mySTL::list::iterator, yaSSL::yassl_int_cpp_local1::SumData); +template yaSSL::yassl_int_cpp_local1::SumBuffer for_each::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer>(mySTL::list::iterator, mySTL::list::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer); +template mySTL::list::iterator find_if::iterator, yaSSL::yassl_int_cpp_local2::sess_match>(mySTL::list::iterator, mySTL::list::iterator, yaSSL::yassl_int_cpp_local2::sess_match); +template mySTL::list::iterator find_if::iterator, yaSSL::yassl_int_cpp_local2::thr_match>(mySTL::list::iterator, mySTL::list::iterator, yaSSL::yassl_int_cpp_local2::thr_match); +} +#endif + -- cgit v1.1