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
26 using System.Collections.Generic;
35 * This is the base class common to SSLClient and SSLServer.
38 public abstract class SSLEngine : Stream {
50 * Functions used to hash handshake messages.
59 * STATE_HANDSHAKE expecting handshake message only
60 * STATE_CCS expecting Change Cipher Spec message only
61 * STATE_APPDATA expecting application data or handshake
62 * STATE_CLOSING expecting only alert (close_notify)
65 internal const int STATE_CLOSED = 0;
66 internal const int STATE_HANDSHAKE = 1;
67 internal const int STATE_CCS = 2;
68 internal const int STATE_APPDATA = 3;
69 internal const int STATE_CLOSING = 4;
72 * Default cipher suites.
74 static int[] DEFAULT_CIPHER_SUITES = {
75 SSL.ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
76 SSL.ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
78 SSL.ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
79 SSL.ECDHE_RSA_WITH_AES_128_GCM_SHA256,
80 SSL.ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
81 SSL.ECDHE_RSA_WITH_AES_256_GCM_SHA384,
82 SSL.ECDHE_ECDSA_WITH_AES_128_CCM,
83 SSL.ECDHE_ECDSA_WITH_AES_256_CCM,
84 SSL.ECDHE_ECDSA_WITH_AES_128_CCM_8,
85 SSL.ECDHE_ECDSA_WITH_AES_256_CCM_8,
86 SSL.ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
87 SSL.ECDHE_RSA_WITH_AES_128_CBC_SHA256,
88 SSL.ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
89 SSL.ECDHE_RSA_WITH_AES_256_CBC_SHA384,
90 SSL.ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
91 SSL.ECDHE_RSA_WITH_AES_128_CBC_SHA,
92 SSL.ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
93 SSL.ECDHE_RSA_WITH_AES_256_CBC_SHA,
95 SSL.ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
96 SSL.ECDH_RSA_WITH_AES_128_GCM_SHA256,
97 SSL.ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
98 SSL.ECDH_RSA_WITH_AES_256_GCM_SHA384,
99 SSL.ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
100 SSL.ECDH_RSA_WITH_AES_128_CBC_SHA256,
101 SSL.ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
102 SSL.ECDH_RSA_WITH_AES_256_CBC_SHA384,
103 SSL.ECDH_ECDSA_WITH_AES_128_CBC_SHA,
104 SSL.ECDH_RSA_WITH_AES_128_CBC_SHA,
105 SSL.ECDH_ECDSA_WITH_AES_256_CBC_SHA,
106 SSL.ECDH_RSA_WITH_AES_256_CBC_SHA,
108 SSL.RSA_WITH_AES_128_GCM_SHA256,
109 SSL.RSA_WITH_AES_256_GCM_SHA384,
110 SSL.RSA_WITH_AES_128_CCM,
111 SSL.RSA_WITH_AES_256_CCM,
112 SSL.RSA_WITH_AES_128_CCM_8,
113 SSL.RSA_WITH_AES_256_CCM_8,
114 SSL.RSA_WITH_AES_128_CBC_SHA256,
115 SSL.RSA_WITH_AES_256_CBC_SHA256,
116 SSL.RSA_WITH_AES_128_CBC_SHA,
117 SSL.RSA_WITH_AES_256_CBC_SHA,
119 SSL.ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
120 SSL.ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
121 SSL.ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
122 SSL.ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
123 SSL.RSA_WITH_3DES_EDE_CBC_SHA
129 static int[] DEFAULT_CURVES = {
137 * Default hash and sign algorithms.
139 static int[] DEFAULT_HASHANDSIGN = {
152 internal byte[] clientRandom;
153 internal byte[] serverRandom;
154 internal byte[] sessionID;
157 * 'renegSupport' is one of:
158 * 0 initial handshake not done yet
159 * 1 peer supports secure renegotiation
160 * -1 peer does not support secure renegotiation
162 internal int renegSupport;
163 internal byte[] savedClientFinished;
164 internal byte[] savedServerFinished;
169 * Create a new engine over the provided transport stream.
171 public SSLEngine(Stream sub)
174 inRec = new InputRecord(sub);
175 outRec = new OutputRecord(sub);
178 sha256 = new SHA256();
179 sha384 = new SHA384();
180 state = STATE_HANDSHAKE;
185 NoCloseNotify = false;
186 ClosedWithoutNotify = false;
187 MaximumHandshakeMessageLength = 65536;
188 SupportedCipherSuites = DEFAULT_CIPHER_SUITES;
189 SupportedCurves = DEFAULT_CURVES;
190 SupportedHashAndSign = DEFAULT_HASHANDSIGN;
191 VersionMin = SSL.TLS10;
192 VersionMax = SSL.TLS12;
193 AllowRenegotiation = true;
194 receivedNoReneg = false;
195 clientRandom = new byte[32];
196 serverRandom = new byte[32];
197 masterSecret = new byte[48];
202 * If 'NormalizeIOError' is true, then I/O errors while writing
203 * on the underlying stream will be reported as a generic
204 * SSLException with message "Unexpected transport closure".
205 * This helps test code that expects an asynchronous abort that
206 * may be detected during a read of a write operation, depending
207 * on the exact timing. Default is false.
209 public bool NormalizeIOError {
211 return outRec.NormalizeIOError;
214 outRec.NormalizeIOError = value;
219 * If 'AutoFlush' is true, then after every Write() or WriteByte()
220 * call, the current record is assembled and sent, leaving no
221 * buffered data yet to be sent. Default value is true.
223 public bool AutoFlush {
228 * If 'CloseSub' is true, then the underlying transport stream
229 * will be closed on normal closure or protocol failure. Default
230 * value is true. If a closure callback is set in 'OnClose',
231 * then this flag is ignored.
233 public bool CloseSub {
238 * A generic callback to be invoked when the SSL connection is
239 * closed. If a callback is specified here, then the 'CloseSub'
240 * flag is ignored; the callback is supposed to handle the
241 * closing of the transport stream, if necessary.
243 public delegate void CloseGen(Stream sub);
244 public CloseGen OnClose {
249 * If 'NoCloseNotify' is true, then lack of a close_notify from
250 * the peer before closing the transport stream will NOT be
251 * considered erroneous; i.e. it won't trigger an exception.
252 * If that situation arises, the ClosedWithoutNotify flag will
253 * return true, so the caller may still test for it.
255 * Not sending close_notify alerts before closing is a widespread
256 * practice, since it simplifies timeout management. It is unsafe,
257 * in that it allows truncation attacks, unless the application
258 * protocol is self-terminated (e.g. HTTP/1.1 is self-terminated,
261 * Default value is false: lack of close_notify triggers an
264 public bool NoCloseNotify {
269 * The 'ClosedWithoutNotify' flag is set to true if the connection
270 * was closed abruptly (no close_notify alert), but this engine
271 * was configured to tolerate that situation ('NoCloseNotify' was
274 public bool ClosedWithoutNotify {
279 * Maximum allowed size for a handshake message. The protocol
280 * allows for messages up to 16 megabytes, but these hardly
281 * make sense in practice. In the interest of avoiding
282 * memory-based denials of service, a lower limit can be set.
283 * If an incoming handshake message exceeds that size, then
284 * an exception is thrown. Default value is 65536.
286 public int MaximumHandshakeMessageLength {
291 * Set the cipher suites supported by this engine, in preference
292 * order (most preferred comes first). Default value should ensure
293 * maximum interoperability and good security and performance.
295 public int[] SupportedCipherSuites {
300 * Set the elliptic curves supported by this engine, for ECDH
301 * and ECDHE. The list is in preference order (most preferred
302 * comes first). Default list is Curve25519 followed by the
303 * usual NIST curves (P-256, P-384 and P-521, in that order).
305 public int[] SupportedCurves {
310 * Set the supported hash and sign algorithm combinations. Each
311 * value is a 16-bit integer: high byte is the hash algorithm
312 * identifier, while low byte is the signature algorithm identifier.
313 * List is ordered by preference order. Default list applies the
316 * - Hash function order is:
317 * SHA-256, SHA-224, SHA-384, SHA-512, SHA-1
319 * - For the same hash function, ECDSA is preferred over RSA.
321 * Note that the special RSA with MD5+SHA-1 shall not be part of
322 * this list. Its use is implicit when using TLS 1.0 or 1.1 with
323 * a cipher suite or client authentication that uses RSA signatures.
325 public int[] SupportedHashAndSign {
330 * Set the minimum supported protocol version. Default is TLS 1.0.
332 public int VersionMin {
337 SetOutputRecordVersion(value);
343 * Set the maximum supported protocol version. Default is TLS 1.2.
345 public int VersionMax {
350 * Get the actual protocol version. This is set only when the
351 * version is chosen, within the handshake.
355 return actualVersion;
358 actualVersion = value;
359 SetOutputRecordVersion(value);
364 * Get the actual cipher suite. This is set only when it is chosen,
365 * within the handshake.
367 public int CipherSuite {
372 * Get or set the server name associated with this connection.
374 * On a client, the caller shall set that name; if non-null and
375 * non-empty, then it will be sent to the server as a SNI
376 * extension; it will moreover be matched against the names
377 * found in the server's certificate.
379 * On a server, this value is set to the host name received from
380 * the client as a SNI extension (if any).
382 public string ServerName {
387 * Get the current session parameters. If the initial handshake
388 * was not performed yet, then the handshake is performed now
389 * (thus, this call may trigger an exception in case of I/O or
392 * The returned object is a freshly allocated copy, which is not
393 * impacted by further activity on this engine.
395 public SSLSessionParameters SessionParameters {
397 if (state == STATE_HANDSHAKE) {
398 DoHandshakeWrapper();
400 return new SSLSessionParameters(sessionID, Version,
401 CipherSuite, ServerName, masterSecret);
406 * Renegotiation support: if true, then renegotiations will be
407 * accepted (both explicit calls to Renegotiate(), and requests
408 * from the peer); if false, then all renegotiation attempts will
411 * Default value is true. Regardless of the value of this flag,
412 * renegotiation attempts will be denied if the peer does not
413 * support the "Secure Renegotiation" extension (RFC 5746).
415 public bool AllowRenegotiation {
420 * Set "quirks" to alter engine behaviour. When null (which is the
421 * default), normal behaviour occurs.
423 public SSLQuirks Quirks {
428 * Get the current handshake count. This starts at 0 (before
429 * the initial handshake) and is incremented for each handshake.
430 * The increment occurs at the start of the handshake (after
431 * confirmation that a handshake will be indeed attempted, when
432 * doing a renegotiation).
434 public long HandshakeCount {
439 * Tell whether the last handshake was a session resumption or not.
440 * This flag is set at the end of the handshake.
442 public bool IsResume {
447 * Trigger a new handshake. If the initial handshake was not done
448 * yet, then it is performed at that point. Otherwise, this is
449 * a renegotiation attempt.
451 * Returned value is true if a new handshake happened, false
452 * otherwise. For the initial handshake, true is always returned
453 * (handshake failures trigger exceptions). For a renegotiation,
454 * a 'false' value may be returned if one of the following holds:
455 * - This engine was configured not to use renegotiations.
456 * - The peer does not support secure renegotiation.
457 * - A renegotiation was attempted, but denied by the peer.
459 public bool Renegotiate()
461 if (!FirstHandshakeDone) {
462 DoHandshakeWrapper();
466 if (!AllowRenegotiation) {
469 if (!GetQuirkBool("noSecureReneg") && renegSupport < 0) {
472 int rt = outRec.RecordType;
474 PrepareRenegotiate();
479 if (!DoHandshakeWrapper()) {
480 outRec.RecordType = rt;
486 /* ============================================================ */
488 * Stream standard API.
491 public override int ReadByte()
493 if (state == STATE_CLOSED) {
505 public override int Read(byte[] buf, int off, int len)
507 if (state == STATE_CLOSED) {
512 return ZRead(buf, off, len);
519 public override void WriteByte(byte x)
533 public override void Write(byte[] buf, int off, int len)
537 outRec.Write(buf, off, len);
547 public override void Flush()
558 public override void Close()
563 void Close(bool expectCloseNotify)
565 if (state == STATE_CLOSED) {
569 if (state == STATE_APPDATA) {
570 SendWarning(SSL.CLOSE_NOTIFY);
571 state = STATE_CLOSING;
572 if (expectCloseNotify) {
576 throw new SSLException(
577 "Peer does not want to close");
587 public override long Seek(long off, SeekOrigin origin)
589 throw new NotSupportedException();
592 public override void SetLength(long len)
594 throw new NotSupportedException();
597 public override bool CanRead {
599 return state != STATE_CLOSED;
603 public override bool CanWrite {
605 return state != STATE_CLOSED;
609 public override bool CanSeek {
615 public override long Length {
617 throw new NotSupportedException();
621 public override long Position {
623 throw new NotSupportedException();
626 throw new NotSupportedException();
630 /* ============================================================ */
633 * Test whether this engine is a client or a server.
635 internal abstract bool IsClient {
640 * Test the configuration of hash-and-sign with regards to
641 * cipher suites: if the list of cipher suites includes an
642 * ECDHE suite, then there must be at least one supported
643 * hash-and-sign with the corresponding signature type.
645 internal void CheckConfigHashAndSign()
648 * The hash-and-sign are only for TLS 1.2.
650 if (VersionMax < SSL.TLS12) {
655 * If the list is empty then we will work over the default
656 * list inferred by the peer (no extension sent).
658 if (SupportedHashAndSign == null
659 || SupportedHashAndSign.Length == 0)
664 bool needRSA = false;
665 bool needECDSA = false;
666 foreach (int cs in SupportedCipherSuites) {
667 if (SSL.IsECDHE_RSA(cs)) {
670 if (SSL.IsECDHE_ECDSA(cs)) {
674 foreach (int hs in SupportedHashAndSign) {
676 if (needRSA && sa == SSL.RSA) {
679 if (needECDSA && sa == SSL.ECDSA) {
684 throw new SSLException("Incoherent configuration:"
685 + " supports ECDHE_RSA but no RSA signature"
689 throw new SSLException("Incoherent configuration:"
690 + " supports ECDHE_ECDSA but no ECDSA signature"
695 internal bool HasQuirk(string name)
697 return Quirks != null && Quirks.GetString(name, null) != null;
700 internal bool GetQuirkBool(string name)
702 return GetQuirkBool(name, false);
705 internal bool GetQuirkBool(string name, bool defaultValue)
707 if (Quirks == null) {
710 return Quirks.GetBoolean(name, defaultValue);
713 internal int GetQuirkInt(string name)
715 return GetQuirkInt(name, 0);
718 internal int GetQuirkInt(string name, int defaultValue)
720 if (Quirks == null) {
723 return Quirks.GetInteger(name, defaultValue);
726 internal string GetQuirkString(string name)
728 return GetQuirkString(name, null);
731 internal string GetQuirkString(string name, string defaultValue)
733 if (Quirks == null) {
736 return Quirks.GetString(name, defaultValue);
740 * Test whether the first handshake has been done or not.
742 internal bool FirstHandshakeDone {
744 return savedClientFinished != null;
749 * Close the engine. No I/O may happen beyond this call.
751 internal void MarkFailed()
755 if (OnClose != null) {
757 } else if (CloseSub) {
765 state = STATE_CLOSED;
769 * Check that the current state is not closed.
771 void CheckNotClosed()
773 if (state == STATE_CLOSED) {
774 throw new SSLException("Connection is closed");
779 * Check that we are ready to exchange application data. A
780 * handshake is performed if necessary.
785 if (!FirstHandshakeDone) {
786 DoHandshakeWrapper();
787 } else if (state != STATE_APPDATA) {
788 throw new SSLException(
789 "Connection not ready for application data");
794 * Set the version for outgoing records.
796 internal void SetOutputRecordVersion(int version)
798 outRec.SetVersion(version);
802 * Set the expected version for incoming records. This should be
803 * used by the server code just after parsing the ClientHello,
804 * because the client is supposed to send records matching the
805 * protocol version decided by the server and sent in the
808 * For a SSL client, this call in unnecessary because default
809 * behaviour is to look at the version of the first incoming
810 * record (containing the ServerHello for the server) and expect
811 * all subsequent records to have the same version.
813 internal void SetInputRecordVersion(int version)
815 inRec.SetExpectedVersion(version);
819 * Flush the underlying record engine.
821 internal void FlushSub()
827 * Get next record. This returns false only if the connection
828 * turned out to be ended "properly".
830 * In all other cases, a record is obtained, and true is
831 * returned. It is possible that the record contains no unread
832 * data (it could be an empty record, or it could be an alert
833 * record whose contents are automatically processed).
835 internal bool NextRecord()
837 if (!inRec.NextRecord()) {
838 if (NoCloseNotify && (state == STATE_APPDATA
839 || state == STATE_CLOSING))
842 * No close_notify, but we have been set
845 ClosedWithoutNotify = true;
849 throw new SSLException("Unexpected transport closure");
853 * We basically ignore empty records, regardless of state.
855 if (inRec.BufferedLength == 0) {
859 int rt = inRec.RecordType;
864 * Fatal alerts trigger an exception. Warnings are
865 * ignored, except close_notify and no_renegotiation.
867 while (inRec.BufferedLength > 0) {
868 int level = deferredAlert;
871 level = inRec.Read();
872 if (inRec.BufferedLength == 0) {
873 deferredAlert = level;
877 int desc = inRec.Read();
878 if (level == SSL.FATAL) {
879 throw new SSLException(desc);
881 if (level != SSL.WARNING) {
882 throw new SSLException("Unknown"
883 + " alert level: " + level);
885 if (desc == SSL.CLOSE_NOTIFY) {
886 if (state == STATE_CLOSING) {
890 if (state != STATE_APPDATA) {
891 throw new SSLException(
892 "Unexpected closure");
896 } else if (desc == SSL.NO_RENEGOTIATION) {
897 receivedNoReneg = true;
904 case STATE_HANDSHAKE:
907 ProcessExtraHandshakeWrapper();
910 throw new SSLException("Unexpected handshake message");
912 case SSL.CHANGE_CIPHER_SPEC:
913 if (state == STATE_CCS) {
916 throw new SSLException("Unexpected Change Cipher Spec");
918 case SSL.APPLICATION_DATA:
919 if (state == STATE_APPDATA) {
922 throw new SSLException("Unexpected application data");
925 throw new SSLException("Invalid record type: " + rt);
931 * ZRead() reads the next byte, possibly obtaining further records
932 * to do so. It may return -1 only if the end-of-stream was reached,
933 * which can happen only in "application data" state (after a
934 * successful handshake).
938 int x = ZReadNoHash();
939 if (x >= 0 && inRec.RecordType == SSL.HANDSHAKE) {
946 * ZReadNoHash() is similar to ZRead() except that it skips
947 * the automatic hashing of handshake messages.
951 while (inRec.BufferedLength == 0) {
960 * ZReadNoHashNoReneg() is similar to ZReadNoHash() except
961 * that it may return -1 while being in state STATE_HANDSHAKE
962 * in case a no_renegotiation alert is received.
964 int ZReadNoHashNoReneg()
966 while (inRec.BufferedLength == 0) {
967 receivedNoReneg = false;
968 if (!NextRecord() || receivedNoReneg) {
976 * Read some bytes. At least one byte will be obtained, unless
977 * EOF is reached. Extra records are obtained if necessary.
979 int ZRead(byte[] buf)
981 return ZRead(buf, 0, buf.Length);
985 * Read some bytes. At least one byte will be obtained, unless
986 * EOF is reached. Extra records are obtained if necessary.
988 int ZRead(byte[] buf, int off, int len)
990 while (inRec.BufferedLength == 0) {
995 int rlen = inRec.Read(buf, off, len);
996 if (rlen > 0 && inRec.RecordType == SSL.HANDSHAKE) {
997 md5.Update(buf, off, rlen);
998 sha1.Update(buf, off, rlen);
999 sha256.Update(buf, off, rlen);
1000 sha384.Update(buf, off, rlen);
1005 bool DoHandshakeWrapper()
1008 * Record split mode syntax: name:[types]
1010 * 'name' is a symbolic name.
1012 * 'types' is a comma-separated list of record types on
1013 * which the splitting mode applies. Record types are
1014 * numeric values (in decimal).
1016 string splitMode = GetQuirkString("recordSplitMode");
1017 if (splitMode != null) {
1018 splitMode = splitMode.Trim();
1019 int j = splitMode.IndexOf(':');
1022 string w = splitMode.Substring(j + 1);
1023 foreach (string s in w.Split(',')) {
1024 m |= 1 << Int32.Parse(s.Trim());
1026 splitMode = splitMode.Substring(0, j).Trim();
1028 switch (splitMode.ToLowerInvariant()) {
1030 m |= OutputRecord.MODE_SPLIT_HALF;
1033 m |= OutputRecord.MODE_SPLIT_ZERO_BEFORE;
1036 m |= OutputRecord.MODE_SPLIT_ZERO_HALF;
1039 m |= OutputRecord.MODE_SPLIT_ONE_START;
1042 m |= OutputRecord.MODE_SPLIT_ONE_END;
1045 m |= OutputRecord.MODE_SPLIT_MULTI_ONE;
1048 throw new SSLException(string.Format(
1049 "Bad recordSplitMode name: '{0}'",
1052 outRec.SetSplitMode(m);
1056 * Triggers for extra empty records.
1058 outRec.SetThresholdZeroHandshake(
1059 GetQuirkInt("thresholdZeroHandshake"));
1060 outRec.SetThresholdZeroAppData(
1061 GetQuirkInt("thresholdZeroAppData"));
1065 bool ret = DoHandshake();
1070 * There could be some extra handshake
1071 * data lingering in the input buffer, in
1072 * which case we must process it right away.
1074 if (HasBufferedHandshake) {
1075 ProcessExtraHandshakeWrapper();
1085 void ProcessExtraHandshakeWrapper()
1088 while (HasBufferedHandshake) {
1089 ProcessExtraHandshake();
1098 * Set the state to the provided value.
1100 internal void SetState(int state)
1106 * Reset running hashes for handshake messages.
1108 internal void ResetHashes()
1117 * Inject a specific byte value in the hash functions for handshake
1120 void HashExtra(byte b)
1129 * Run a handshake. This function normally returns true; it returns
1130 * false only if the call was a renegotiation attempt AND it was
1131 * denied by the peer.
1133 internal abstract bool DoHandshake();
1136 * A non-empty handshake record has been received while we
1137 * were in post-handshake "application data" state. This
1138 * method should handle that message with the necessary
1139 * actions; if it returns false then the caller will fail
1140 * the connection with an exception.
1142 internal abstract void ProcessExtraHandshake();
1145 * Perform the preparatory steps for a renegotiation. For a client,
1146 * there are no such steps, so this call is a no-op. For a server,
1147 * an HelloRequest should be sent.
1149 internal abstract void PrepareRenegotiate();
1152 * Read the next handshake message. This also sets the state
1153 * to STATE_HANDSHAKE.
1155 internal byte[] ReadHandshakeMessage(out int msgType)
1157 return ReadHandshakeMessage(out msgType, false);
1161 * Read the next handshake message. This also sets the state
1162 * to STATE_HANDSHAKE. If tolerateNoReneg is true, then a
1163 * received no_renegotiation alert interrupts the reading, in
1164 * which case this function sets the state back to its previous
1165 * value and returns null.
1167 internal byte[] ReadHandshakeMessage(
1168 out int msgType, bool tolerateNoReneg)
1170 int oldState = state;
1171 state = STATE_HANDSHAKE;
1174 * In STATE_HANDSHAKE, an unexpected closure is never
1175 * tolerated, so ZRead() won't return -1.
1178 msgType = ZReadNoHashNoReneg();
1180 if (tolerateNoReneg) {
1186 if (msgType == SSL.HELLO_REQUEST && IsClient) {
1188 * Extra HelloRequest messages are ignored
1189 * (as long as they are properly empty), and
1190 * they don't contribute to the running hashes.
1192 if (ZReadNoHash() != 0
1193 || ZReadNoHash() != 0
1194 || ZReadNoHash() != 0)
1196 throw new SSLException(
1197 "Non-empty HelloRequest");
1201 HashExtra((byte)msgType);
1203 len = (len << 8) + ZRead();
1204 len = (len << 8) + ZRead();
1205 if (len > MaximumHandshakeMessageLength) {
1206 throw new SSLException(
1207 "Oversized handshake message: len="
1210 byte[] buf = new byte[len];
1213 off += ZRead(buf, off, len - off);
1220 * Read the next handshake message; fail (with an exception) if
1221 * it does not have the specified type. This also sets the state
1222 * to STATE_HANDSHAKE.
1224 internal byte[] ReadHandshakeMessageExpected(int msgType)
1227 byte[] msg = ReadHandshakeMessage(out rmt);
1228 if (rmt != msgType) {
1229 throw new SSLException(string.Format("Unexpected"
1230 + " handshake message {0} (expected: {1})",
1237 * Read an HelloRequest message. If, after reading an HelloRequest,
1238 * the record is not empty, then other HelloRequest messages are
1241 * This method shall be called only when a non-empty record of type
1242 * handshake is buffered. It switches the state to STATE_HANDSHAKE.
1244 internal void ReadHelloRequests()
1246 state = STATE_HANDSHAKE;
1247 while (inRec.BufferedLength > 0) {
1248 int x = ZReadNoHash();
1249 if (x != SSL.HELLO_REQUEST) {
1250 throw new SSLException(
1251 "Unexpected handshake message");
1253 if (ZReadNoHash() != 0x00
1254 || ZReadNoHash() != 0x00
1255 || ZReadNoHash() != 0x00)
1257 throw new SSLException(
1258 "Non-empty HelloRequest");
1264 * Test whether there is some buffered handshake data.
1266 internal bool HasBufferedHandshake {
1268 return inRec.RecordType == SSL.HANDSHAKE
1269 && inRec.BufferedLength > 0;
1273 static DateTime EPOCH =
1274 new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
1277 * Create a new client or server random.
1279 internal void MakeRandom(byte[] dst)
1281 uint utc = (uint)((DateTime.UtcNow - EPOCH).Ticks / 10000000);
1282 IO.Enc32be(utc, dst, 0);
1283 RNG.GetBytes(dst, 4, dst.Length - 4);
1287 * Create a MemoryStream with preloaded 4-byte handshake message
1290 internal MemoryStream StartHandshakeMessage(int type)
1292 MemoryStream ms = new MemoryStream();
1293 ms.WriteByte((byte)type);
1299 * Finalise a handshake message, and send it.
1301 internal void EndHandshakeMessage(MemoryStream ms)
1303 byte[] buf = ms.ToArray();
1304 IO.Enc24be(buf.Length - 4, buf, 1);
1305 outRec.RecordType = SSL.HANDSHAKE;
1314 * Get the PRF corresponding to the negotiated protocol version
1317 internal PRF GetPRF()
1319 if (Version <= SSL.TLS11) {
1322 return SSL.GetPRFForTLS12(CipherSuite);
1327 * Compute the master secret from the provided premaster secret.
1329 internal void ComputeMaster(byte[] pms)
1332 byte[] seed = new byte[64];
1333 Array.Copy(clientRandom, 0, seed, 0, 32);
1334 Array.Copy(serverRandom, 0, seed, 32, 32);
1335 prf.GetBytes(pms, PRF.LABEL_MASTER_SECRET, seed, masterSecret);
1339 * Set the master secret to the provided value. This is used when
1340 * resuming a session.
1342 internal void SetMasterSecret(byte[] rms)
1344 Array.Copy(rms, 0, masterSecret, 0, rms.Length);
1348 * Switch to new security parameters.
1349 * 'write' is true if we switch encryption for our sending channel,
1350 * false for our receiving channel.
1352 internal void SwitchEncryption(bool write)
1354 int macLen, encLen, ivLen;
1355 IBlockCipher block = null;
1356 IDigest hash = null;
1359 bool isCCM8 = false;
1360 switch (CipherSuite) {
1361 case SSL.RSA_WITH_3DES_EDE_CBC_SHA:
1362 case SSL.DH_DSS_WITH_3DES_EDE_CBC_SHA:
1363 case SSL.DH_RSA_WITH_3DES_EDE_CBC_SHA:
1364 case SSL.DHE_DSS_WITH_3DES_EDE_CBC_SHA:
1365 case SSL.DHE_RSA_WITH_3DES_EDE_CBC_SHA:
1366 case SSL.DH_anon_WITH_3DES_EDE_CBC_SHA:
1367 case SSL.ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
1368 case SSL.ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
1369 case SSL.ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
1370 case SSL.ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
1371 case SSL.ECDH_anon_WITH_3DES_EDE_CBC_SHA:
1379 case SSL.RSA_WITH_AES_128_CBC_SHA:
1380 case SSL.DH_DSS_WITH_AES_128_CBC_SHA:
1381 case SSL.DH_RSA_WITH_AES_128_CBC_SHA:
1382 case SSL.DHE_DSS_WITH_AES_128_CBC_SHA:
1383 case SSL.DHE_RSA_WITH_AES_128_CBC_SHA:
1384 case SSL.DH_anon_WITH_AES_128_CBC_SHA:
1385 case SSL.ECDH_ECDSA_WITH_AES_128_CBC_SHA:
1386 case SSL.ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
1387 case SSL.ECDH_RSA_WITH_AES_128_CBC_SHA:
1388 case SSL.ECDHE_RSA_WITH_AES_128_CBC_SHA:
1389 case SSL.ECDH_anon_WITH_AES_128_CBC_SHA:
1397 case SSL.RSA_WITH_AES_256_CBC_SHA:
1398 case SSL.DH_DSS_WITH_AES_256_CBC_SHA:
1399 case SSL.DH_RSA_WITH_AES_256_CBC_SHA:
1400 case SSL.DHE_DSS_WITH_AES_256_CBC_SHA:
1401 case SSL.DHE_RSA_WITH_AES_256_CBC_SHA:
1402 case SSL.DH_anon_WITH_AES_256_CBC_SHA:
1403 case SSL.ECDH_ECDSA_WITH_AES_256_CBC_SHA:
1404 case SSL.ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
1405 case SSL.ECDH_RSA_WITH_AES_256_CBC_SHA:
1406 case SSL.ECDHE_RSA_WITH_AES_256_CBC_SHA:
1407 case SSL.ECDH_anon_WITH_AES_256_CBC_SHA:
1415 case SSL.RSA_WITH_AES_128_CBC_SHA256:
1416 case SSL.DH_DSS_WITH_AES_128_CBC_SHA256:
1417 case SSL.DH_RSA_WITH_AES_128_CBC_SHA256:
1418 case SSL.DHE_DSS_WITH_AES_128_CBC_SHA256:
1419 case SSL.DHE_RSA_WITH_AES_128_CBC_SHA256:
1420 case SSL.DH_anon_WITH_AES_128_CBC_SHA256:
1421 case SSL.ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
1422 case SSL.ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
1423 case SSL.ECDHE_RSA_WITH_AES_128_CBC_SHA256:
1424 case SSL.ECDH_RSA_WITH_AES_128_CBC_SHA256:
1429 hash = new SHA256();
1432 case SSL.RSA_WITH_AES_256_CBC_SHA256:
1433 case SSL.DH_DSS_WITH_AES_256_CBC_SHA256:
1434 case SSL.DH_RSA_WITH_AES_256_CBC_SHA256:
1435 case SSL.DHE_DSS_WITH_AES_256_CBC_SHA256:
1436 case SSL.DHE_RSA_WITH_AES_256_CBC_SHA256:
1437 case SSL.DH_anon_WITH_AES_256_CBC_SHA256:
1442 hash = new SHA256();
1445 case SSL.ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
1446 case SSL.ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
1447 case SSL.ECDHE_RSA_WITH_AES_256_CBC_SHA384:
1448 case SSL.ECDH_RSA_WITH_AES_256_CBC_SHA384:
1453 hash = new SHA384();
1456 case SSL.RSA_WITH_AES_128_GCM_SHA256:
1457 case SSL.DHE_RSA_WITH_AES_128_GCM_SHA256:
1458 case SSL.DH_RSA_WITH_AES_128_GCM_SHA256:
1459 case SSL.DHE_DSS_WITH_AES_128_GCM_SHA256:
1460 case SSL.DH_DSS_WITH_AES_128_GCM_SHA256:
1461 case SSL.DH_anon_WITH_AES_128_GCM_SHA256:
1462 case SSL.ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
1463 case SSL.ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
1464 case SSL.ECDHE_RSA_WITH_AES_128_GCM_SHA256:
1465 case SSL.ECDH_RSA_WITH_AES_128_GCM_SHA256:
1472 case SSL.RSA_WITH_AES_256_GCM_SHA384:
1473 case SSL.DHE_RSA_WITH_AES_256_GCM_SHA384:
1474 case SSL.DH_RSA_WITH_AES_256_GCM_SHA384:
1475 case SSL.DHE_DSS_WITH_AES_256_GCM_SHA384:
1476 case SSL.DH_DSS_WITH_AES_256_GCM_SHA384:
1477 case SSL.DH_anon_WITH_AES_256_GCM_SHA384:
1478 case SSL.ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
1479 case SSL.ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
1480 case SSL.ECDHE_RSA_WITH_AES_256_GCM_SHA384:
1481 case SSL.ECDH_RSA_WITH_AES_256_GCM_SHA384:
1488 case SSL.RSA_WITH_AES_128_CCM:
1489 case SSL.ECDHE_ECDSA_WITH_AES_128_CCM:
1497 case SSL.RSA_WITH_AES_256_CCM:
1498 case SSL.ECDHE_ECDSA_WITH_AES_256_CCM:
1506 case SSL.RSA_WITH_AES_128_CCM_8:
1507 case SSL.ECDHE_ECDSA_WITH_AES_128_CCM_8:
1515 case SSL.RSA_WITH_AES_256_CCM_8:
1516 case SSL.ECDHE_ECDSA_WITH_AES_256_CCM_8:
1524 case SSL.ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
1525 case SSL.ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
1526 case SSL.DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
1530 pp = new Poly1305();
1531 pp.ChaCha = new ChaCha20();
1535 throw new SSLException("Unsupported cipher suite");
1539 * Normally we don't need IV when using CBC+HMAC with
1542 if (Version >= SSL.TLS11 && hash != null) {
1546 byte[] seed = new byte[64];
1547 Array.Copy(serverRandom, 0, seed, 0, 32);
1548 Array.Copy(clientRandom, 0, seed, 32, 32);
1549 byte[] kb = GetPRF().GetBytes(masterSecret,
1550 PRF.LABEL_KEY_EXPANSION, seed,
1551 (macLen + encLen + ivLen) << 1);
1554 * Test whether we need the client write keys, or the
1555 * server write keys.
1557 bool clientWrite = (IsClient == write);
1560 hm = new HMAC(hash);
1561 hm.SetKey(kb, clientWrite ? 0 : macLen, macLen);
1563 if (block != null) {
1564 block.SetKey(kb, (macLen << 1)
1565 + (clientWrite ? 0 : encLen), encLen);
1566 } else if (pp != null) {
1567 pp.ChaCha.SetKey(kb, (macLen << 1)
1568 + (clientWrite ? 0 : encLen), encLen);
1572 iv = new byte[ivLen];
1573 Array.Copy(kb, ((macLen + encLen) << 1)
1574 + (clientWrite ? 0 : ivLen), iv, 0, ivLen);
1579 * CBC+HMAC cipher suite.
1582 outRec.SetEncryption(
1583 new RecordEncryptCBC(block, hm, iv));
1585 inRec.SetDecryption(
1586 new RecordDecryptCBC(block, hm, iv));
1593 outRec.SetEncryption(
1594 new RecordEncryptCCM(block, iv, false));
1596 inRec.SetDecryption(
1597 new RecordDecryptCCM(block, iv, false));
1599 } else if (isCCM8) {
1601 * CCM cipher suite with truncated MAC value.
1604 outRec.SetEncryption(
1605 new RecordEncryptCCM(block, iv, true));
1607 inRec.SetDecryption(
1608 new RecordDecryptCCM(block, iv, true));
1610 } else if (block != null) {
1615 outRec.SetEncryption(
1616 new RecordEncryptGCM(block, iv));
1618 inRec.SetDecryption(
1619 new RecordDecryptGCM(block, iv));
1621 } else if (pp != null) {
1623 * ChaCha20 + Poly1305 cipher suite.
1626 outRec.SetEncryption(
1627 new RecordEncryptChaPol(pp, iv));
1629 inRec.SetDecryption(
1630 new RecordDecryptChaPol(pp, iv));
1633 throw new Exception("NYI");
1638 * Compute Finished message. The 'client' flag is set to true
1639 * for the Finished message sent by the client, false for the
1640 * Finished message sent by the server.
1642 internal byte[] ComputeFinished(bool client)
1646 if (Version <= SSL.TLS11) {
1647 seed = new byte[36];
1648 md5.DoPartial(seed, 0);
1649 sha1.DoPartial(seed, 16);
1651 } else if (SSL.IsSHA384(CipherSuite)) {
1652 seed = sha384.DoPartial();
1653 prf = new PRF(new SHA384());
1655 seed = sha256.DoPartial();
1656 prf = new PRF(new SHA256());
1658 byte[] label = client
1659 ? PRF.LABEL_CLIENT_FINISHED
1660 : PRF.LABEL_SERVER_FINISHED;
1661 return prf.GetBytes(masterSecret, label, seed, 12);
1665 * Send a ChangeCipherSpec, then a Finished message. This
1666 * call implies switching to the new encryption parameters for
1667 * the sending channel.
1669 internal void SendCCSAndFinished()
1671 outRec.RecordType = SSL.CHANGE_CIPHER_SPEC;
1673 outRec.RecordType = SSL.HANDSHAKE;
1674 SwitchEncryption(true);
1675 byte[] fin = ComputeFinished(IsClient);
1677 savedClientFinished = fin;
1679 savedServerFinished = fin;
1681 MemoryStream ms = StartHandshakeMessage(SSL.FINISHED);
1682 ms.Write(fin, 0, fin.Length);
1683 EndHandshakeMessage(ms);
1687 * Receive a ChangeCipherSpec, then a Finished message. This
1688 * call implies switching to the new encryption parameters for
1689 * the receiving channel.
1691 internal void ParseCCSAndFinished()
1693 if (inRec.BufferedLength > 0) {
1694 throw new SSLException(
1695 "Buffered data while expecting CCS");
1699 if (x != 0x01 || inRec.BufferedLength > 0) {
1700 throw new SSLException("Invalid CCS contents");
1702 SwitchEncryption(false);
1703 state = STATE_HANDSHAKE;
1704 byte[] fin = ComputeFinished(!IsClient);
1705 byte[] msg = ReadHandshakeMessageExpected(SSL.FINISHED);
1706 if (!Eq(fin, msg)) {
1707 throw new SSLException("Wrong Finished value");
1709 if (inRec.BufferedLength > 0) {
1710 throw new SSLException(
1711 "Extra handshake data after Finished message");
1714 savedServerFinished = fin;
1716 savedClientFinished = fin;
1721 * Switch to "application data" state just after the handshake.
1723 internal void SetAppData()
1725 SetState(STATE_APPDATA);
1726 outRec.RecordType = SSL.APPLICATION_DATA;
1730 * Send an alert of level "warning".
1732 internal void SendWarning(int type)
1734 int rt = outRec.RecordType;
1735 outRec.RecordType = SSL.ALERT;
1736 outRec.Write(SSL.WARNING);
1737 outRec.Write((byte)type);
1739 outRec.RecordType = rt;
1742 static bool Eq(byte[] a, byte[] b)
1745 if (n != b.Length) {
1749 for (int i = 0; i < n; i ++) {