aboutsummaryrefslogtreecommitdiff
path: root/mysql/extra/yassl/src
diff options
context:
space:
mode:
Diffstat (limited to 'mysql/extra/yassl/src')
-rw-r--r--mysql/extra/yassl/src/buffer.cpp330
-rw-r--r--mysql/extra/yassl/src/cert_wrapper.cpp408
-rw-r--r--mysql/extra/yassl/src/crypto_wrapper.cpp1016
-rw-r--r--mysql/extra/yassl/src/get_password.c218
-rw-r--r--mysql/extra/yassl/src/handshake.cpp1190
-rw-r--r--mysql/extra/yassl/src/lock.cpp87
-rw-r--r--mysql/extra/yassl/src/log.cpp147
-rw-r--r--mysql/extra/yassl/src/socket_wrapper.cpp238
-rw-r--r--mysql/extra/yassl/src/ssl.cpp1883
-rw-r--r--mysql/extra/yassl/src/timer.cpp80
-rw-r--r--mysql/extra/yassl/src/yassl_error.cpp288
-rw-r--r--mysql/extra/yassl/src/yassl_imp.cpp2642
-rw-r--r--mysql/extra/yassl/src/yassl_int.cpp2826
13 files changed, 11353 insertions, 0 deletions
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 <string.h> // 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<int>(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<opaque*>(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<TaoCrypt::MD5> 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<TaoCrypt::SHA> 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<TaoCrypt::RIPEMD160> 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<x509> 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>(DiffieHellman::DHImpl*);
+template void ysDelete<Integer::IntegerImpl>(Integer::IntegerImpl*);
+template void ysDelete<RSA::RSAImpl>(RSA::RSAImpl*);
+template void ysDelete<DSS::DSSImpl>(DSS::DSSImpl*);
+template void ysDelete<RandomPool::RandomImpl>(RandomPool::RandomImpl*);
+template void ysDelete<AES::AESImpl>(AES::AESImpl*);
+template void ysDelete<RC4::RC4Impl>(RC4::RC4Impl*);
+template void ysDelete<DES_EDE::DES_EDEImpl>(DES_EDE::DES_EDEImpl*);
+template void ysDelete<DES::DESImpl>(DES::DESImpl*);
+template void ysDelete<HMAC_RMD::HMAC_RMDImpl>(HMAC_RMD::HMAC_RMDImpl*);
+template void ysDelete<HMAC_SHA::HMAC_SHAImpl>(HMAC_SHA::HMAC_SHAImpl*);
+template void ysDelete<HMAC_MD5::HMAC_MD5Impl>(HMAC_MD5::HMAC_MD5Impl*);
+template void ysDelete<RMD::RMDImpl>(RMD::RMDImpl*);
+template void ysDelete<SHA::SHAImpl>(SHA::SHAImpl*);
+template void ysDelete<MD5::MD5Impl>(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 <my_global.h>
+#include <my_sys.h>
+#include "mysql.h"
+#include <m_string.h>
+#include <m_ctype.h>
+#include <mysql/get_password.h>
+
+#ifdef HAVE_GETPASS
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif /* HAVE_PWD_H */
+#else /* ! HAVE_GETPASS */
+#ifndef _WIN32
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_TERMIOS_H /* For tty-password */
+#include <termios.h>
+#define TERMIO struct termios
+#else
+#ifdef HAVE_TERMIO_H /* For tty-password */
+#include <termio.h>
+#define TERMIO struct termio
+#else
+#include <sgtty.h>
+#define TERMIO struct sgttyb
+#endif
+#endif
+#else
+#include <conio.h>
+#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<Digest> 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<Digest> 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<uint>(-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<uint>(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<Message> 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<output_buffer> 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<output_buffer> 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<output_buffer> 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<output_buffer> 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<const opaque*>(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<const opaque*>(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<output_buffer> 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<output_buffer> 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<output_buffer> 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<output_buffer> 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<output_buffer> 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 <time.h>
+ #include <stdio.h>
+ #include <string.h>
+#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<const char*>(&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<unsigned short>(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 <errno.h>
+ #include <netdb.h>
+ #include <unistd.h>
+ #include <arpa/inet.h>
+ #include <netinet/in.h>
+ #include <sys/ioctl.h>
+ #include <string.h>
+ #include <fcntl.h>
+#endif // _WIN32
+
+#if defined(__sun) || defined(__SCO_VERSION__)
+ #include <sys/filio.h>
+#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<char *>(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<const char *>(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<int>(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<uint>(-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<uint>(-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 <stdio.h>
+
+#ifdef _WIN32
+ #include <windows.h> // FindFirstFile etc..
+#else
+ #include <sys/types.h> // file helper
+ #include <sys/stat.h> // stat
+ #include <dirent.h> // 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<BulkCipher> 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<x509> 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<opaque*>(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<BIGNUM> 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<int>(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<yassl_pointer>(md4->buffer)) TaoCrypt::MD4();
+}
+
+
+void MD4_Update(MD4_CTX* md4, const void* data, unsigned long sz)
+{
+ reinterpret_cast<TaoCrypt::MD4*>(md4->buffer)->Update(
+ static_cast<const byte*>(data), static_cast<unsigned int>(sz));
+}
+
+
+void MD4_Final(unsigned char* hash, MD4_CTX* md4)
+{
+ reinterpret_cast<TaoCrypt::MD4*>(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<yassl_pointer>(md5->buffer)) TaoCrypt::MD5();
+}
+
+
+void MD5_Update(MD5_CTX* md5, const void* data, unsigned long sz)
+{
+ reinterpret_cast<TaoCrypt::MD5*>(md5->buffer)->Update(
+ static_cast<const byte*>(data), static_cast<unsigned int>(sz));
+}
+
+
+void MD5_Final(unsigned char* hash, MD5_CTX* md5)
+{
+ reinterpret_cast<TaoCrypt::MD5*>(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<opaque*>(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 <windows.h>
+#else
+#include <sys/time.h>
+#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<double>(count.QuadPart) / freq.QuadPart;
+ }
+
+
+ uint lowResTimer()
+ {
+ return static_cast<uint>(timer());
+ }
+
+#else // _WIN32
+
+ timer_d timer()
+ {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+
+ return static_cast<double>(tv.tv_sec)
+ + static_cast<double>(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 <string.h> // 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> 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<HandShakeBase> 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<uint16>(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<DistinguishedName>::const_iterator first =
+ request.certificate_authorities_.begin();
+ STL::list<DistinguishedName>::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<byte> 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<opaque*>(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<Windows.h>
+#else
+#include <pthread.h>
+#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 <mysql/get_password.h>
+
+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<output_buffer> tmp(out);
+ Send(out->get_buffer(), out->get_size());
+ }
+}
+
+
+// get sequence number, if verify get peer's
+uint SSL::get_SEQIncrement(bool verify)
+{
+ if (verify)
+ return secure_.use_connection().peer_sequence_number_++;
+ else
+ return secure_.use_connection().sequence_number_++;
+}
+
+
+const byte* SSL::get_macSecret(bool verify)
+{
+ if ( (secure_.get_parms().entity_ == client_end && !verify) ||
+ (secure_.get_parms().entity_ == server_end && verify) )
+ return secure_.get_connection().client_write_MAC_secret_;
+ else
+ return secure_.get_connection().server_write_MAC_secret_;
+}
+
+
+void SSL::verifyState(const RecordLayerHeader& rlHeader)
+{
+ if (GetError()) return;
+
+ if (rlHeader.version_.major_ != 3 || rlHeader.version_.minor_ > 2) {
+ SetError(badVersion_error);
+ return;
+ }
+
+ if (states_.getRecord() == recordNotReady ||
+ (rlHeader.type_ == application_data && // data and handshake
+ states_.getHandShake() != handShakeReady) ) // isn't complete yet
+ SetError(record_layer);
+}
+
+
+void SSL::verifyState(const HandShakeHeader& hsHeader)
+{
+ if (GetError()) return;
+
+ if (states_.getHandShake() == handShakeNotReady) {
+ SetError(handshake_layer);
+ return;
+ }
+
+ if (states_.SetMessageRecvd(hsHeader.get_handshakeType()) != 0) {
+ order_error();
+ return;
+ }
+
+ if (secure_.get_parms().entity_ == client_end)
+ verifyClientState(hsHeader.get_handshakeType());
+ else
+ verifyServerState(hsHeader.get_handshakeType());
+}
+
+
+void SSL::verifyState(ClientState cs)
+{
+ if (GetError()) return;
+ if (states_.getClient() != cs) order_error();
+}
+
+
+void SSL::verifyState(ServerState ss)
+{
+ if (GetError()) return;
+ if (states_.getServer() != ss) order_error();
+}
+
+
+void SSL::verfiyHandShakeComplete()
+{
+ if (GetError()) return;
+ if (states_.getHandShake() != handShakeReady) order_error();
+}
+
+
+void SSL::verifyClientState(HandShakeType hsType)
+{
+ if (GetError()) return;
+
+ switch(hsType) {
+ case server_hello :
+ if (states_.getClient() != serverNull)
+ order_error();
+ break;
+ case certificate :
+ if (states_.getClient() != serverHelloComplete)
+ order_error();
+ break;
+ case server_key_exchange :
+ if (states_.getClient() != serverCertComplete)
+ order_error();
+ break;
+ case certificate_request :
+ if (states_.getClient() != serverCertComplete &&
+ states_.getClient() != serverKeyExchangeComplete)
+ order_error();
+ break;
+ case server_hello_done :
+ if (states_.getClient() != serverCertComplete &&
+ states_.getClient() != serverKeyExchangeComplete)
+ order_error();
+ break;
+ case finished :
+ if (states_.getClient() != serverHelloDoneComplete ||
+ secure_.get_parms().pending_) // no change
+ order_error(); // cipher yet
+ break;
+ default :
+ order_error();
+ };
+}
+
+
+void SSL::verifyServerState(HandShakeType hsType)
+{
+ if (GetError()) return;
+
+ switch(hsType) {
+ case client_hello :
+ if (states_.getServer() != clientNull)
+ order_error();
+ break;
+ case certificate :
+ if (states_.getServer() != clientHelloComplete)
+ order_error();
+ break;
+ case client_key_exchange :
+ if (states_.getServer() != clientHelloComplete)
+ order_error();
+ break;
+ case certificate_verify :
+ if (states_.getServer() != clientKeyExchangeComplete)
+ order_error();
+ break;
+ case finished :
+ if (states_.getServer() != clientKeyExchangeComplete ||
+ secure_.get_parms().pending_) // no change
+ order_error(); // cipher yet
+ break;
+ default :
+ order_error();
+ };
+}
+
+
+// try to find a suite match
+void SSL::matchSuite(const opaque* peer, uint length)
+{
+ if (length == 0 || (length % 2) != 0) {
+ SetError(bad_input);
+ return;
+ }
+
+ // start with best, if a match we are good, Ciphers are at odd index
+ // since all SSL and TLS ciphers have 0x00 first byte
+ for (uint i = 1; i < secure_.get_parms().suites_size_; i += 2)
+ for (uint j = 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<SSL_SESSION*>::iterator sess_iterator;
+typedef STL::list<ThreadError>::iterator thr_iterator;
+
+struct sess_match {
+ const opaque* id_;
+ explicit sess_match(const opaque* p) : id_(p) {}
+
+ bool operator()(SSL_SESSION* sess)
+ {
+ if ( memcmp(sess->GetID(), id_, ID_LEN) == 0)
+ return true;
+ return false;
+ }
+};
+
+
+THREAD_ID_T GetSelf()
+{
+#ifndef _POSIX_THREADS
+ return GetCurrentThreadId();
+#else
+ return pthread_self();
+#endif
+}
+
+struct thr_match {
+ THREAD_ID_T id_;
+ explicit thr_match() : id_(GetSelf()) {}
+
+ bool operator()(ThreadError thr)
+ {
+ if (thr.threadID_ == id_)
+ return true;
+ return false;
+ }
+};
+
+
+} // local namespace
+using namespace yassl_int_cpp_local2;
+
+
+// lookup session by id, return a copy if space provided
+SSL_SESSION* Sessions::lookup(const opaque* id, SSL_SESSION* copy)
+{
+ Lock guard(mutex_);
+ sess_iterator find = STL::find_if(list_.begin(), list_.end(),
+ sess_match(id));
+ if (find != list_.end()) {
+ uint current = lowResTimer();
+ if ( ((*find)->GetBornOn() + (*find)->GetTimeOut()) < current) {
+ del_ptr_zero()(*find);
+ list_.erase(find);
+ return 0;
+ }
+ if (copy)
+ *copy = *(*find);
+ return *find;
+ }
+ return 0;
+}
+
+
+// remove a session by id
+void Sessions::remove(const opaque* id)
+{
+ Lock guard(mutex_);
+ sess_iterator find = STL::find_if(list_.begin(), list_.end(),
+ sess_match(id));
+ if (find != list_.end()) {
+ del_ptr_zero()(*find);
+ list_.erase(find);
+ }
+}
+
+
+// flush expired sessions from cache
+void Sessions::Flush()
+{
+ Lock guard(mutex_);
+ sess_iterator next = list_.begin();
+ uint current = lowResTimer();
+
+ while (next != list_.end()) {
+ sess_iterator si = next;
+ ++next;
+ if ( ((*si)->GetBornOn() + (*si)->GetTimeOut()) < current) {
+ del_ptr_zero()(*si);
+ list_.erase(si);
+ }
+ }
+ count_ = 0; // reset flush counter
+}
+
+
+// remove a self thread error
+void Errors::Remove()
+{
+ Lock guard(mutex_);
+ thr_iterator find = STL::find_if(list_.begin(), list_.end(),
+ thr_match());
+ if (find != list_.end())
+ list_.erase(find);
+}
+
+
+// lookup self error code
+int Errors::Lookup(bool peek)
+{
+ Lock guard(mutex_);
+ thr_iterator find = STL::find_if(list_.begin(), list_.end(),
+ thr_match());
+ if (find != list_.end()) {
+ int ret = find->errorID_;
+ if (!peek)
+ list_.erase(find);
+ return ret;
+ }
+ else
+ return 0;
+}
+
+
+// add a new error code for self
+void Errors::Add(int error)
+{
+ ThreadError add;
+ add.errorID_ = error;
+ add.threadID_ = GetSelf();
+
+ Remove(); // may have old error
+
+ Lock guard(mutex_);
+ list_.push_back(add);
+}
+
+
+SSL_METHOD::SSL_METHOD(ConnectionEnd ce, ProtocolVersion pv, bool multiProto)
+ : version_(pv), side_(ce), verifyPeer_(false), verifyNone_(false),
+ failNoCert_(false), multipleProtocol_(multiProto)
+{}
+
+
+ProtocolVersion SSL_METHOD::getVersion() const
+{
+ return version_;
+}
+
+
+ConnectionEnd SSL_METHOD::getSide() const
+{
+ return side_;
+}
+
+
+void SSL_METHOD::setVerifyPeer()
+{
+ verifyPeer_ = true;
+}
+
+
+void SSL_METHOD::setVerifyNone()
+{
+ verifyNone_ = true;
+}
+
+
+void SSL_METHOD::setFailNoCert()
+{
+ failNoCert_ = true;
+}
+
+
+bool SSL_METHOD::verifyPeer() const
+{
+ return verifyPeer_;
+}
+
+
+bool SSL_METHOD::verifyNone() const
+{
+ return verifyNone_;
+}
+
+
+bool SSL_METHOD::failNoCert() const
+{
+ return failNoCert_;
+}
+
+
+bool SSL_METHOD::multipleProtocol() const
+{
+ return multipleProtocol_;
+}
+
+
+/** 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<char*>(list);
+ char* prev;
+
+ const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]);
+ int idx = 0;
+
+ for(;;) {
+ size_t len;
+ prev = haystack;
+ haystack = strstr(haystack, needle);
+
+ if (!haystack) // last cipher
+ len = min(sizeof(name), strlen(prev));
+ else
+ len = min(sizeof(name), (size_t)(haystack - prev));
+
+ strncpy(name, prev, len);
+ name[(len == sizeof(name)) ? len - 1 : len] = 0;
+
+ for (int i = 0; i < suiteSz; i++)
+ if (strncmp(name, cipher_names[i], sizeof(name)) == 0) {
+
+ ciphers_.suites_[idx++] = 0x00; // first byte always zero
+ ciphers_.suites_[idx++] = i;
+
+ if (!ret) ret = true; // found at least one
+ break;
+ }
+ if (!haystack) break;
+ haystack++;
+ }
+
+ if (ret) {
+ ciphers_.setSuites_ = true;
+ ciphers_.suiteSz_ = idx;
+ }
+
+ return ret;
+}
+
+
+void SSL_CTX::IncrementStats(StatsField fd)
+{
+
+ Lock guard(mutex_);
+
+ switch (fd) {
+
+ case Accept:
+ ++stats_.accept_;
+ break;
+
+ case Connect:
+ ++stats_.connect_;
+ break;
+
+ case AcceptGood:
+ ++stats_.acceptGood_;
+ break;
+
+ case ConnectGood:
+ ++stats_.connectGood_;
+ break;
+
+ case AcceptRenegotiate:
+ ++stats_.acceptRenegotiate_;
+ break;
+
+ case ConnectRenegotiate:
+ ++stats_.connectRenegotiate_;
+ break;
+
+ case Hits:
+ ++stats_.hits_;
+ break;
+
+ case CbHits:
+ ++stats_.cbHits_;
+ break;
+
+ case CacheFull:
+ ++stats_.cacheFull_;
+ break;
+
+ case Misses:
+ ++stats_.misses_;
+ break;
+
+ case Timeouts:
+ ++stats_.timeouts_;
+ break;
+
+ case Number:
+ ++stats_.number_;
+ break;
+
+ case GetCacheSize:
+ ++stats_.getCacheSize_;
+ break;
+
+ case VerifyMode:
+ ++stats_.verifyMode_;
+ break;
+
+ case VerifyDepth:
+ ++stats_.verifyDepth_;
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+Crypto::Crypto()
+ : digest_(0), cipher_(0), dh_(0)
+{}
+
+
+Crypto::~Crypto()
+{
+ ysDelete(dh_);
+ ysDelete(cipher_);
+ ysDelete(digest_);
+}
+
+
+const Digest& Crypto::get_digest() const
+{
+ return *digest_;
+}
+
+
+const BulkCipher& Crypto::get_cipher() const
+{
+ return *cipher_;
+}
+
+
+const DiffieHellman& Crypto::get_dh() const
+{
+ return *dh_;
+}
+
+
+const RandomPool& Crypto::get_random() const
+{
+ return random_;
+}
+
+
+const CertManager& Crypto::get_certManager() const
+{
+ return cert_;
+}
+
+
+
+Digest& Crypto::use_digest()
+{
+ return *digest_;
+}
+
+
+BulkCipher& Crypto::use_cipher()
+{
+ return *cipher_;
+}
+
+
+DiffieHellman& Crypto::use_dh()
+{
+ return *dh_;
+}
+
+
+RandomPool& Crypto::use_random()
+{
+ return random_;
+}
+
+
+CertManager& Crypto::use_certManager()
+{
+ return cert_;
+}
+
+
+
+void Crypto::SetDH(DiffieHellman* dh)
+{
+ dh_ = dh;
+}
+
+
+void Crypto::SetDH(const DH_Parms& dh)
+{
+ if (dh.set_)
+ dh_ = NEW_YS DiffieHellman(dh.p_, dh.g_, random_);
+}
+
+
+bool Crypto::DhSet()
+{
+ return dh_ != 0;
+}
+
+
+void Crypto::setDigest(Digest* digest)
+{
+ digest_ = digest;
+}
+
+
+void Crypto::setCipher(BulkCipher* c)
+{
+ cipher_ = c;
+}
+
+
+const MD5& sslHashes::get_MD5() const
+{
+ return md5HandShake_;
+}
+
+
+const SHA& sslHashes::get_SHA() const
+{
+ return shaHandShake_;
+}
+
+
+const Finished& sslHashes::get_verify() const
+{
+ return verify_;
+}
+
+
+const Hashes& sslHashes::get_certVerify() const
+{
+ return certVerify_;
+}
+
+
+MD5& sslHashes::use_MD5(){
+ return md5HandShake_;
+}
+
+
+SHA& sslHashes::use_SHA()
+{
+ return shaHandShake_;
+}
+
+
+Finished& sslHashes::use_verify()
+{
+ return verify_;
+}
+
+
+Hashes& sslHashes::use_certVerify()
+{
+ return certVerify_;
+}
+
+
+Buffers::Buffers() : prevSent(0), plainSz(0), rawInput_(0), output_(0)
+{}
+
+
+Buffers::~Buffers()
+{
+ STL::for_each(handShakeList_.begin(), handShakeList_.end(),
+ del_ptr_zero()) ;
+ STL::for_each(dataList_.begin(), dataList_.end(),
+ del_ptr_zero()) ;
+ ysDelete(rawInput_);
+ ysDelete(output_);
+}
+
+
+void Buffers::SetOutput(output_buffer* ob)
+{
+ output_ = ob;
+}
+
+
+void Buffers::SetRawInput(input_buffer* ib)
+{
+ rawInput_ = ib;
+}
+
+
+input_buffer* Buffers::TakeRawInput()
+{
+ input_buffer* ret = rawInput_;
+ rawInput_ = 0;
+
+ return ret;
+}
+
+
+output_buffer* Buffers::TakeOutput()
+{
+ output_buffer* ret = output_;
+ output_ = 0;
+
+ return ret;
+}
+
+
+const Buffers::inputList& Buffers::getData() const
+{
+ return dataList_;
+}
+
+
+const Buffers::outputList& Buffers::getHandShake() const
+{
+ return handShakeList_;
+}
+
+
+Buffers::inputList& Buffers::useData()
+{
+ return dataList_;
+}
+
+
+Buffers::outputList& Buffers::useHandShake()
+{
+ return handShakeList_;
+}
+
+
+Security::Security(ProtocolVersion pv, RandomPool& ran, ConnectionEnd ce,
+ const Ciphers& ciphers, SSL_CTX* ctx, bool haveDH)
+ : conn_(pv, ran), parms_(ce, ciphers, pv, haveDH), resumeSession_(ran),
+ ctx_(ctx), resuming_(false)
+{}
+
+
+const Connection& Security::get_connection() const
+{
+ return conn_;
+}
+
+
+const SSL_CTX* Security::GetContext() const
+{
+ return ctx_;
+}
+
+
+const Parameters& Security::get_parms() const
+{
+ return parms_;
+}
+
+
+const SSL_SESSION& Security::get_resume() const
+{
+ return resumeSession_;
+}
+
+
+bool Security::get_resuming() const
+{
+ return resuming_;
+}
+
+
+Connection& Security::use_connection()
+{
+ return conn_;
+}
+
+
+Parameters& Security::use_parms()
+{
+ return parms_;
+}
+
+
+SSL_SESSION& Security::use_resume()
+{
+ return resumeSession_;
+}
+
+
+void Security::set_resuming(bool b)
+{
+ resuming_ = b;
+}
+
+
+X509_NAME::X509_NAME(const char* n, size_t sz, int pos, int len)
+ : name_(0), sz_(sz), cnPosition_(pos), cnLen_(len)
+{
+ if (sz) {
+ name_ = NEW_YS char[sz];
+ memcpy(name_, n, sz);
+ }
+ entry_.data = 0;
+}
+
+
+X509_NAME::~X509_NAME()
+{
+ ysArrayDelete(name_);
+ ysArrayDelete(entry_.data);
+}
+
+
+const char* X509_NAME::GetName() const
+{
+ return name_;
+}
+
+
+size_t X509_NAME::GetLength() const
+{
+ return sz_;
+}
+
+
+X509::X509(const char* i, size_t iSz, const char* s, size_t sSz,
+ 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<unsigned char*>(memory);
+ yaSSL::ysArrayDelete(ptr);
+ }
+
+
+ // put size in front of compressed data
+ int Compress(const byte* in, int sz, input_buffer& buffer)
+ {
+ byte tmp[LENGTH_SZ];
+ z_stream c_stream; /* compression stream */
+
+ buffer.allocate(sz + sizeof(uint16) + COMPRESS_EXTRA);
+
+ c_stream.zalloc = myAlloc;
+ c_stream.zfree = myFree;
+ c_stream.opaque = (voidpf)0;
+
+ c_stream.next_in = const_cast<byte*>(in);
+ c_stream.avail_in = sz;
+ c_stream.next_out = buffer.get_buffer() + sizeof(tmp);
+ c_stream.avail_out = buffer.get_capacity() - sizeof(tmp);
+
+ if (deflateInit(&c_stream, 8) != Z_OK) return -1;
+ int err = deflate(&c_stream, Z_FINISH);
+ deflateEnd(&c_stream);
+ if (err != Z_OK && err != Z_STREAM_END) return -1;
+
+ c16toa(sz, tmp);
+ memcpy(buffer.get_buffer(), tmp, sizeof(tmp));
+ buffer.add_size(c_stream.total_out + sizeof(tmp));
+
+ return 0;
+ }
+
+
+ // get uncompressed size in front
+ int DeCompress(input_buffer& in, int sz, input_buffer& out)
+ {
+ byte tmp[LENGTH_SZ];
+
+ tmp[0] = in[AUTO];
+ tmp[1] = in[AUTO];
+
+ uint16 len;
+ ato16(tmp, len);
+
+ out.allocate(len);
+
+ z_stream d_stream; /* decompression stream */
+
+ d_stream.zalloc = myAlloc;
+ d_stream.zfree = myFree;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = in.get_buffer() + in.get_current();
+ d_stream.avail_in = sz - sizeof(tmp);
+ d_stream.next_out = out.get_buffer();
+ d_stream.avail_out = out.get_capacity();
+
+ if (inflateInit(&d_stream) != Z_OK) return -1;
+ int err = inflate(&d_stream, Z_FINISH);
+ inflateEnd(&d_stream);
+ if (err != Z_OK && err != Z_STREAM_END) return -1;
+
+ out.add_size(d_stream.total_out);
+ in.set_current(in.get_current() + sz - sizeof(tmp));
+
+ return 0;
+ }
+
+
+#else // LIBZ
+
+ // these versions should never get called
+ int Compress(const byte* in, int sz, input_buffer& buffer)
+ {
+ return -1;
+ }
+
+
+ int DeCompress(input_buffer& in, int sz, input_buffer& out)
+ {
+ return -1;
+ }
+
+
+#endif // LIBZ
+
+
+} // namespace
+
+
+
+extern "C" void yaSSL_CleanUp()
+{
+ TaoCrypt::CleanUp();
+ yaSSL::ysDelete(yaSSL::sslFactoryInstance);
+ yaSSL::ysDelete(yaSSL::sessionsInstance);
+ yaSSL::ysDelete(yaSSL::errorsInstance);
+
+ // In case user calls more than once, prevent seg fault
+ yaSSL::sslFactoryInstance = 0;
+ yaSSL::sessionsInstance = 0;
+ yaSSL::errorsInstance = 0;
+}
+
+
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
+namespace mySTL {
+template yaSSL::yassl_int_cpp_local1::SumData for_each<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData);
+template yaSSL::yassl_int_cpp_local1::SumBuffer for_each<mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer>(mySTL::list<yaSSL::output_buffer*>::iterator, mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer);
+template mySTL::list<yaSSL::SSL_SESSION*>::iterator find_if<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match);
+template mySTL::list<yaSSL::ThreadError>::iterator find_if<mySTL::list<yaSSL::ThreadError>::iterator, yaSSL::yassl_int_cpp_local2::thr_match>(mySTL::list<yaSSL::ThreadError>::iterator, mySTL::list<yaSSL::ThreadError>::iterator, yaSSL::yassl_int_cpp_local2::thr_match);
+}
+#endif
+