DtlsClientProtocol.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections;
  5. using System.IO;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  8. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Tls
  9. {
  10. public class DtlsClientProtocol
  11. : DtlsProtocol
  12. {
  13. public DtlsClientProtocol(SecureRandom secureRandom)
  14. : base(secureRandom)
  15. {
  16. }
  17. public virtual DtlsTransport Connect(TlsClient client, DatagramTransport transport)
  18. {
  19. if (client == null)
  20. throw new ArgumentNullException("client");
  21. if (transport == null)
  22. throw new ArgumentNullException("transport");
  23. SecurityParameters securityParameters = new SecurityParameters();
  24. securityParameters.entity = ConnectionEnd.client;
  25. ClientHandshakeState state = new ClientHandshakeState();
  26. state.client = client;
  27. state.clientContext = new TlsClientContextImpl(mSecureRandom, securityParameters);
  28. securityParameters.clientRandom = TlsProtocol.CreateRandomBlock(client.ShouldUseGmtUnixTime(),
  29. state.clientContext.NonceRandomGenerator);
  30. client.Init(state.clientContext);
  31. DtlsRecordLayer recordLayer = new DtlsRecordLayer(transport, state.clientContext, client, ContentType.handshake);
  32. TlsSession sessionToResume = state.client.GetSessionToResume();
  33. if (sessionToResume != null && sessionToResume.IsResumable)
  34. {
  35. SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
  36. if (sessionParameters != null && sessionParameters.IsExtendedMasterSecret)
  37. {
  38. state.tlsSession = sessionToResume;
  39. state.sessionParameters = sessionParameters;
  40. }
  41. }
  42. try
  43. {
  44. return ClientHandshake(state, recordLayer);
  45. }
  46. catch (TlsFatalAlert fatalAlert)
  47. {
  48. AbortClientHandshake(state, recordLayer, fatalAlert.AlertDescription);
  49. throw fatalAlert;
  50. }
  51. catch (IOException e)
  52. {
  53. AbortClientHandshake(state, recordLayer, AlertDescription.internal_error);
  54. throw e;
  55. }
  56. catch (Exception e)
  57. {
  58. AbortClientHandshake(state, recordLayer, AlertDescription.internal_error);
  59. throw new TlsFatalAlert(AlertDescription.internal_error, e);
  60. }
  61. finally
  62. {
  63. securityParameters.Clear();
  64. }
  65. }
  66. internal virtual void AbortClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer, byte alertDescription)
  67. {
  68. recordLayer.Fail(alertDescription);
  69. InvalidateSession(state);
  70. }
  71. internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer)
  72. {
  73. SecurityParameters securityParameters = state.clientContext.SecurityParameters;
  74. DtlsReliableHandshake handshake = new DtlsReliableHandshake(state.clientContext, recordLayer);
  75. byte[] clientHelloBody = GenerateClientHello(state, state.client);
  76. recordLayer.SetWriteVersion(ProtocolVersion.DTLSv10);
  77. handshake.SendMessage(HandshakeType.client_hello, clientHelloBody);
  78. DtlsReliableHandshake.Message serverMessage = handshake.ReceiveMessage();
  79. while (serverMessage.Type == HandshakeType.hello_verify_request)
  80. {
  81. ProtocolVersion recordLayerVersion = recordLayer.ReadVersion;
  82. ProtocolVersion client_version = state.clientContext.ClientVersion;
  83. /*
  84. * RFC 6347 4.2.1 DTLS 1.2 server implementations SHOULD use DTLS version 1.0 regardless of
  85. * the version of TLS that is expected to be negotiated. DTLS 1.2 and 1.0 clients MUST use
  86. * the version solely to indicate packet formatting (which is the same in both DTLS 1.2 and
  87. * 1.0) and not as part of version negotiation.
  88. */
  89. if (!recordLayerVersion.IsEqualOrEarlierVersionOf(client_version))
  90. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  91. recordLayer.ReadVersion = null;
  92. byte[] cookie = ProcessHelloVerifyRequest(state, serverMessage.Body);
  93. byte[] patched = PatchClientHelloWithCookie(clientHelloBody, cookie);
  94. handshake.ResetHandshakeMessagesDigest();
  95. handshake.SendMessage(HandshakeType.client_hello, patched);
  96. serverMessage = handshake.ReceiveMessage();
  97. }
  98. if (serverMessage.Type == HandshakeType.server_hello)
  99. {
  100. ProtocolVersion recordLayerVersion = recordLayer.ReadVersion;
  101. ReportServerVersion(state, recordLayerVersion);
  102. recordLayer.SetWriteVersion(recordLayerVersion);
  103. ProcessServerHello(state, serverMessage.Body);
  104. }
  105. else
  106. {
  107. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  108. }
  109. handshake.NotifyHelloComplete();
  110. ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);
  111. if (state.resumedSession)
  112. {
  113. securityParameters.masterSecret = Arrays.Clone(state.sessionParameters.MasterSecret);
  114. recordLayer.InitPendingEpoch(state.client.GetCipher());
  115. // NOTE: Calculated exclusive of the actual Finished message from the server
  116. byte[] resExpectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished,
  117. TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
  118. ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), resExpectedServerVerifyData);
  119. // NOTE: Calculated exclusive of the Finished message itself
  120. byte[] resClientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished,
  121. TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
  122. handshake.SendMessage(HandshakeType.finished, resClientVerifyData);
  123. handshake.Finish();
  124. state.clientContext.SetResumableSession(state.tlsSession);
  125. state.client.NotifyHandshakeComplete();
  126. return new DtlsTransport(recordLayer);
  127. }
  128. InvalidateSession(state);
  129. if (state.selectedSessionID.Length > 0)
  130. {
  131. state.tlsSession = new TlsSessionImpl(state.selectedSessionID, null);
  132. }
  133. serverMessage = handshake.ReceiveMessage();
  134. if (serverMessage.Type == HandshakeType.supplemental_data)
  135. {
  136. ProcessServerSupplementalData(state, serverMessage.Body);
  137. serverMessage = handshake.ReceiveMessage();
  138. }
  139. else
  140. {
  141. state.client.ProcessServerSupplementalData(null);
  142. }
  143. state.keyExchange = state.client.GetKeyExchange();
  144. state.keyExchange.Init(state.clientContext);
  145. Certificate serverCertificate = null;
  146. if (serverMessage.Type == HandshakeType.certificate)
  147. {
  148. serverCertificate = ProcessServerCertificate(state, serverMessage.Body);
  149. serverMessage = handshake.ReceiveMessage();
  150. }
  151. else
  152. {
  153. // Okay, Certificate is optional
  154. state.keyExchange.SkipServerCredentials();
  155. }
  156. // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
  157. if (serverCertificate == null || serverCertificate.IsEmpty)
  158. {
  159. state.allowCertificateStatus = false;
  160. }
  161. if (serverMessage.Type == HandshakeType.certificate_status)
  162. {
  163. ProcessCertificateStatus(state, serverMessage.Body);
  164. serverMessage = handshake.ReceiveMessage();
  165. }
  166. else
  167. {
  168. // Okay, CertificateStatus is optional
  169. }
  170. if (serverMessage.Type == HandshakeType.server_key_exchange)
  171. {
  172. ProcessServerKeyExchange(state, serverMessage.Body);
  173. serverMessage = handshake.ReceiveMessage();
  174. }
  175. else
  176. {
  177. // Okay, ServerKeyExchange is optional
  178. state.keyExchange.SkipServerKeyExchange();
  179. }
  180. if (serverMessage.Type == HandshakeType.certificate_request)
  181. {
  182. ProcessCertificateRequest(state, serverMessage.Body);
  183. /*
  184. * TODO Give the client a chance to immediately select the CertificateVerify hash
  185. * algorithm here to avoid tracking the other hash algorithms unnecessarily?
  186. */
  187. TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash,
  188. state.certificateRequest.SupportedSignatureAlgorithms);
  189. serverMessage = handshake.ReceiveMessage();
  190. }
  191. else
  192. {
  193. // Okay, CertificateRequest is optional
  194. }
  195. if (serverMessage.Type == HandshakeType.server_hello_done)
  196. {
  197. if (serverMessage.Body.Length != 0)
  198. {
  199. throw new TlsFatalAlert(AlertDescription.decode_error);
  200. }
  201. }
  202. else
  203. {
  204. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  205. }
  206. handshake.HandshakeHash.SealHashAlgorithms();
  207. IList clientSupplementalData = state.client.GetClientSupplementalData();
  208. if (clientSupplementalData != null)
  209. {
  210. byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData);
  211. handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
  212. }
  213. if (state.certificateRequest != null)
  214. {
  215. state.clientCredentials = state.authentication.GetClientCredentials(state.clientContext, state.certificateRequest);
  216. /*
  217. * RFC 5246 If no suitable certificate is available, the client MUST send a certificate
  218. * message containing no certificates.
  219. *
  220. * NOTE: In previous RFCs, this was SHOULD instead of MUST.
  221. */
  222. Certificate clientCertificate = null;
  223. if (state.clientCredentials != null)
  224. {
  225. clientCertificate = state.clientCredentials.Certificate;
  226. }
  227. if (clientCertificate == null)
  228. {
  229. clientCertificate = Certificate.EmptyChain;
  230. }
  231. byte[] certificateBody = GenerateCertificate(clientCertificate);
  232. handshake.SendMessage(HandshakeType.certificate, certificateBody);
  233. }
  234. if (state.clientCredentials != null)
  235. {
  236. state.keyExchange.ProcessClientCredentials(state.clientCredentials);
  237. }
  238. else
  239. {
  240. state.keyExchange.SkipClientCredentials();
  241. }
  242. byte[] clientKeyExchangeBody = GenerateClientKeyExchange(state);
  243. handshake.SendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody);
  244. TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish();
  245. securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.clientContext, prepareFinishHash, null);
  246. TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange);
  247. recordLayer.InitPendingEpoch(state.client.GetCipher());
  248. if (state.clientCredentials != null && state.clientCredentials is TlsSignerCredentials)
  249. {
  250. TlsSignerCredentials signerCredentials = (TlsSignerCredentials)state.clientCredentials;
  251. /*
  252. * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
  253. */
  254. SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
  255. state.clientContext, signerCredentials);
  256. byte[] hash;
  257. if (signatureAndHashAlgorithm == null)
  258. {
  259. hash = securityParameters.SessionHash;
  260. }
  261. else
  262. {
  263. hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
  264. }
  265. byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
  266. DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
  267. byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify);
  268. handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody);
  269. }
  270. // NOTE: Calculated exclusive of the Finished message itself
  271. byte[] clientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished,
  272. TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
  273. handshake.SendMessage(HandshakeType.finished, clientVerifyData);
  274. if (state.expectSessionTicket)
  275. {
  276. serverMessage = handshake.ReceiveMessage();
  277. if (serverMessage.Type == HandshakeType.session_ticket)
  278. {
  279. ProcessNewSessionTicket(state, serverMessage.Body);
  280. }
  281. else
  282. {
  283. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  284. }
  285. }
  286. // NOTE: Calculated exclusive of the actual Finished message from the server
  287. byte[] expectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished,
  288. TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
  289. ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedServerVerifyData);
  290. handshake.Finish();
  291. if (state.tlsSession != null)
  292. {
  293. state.sessionParameters = new SessionParameters.Builder()
  294. .SetCipherSuite(securityParameters.CipherSuite)
  295. .SetCompressionAlgorithm(securityParameters.CompressionAlgorithm)
  296. .SetExtendedMasterSecret(securityParameters.IsExtendedMasterSecret)
  297. .SetMasterSecret(securityParameters.MasterSecret)
  298. .SetPeerCertificate(serverCertificate)
  299. .SetPskIdentity(securityParameters.PskIdentity)
  300. .SetSrpIdentity(securityParameters.SrpIdentity)
  301. // TODO Consider filtering extensions that aren't relevant to resumed sessions
  302. .SetServerExtensions(state.serverExtensions)
  303. .Build();
  304. state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters);
  305. state.clientContext.SetResumableSession(state.tlsSession);
  306. }
  307. state.client.NotifyHandshakeComplete();
  308. return new DtlsTransport(recordLayer);
  309. }
  310. protected virtual byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
  311. {
  312. MemoryStream buf = new MemoryStream();
  313. certificateVerify.Encode(buf);
  314. return buf.ToArray();
  315. }
  316. protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client)
  317. {
  318. ProtocolVersion client_version = client.ClientVersion;
  319. if (!client_version.IsDtls)
  320. throw new TlsFatalAlert(AlertDescription.internal_error);
  321. TlsClientContextImpl context = state.clientContext;
  322. context.SetClientVersion(client_version);
  323. SecurityParameters securityParameters = context.SecurityParameters;
  324. // Session ID
  325. byte[] session_id = TlsUtilities.EmptyBytes;
  326. if (state.tlsSession != null)
  327. {
  328. session_id = state.tlsSession.SessionID;
  329. if (session_id == null || session_id.Length > 32)
  330. {
  331. session_id = TlsUtilities.EmptyBytes;
  332. }
  333. }
  334. bool fallback = client.IsFallback;
  335. state.offeredCipherSuites = client.GetCipherSuites();
  336. if (session_id.Length > 0 && state.sessionParameters != null)
  337. {
  338. if (!state.sessionParameters.IsExtendedMasterSecret
  339. || !Arrays.Contains(state.offeredCipherSuites, state.sessionParameters.CipherSuite)
  340. || CompressionMethod.cls_null != state.sessionParameters.CompressionAlgorithm)
  341. {
  342. session_id = TlsUtilities.EmptyBytes;
  343. }
  344. }
  345. state.clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(client.GetClientExtensions());
  346. TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.clientExtensions);
  347. MemoryStream buf = new MemoryStream();
  348. TlsUtilities.WriteVersion(client_version, buf);
  349. buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length);
  350. TlsUtilities.WriteOpaque8(session_id, buf);
  351. // Cookie
  352. TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);
  353. // Cipher Suites (and SCSV)
  354. {
  355. /*
  356. * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
  357. * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
  358. * ClientHello. Including both is NOT RECOMMENDED.
  359. */
  360. byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
  361. bool noRenegExt = (null == renegExtData);
  362. bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
  363. if (noRenegExt && noRenegSCSV)
  364. {
  365. // TODO Consider whether to default to a client extension instead
  366. state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
  367. }
  368. /*
  369. * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value
  370. * than the latest (highest-valued) version supported by the client, it SHOULD include
  371. * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The
  372. * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
  373. * to negotiate.)
  374. */
  375. if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
  376. {
  377. state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
  378. }
  379. TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf);
  380. }
  381. TlsUtilities.WriteUint8ArrayWithUint8Length(new byte[]{ CompressionMethod.cls_null }, buf);
  382. TlsProtocol.WriteExtensions(buf, state.clientExtensions);
  383. return buf.ToArray();
  384. }
  385. protected virtual byte[] GenerateClientKeyExchange(ClientHandshakeState state)
  386. {
  387. MemoryStream buf = new MemoryStream();
  388. state.keyExchange.GenerateClientKeyExchange(buf);
  389. return buf.ToArray();
  390. }
  391. protected virtual void InvalidateSession(ClientHandshakeState state)
  392. {
  393. if (state.sessionParameters != null)
  394. {
  395. state.sessionParameters.Clear();
  396. state.sessionParameters = null;
  397. }
  398. if (state.tlsSession != null)
  399. {
  400. state.tlsSession.Invalidate();
  401. state.tlsSession = null;
  402. }
  403. }
  404. protected virtual void ProcessCertificateRequest(ClientHandshakeState state, byte[] body)
  405. {
  406. if (state.authentication == null)
  407. {
  408. /*
  409. * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server to
  410. * request client identification.
  411. */
  412. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  413. }
  414. MemoryStream buf = new MemoryStream(body, false);
  415. state.certificateRequest = CertificateRequest.Parse(state.clientContext, buf);
  416. TlsProtocol.AssertEmpty(buf);
  417. state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
  418. }
  419. protected virtual void ProcessCertificateStatus(ClientHandshakeState state, byte[] body)
  420. {
  421. if (!state.allowCertificateStatus)
  422. {
  423. /*
  424. * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
  425. * server MUST have included an extension of type "status_request" with empty
  426. * "extension_data" in the extended server hello..
  427. */
  428. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  429. }
  430. MemoryStream buf = new MemoryStream(body, false);
  431. state.certificateStatus = CertificateStatus.Parse(buf);
  432. TlsProtocol.AssertEmpty(buf);
  433. // TODO[RFC 3546] Figure out how to provide this to the client/authentication.
  434. }
  435. protected virtual byte[] ProcessHelloVerifyRequest(ClientHandshakeState state, byte[] body)
  436. {
  437. MemoryStream buf = new MemoryStream(body, false);
  438. ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
  439. byte[] cookie = TlsUtilities.ReadOpaque8(buf);
  440. TlsProtocol.AssertEmpty(buf);
  441. // TODO Seems this behaviour is not yet in line with OpenSSL for DTLS 1.2
  442. // reportServerVersion(state, server_version);
  443. if (!server_version.IsEqualOrEarlierVersionOf(state.clientContext.ClientVersion))
  444. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  445. /*
  446. * RFC 6347 This specification increases the cookie size limit to 255 bytes for greater
  447. * future flexibility. The limit remains 32 for previous versions of DTLS.
  448. */
  449. if (!ProtocolVersion.DTLSv12.IsEqualOrEarlierVersionOf(server_version) && cookie.Length > 32)
  450. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  451. return cookie;
  452. }
  453. protected virtual void ProcessNewSessionTicket(ClientHandshakeState state, byte[] body)
  454. {
  455. MemoryStream buf = new MemoryStream(body, false);
  456. NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);
  457. TlsProtocol.AssertEmpty(buf);
  458. state.client.NotifyNewSessionTicket(newSessionTicket);
  459. }
  460. protected virtual Certificate ProcessServerCertificate(ClientHandshakeState state, byte[] body)
  461. {
  462. MemoryStream buf = new MemoryStream(body, false);
  463. Certificate serverCertificate = Certificate.Parse(buf);
  464. TlsProtocol.AssertEmpty(buf);
  465. state.keyExchange.ProcessServerCertificate(serverCertificate);
  466. state.authentication = state.client.GetAuthentication();
  467. state.authentication.NotifyServerCertificate(serverCertificate);
  468. return serverCertificate;
  469. }
  470. protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] body)
  471. {
  472. SecurityParameters securityParameters = state.clientContext.SecurityParameters;
  473. MemoryStream buf = new MemoryStream(body, false);
  474. {
  475. ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
  476. ReportServerVersion(state, server_version);
  477. }
  478. securityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
  479. state.selectedSessionID = TlsUtilities.ReadOpaque8(buf);
  480. if (state.selectedSessionID.Length > 32)
  481. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  482. state.client.NotifySessionID(state.selectedSessionID);
  483. state.resumedSession = state.selectedSessionID.Length > 0 && state.tlsSession != null
  484. && Arrays.AreEqual(state.selectedSessionID, state.tlsSession.SessionID);
  485. int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
  486. if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite)
  487. || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
  488. || CipherSuite.IsScsv(selectedCipherSuite)
  489. || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.clientContext.ServerVersion))
  490. {
  491. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  492. }
  493. ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.illegal_parameter);
  494. state.client.NotifySelectedCipherSuite(selectedCipherSuite);
  495. byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
  496. if (CompressionMethod.cls_null != selectedCompressionMethod)
  497. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  498. state.client.NotifySelectedCompressionMethod(selectedCompressionMethod);
  499. /*
  500. * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
  501. * hello message when the client has requested extended functionality via the extended
  502. * client hello message specified in Section 2.1. ... Note that the extended server hello
  503. * message is only sent in response to an extended client hello message. This prevents the
  504. * possibility that the extended server hello message could "break" existing TLS 1.0
  505. * clients.
  506. */
  507. /*
  508. * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
  509. * extensions appearing in the client hello, and send a server hello containing no
  510. * extensions.
  511. */
  512. // Integer -> byte[]
  513. state.serverExtensions = TlsProtocol.ReadExtensions(buf);
  514. /*
  515. * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended
  516. * master secret [..]. (and see 5.2, 5.3)
  517. */
  518. securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.serverExtensions);
  519. if (!securityParameters.IsExtendedMasterSecret
  520. && (state.resumedSession || state.client.RequiresExtendedMasterSecret()))
  521. {
  522. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  523. }
  524. /*
  525. * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
  526. * extended client hello message. However, see RFC 5746 exception below. We always include
  527. * the SCSV, so an Extended Server Hello is always allowed.
  528. */
  529. if (state.serverExtensions != null)
  530. {
  531. foreach (int extType in state.serverExtensions.Keys)
  532. {
  533. /*
  534. * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a
  535. * ClientHello containing only the SCSV is an explicit exception to the prohibition
  536. * in RFC 5246, Section 7.4.1.4, on the server sending unsolicited extensions and is
  537. * only allowed because the client is signaling its willingness to receive the
  538. * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
  539. */
  540. if (extType == ExtensionType.renegotiation_info)
  541. continue;
  542. /*
  543. * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
  544. * same extension type appeared in the corresponding ClientHello. If a client
  545. * receives an extension type in ServerHello that it did not request in the
  546. * associated ClientHello, it MUST abort the handshake with an unsupported_extension
  547. * fatal alert.
  548. */
  549. if (null == TlsUtilities.GetExtensionData(state.clientExtensions, extType))
  550. throw new TlsFatalAlert(AlertDescription.unsupported_extension);
  551. /*
  552. * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
  553. * extensions appearing in the client hello, and send a server hello containing no
  554. * extensions[.]
  555. */
  556. if (state.resumedSession)
  557. {
  558. // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats
  559. // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats
  560. // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats
  561. //throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  562. }
  563. }
  564. }
  565. /*
  566. * RFC 5746 3.4. Client Behavior: Initial Handshake
  567. */
  568. {
  569. /*
  570. * When a ServerHello is received, the client MUST check if it includes the
  571. * "renegotiation_info" extension:
  572. */
  573. byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
  574. if (renegExtData != null)
  575. {
  576. /*
  577. * If the extension is present, set the secure_renegotiation flag to TRUE. The
  578. * client MUST then verify that the length of the "renegotiated_connection"
  579. * field is zero, and if it is not, MUST abort the handshake (by sending a fatal
  580. * handshake_failure alert).
  581. */
  582. state.secure_renegotiation = true;
  583. if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
  584. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  585. }
  586. }
  587. // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming
  588. state.client.NotifySecureRenegotiation(state.secure_renegotiation);
  589. IDictionary sessionClientExtensions = state.clientExtensions, sessionServerExtensions = state.serverExtensions;
  590. if (state.resumedSession)
  591. {
  592. if (selectedCipherSuite != state.sessionParameters.CipherSuite
  593. || selectedCompressionMethod != state.sessionParameters.CompressionAlgorithm)
  594. {
  595. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  596. }
  597. sessionClientExtensions = null;
  598. sessionServerExtensions = state.sessionParameters.ReadServerExtensions();
  599. }
  600. securityParameters.cipherSuite = selectedCipherSuite;
  601. securityParameters.compressionAlgorithm = selectedCompressionMethod;
  602. if (sessionServerExtensions != null && sessionServerExtensions.Count > 0)
  603. {
  604. {
  605. /*
  606. * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
  607. * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
  608. * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
  609. * client.
  610. */
  611. bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
  612. if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(securityParameters.CipherSuite))
  613. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  614. securityParameters.encryptThenMac = serverSentEncryptThenMAC;
  615. }
  616. securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
  617. sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
  618. securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);
  619. /*
  620. * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be
  621. * sent in a session resumption handshake.
  622. */
  623. state.allowCertificateStatus = !state.resumedSession
  624. && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
  625. AlertDescription.illegal_parameter);
  626. state.expectSessionTicket = !state.resumedSession
  627. && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
  628. AlertDescription.illegal_parameter);
  629. }
  630. if (sessionClientExtensions != null)
  631. {
  632. state.client.ProcessServerExtensions(sessionServerExtensions);
  633. }
  634. securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.clientContext,
  635. securityParameters.CipherSuite);
  636. /*
  637. * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
  638. * a verify_data_length equal to 12. This includes all existing cipher suites.
  639. */
  640. securityParameters.verifyDataLength = 12;
  641. }
  642. protected virtual void ProcessServerKeyExchange(ClientHandshakeState state, byte[] body)
  643. {
  644. MemoryStream buf = new MemoryStream(body, false);
  645. state.keyExchange.ProcessServerKeyExchange(buf);
  646. TlsProtocol.AssertEmpty(buf);
  647. }
  648. protected virtual void ProcessServerSupplementalData(ClientHandshakeState state, byte[] body)
  649. {
  650. MemoryStream buf = new MemoryStream(body, false);
  651. IList serverSupplementalData = TlsProtocol.ReadSupplementalDataMessage(buf);
  652. state.client.ProcessServerSupplementalData(serverSupplementalData);
  653. }
  654. protected virtual void ReportServerVersion(ClientHandshakeState state, ProtocolVersion server_version)
  655. {
  656. TlsClientContextImpl clientContext = state.clientContext;
  657. ProtocolVersion currentServerVersion = clientContext.ServerVersion;
  658. if (null == currentServerVersion)
  659. {
  660. clientContext.SetServerVersion(server_version);
  661. state.client.NotifyServerVersion(server_version);
  662. }
  663. else if (!currentServerVersion.Equals(server_version))
  664. {
  665. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  666. }
  667. }
  668. protected static byte[] PatchClientHelloWithCookie(byte[] clientHelloBody, byte[] cookie)
  669. {
  670. int sessionIDPos = 34;
  671. int sessionIDLength = TlsUtilities.ReadUint8(clientHelloBody, sessionIDPos);
  672. int cookieLengthPos = sessionIDPos + 1 + sessionIDLength;
  673. int cookiePos = cookieLengthPos + 1;
  674. byte[] patched = new byte[clientHelloBody.Length + cookie.Length];
  675. Array.Copy(clientHelloBody, 0, patched, 0, cookieLengthPos);
  676. TlsUtilities.CheckUint8(cookie.Length);
  677. TlsUtilities.WriteUint8((byte)cookie.Length, patched, cookieLengthPos);
  678. Array.Copy(cookie, 0, patched, cookiePos, cookie.Length);
  679. Array.Copy(clientHelloBody, cookiePos, patched, cookiePos + cookie.Length, clientHelloBody.Length - cookiePos);
  680. return patched;
  681. }
  682. protected internal class ClientHandshakeState
  683. {
  684. internal TlsClient client = null;
  685. internal TlsClientContextImpl clientContext = null;
  686. internal TlsSession tlsSession = null;
  687. internal SessionParameters sessionParameters = null;
  688. internal SessionParameters.Builder sessionParametersBuilder = null;
  689. internal int[] offeredCipherSuites = null;
  690. internal IDictionary clientExtensions = null;
  691. internal IDictionary serverExtensions = null;
  692. internal byte[] selectedSessionID = null;
  693. internal bool resumedSession = false;
  694. internal bool secure_renegotiation = false;
  695. internal bool allowCertificateStatus = false;
  696. internal bool expectSessionTicket = false;
  697. internal TlsKeyExchange keyExchange = null;
  698. internal TlsAuthentication authentication = null;
  699. internal CertificateStatus certificateStatus = null;
  700. internal CertificateRequest certificateRequest = null;
  701. internal TlsCredentials clientCredentials = null;
  702. }
  703. }
  704. }
  705. #pragma warning restore
  706. #endif