2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 internal class InputRecord {
34 int recordPtr, recordEnd;
41 * Get the length (in bytes) of the data that remains to be
42 * read from the received buffer.
44 internal int BufferedLength {
46 return recordEnd - recordPtr;
51 * Get the current record type (-1 if no record was read yet).
53 internal int RecordType {
60 * Get the current record version (-1 if no record was read yet).
62 internal int RecordVersion {
68 internal InputRecord(Stream sub)
71 buffer = new byte[16384 + 500];
77 rdec = new RecordDecryptPlain();
81 * Set the expected version. If this value is nonnegative, then
82 * all subsequent records are expected to match this version; a
83 * version mismatch will trigger an exception.
85 * If not initially set explicitly, then this value is automatically
86 * set to the version of the first incoming record.
88 internal void SetExpectedVersion(int expectedVersion)
90 this.expectedVersion = expectedVersion;
94 * Set the new decryption engine. This is possible only if the
95 * end of the current record was reached.
97 internal void SetDecryption(RecordDecrypt rdec)
99 if (recordPtr != recordEnd) {
100 throw new SSLException(
101 "Cannot switch encryption: buffered data");
107 * Get next record. Returned value is false if EOF was reached
108 * before obtaining the first record header byte.
110 internal bool NextRecord()
112 if (!IO.ReadAll(sub, buffer, 0, 5, true)) {
115 recordType = buffer[0];
116 recordVersion = IO.Dec16be(buffer, 1);
117 int len = IO.Dec16be(buffer, 3);
118 if (expectedVersion >= 0 && expectedVersion != recordVersion) {
119 throw new SSLException(string.Format(
120 "Wrong record version: 0x{0:X4}"
121 + " (expected: 0x{1:X4})",
122 recordVersion, expectedVersion));
124 if ((recordVersion >> 8) != 0x03) {
125 throw new SSLException(string.Format(
126 "Unsupported record version: 0x{0:X4}",
129 if (expectedVersion < 0) {
130 expectedVersion = recordVersion;
133 if (!rdec.CheckLength(len)) {
134 throw new SSLException("Wrong record length: " + len);
136 IO.ReadAll(sub, buffer, 0, len, false);
138 if (!rdec.Decrypt(recordType, recordVersion,
139 buffer, ref off, ref len))
141 throw new SSLException("Decryption failure");
144 recordEnd = off + len;
149 * Read the next byte from the current record. -1 is returned if
150 * the current record is finished.
154 if (recordPtr == recordEnd) {
157 return buffer[recordPtr ++];
162 * Read some bytes from the current record. The number of
163 * obtained bytes is returned; a short count (including 0)
164 * is possible only if the end of the current record was
167 internal int Read(byte[] buf)
169 return Read(buf, 0, buf.Length);
173 * Read some bytes from the current record. The number of
174 * obtained bytes is returned; a short count (including 0)
175 * is possible only if the end of the current record was
178 internal int Read(byte[] buf, int off, int len)
180 int clen = Math.Min(len, recordEnd - recordPtr);
181 Array.Copy(buffer, recordPtr, buf, off, clen);