File: Packet.pike

package info (click to toggle)
pike8.0 8.0.1956-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 60,580 kB
  • sloc: ansic: 259,734; xml: 36,320; makefile: 3,748; sh: 1,713; cpp: 1,349; awk: 1,036; lisp: 655; javascript: 468; asm: 242; objc: 240; pascal: 157; sed: 34
file content (137 lines) | stat: -rw-r--r-- 3,765 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#pike __REAL_VERSION__

//! SSL Record Layer. Handle formatting and parsing of packets.

import .Constants;

int content_type;
ProtocolVersion protocol_version;
string(8bit) fragment;  /* At most 2^14 */

constant HEADER_SIZE = 5;

private string buffer = "";
private int needed_chars = HEADER_SIZE;

// The fragment max size is 2^14 (RFC 5246 6.2.1). Compressed
// fragments are however allowed to be 1024 bytes over (6.2.2), and
// Ciphertexts 2048 bytes (6.2.3). State the additional headroom in
// this variable.
protected int marginal_size;

/* Circular dependence */
program Alert = master()->resolv("SSL")["Alert"];

//! @param version
//!   The version sent packets will be created for.
//! @param extra
//!   Additional fragment size, over the 2^14 bytes for a plaintext
//!   TLS fragment.
protected void create(ProtocolVersion version, void|int extra)
{
  protocol_version = version;
  marginal_size = extra;
}

protected object check_size(string data, int extra)
{
  if (sizeof(data) > (PACKET_MAX_SIZE + extra))
    return Alert(ALERT_fatal, ALERT_record_overflow, version);
  marginal_size = extra;
  fragment = data;
  return 0;
}

object set_plaintext(string data)
{
  return check_size(data, 0);
}

object set_compressed(string data)
{
  return check_size(data, 1024);
}

object set_encrypted(string data)
{
  return check_size(data, 2048);
}

//! Receive data read from the network.
//!
//! @param data
//!   Raw data from the network.
//!
//! @returns
//!   Returns a string of leftover data if packet is complete,
//!   otherwise @expr{0@}.
//!
//!   If there's an error, an alert object is returned.
//!
string(8bit)|.Packet recv(string(8bit) data)
{
  buffer += data;
  while (sizeof(buffer) >= needed_chars)
  {
    if (needed_chars == HEADER_SIZE)
    {
      content_type = buffer[0];
      fragment = 0;
      int length;

      /* Support only short SSL2 headers */
      if ( (content_type & 0x80) && (buffer[2] == 1) )
      {
#ifdef SSL3_DEBUG
	werror("SSL.Packet: Receiving SSL2 packet %O\n", buffer[..4]);
#endif
        return Alert(ALERT_fatal, ALERT_insufficient_security, PROTOCOL_SSL_3_0);
      }
      if( !PACKET_types[content_type] )
        return Alert(ALERT_fatal, ALERT_unexpected_message, protocol_version);

      sscanf(buffer, "%*c%2c%2c", protocol_version, length);
      if ( (length <= 0) || (length > (PACKET_MAX_SIZE + marginal_size)))
	return Alert(ALERT_fatal, ALERT_unexpected_message, protocol_version);
      if ((protocol_version & ~0xff) != PROTOCOL_SSL_3_0)
	return Alert(ALERT_fatal, ALERT_unexpected_message, protocol_version,
		     sprintf("SSL.Packet->send: Version %d.%d "
			     "is not supported\n",
			     protocol_version>>8, protocol_version & 0xff));
#ifdef SSL3_DEBUG
      if (protocol_version > PROTOCOL_TLS_MAX)
	werror("SSL.Packet->recv: received version %d.%d packet\n",
	       protocol_version>>8, protocol_version & 0xff);
#endif

      needed_chars += length;
    } else {
      fragment = buffer[HEADER_SIZE .. needed_chars - 1];
      return buffer[needed_chars ..];
    }
  }
  return 0;
}

//! Serialize the packet for sending.
//!
//! @returns
//!   Returns the serialized packet.
string send()
{
  if (! PACKET_types[content_type] )
    error( "Invalid type" );
  
  if ((protocol_version & ~0xff) != PROTOCOL_SSL_3_0)
    error( "Version %d is not supported\n", protocol_version>>8 );
#ifdef SSL3_DEBUG
  if (protocol_version > PROTOCOL_TLS_MAX)
    werror("SSL.Packet->send: Sending version %d.%d packet\n",
	   protocol_version>>8, protocol_version & 0xff);
#endif
  if (sizeof(fragment) > (PACKET_MAX_SIZE + marginal_size))
    error( "Maximum packet size exceeded\n" );

  return sprintf("%c%2c%2c%s", content_type, protocol_version,
		 sizeof(fragment), fragment);
}