DtlsClientProtocol.cs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  8. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Tls
  9. {
  10. public class DtlsClientProtocol
  11. : DtlsProtocol
  12. {
  13. public DtlsClientProtocol()
  14. : base()
  15. {
  16. }
  17. /// <exception cref="IOException"/>
  18. public virtual DtlsTransport Connect(TlsClient client, DatagramTransport transport)
  19. {
  20. if (client == null)
  21. throw new ArgumentNullException("client");
  22. if (transport == null)
  23. throw new ArgumentNullException("transport");
  24. ClientHandshakeState state = new ClientHandshakeState();
  25. state.client = client;
  26. state.clientContext = new TlsClientContextImpl(client.Crypto);
  27. client.Init(state.clientContext);
  28. state.clientContext.HandshakeBeginning(client);
  29. SecurityParameters securityParameters = state.clientContext.SecurityParameters;
  30. securityParameters.m_extendedPadding = client.ShouldUseExtendedPadding();
  31. TlsSession sessionToResume = state.client.GetSessionToResume();
  32. if (sessionToResume != null && sessionToResume.IsResumable)
  33. {
  34. SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
  35. /*
  36. * NOTE: If we ever enable session resumption without extended_master_secret, then
  37. * renegotiation MUST be disabled (see RFC 7627 5.4).
  38. */
  39. if (sessionParameters != null
  40. && (sessionParameters.IsExtendedMasterSecret
  41. || (!state.client.RequiresExtendedMasterSecret() && state.client.AllowLegacyResumption())))
  42. {
  43. TlsSecret masterSecret = sessionParameters.MasterSecret;
  44. lock (masterSecret)
  45. {
  46. if (masterSecret.IsAlive())
  47. {
  48. state.tlsSession = sessionToResume;
  49. state.sessionParameters = sessionParameters;
  50. state.sessionMasterSecret = state.clientContext.Crypto.AdoptSecret(masterSecret);
  51. }
  52. }
  53. }
  54. }
  55. DtlsRecordLayer recordLayer = new DtlsRecordLayer(state.clientContext, state.client, transport);
  56. client.NotifyCloseHandle(recordLayer);
  57. try
  58. {
  59. return ClientHandshake(state, recordLayer);
  60. }
  61. catch (TlsFatalAlert fatalAlert)
  62. {
  63. AbortClientHandshake(state, recordLayer, fatalAlert.AlertDescription);
  64. throw fatalAlert;
  65. }
  66. catch (IOException e)
  67. {
  68. AbortClientHandshake(state, recordLayer, AlertDescription.internal_error);
  69. throw e;
  70. }
  71. catch (Exception e)
  72. {
  73. AbortClientHandshake(state, recordLayer, AlertDescription.internal_error);
  74. throw new TlsFatalAlert(AlertDescription.internal_error, e);
  75. }
  76. finally
  77. {
  78. securityParameters.Clear();
  79. }
  80. }
  81. internal virtual void AbortClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer,
  82. short alertDescription)
  83. {
  84. recordLayer.Fail(alertDescription);
  85. InvalidateSession(state);
  86. }
  87. /// <exception cref="IOException"/>
  88. internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer)
  89. {
  90. SecurityParameters securityParameters = state.clientContext.SecurityParameters;
  91. DtlsReliableHandshake handshake = new DtlsReliableHandshake(state.clientContext, recordLayer,
  92. state.client.GetHandshakeTimeoutMillis(), null);
  93. byte[] clientHelloBody = GenerateClientHello(state);
  94. recordLayer.SetWriteVersion(ProtocolVersion.DTLSv10);
  95. handshake.SendMessage(HandshakeType.client_hello, clientHelloBody);
  96. DtlsReliableHandshake.Message serverMessage = handshake.ReceiveMessage();
  97. // TODO Consider stricter HelloVerifyRequest protocol
  98. //if (serverMessage.Type == HandshakeType.hello_verify_request)
  99. while (serverMessage.Type == HandshakeType.hello_verify_request)
  100. {
  101. byte[] cookie = ProcessHelloVerifyRequest(state, serverMessage.Body);
  102. byte[] patched = PatchClientHelloWithCookie(clientHelloBody, cookie);
  103. handshake.ResetAfterHelloVerifyRequestClient();
  104. handshake.SendMessage(HandshakeType.client_hello, patched);
  105. serverMessage = handshake.ReceiveMessage();
  106. }
  107. if (serverMessage.Type == HandshakeType.server_hello)
  108. {
  109. ProtocolVersion recordLayerVersion = recordLayer.ReadVersion;
  110. ReportServerVersion(state, recordLayerVersion);
  111. recordLayer.SetWriteVersion(recordLayerVersion);
  112. ProcessServerHello(state, serverMessage.Body);
  113. }
  114. else
  115. {
  116. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  117. }
  118. handshake.HandshakeHash.NotifyPrfDetermined();
  119. ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.MaxFragmentLength);
  120. if (state.resumedSession)
  121. {
  122. securityParameters.m_masterSecret = state.sessionMasterSecret;
  123. recordLayer.InitPendingEpoch(TlsUtilities.InitCipher(state.clientContext));
  124. // NOTE: Calculated exclusive of the actual Finished message from the server
  125. securityParameters.m_peerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext,
  126. handshake.HandshakeHash, true);
  127. ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished),
  128. securityParameters.PeerVerifyData);
  129. // NOTE: Calculated exclusive of the Finished message itself
  130. securityParameters.m_localVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext,
  131. handshake.HandshakeHash, false);
  132. handshake.SendMessage(HandshakeType.finished, securityParameters.LocalVerifyData);
  133. handshake.Finish();
  134. if (securityParameters.IsExtendedMasterSecret)
  135. {
  136. securityParameters.m_tlsUnique = securityParameters.PeerVerifyData;
  137. }
  138. securityParameters.m_localCertificate = state.sessionParameters.LocalCertificate;
  139. securityParameters.m_peerCertificate = state.sessionParameters.PeerCertificate;
  140. securityParameters.m_pskIdentity = state.sessionParameters.PskIdentity;
  141. securityParameters.m_srpIdentity = state.sessionParameters.SrpIdentity;
  142. state.clientContext.HandshakeComplete(state.client, state.tlsSession);
  143. recordLayer.InitHeartbeat(state.heartbeat,
  144. HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy);
  145. return new DtlsTransport(recordLayer, state.client.IgnoreCorruptDtlsRecords);
  146. }
  147. InvalidateSession(state);
  148. state.tlsSession = TlsUtilities.ImportSession(securityParameters.SessionID, null);
  149. serverMessage = handshake.ReceiveMessage();
  150. if (serverMessage.Type == HandshakeType.supplemental_data)
  151. {
  152. ProcessServerSupplementalData(state, serverMessage.Body);
  153. serverMessage = handshake.ReceiveMessage();
  154. }
  155. else
  156. {
  157. state.client.ProcessServerSupplementalData(null);
  158. }
  159. state.keyExchange = TlsUtilities.InitKeyExchangeClient(state.clientContext, state.client);
  160. if (serverMessage.Type == HandshakeType.certificate)
  161. {
  162. ProcessServerCertificate(state, serverMessage.Body);
  163. serverMessage = handshake.ReceiveMessage();
  164. }
  165. else
  166. {
  167. // Okay, Certificate is optional
  168. state.authentication = null;
  169. }
  170. if (serverMessage.Type == HandshakeType.certificate_status)
  171. {
  172. if (securityParameters.StatusRequestVersion < 1)
  173. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  174. ProcessCertificateStatus(state, serverMessage.Body);
  175. serverMessage = handshake.ReceiveMessage();
  176. }
  177. else
  178. {
  179. // Okay, CertificateStatus is optional
  180. }
  181. TlsUtilities.ProcessServerCertificate(state.clientContext, state.certificateStatus, state.keyExchange,
  182. state.authentication, state.clientExtensions, state.serverExtensions);
  183. if (serverMessage.Type == HandshakeType.server_key_exchange)
  184. {
  185. ProcessServerKeyExchange(state, serverMessage.Body);
  186. serverMessage = handshake.ReceiveMessage();
  187. }
  188. else
  189. {
  190. // Okay, ServerKeyExchange is optional
  191. state.keyExchange.SkipServerKeyExchange();
  192. }
  193. if (serverMessage.Type == HandshakeType.certificate_request)
  194. {
  195. ProcessCertificateRequest(state, serverMessage.Body);
  196. TlsUtilities.EstablishServerSigAlgs(securityParameters, state.certificateRequest);
  197. serverMessage = handshake.ReceiveMessage();
  198. }
  199. else
  200. {
  201. // Okay, CertificateRequest is optional
  202. }
  203. if (serverMessage.Type == HandshakeType.server_hello_done)
  204. {
  205. if (serverMessage.Body.Length != 0)
  206. {
  207. throw new TlsFatalAlert(AlertDescription.decode_error);
  208. }
  209. }
  210. else
  211. {
  212. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  213. }
  214. TlsCredentials clientAuthCredentials = null;
  215. TlsCredentialedSigner clientAuthSigner = null;
  216. Certificate clientAuthCertificate = null;
  217. SignatureAndHashAlgorithm clientAuthAlgorithm = null;
  218. TlsStreamSigner clientAuthStreamSigner = null;
  219. if (state.certificateRequest != null)
  220. {
  221. clientAuthCredentials = TlsUtilities.EstablishClientCredentials(state.authentication,
  222. state.certificateRequest);
  223. if (clientAuthCredentials != null)
  224. {
  225. clientAuthCertificate = clientAuthCredentials.Certificate;
  226. if (clientAuthCredentials is TlsCredentialedSigner)
  227. {
  228. clientAuthSigner = (TlsCredentialedSigner)clientAuthCredentials;
  229. clientAuthAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
  230. securityParameters.NegotiatedVersion, clientAuthSigner);
  231. clientAuthStreamSigner = clientAuthSigner.GetStreamSigner();
  232. if (ProtocolVersion.DTLSv12.Equals(securityParameters.NegotiatedVersion))
  233. {
  234. TlsUtilities.VerifySupportedSignatureAlgorithm(securityParameters.ServerSigAlgs,
  235. clientAuthAlgorithm, AlertDescription.internal_error);
  236. if (clientAuthStreamSigner == null)
  237. {
  238. TlsUtilities.TrackHashAlgorithmClient(handshake.HandshakeHash, clientAuthAlgorithm);
  239. }
  240. }
  241. if (clientAuthStreamSigner != null)
  242. {
  243. handshake.HandshakeHash.ForceBuffering();
  244. }
  245. }
  246. }
  247. }
  248. handshake.HandshakeHash.SealHashAlgorithms();
  249. if (clientAuthCredentials == null)
  250. {
  251. state.keyExchange.SkipClientCredentials();
  252. }
  253. else
  254. {
  255. state.keyExchange.ProcessClientCredentials(clientAuthCredentials);
  256. }
  257. var clientSupplementalData = state.client.GetClientSupplementalData();
  258. if (clientSupplementalData != null)
  259. {
  260. byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData);
  261. handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
  262. }
  263. if (null != state.certificateRequest)
  264. {
  265. SendCertificateMessage(state.clientContext, handshake, clientAuthCertificate, null);
  266. }
  267. byte[] clientKeyExchangeBody = GenerateClientKeyExchange(state);
  268. handshake.SendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody);
  269. securityParameters.m_sessionHash = TlsUtilities.GetCurrentPrfHash(handshake.HandshakeHash);
  270. TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange);
  271. recordLayer.InitPendingEpoch(TlsUtilities.InitCipher(state.clientContext));
  272. if (clientAuthSigner != null)
  273. {
  274. DigitallySigned certificateVerify = TlsUtilities.GenerateCertificateVerifyClient(state.clientContext,
  275. clientAuthSigner, clientAuthAlgorithm, clientAuthStreamSigner, handshake.HandshakeHash);
  276. byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify);
  277. handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody);
  278. }
  279. handshake.PrepareToFinish();
  280. securityParameters.m_localVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext,
  281. handshake.HandshakeHash, false);
  282. handshake.SendMessage(HandshakeType.finished, securityParameters.LocalVerifyData);
  283. if (state.expectSessionTicket)
  284. {
  285. serverMessage = handshake.ReceiveMessage();
  286. if (serverMessage.Type == HandshakeType.new_session_ticket)
  287. {
  288. /*
  289. * RFC 5077 3.4. If the client receives a session ticket from the server, then it
  290. * discards any Session ID that was sent in the ServerHello.
  291. */
  292. securityParameters.m_sessionID = TlsUtilities.EmptyBytes;
  293. InvalidateSession(state);
  294. state.tlsSession = TlsUtilities.ImportSession(securityParameters.SessionID, null);
  295. ProcessNewSessionTicket(state, serverMessage.Body);
  296. }
  297. else
  298. {
  299. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  300. }
  301. }
  302. // NOTE: Calculated exclusive of the actual Finished message from the server
  303. securityParameters.m_peerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext,
  304. handshake.HandshakeHash, true);
  305. ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), securityParameters.PeerVerifyData);
  306. handshake.Finish();
  307. state.sessionMasterSecret = securityParameters.MasterSecret;
  308. state.sessionParameters = new SessionParameters.Builder()
  309. .SetCipherSuite(securityParameters.CipherSuite)
  310. .SetExtendedMasterSecret(securityParameters.IsExtendedMasterSecret)
  311. .SetLocalCertificate(securityParameters.LocalCertificate)
  312. .SetMasterSecret(state.clientContext.Crypto.AdoptSecret(state.sessionMasterSecret))
  313. .SetNegotiatedVersion(securityParameters.NegotiatedVersion)
  314. .SetPeerCertificate(securityParameters.PeerCertificate)
  315. .SetPskIdentity(securityParameters.PskIdentity)
  316. .SetSrpIdentity(securityParameters.SrpIdentity)
  317. // TODO Consider filtering extensions that aren't relevant to resumed sessions
  318. .SetServerExtensions(state.serverExtensions)
  319. .Build();
  320. state.tlsSession = TlsUtilities.ImportSession(securityParameters.SessionID, state.sessionParameters);
  321. securityParameters.m_tlsUnique = securityParameters.LocalVerifyData;
  322. state.clientContext.HandshakeComplete(state.client, state.tlsSession);
  323. recordLayer.InitHeartbeat(state.heartbeat, HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy);
  324. return new DtlsTransport(recordLayer, state.client.IgnoreCorruptDtlsRecords);
  325. }
  326. /// <exception cref="IOException"/>
  327. protected virtual byte[] GenerateCertificateVerify(ClientHandshakeState state,
  328. DigitallySigned certificateVerify)
  329. {
  330. MemoryStream buf = new MemoryStream();
  331. certificateVerify.Encode(buf);
  332. return buf.ToArray();
  333. }
  334. /// <exception cref="IOException"/>
  335. protected virtual byte[] GenerateClientHello(ClientHandshakeState state)
  336. {
  337. TlsClientContextImpl context = state.clientContext;
  338. SecurityParameters securityParameters = context.SecurityParameters;
  339. context.SetClientSupportedVersions(state.client.GetProtocolVersions());
  340. ProtocolVersion client_version = ProtocolVersion.GetLatestDtls(context.ClientSupportedVersions);
  341. if (!ProtocolVersion.IsSupportedDtlsVersionClient(client_version))
  342. throw new TlsFatalAlert(AlertDescription.internal_error);
  343. context.SetClientVersion(client_version);
  344. {
  345. bool useGmtUnixTime = ProtocolVersion.DTLSv12.IsEqualOrLaterVersionOf(client_version)
  346. && state.client.ShouldUseGmtUnixTime();
  347. securityParameters.m_clientRandom = TlsProtocol.CreateRandomBlock(useGmtUnixTime, state.clientContext);
  348. }
  349. byte[] session_id = TlsUtilities.GetSessionID(state.tlsSession);
  350. bool fallback = state.client.IsFallback();
  351. state.offeredCipherSuites = state.client.GetCipherSuites();
  352. if (session_id.Length > 0 && state.sessionParameters != null)
  353. {
  354. if (!Arrays.Contains(state.offeredCipherSuites, state.sessionParameters.CipherSuite))
  355. {
  356. session_id = TlsUtilities.EmptyBytes;
  357. }
  358. }
  359. state.clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(
  360. state.client.GetClientExtensions());
  361. ProtocolVersion legacy_version = client_version;
  362. if (client_version.IsLaterVersionOf(ProtocolVersion.DTLSv12))
  363. {
  364. legacy_version = ProtocolVersion.DTLSv12;
  365. TlsExtensionsUtilities.AddSupportedVersionsExtensionClient(state.clientExtensions,
  366. context.ClientSupportedVersions);
  367. }
  368. context.SetRsaPreMasterSecretVersion(legacy_version);
  369. securityParameters.m_clientServerNames = TlsExtensionsUtilities.GetServerNameExtensionClient(
  370. state.clientExtensions);
  371. if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(client_version))
  372. {
  373. TlsUtilities.EstablishClientSigAlgs(securityParameters, state.clientExtensions);
  374. }
  375. securityParameters.m_clientSupportedGroups = TlsExtensionsUtilities.GetSupportedGroupsExtension(
  376. state.clientExtensions);
  377. state.clientAgreements = TlsUtilities.AddKeyShareToClientHello(state.clientContext, state.client,
  378. state.clientExtensions);
  379. if (TlsUtilities.IsExtendedMasterSecretOptionalDtls(context.ClientSupportedVersions)
  380. && state.client.ShouldUseExtendedMasterSecret())
  381. {
  382. TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.clientExtensions);
  383. }
  384. else if (!TlsUtilities.IsTlsV13(client_version)
  385. && state.client.RequiresExtendedMasterSecret())
  386. {
  387. throw new TlsFatalAlert(AlertDescription.internal_error);
  388. }
  389. // Cipher Suites (and SCSV)
  390. {
  391. /*
  392. * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
  393. * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
  394. * ClientHello. Including both is NOT RECOMMENDED.
  395. */
  396. bool noRenegExt = (null == TlsUtilities.GetExtensionData(state.clientExtensions,
  397. ExtensionType.renegotiation_info));
  398. bool noRenegScsv = !Arrays.Contains(state.offeredCipherSuites,
  399. CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
  400. if (noRenegExt && noRenegScsv)
  401. {
  402. state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites,
  403. CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
  404. }
  405. }
  406. /* (Fallback SCSV)
  407. * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value
  408. * than the latest (highest-valued) version supported by the client, it SHOULD include
  409. * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The
  410. * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
  411. * to negotiate.)
  412. */
  413. if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
  414. {
  415. state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
  416. }
  417. // Heartbeats
  418. {
  419. state.heartbeat = state.client.GetHeartbeat();
  420. state.heartbeatPolicy = state.client.GetHeartbeatPolicy();
  421. if (null != state.heartbeat || HeartbeatMode.peer_allowed_to_send == state.heartbeatPolicy)
  422. {
  423. TlsExtensionsUtilities.AddHeartbeatExtension(state.clientExtensions,
  424. new HeartbeatExtension(state.heartbeatPolicy));
  425. }
  426. }
  427. ClientHello clientHello = new ClientHello(legacy_version, securityParameters.ClientRandom, session_id,
  428. TlsUtilities.EmptyBytes, state.offeredCipherSuites, state.clientExtensions, 0);
  429. MemoryStream buf = new MemoryStream();
  430. clientHello.Encode(state.clientContext, buf);
  431. return buf.ToArray();
  432. }
  433. /// <exception cref="IOException"/>
  434. protected virtual byte[] GenerateClientKeyExchange(ClientHandshakeState state)
  435. {
  436. MemoryStream buf = new MemoryStream();
  437. state.keyExchange.GenerateClientKeyExchange(buf);
  438. return buf.ToArray();
  439. }
  440. protected virtual void InvalidateSession(ClientHandshakeState state)
  441. {
  442. if (state.sessionMasterSecret != null)
  443. {
  444. state.sessionMasterSecret.Destroy();
  445. state.sessionMasterSecret = null;
  446. }
  447. if (state.sessionParameters != null)
  448. {
  449. state.sessionParameters.Clear();
  450. state.sessionParameters = null;
  451. }
  452. if (state.tlsSession != null)
  453. {
  454. state.tlsSession.Invalidate();
  455. state.tlsSession = null;
  456. }
  457. }
  458. /// <exception cref="IOException"/>
  459. protected virtual void ProcessCertificateRequest(ClientHandshakeState state, byte[] body)
  460. {
  461. if (null == state.authentication)
  462. {
  463. /*
  464. * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server to
  465. * request client identification.
  466. */
  467. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  468. }
  469. MemoryStream buf = new MemoryStream(body, false);
  470. CertificateRequest certificateRequest = CertificateRequest.Parse(state.clientContext, buf);
  471. TlsProtocol.AssertEmpty(buf);
  472. state.certificateRequest = TlsUtilities.ValidateCertificateRequest(certificateRequest, state.keyExchange);
  473. state.clientContext.SecurityParameters.m_clientCertificateType =
  474. TlsExtensionsUtilities.GetClientCertificateTypeExtensionServer(state.serverExtensions,
  475. CertificateType.X509);
  476. }
  477. /// <exception cref="IOException"/>
  478. protected virtual void ProcessCertificateStatus(ClientHandshakeState state, byte[] body)
  479. {
  480. MemoryStream buf = new MemoryStream(body, false);
  481. // TODO[tls13] Ensure this cannot happen for (D)TLS1.3+
  482. state.certificateStatus = CertificateStatus.Parse(state.clientContext, buf);
  483. TlsProtocol.AssertEmpty(buf);
  484. }
  485. /// <exception cref="IOException"/>
  486. protected virtual byte[] ProcessHelloVerifyRequest(ClientHandshakeState state, byte[] body)
  487. {
  488. MemoryStream buf = new MemoryStream(body, false);
  489. ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
  490. /*
  491. * RFC 6347 This specification increases the cookie size limit to 255 bytes for greater
  492. * future flexibility. The limit remains 32 for previous versions of DTLS.
  493. */
  494. int maxCookieLength = ProtocolVersion.DTLSv12.IsEqualOrEarlierVersionOf(server_version) ? 255 : 32;
  495. byte[] cookie = TlsUtilities.ReadOpaque8(buf, 0, maxCookieLength);
  496. TlsProtocol.AssertEmpty(buf);
  497. // TODO Seems this behaviour is not yet in line with OpenSSL for DTLS 1.2
  498. //ReportServerVersion(state, server_version);
  499. if (!server_version.IsEqualOrEarlierVersionOf(state.clientContext.ClientVersion))
  500. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  501. return cookie;
  502. }
  503. /// <exception cref="IOException"/>
  504. protected virtual void ProcessNewSessionTicket(ClientHandshakeState state, byte[] body)
  505. {
  506. MemoryStream buf = new MemoryStream(body, false);
  507. NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);
  508. TlsProtocol.AssertEmpty(buf);
  509. state.client.NotifyNewSessionTicket(newSessionTicket);
  510. }
  511. /// <exception cref="IOException"/>
  512. protected virtual void ProcessServerCertificate(ClientHandshakeState state, byte[] body)
  513. {
  514. state.authentication = TlsUtilities.ReceiveServerCertificate(state.clientContext, state.client,
  515. new MemoryStream(body, false), state.serverExtensions);
  516. }
  517. /// <exception cref="IOException"/>
  518. protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] body)
  519. {
  520. MemoryStream buf = new MemoryStream(body, false);
  521. ServerHello serverHello = ServerHello.Parse(buf);
  522. ProtocolVersion server_version = serverHello.Version;
  523. state.serverExtensions = serverHello.Extensions;
  524. SecurityParameters securityParameters = state.clientContext.SecurityParameters;
  525. // TODO[dtls13] Check supported_version extension for negotiated version
  526. ReportServerVersion(state, server_version);
  527. securityParameters.m_serverRandom = serverHello.Random;
  528. if (!state.clientContext.ClientVersion.Equals(server_version))
  529. {
  530. TlsUtilities.CheckDowngradeMarker(server_version, securityParameters.ServerRandom);
  531. }
  532. {
  533. byte[] selectedSessionID = serverHello.SessionID;
  534. securityParameters.m_sessionID = selectedSessionID;
  535. state.client.NotifySessionID(selectedSessionID);
  536. state.resumedSession = selectedSessionID.Length > 0 && state.tlsSession != null
  537. && Arrays.AreEqual(selectedSessionID, state.tlsSession.SessionID);
  538. }
  539. /*
  540. * Find out which CipherSuite the server has chosen and check that it was one of the offered
  541. * ones, and is a valid selection for the negotiated version.
  542. */
  543. {
  544. int cipherSuite = ValidateSelectedCipherSuite(serverHello.CipherSuite,
  545. AlertDescription.illegal_parameter);
  546. if (!TlsUtilities.IsValidCipherSuiteSelection(state.offeredCipherSuites, cipherSuite) ||
  547. !TlsUtilities.IsValidVersionForCipherSuite(cipherSuite, securityParameters.NegotiatedVersion))
  548. {
  549. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  550. }
  551. TlsUtilities.NegotiatedCipherSuite(securityParameters, cipherSuite);
  552. state.client.NotifySelectedCipherSuite(cipherSuite);
  553. }
  554. /*
  555. * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
  556. * hello message when the client has requested extended functionality via the extended
  557. * client hello message specified in Section 2.1. ... Note that the extended server hello
  558. * message is only sent in response to an extended client hello message. This prevents the
  559. * possibility that the extended server hello message could "break" existing TLS 1.0
  560. * clients.
  561. */
  562. /*
  563. * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
  564. * extensions appearing in the client hello, and send a server hello containing no
  565. * extensions.
  566. */
  567. /*
  568. * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended
  569. * master secret [..]. (and see 5.2, 5.3)
  570. *
  571. * RFC 8446 Appendix D. Because TLS 1.3 always hashes in the transcript up to the server
  572. * Finished, implementations which support both TLS 1.3 and earlier versions SHOULD indicate
  573. * the use of the Extended Master Secret extension in their APIs whenever TLS 1.3 is used.
  574. */
  575. if (TlsUtilities.IsTlsV13(server_version))
  576. {
  577. securityParameters.m_extendedMasterSecret = true;
  578. }
  579. else
  580. {
  581. bool acceptedExtendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(
  582. state.serverExtensions);
  583. if (acceptedExtendedMasterSecret)
  584. {
  585. if (!state.resumedSession && !state.client.ShouldUseExtendedMasterSecret())
  586. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  587. }
  588. else
  589. {
  590. if (state.client.RequiresExtendedMasterSecret()
  591. || (state.resumedSession && !state.client.AllowLegacyResumption()))
  592. {
  593. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  594. }
  595. }
  596. securityParameters.m_extendedMasterSecret = acceptedExtendedMasterSecret;
  597. }
  598. /*
  599. *
  600. * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
  601. * extended client hello message. However, see RFC 5746 exception below. We always include
  602. * the SCSV, so an Extended Server Hello is always allowed.
  603. */
  604. if (state.serverExtensions != null)
  605. {
  606. foreach (int extType in state.serverExtensions.Keys)
  607. {
  608. /*
  609. * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a
  610. * ClientHello containing only the SCSV is an explicit exception to the prohibition
  611. * in RFC 5246, Section 7.4.1.4, on the server sending unsolicited extensions and is
  612. * only allowed because the client is signaling its willingness to receive the
  613. * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
  614. */
  615. if (extType == ExtensionType.renegotiation_info)
  616. continue;
  617. /*
  618. * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
  619. * same extension type appeared in the corresponding ClientHello. If a client
  620. * receives an extension type in ServerHello that it did not request in the
  621. * associated ClientHello, it MUST abort the handshake with an unsupported_extension
  622. * fatal alert.
  623. */
  624. if (null == TlsUtilities.GetExtensionData(state.clientExtensions, extType))
  625. throw new TlsFatalAlert(AlertDescription.unsupported_extension);
  626. /*
  627. * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
  628. * extensions appearing in the client hello, and send a server hello containing no
  629. * extensions[.]
  630. */
  631. if (state.resumedSession)
  632. {
  633. // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats
  634. // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats
  635. // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats
  636. //throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  637. }
  638. }
  639. }
  640. /*
  641. * RFC 5746 3.4. Client Behavior: Initial Handshake
  642. */
  643. {
  644. /*
  645. * When a ServerHello is received, the client MUST check if it includes the
  646. * "renegotiation_info" extension:
  647. */
  648. byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions,
  649. ExtensionType.renegotiation_info);
  650. if (renegExtData != null)
  651. {
  652. /*
  653. * If the extension is present, set the secure_renegotiation flag to TRUE. The
  654. * client MUST then verify that the length of the "renegotiated_connection"
  655. * field is zero, and if it is not, MUST abort the handshake (by sending a fatal
  656. * handshake_failure alert).
  657. */
  658. securityParameters.m_secureRenegotiation = true;
  659. if (!Arrays.ConstantTimeAreEqual(renegExtData,
  660. TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
  661. {
  662. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  663. }
  664. }
  665. }
  666. // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming
  667. state.client.NotifySecureRenegotiation(securityParameters.IsSecureRenegotiation);
  668. /*
  669. * RFC 7301 3.1. When session resumption or session tickets [...] are used, the previous
  670. * contents of this extension are irrelevant, and only the values in the new handshake
  671. * messages are considered.
  672. */
  673. securityParameters.m_applicationProtocol = TlsExtensionsUtilities.GetAlpnExtensionServer(
  674. state.serverExtensions);
  675. securityParameters.m_applicationProtocolSet = true;
  676. // Heartbeats
  677. {
  678. HeartbeatExtension heartbeatExtension = TlsExtensionsUtilities.GetHeartbeatExtension(
  679. state.serverExtensions);
  680. if (null == heartbeatExtension)
  681. {
  682. state.heartbeat = null;
  683. state.heartbeatPolicy = HeartbeatMode.peer_not_allowed_to_send;
  684. }
  685. else if (HeartbeatMode.peer_allowed_to_send != heartbeatExtension.Mode)
  686. {
  687. state.heartbeat = null;
  688. }
  689. }
  690. var sessionClientExtensions = state.clientExtensions;
  691. var sessionServerExtensions = state.serverExtensions;
  692. if (state.resumedSession)
  693. {
  694. if (securityParameters.CipherSuite != state.sessionParameters.CipherSuite
  695. || !server_version.Equals(state.sessionParameters.NegotiatedVersion))
  696. {
  697. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  698. }
  699. sessionClientExtensions = null;
  700. sessionServerExtensions = state.sessionParameters.ReadServerExtensions();
  701. }
  702. if (sessionServerExtensions != null && sessionServerExtensions.Count > 0)
  703. {
  704. {
  705. /*
  706. * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
  707. * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
  708. * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
  709. * client.
  710. */
  711. bool serverSentEncryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(
  712. sessionServerExtensions);
  713. if (serverSentEncryptThenMac && !TlsUtilities.IsBlockCipherSuite(securityParameters.CipherSuite))
  714. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  715. securityParameters.m_encryptThenMac = serverSentEncryptThenMac;
  716. }
  717. securityParameters.m_maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
  718. sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
  719. securityParameters.m_truncatedHmac = TlsExtensionsUtilities.HasTruncatedHmacExtension(
  720. sessionServerExtensions);
  721. if (!state.resumedSession)
  722. {
  723. // TODO[tls13] See RFC 8446 4.4.2.1
  724. if (TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions,
  725. ExtensionType.status_request_v2, AlertDescription.illegal_parameter))
  726. {
  727. securityParameters.m_statusRequestVersion = 2;
  728. }
  729. else if (TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions,
  730. ExtensionType.status_request, AlertDescription.illegal_parameter))
  731. {
  732. securityParameters.m_statusRequestVersion = 1;
  733. }
  734. }
  735. state.expectSessionTicket = !state.resumedSession
  736. && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions,
  737. ExtensionType.session_ticket, AlertDescription.illegal_parameter);
  738. }
  739. if (sessionClientExtensions != null)
  740. {
  741. state.client.ProcessServerExtensions(sessionServerExtensions);
  742. }
  743. }
  744. /// <exception cref="IOException"/>
  745. protected virtual void ProcessServerKeyExchange(ClientHandshakeState state, byte[] body)
  746. {
  747. MemoryStream buf = new MemoryStream(body, false);
  748. state.keyExchange.ProcessServerKeyExchange(buf);
  749. TlsProtocol.AssertEmpty(buf);
  750. }
  751. /// <exception cref="IOException"/>
  752. protected virtual void ProcessServerSupplementalData(ClientHandshakeState state, byte[] body)
  753. {
  754. MemoryStream buf = new MemoryStream(body, false);
  755. var serverSupplementalData = TlsProtocol.ReadSupplementalDataMessage(buf);
  756. state.client.ProcessServerSupplementalData(serverSupplementalData);
  757. }
  758. /// <exception cref="IOException"/>
  759. protected virtual void ReportServerVersion(ClientHandshakeState state, ProtocolVersion server_version)
  760. {
  761. TlsClientContextImpl context = state.clientContext;
  762. SecurityParameters securityParameters = context.SecurityParameters;
  763. ProtocolVersion currentServerVersion = securityParameters.NegotiatedVersion;
  764. if (null != currentServerVersion)
  765. {
  766. if (!currentServerVersion.Equals(server_version))
  767. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  768. return;
  769. }
  770. if (!ProtocolVersion.Contains(context.ClientSupportedVersions, server_version))
  771. throw new TlsFatalAlert(AlertDescription.protocol_version);
  772. securityParameters.m_negotiatedVersion = server_version;
  773. TlsUtilities.NegotiatedVersionDtlsClient(state.clientContext, state.client);
  774. }
  775. /// <exception cref="IOException"/>
  776. protected static byte[] PatchClientHelloWithCookie(byte[] clientHelloBody, byte[] cookie)
  777. {
  778. int sessionIDPos = 34;
  779. int sessionIDLength = TlsUtilities.ReadUint8(clientHelloBody, sessionIDPos);
  780. int cookieLengthPos = sessionIDPos + 1 + sessionIDLength;
  781. int cookiePos = cookieLengthPos + 1;
  782. byte[] patched = new byte[clientHelloBody.Length + cookie.Length];
  783. Array.Copy(clientHelloBody, 0, patched, 0, cookieLengthPos);
  784. TlsUtilities.CheckUint8(cookie.Length);
  785. TlsUtilities.WriteUint8(cookie.Length, patched, cookieLengthPos);
  786. Array.Copy(cookie, 0, patched, cookiePos, cookie.Length);
  787. Array.Copy(clientHelloBody, cookiePos, patched, cookiePos + cookie.Length,
  788. clientHelloBody.Length - cookiePos);
  789. return patched;
  790. }
  791. protected internal class ClientHandshakeState
  792. {
  793. internal TlsClient client = null;
  794. internal TlsClientContextImpl clientContext = null;
  795. internal TlsSession tlsSession = null;
  796. internal SessionParameters sessionParameters = null;
  797. internal TlsSecret sessionMasterSecret = null;
  798. internal SessionParameters.Builder sessionParametersBuilder = null;
  799. internal int[] offeredCipherSuites = null;
  800. internal IDictionary<int, byte[]> clientExtensions = null;
  801. internal IDictionary<int, byte[]> serverExtensions = null;
  802. internal bool resumedSession = false;
  803. internal bool expectSessionTicket = false;
  804. internal IDictionary<int, TlsAgreement> clientAgreements = null;
  805. internal TlsKeyExchange keyExchange = null;
  806. internal TlsAuthentication authentication = null;
  807. internal CertificateStatus certificateStatus = null;
  808. internal CertificateRequest certificateRequest = null;
  809. internal TlsHeartbeat heartbeat = null;
  810. internal short heartbeatPolicy = HeartbeatMode.peer_not_allowed_to_send;
  811. }
  812. }
  813. }
  814. #pragma warning restore
  815. #endif