📄 handshake.cpp
字号:
/* handshake.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
*/
/* 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 {
using mySTL::min;
// Build a client hello message from cipher suites and compression method
void buildClientHello(SSL& ssl, ClientHello& hello,
CompressionMethod compression = no_compression)
{
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.compression_methods_ = compression;
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_ = no_compression;
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)
{
uint sz = output.get_size() - RECORD_HEADER;
const opaque* buffer = output.get_buffer() + RECORD_HEADER;
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));
}
// 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();
ssl.useCrypto().use_cipher().decrypt(plain.get_buffer(), cipher, sz);
memcpy(cipher, plain.get_buffer(), sz);
ssl.useSecurity().use_parms().encrypt_size_ = sz;
}
// 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;
if (ssl.getSecurity().get_parms().cipher_type_ == block) {
sz += 1; // pad byte
uint blockSz = ssl.getCrypto().get_cipher().get_blockSize();
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
output.allocate(sz);
output << rlHeader << hsHeader << fin;
hashHandShake(ssl, output);
opaque digest[SHA_LEN]; // max size
if (ssl.isTLS())
TLS_hmac(ssl, digest, output.get_buffer() + RECORD_HEADER,
output.get_size() - RECORD_HEADER, 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;
if (ssl.getSecurity().get_parms().cipher_type_ == block) {
sz += 1; // pad byte
uint blockSz = ssl.getCrypto().get_cipher().get_blockSize();
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
output.allocate(sz);
output << rlHeader << msg;
opaque digest[SHA_LEN]; // max size
if (ssl.isTLS())
TLS_hmac(ssl, digest, output.get_buffer() + RECORD_HEADER,
output.get_size() - RECORD_HEADER, 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -