Context.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. // Transport Security Layer (TLS)
  2. // Copyright (c) 2003-2004 Carlos Guzman Alvarez
  3. // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining
  6. // a copy of this software and associated documentation files (the
  7. // "Software"), to deal in the Software without restriction, including
  8. // without limitation the rights to use, copy, modify, merge, publish,
  9. // distribute, sublicense, and/or sell copies of the Software, and to
  10. // permit persons to whom the Software is furnished to do so, subject to
  11. // the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  20. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  21. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  22. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. //
  24. using System;
  25. using System.Text;
  26. using System.Collections;
  27. using System.Security.Cryptography;
  28. using System.Security.Cryptography.X509Certificates;
  29. using Mono.Security.Cryptography;
  30. using Mono.Security.Protocol.Tls.Handshake;
  31. namespace Mono.Security.Protocol.Tls
  32. {
  33. internal abstract class Context
  34. {
  35. #region Internal Constants
  36. internal const short MAX_FRAGMENT_SIZE = 16384; // 2^14
  37. internal const short TLS1_PROTOCOL_CODE = (0x03 << 8) | 0x01;
  38. internal const short SSL3_PROTOCOL_CODE = (0x03 << 8) | 0x00;
  39. internal const long UNIX_BASE_TICKS = 621355968000000000;
  40. #endregion
  41. #region Fields
  42. // Protocol version
  43. private SecurityProtocolType securityProtocol;
  44. // Sesison ID
  45. private byte[] sessionId;
  46. // Compression method
  47. private SecurityCompressionType compressionMethod;
  48. // Information sent and request by the server in the Handshake protocol
  49. private TlsServerSettings serverSettings;
  50. // Client configuration
  51. private TlsClientSettings clientSettings;
  52. // Cipher suite information
  53. private SecurityParameters current;
  54. private SecurityParameters negotiating;
  55. private SecurityParameters read;
  56. private SecurityParameters write;
  57. private CipherSuiteCollection supportedCiphers;
  58. // Last handshake message received
  59. private HandshakeType lastHandshakeMsg;
  60. // Handshake negotiation state
  61. private HandshakeState handshakeState;
  62. // Misc
  63. private bool abbreviatedHandshake;
  64. private bool connectionEnd;
  65. private bool protocolNegotiated;
  66. // Sequence numbers
  67. private ulong writeSequenceNumber;
  68. private ulong readSequenceNumber;
  69. // Random data
  70. private byte[] clientRandom;
  71. private byte[] serverRandom;
  72. private byte[] randomCS;
  73. private byte[] randomSC;
  74. // Key information
  75. private byte[] masterSecret;
  76. private byte[] clientWriteKey;
  77. private byte[] serverWriteKey;
  78. private byte[] clientWriteIV;
  79. private byte[] serverWriteIV;
  80. // Handshake hashes
  81. private TlsStream handshakeMessages;
  82. // Secure Random generator
  83. private RandomNumberGenerator random;
  84. // Record protocol
  85. private RecordProtocol recordProtocol;
  86. #endregion
  87. #region Properties
  88. public bool AbbreviatedHandshake
  89. {
  90. get { return abbreviatedHandshake; }
  91. set { abbreviatedHandshake = value; }
  92. }
  93. public bool ProtocolNegotiated
  94. {
  95. get { return this.protocolNegotiated; }
  96. set { this.protocolNegotiated = value; }
  97. }
  98. public SecurityProtocolType SecurityProtocol
  99. {
  100. get
  101. {
  102. if ((this.securityProtocol & SecurityProtocolType.Tls) == SecurityProtocolType.Tls ||
  103. (this.securityProtocol & SecurityProtocolType.Default) == SecurityProtocolType.Default)
  104. {
  105. return SecurityProtocolType.Tls;
  106. }
  107. else
  108. {
  109. if ((this.securityProtocol & SecurityProtocolType.Ssl3) == SecurityProtocolType.Ssl3)
  110. {
  111. return SecurityProtocolType.Ssl3;
  112. }
  113. }
  114. throw new NotSupportedException("Unsupported security protocol type");
  115. }
  116. set { this.securityProtocol = value; }
  117. }
  118. public SecurityProtocolType SecurityProtocolFlags
  119. {
  120. get { return this.securityProtocol; }
  121. }
  122. public short Protocol
  123. {
  124. get
  125. {
  126. switch (this.SecurityProtocol)
  127. {
  128. case SecurityProtocolType.Tls:
  129. case SecurityProtocolType.Default:
  130. return Context.TLS1_PROTOCOL_CODE;
  131. case SecurityProtocolType.Ssl3:
  132. return Context.SSL3_PROTOCOL_CODE;
  133. case SecurityProtocolType.Ssl2:
  134. default:
  135. throw new NotSupportedException("Unsupported security protocol type");
  136. }
  137. }
  138. }
  139. public byte[] SessionId
  140. {
  141. get { return this.sessionId; }
  142. set { this.sessionId = value; }
  143. }
  144. public SecurityCompressionType CompressionMethod
  145. {
  146. get { return this.compressionMethod; }
  147. set { this.compressionMethod = value; }
  148. }
  149. public TlsServerSettings ServerSettings
  150. {
  151. get { return this.serverSettings; }
  152. }
  153. public TlsClientSettings ClientSettings
  154. {
  155. get { return this.clientSettings; }
  156. }
  157. public HandshakeType LastHandshakeMsg
  158. {
  159. get { return this.lastHandshakeMsg; }
  160. set { this.lastHandshakeMsg = value; }
  161. }
  162. public HandshakeState HandshakeState
  163. {
  164. get { return this.handshakeState; }
  165. set { this.handshakeState = value; }
  166. }
  167. public bool ConnectionEnd
  168. {
  169. get { return this.connectionEnd; }
  170. set { this.connectionEnd = value; }
  171. }
  172. public CipherSuiteCollection SupportedCiphers
  173. {
  174. get { return supportedCiphers; }
  175. set { supportedCiphers = value; }
  176. }
  177. public TlsStream HandshakeMessages
  178. {
  179. get { return this.handshakeMessages; }
  180. }
  181. public ulong WriteSequenceNumber
  182. {
  183. get { return this.writeSequenceNumber; }
  184. set { this.writeSequenceNumber = value; }
  185. }
  186. public ulong ReadSequenceNumber
  187. {
  188. get { return this.readSequenceNumber; }
  189. set { this.readSequenceNumber = value; }
  190. }
  191. public byte[] ClientRandom
  192. {
  193. get { return this.clientRandom; }
  194. set { this.clientRandom = value; }
  195. }
  196. public byte[] ServerRandom
  197. {
  198. get { return this.serverRandom; }
  199. set { this.serverRandom = value; }
  200. }
  201. public byte[] RandomCS
  202. {
  203. get { return this.randomCS; }
  204. set { this.randomCS = value; }
  205. }
  206. public byte[] RandomSC
  207. {
  208. get { return this.randomSC; }
  209. set { this.randomSC = value; }
  210. }
  211. public byte[] MasterSecret
  212. {
  213. get { return this.masterSecret; }
  214. set { this.masterSecret = value; }
  215. }
  216. public byte[] ClientWriteKey
  217. {
  218. get { return this.clientWriteKey; }
  219. set { this.clientWriteKey = value; }
  220. }
  221. public byte[] ServerWriteKey
  222. {
  223. get { return this.serverWriteKey; }
  224. set { this.serverWriteKey = value; }
  225. }
  226. public byte[] ClientWriteIV
  227. {
  228. get { return this.clientWriteIV; }
  229. set { this.clientWriteIV = value; }
  230. }
  231. public byte[] ServerWriteIV
  232. {
  233. get { return this.serverWriteIV; }
  234. set { this.serverWriteIV = value; }
  235. }
  236. public RecordProtocol RecordProtocol
  237. {
  238. get { return this.recordProtocol; }
  239. set { this.recordProtocol = value; }
  240. }
  241. #endregion
  242. #region Constructors
  243. public Context(SecurityProtocolType securityProtocolType)
  244. {
  245. this.SecurityProtocol = securityProtocolType;
  246. this.compressionMethod = SecurityCompressionType.None;
  247. this.serverSettings = new TlsServerSettings();
  248. this.clientSettings = new TlsClientSettings();
  249. this.handshakeMessages = new TlsStream();
  250. this.sessionId = null;
  251. this.handshakeState = HandshakeState.None;
  252. this.random = RandomNumberGenerator.Create();
  253. }
  254. #endregion
  255. #region Methods
  256. public int GetUnixTime()
  257. {
  258. DateTime now = DateTime.UtcNow;
  259. return (int)((now.Ticks - UNIX_BASE_TICKS) / TimeSpan.TicksPerSecond);
  260. }
  261. public byte[] GetSecureRandomBytes(int count)
  262. {
  263. byte[] secureBytes = new byte[count];
  264. this.random.GetNonZeroBytes(secureBytes);
  265. return secureBytes;
  266. }
  267. public virtual void Clear()
  268. {
  269. this.compressionMethod = SecurityCompressionType.None;
  270. this.serverSettings = new TlsServerSettings();
  271. this.clientSettings = new TlsClientSettings();
  272. this.handshakeMessages = new TlsStream();
  273. this.sessionId = null;
  274. this.handshakeState = HandshakeState.None;
  275. this.ClearKeyInfo();
  276. }
  277. public virtual void ClearKeyInfo()
  278. {
  279. // Clear Master Secret
  280. if (masterSecret != null) {
  281. Array.Clear (masterSecret, 0, masterSecret.Length);
  282. masterSecret = null;
  283. }
  284. // Clear client and server random
  285. if (clientRandom != null) {
  286. Array.Clear (clientRandom, 0, clientRandom.Length);
  287. clientRandom = null;
  288. }
  289. if (serverRandom != null) {
  290. Array.Clear (serverRandom, 0, serverRandom.Length);
  291. serverRandom = null;
  292. }
  293. if (randomCS != null) {
  294. Array.Clear (randomCS, 0, randomCS.Length);
  295. randomCS = null;
  296. }
  297. if (randomSC != null) {
  298. Array.Clear (randomSC, 0, randomSC.Length);
  299. randomSC = null;
  300. }
  301. // Clear client keys
  302. if (clientWriteKey != null) {
  303. Array.Clear (clientWriteKey, 0, clientWriteKey.Length);
  304. clientWriteKey = null;
  305. }
  306. if (clientWriteIV != null) {
  307. Array.Clear (clientWriteIV, 0, clientWriteIV.Length);
  308. clientWriteIV = null;
  309. }
  310. // Clear server keys
  311. if (serverWriteKey != null) {
  312. Array.Clear (serverWriteKey, 0, serverWriteKey.Length);
  313. serverWriteKey = null;
  314. }
  315. if (serverWriteIV != null) {
  316. Array.Clear (serverWriteIV, 0, serverWriteIV.Length);
  317. serverWriteIV = null;
  318. }
  319. // Reset handshake messages
  320. this.handshakeMessages.Reset();
  321. // Clear MAC keys if protocol is different than Ssl3
  322. // SSLv3 needs them inside Mono.Security.Protocol.Tls.SslCipherSuite.Compute[Client|Server]RecordMAC
  323. if (this.securityProtocol != SecurityProtocolType.Ssl3)
  324. {
  325. // this.clientWriteMAC = null;
  326. // this.serverWriteMAC = null;
  327. }
  328. }
  329. public SecurityProtocolType DecodeProtocolCode(short code)
  330. {
  331. switch (code)
  332. {
  333. case Context.TLS1_PROTOCOL_CODE:
  334. return SecurityProtocolType.Tls;
  335. case Context.SSL3_PROTOCOL_CODE:
  336. return SecurityProtocolType.Ssl3;
  337. default:
  338. throw new NotSupportedException("Unsupported security protocol type");
  339. }
  340. }
  341. public void ChangeProtocol(short protocol)
  342. {
  343. SecurityProtocolType protocolType = this.DecodeProtocolCode(protocol);
  344. if ((protocolType & this.SecurityProtocolFlags) == protocolType ||
  345. (this.SecurityProtocolFlags & SecurityProtocolType.Default) == SecurityProtocolType.Default)
  346. {
  347. this.SecurityProtocol = protocolType;
  348. this.SupportedCiphers.Clear();
  349. this.SupportedCiphers = null;
  350. this.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers(protocolType);
  351. }
  352. else
  353. {
  354. throw new TlsException(AlertDescription.ProtocolVersion, "Incorrect protocol version received from server");
  355. }
  356. }
  357. public SecurityParameters Current
  358. {
  359. get
  360. {
  361. if (current == null)
  362. current = new SecurityParameters ();
  363. if (current.Cipher != null)
  364. current.Cipher.Context = this;
  365. return current;
  366. }
  367. }
  368. public SecurityParameters Negotiating
  369. {
  370. get
  371. {
  372. if (negotiating == null)
  373. negotiating = new SecurityParameters ();
  374. if (negotiating.Cipher != null)
  375. negotiating.Cipher.Context = this;
  376. return negotiating;
  377. }
  378. }
  379. public SecurityParameters Read
  380. {
  381. get { return read; }
  382. }
  383. public SecurityParameters Write
  384. {
  385. get { return write; }
  386. }
  387. public void StartSwitchingSecurityParameters (bool client)
  388. {
  389. if (client) {
  390. // everything we write from now on is encrypted
  391. write = negotiating;
  392. // but we still read with the older cipher until we
  393. // receive the ChangeCipherSpec message
  394. read = current;
  395. } else {
  396. // everything we read from now on is encrypted
  397. read = negotiating;
  398. // but we still write with the older cipher until we
  399. // receive the ChangeCipherSpec message
  400. write = current;
  401. }
  402. current = negotiating;
  403. }
  404. public void EndSwitchingSecurityParameters (bool client)
  405. {
  406. SecurityParameters temp;
  407. if (client) {
  408. temp = read;
  409. // we now read with the new, negotiated, security parameters
  410. read = current;
  411. } else {
  412. temp = write;
  413. // we now write with the new, negotiated, security parameters
  414. write = current;
  415. }
  416. // so we clear the old one (last reference)
  417. if (temp != null)
  418. temp.Clear ();
  419. negotiating = temp;
  420. // and are now ready for a future renegotiation
  421. }
  422. #endregion
  423. }
  424. }