// send certificate verify void sendCertificateVerify(SSL& ssl, BufferOutput buffer) { if (ssl.GetError()) return; CertificateVerify verify; verify.Build(ssl); 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()); }
// 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 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 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()); }
// do process input requests, return 0 is done, 1 is call again to complete int DoProcessReply(SSL& ssl) { // wait for input if blocking if (!ssl.useSocket().wait()) { ssl.SetError(receive_error); return 0; } 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; } 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; }