summaryrefslogtreecommitdiff
path: root/extra/yassl/src/yassl_imp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'extra/yassl/src/yassl_imp.cpp')
-rw-r--r--extra/yassl/src/yassl_imp.cpp2118
1 files changed, 2118 insertions, 0 deletions
diff --git a/extra/yassl/src/yassl_imp.cpp b/extra/yassl/src/yassl_imp.cpp
new file mode 100644
index 00000000000..c1485cce986
--- /dev/null
+++ b/extra/yassl/src/yassl_imp.cpp
@@ -0,0 +1,2118 @@
+/* yassl_imp.cpp
+ *
+ * Copyright (C) 2003 Sawtooth Consulting Ltd.
+ *
+ * This file is part of yaSSL.
+ *
+ * yaSSL 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * yaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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().version_;
+ 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());
+ 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)
+ auth.reset(new (ys) RSA(cert.get_privateKey(),
+ cert.get_privateKeyLength(), false));
+ else {
+ auth.reset(new (ys) DSS(cert.get_privateKey(),
+ cert.get_privateKeyLength(), false));
+ sigSz += DSS_ENCODED_EXTRA;
+ }
+
+
+ sigSz += auth->get_signatureLength();
+
+
+ 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());
+ 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)
+{
+ 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];
+ input.read(len, sizeof(len));
+ ato16(len, cipherLen);
+ }
+ alloc(cipherLen);
+ input.read(secret_, length_);
+
+ opaque preMasterSecret[SECRET_LEN];
+ rsa.decrypt(preMasterSecret, secret_, length_,
+ ssl.getCrypto().get_random());
+
+ ssl.set_preMaster(preMasterSecret, SECRET_LEN);
+ ssl.makeMasterSecret();
+}
+
+
+EncryptedPreMasterSecret::EncryptedPreMasterSecret()
+ : secret_(0), length_(0)
+{}
+
+
+EncryptedPreMasterSecret::~EncryptedPreMasterSecret()
+{
+ delete[] 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)
+{
+ DiffieHellman& dh = ssl.useCrypto().use_dh();
+
+ uint16 keyLength;
+ byte tmp[2];
+ tmp[0] = input[AUTO];
+ tmp[1] = input[AUTO];
+ ato16(tmp, keyLength);
+
+ alloc(keyLength);
+ input.read(Yc_, length_);
+ dh.makeAgreement(Yc_);
+
+ ssl.set_preMaster(dh.get_agreedKey(), keyLength);
+ ssl.makeMasterSecret();
+}
+
+
+ClientDiffieHellmanPublic::ClientDiffieHellmanPublic()
+ : length_(0), Yc_(0)
+{}
+
+
+ClientDiffieHellmanPublic::~ClientDiffieHellmanPublic()
+{
+ delete[] 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)
+{
+ 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);
+
+ // g
+ tmp[0] = input[AUTO];
+ tmp[1] = input[AUTO];
+ ato16(tmp, length);
+ messageTotal += length;
+
+ input.read(parms_.alloc_g(length), length);
+
+ // pub
+ tmp[0] = input[AUTO];
+ tmp[1] = input[AUTO];
+ ato16(tmp, length);
+ messageTotal += length;
+
+ input.read(parms_.alloc_pub(length), length);
+
+ // 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);
+
+ // signature
+ tmp[0] = input[AUTO];
+ tmp[1] = input[AUTO];
+ ato16(tmp, length);
+
+ signature_ = new (ys) byte[length];
+ input.read(signature_, length);
+
+ // 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()
+{
+ delete[] keyMessage_;
+ delete[] 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) : entity_(ce)
+{
+ pending_ = true; // suite not set yet
+
+ if (ciphers.setSuites_) { // use user set list
+ suites_size_ = ciphers.suiteSz_;
+ memcpy(suites_, ciphers.suites_, ciphers.suiteSz_);
+ SetCipherNames();
+ }
+ else
+ SetSuites(pv); // defaults
+}
+
+
+void Parameters::SetSuites(ProtocolVersion pv)
+{
+ int i = 0;
+ // available suites, best first
+ // when adding more, make sure cipher_names is updated and
+ // MAX_CIPHER_LIST is big enough
+
+ if (isTLS(pv)) {
+ suites_[i++] = 0x00;
+ suites_[i++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+ suites_[i++] = 0x00;
+ suites_[i++] = TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
+ suites_[i++] = 0x00;
+ suites_[i++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+
+ suites_[i++] = 0x00;
+ suites_[i++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ suites_[i++] = 0x00;
+ suites_[i++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+ suites_[i++] = 0x00;
+ suites_[i++] = TLS_DHE_DSS_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;
+
+ 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;
+
+ 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;
+ }
+
+ 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;
+
+ suites_[i++] = 0x00;
+ suites_[i++] = SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+ suites_[i++] = 0x00;
+ suites_[i++] = SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
+
+ suites_[i++] = 0x00;
+ suites_[i++] = SSL_DHE_RSA_WITH_DES_CBC_SHA;
+ 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
+ int len = strlen(cipher_names[index]);
+ memcpy(&cipher_list_[pos], cipher_names[index], len);
+ pos += len;
+ cipher_list_[pos++] = ':';
+ }
+ if (suites)
+ cipher_list_[--pos] = 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);
+ const HandShakeFactory& hsf = ssl.getFactory().getHandShake();
+ mySTL::auto_ptr<HandShakeBase> hs(hsf.CreateObject(type_));
+ if (!hs.get()) {
+ ssl.SetError(factory_error);
+ return;
+ }
+ hashHandShake(ssl, input, c24to32(length_));
+
+ 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&, SSL& ssl)
+{
+ 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 (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 fill
+ int digestSz = ssl.getCrypto().get_digest().get_digestSize();
+ opaque mac[SHA_LEN];
+ input.read(mac, digestSz);
+
+ opaque fill;
+ int padSz = ssl.getSecurity().get_parms().encrypt_size_ - aSz -
+ digestSz;
+ for (int i = 0; i < padSz; i++)
+ fill = input[AUTO];
+
+ // 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)
+{}
+
+
+Data::Data(uint16 len, const opaque* w)
+ : length_(len), buffer_(0), write_buffer_(w)
+{}
+
+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_;
+}
+
+
+const opaque* Data::get_buffer() const
+{
+ return write_buffer_;
+}
+
+
+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;
+}
+
+
+// Process handler for Data
+void Data::Process(input_buffer& input, SSL& ssl)
+{
+ int msgSz = ssl.getSecurity().get_parms().encrypt_size_;
+ int pad = 0, padByte = 0;
+ if (ssl.getSecurity().get_parms().cipher_type_ == block) {
+ pad = *(input.get_buffer() + input.get_current() + msgSz - 1);
+ padByte = 1;
+ }
+ int digestSz = ssl.getCrypto().get_digest().get_digestSize();
+ int dataSz = msgSz - digestSz - pad - padByte;
+ opaque verify[SHA_LEN];
+
+ // read data
+ if (dataSz) {
+ input_buffer* data;
+ ssl.addData(data = new (ys) input_buffer(dataSz));
+ input.read(data->get_buffer(), dataSz);
+ data->add_size(dataSz);
+
+ if (ssl.isTLS())
+ TLS_hmac(ssl, verify, data->get_buffer(), dataSz, application_data,
+ true);
+ else
+ hmac(ssl, verify, data->get_buffer(), dataSz, application_data,
+ true);
+ }
+
+ // read mac and fill
+ opaque mac[SHA_LEN];
+ opaque fill;
+ input.read(mac, digestSz);
+ for (int i = 0; i < pad; i++)
+ fill = input[AUTO];
+ if (padByte)
+ fill = input[AUTO];
+
+ // verify
+ if (dataSz) {
+ if (memcmp(mac, verify, digestSz)) {
+ ssl.SetError(verify_error);
+ return;
+ }
+ }
+ else
+ ssl.get_SEQIncrement(true); // even though no data, increment verify
+}
+
+
+// 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)
+{
+ set_length(cert_->get_length() + 2 * CERT_HEADER); // list and cert size
+}
+
+
+const opaque* Certificate::get_buffer() const
+{
+ return cert_->get_buffer();
+}
+
+
+// output operator for Certificate
+output_buffer& operator<<(output_buffer& output, const Certificate& cert)
+{
+ uint sz = cert.get_length() - 2 * CERT_HEADER;
+ opaque tmp[CERT_HEADER];
+
+ 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)
+{
+ CertManager& cm = ssl.useCrypto().use_certManager();
+
+ uint32 list_sz;
+ byte tmp[3];
+
+ tmp[0] = input[AUTO];
+ tmp[1] = input[AUTO];
+ tmp[2] = input[AUTO];
+ c24to32(tmp, list_sz);
+
+ while (list_sz) {
+ // cert size
+ uint32 cert_sz;
+ tmp[0] = input[AUTO];
+ tmp[1] = input[AUTO];
+ tmp[2] = input[AUTO];
+ c24to32(tmp, 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()
+{
+ delete[] Ys_;
+ delete[] g_;
+ delete[] 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];
+ input.read(hello.session_id_, 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&, SSL& ssl)
+{
+ ssl.set_pending(cipher_suite_[1]);
+ ssl.set_random(random_, server_end);
+ ssl.set_sessionID(session_id_);
+
+ 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");
+ }
+ ssl.useStates().useClient() = serverHelloComplete;
+}
+
+
+ServerHello::ServerHello()
+{
+ memset(random_, 0, RAN_LEN);
+ memset(session_id_, 0, ID_LEN);
+}
+
+
+ServerHello::ServerHello(ProtocolVersion pv)
+ : server_version_(pv)
+{
+ 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&, SSL& ssl)
+{
+ 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)
+{
+ // 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];
+ tmp[0] = input[AUTO];
+ tmp[1] = input[AUTO];
+ ato16(tmp, hello.suite_len_);
+ input.read(hello.cipher_suites_, hello.suite_len_);
+
+ // Compression
+ hello.comp_len_ = input[AUTO];
+ hello.compression_methods_ = CompressionMethod(input[AUTO]);
+
+ 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&, SSL& ssl)
+{
+ if (ssl.isTLS() && client_version_.minor_ == 0) {
+ ssl.useSecurity().use_connection().TurnOffTLS();
+ ProtocolVersion pv = ssl.getSecurity().get_connection().version_;
+ ssl.useSecurity().use_parms().SetSuites(pv); // reset w/ SSL suites
+ }
+ ssl.set_random(random_, client_end);
+
+ while (id_len_) { // trying to resume
+ SSL_SESSION* 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);
+ 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_);
+ ssl.set_pending(ssl.getSecurity().get_parms().suite_[1]);
+
+ 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)
+ : client_version_(pv)
+{
+ 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)
+{
+ createKey(ssl);
+ if (ssl.GetError()) return;
+ server_key_->read(ssl, input);
+
+ ssl.useStates().useClient() = serverKeyExchangeComplete;
+}
+
+
+ServerKeyExchange::ServerKeyExchange(SSL& ssl)
+{
+ createKey(ssl);
+}
+
+
+ServerKeyExchange::ServerKeyExchange()
+ : server_key_(0)
+{}
+
+
+ServerKeyExchange::~ServerKeyExchange()
+{
+ delete 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()
+{
+
+ mySTL::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];
+ for (int i = 0; i < request.typeTotal_; i++)
+ request.certificate_types_[i] = ClientCertificateType(input[AUTO]);
+
+ byte tmp[REQUEST_HEADER];
+ input.read(tmp, sizeof(tmp));
+ uint16 sz;
+ ato16(tmp, sz);
+
+ // authorities
+ while (sz) {
+ uint16 dnSz;
+ input.read(tmp, sizeof(tmp));
+ ato16(tmp, dnSz);
+
+ DistinguishedName dn;
+ request.certificate_authorities_.push_back(dn = new (ys)
+ byte[REQUEST_HEADER + dnSz]);
+ memcpy(dn, tmp, REQUEST_HEADER);
+ input.read(&dn[REQUEST_HEADER], dnSz);
+
+ sz -= dnSz + REQUEST_HEADER;
+ }
+
+ 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));
+
+ mySTL::list<DistinguishedName>::const_iterator first =
+ request.certificate_authorities_.begin();
+ mySTL::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&, SSL& ssl)
+{
+ ssl.useCrypto().use_certManager().setSendVerify();
+}
+
+
+HandShakeType CertificateRequest::get_type() const
+{
+ return certificate_request;
+}
+
+
+// CertificateVerify
+CertificateVerify::CertificateVerify() : signature_(0)
+{}
+
+
+CertificateVerify::~CertificateVerify()
+{
+ delete[] signature_;
+}
+
+
+void CertificateVerify::Build(SSL& ssl)
+{
+ build_certHashes(ssl, hashes_);
+
+ uint16 sz = 0;
+ byte len[VERIFY_HEADER];
+ mySTL::auto_ptr<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());
+ }
+ 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];
+ input.read(tmp, sizeof(tmp));
+
+ uint16 sz = 0;
+ ato16(tmp, sz);
+ request.set_length(sz);
+
+ 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&, SSL& ssl)
+{
+ 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)
+{
+ createKey(ssl);
+ if (ssl.GetError()) return;
+ client_key_->read(ssl, input);
+
+ 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()
+{
+ delete 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)
+{
+ // verify hashes
+ const Finished& verify = ssl.getHashes().get_verify();
+ uint finishedSz = ssl.isTLS() ? TLS_FINISHED_SZ : FINISHED_SZ;
+
+ input.read(hashes_.md5_, finishedSz);
+
+ 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);
+
+ opaque fill;
+ int padSz = ssl.getSecurity().get_parms().encrypt_size_ -
+ HANDSHAKE_HEADER - finishedSz - digestSz;
+ for (int i = 0; i < padSz; i++)
+ fill = input[AUTO];
+
+ // 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), version_(v), random_(ran)
+{}
+
+
+Connection::~Connection()
+{
+ CleanMaster(); CleanPreMaster(); delete[] 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;
+}
+
+
+// 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_);
+
+ delete[] 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
+
+#ifdef __GNUC__
+namespace mySTL {
+template class mySTL::list<unsigned char*>;
+template yaSSL::del_ptr_zero mySTL::for_each(mySTL::list<unsigned char*>::iterator, mySTL::list<unsigned char*>::iterator, yaSSL::del_ptr_zero);
+template mySTL::pair<int, yaSSL::Message* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*>(mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*);
+template mySTL::pair<int, yaSSL::HandShakeBase* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*>(mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*);
+template void mySTL::destroy<mySTL::pair<int, yaSSL::Message* (*)()>*>(mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*);
+template void mySTL::destroy<mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*>(mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*);
+template mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*);
+template void mySTL::destroy<mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*);
+template mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*);
+template class mySTL::list<TaoCrypt::Signer*>;
+template class mySTL::list<yaSSL::SSL_SESSION*>;
+template class mySTL::list<yaSSL::input_buffer*>;
+template class mySTL::list<yaSSL::output_buffer*>;
+template class mySTL::list<yaSSL::x509*>;
+template void mySTL::destroy<mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*);
+template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<TaoCrypt::Signer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<TaoCrypt::Signer*>::iterator, mySTL::list<TaoCrypt::Signer*>::iterator, yaSSL::del_ptr_zero);
+template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::del_ptr_zero);
+template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::del_ptr_zero);
+template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::output_buffer*>::iterator, mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::del_ptr_zero);
+template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::x509*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::x509*>::iterator, mySTL::list<yaSSL::x509*>::iterator, yaSSL::del_ptr_zero);
+}
+#endif
+