1
// ---------------------------------------------------------------------------
3
// - afnix:tls service - tls protocol class implementation -
4
// ---------------------------------------------------------------------------
5
// - This program is free software; you can redistribute it and/or modify -
6
// - it provided that this copyright notice is kept intact. -
8
// - This program is distributed in the hope that it will be useful, but -
9
// - without any warranty; without even the implied warranty of -
10
// - merchantability or fitness for a particular purpose. In no event shall -
11
// - the copyright holder be liable for any direct, indirect, incidental or -
12
// - special damages arising in any way out of the use of this software. -
13
// ---------------------------------------------------------------------------
14
// - copyright (c) 1999-2015 amaury darsch -
15
// ---------------------------------------------------------------------------
18
#include "Integer.hpp"
19
#include "TlsTypes.hxx"
20
#include "TlsShake.hpp"
21
#include "TlsProto.hpp"
22
#include "TlsChello.hpp"
23
#include "TlsShello.hpp"
24
#include "QuarkZone.hpp"
25
#include "Exception.hpp"
29
// -------------------------------------------------------------------------
31
// -------------------------------------------------------------------------
33
// create a tls protocol by version
35
TlsProto* TlsProto::create (const t_byte vmaj, const t_byte vmin) {
37
String vers = tls_vers_tostring (vmaj, vmin);
38
if (tls_vers_isvalid (vmaj, vmin) == false) {
39
throw Exception ("tls-error", "invalid tls version", vers);
41
// process major version
42
if (vmaj == TLS_VMAJ_3XX) {
43
if (vmin == TLS_VMIN_301) return new TlsProto;
45
throw Exception ("tls-error", "cannot create tls protocol version", vers);
48
// create a tls protocol by state
50
TlsProto* TlsProto::create (TlsState* sta) {
52
if (sta == nilp) return nilp;
53
// get version and check
54
t_byte vmaj = sta->getvmaj ();
55
t_byte vmin = sta->getvmin ();
56
// create the protocol
57
return TlsProto::create (vmaj, vmin);
60
// -------------------------------------------------------------------------
62
// -------------------------------------------------------------------------
64
// create a default decoder
66
TlsProto::TlsProto (void) {
69
// return the class name
71
String TlsProto::repr (void) const {
75
// get a record by input stream
77
TlsRecord* TlsProto::getrcd (InputStream* is) const {
80
TlsRecord* result = new TlsRecord (is);
89
// get a message a by input stream
91
TlsMessage* TlsProto::getmsg (InputStream* is) const {
93
TlsRecord* rcd = nilp;
95
// get the next available record
98
TlsMessage* msg = getmsg (rcd);
108
// decode a record into a message
110
TlsMessage* TlsProto::getmsg (TlsRecord* rcd) const {
112
if (rcd == nilp) return nilp;
116
// get the record type and check
117
t_byte type = rcd->gettype ();
119
TlsMessage* result = nilp;
123
result = new TlsShake (rcd);
126
throw Exception ("tls-error", "cannot decode record into a message");
137
// encode a tls message
139
void TlsProto::encode (OutputStream* os, TlsMessage* mesg) const {
141
if ((mesg == nilp) || (os == nilp)) return;
144
// check for an alert
145
//TlsAlert* alt = dynamic_cast <TlsAlert*> (mesg);
146
//if (alt != nilp) alt->encode (os);
147
// check for a handshake
148
TlsShake* hsk = dynamic_cast <TlsShake*> (mesg);
149
if (hsk != nilp) hsk->write (os);
157
// decode a handshake block
159
TlsInfos* TlsProto::decode (TlsHblock* hblk) const {
161
if (hblk == nilp) return nilp;
165
// get the block type and check
166
t_byte type = hblk->gettype ();
168
TlsInfos* result = nilp;
172
result = new TlsChello (hblk);
175
throw Exception ("tls-error", "cannot decode handshake block");
186
// get a client hello by input stream
188
TlsInfos* TlsProto::getchlo (InputStream* is) const {
190
TlsHblock* blk = nilp;
192
// get the next available message
193
TlsMessage* msg = getmsg (is);
198
// map it to a handshake message
199
TlsShake* shk = dynamic_cast <TlsShake*> (msg);
201
throw Exception ("tls-error", "cannot get handshake message");
203
// create a handshake iterator
204
TlsShakeit sit (shk);
205
// get the handshake block
206
blk = dynamic_cast <TlsHblock*> (sit.getobj ());
208
throw Exception ("tls-error", "cannot get handshake block");
210
// move to the end and check
212
if (sit.isend () == false) {
213
throw Exception ("tls-error", "inconsistent handshake message");
215
// get the client block
216
TlsInfos* hlo = decode (blk);
218
throw Exception ("tls-error", "cannot decode client hello block");
230
// map a server hello by state
232
TlsMessage* TlsProto::getshlo (TlsState* sta) const {
233
// check for nil first
234
if (sta == nilp) return nilp;
236
TlsShake* hsk = nilp;
239
// create a tls handshake by state
240
hsk = new TlsShake (sta->getvmaj (), sta->getvmin());
241
// get the server hello chunk by state
242
TlsChunk chk = toshlo (sta);
243
// add the chunk block to the record
244
hsk->add (TLS_HSHK_SRH, chk);
254
// get a server hello chunk by state
256
TlsChunk TlsProto::toshlo (TlsState* sta) const {
260
// check for nil first
262
throw Exception ("tls-error", "cannot generate server hello chunk");
264
// gather the server hello information
265
t_byte vmaj = sta->getvmaj ();
266
t_byte vmin = sta->getvmin ();
267
t_word cifr = sta->getcifr ();
268
// create a server hello
269
TlsShello shlo (vmaj, vmin, cifr);
270
// map it to an info block
271
TlsChunk result = shlo.tochunk ();
280
// -------------------------------------------------------------------------
281
// - object section -
282
// -------------------------------------------------------------------------
285
static const long QUARK_ZONE_LENGTH = 2;
286
static QuarkZone zone (QUARK_ZONE_LENGTH);
288
// the object supported quarks
289
static const long QUARK_DECODE = zone.intern ("decode");
290
static const long QUARK_GETMSG = zone.intern ("get-message");
292
// create a new object in a generic way
294
Object* TlsProto::mknew (Vector* argv) {
295
// get the number of arguments
296
long argc = (argv == nilp) ? 0 : argv->length ();
298
// check for 0 argument
299
if (argc == 0) return new TlsProto;
300
// too many arguments
301
throw Exception ("argument-error",
302
"too many argument with tls decoder constructor");
305
// return true if the given quark is defined
307
bool TlsProto::isquark (const long quark, const bool hflg) const {
310
if (zone.exists (quark) == true) {
314
bool result = hflg ? Object::isquark (quark, hflg) : false;
323
// apply this object with a set of arguments and a quark
325
Object* TlsProto::apply (Runnable* robj, Nameset* nset, const long quark,
327
// get the number of arguments
328
long argc = (argv == nilp) ? 0 : argv->length ();
330
// dispatch 1 argument
332
if (quark == QUARK_DECODE) {
333
Object* obj = argv->get (0);
334
TlsHblock* hblk = dynamic_cast<TlsHblock*> (obj);
336
throw Exception ("type-error", "invalid object as handshake block",
339
return decode (hblk);
341
if (quark == QUARK_GETMSG) {
342
Object* obj = argv->get (0);
343
TlsRecord* rcd = dynamic_cast<TlsRecord*> (obj);
345
throw Exception ("type-error", "invalid object as record",
351
// call the object method
352
return Object::apply (robj, nset, quark, argv);