TlsClientProtocol.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  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 TlsClientProtocol
  11. : TlsProtocol
  12. {
  13. protected TlsClient mTlsClient = null;
  14. internal TlsClientContextImpl mTlsClientContext = null;
  15. protected byte[] mSelectedSessionID = null;
  16. protected TlsKeyExchange mKeyExchange = null;
  17. protected TlsAuthentication mAuthentication = null;
  18. protected CertificateStatus mCertificateStatus = null;
  19. protected CertificateRequest mCertificateRequest = null;
  20. /**
  21. * Constructor for blocking mode.
  22. * @param stream The bi-directional stream of data to/from the server
  23. * @param secureRandom Random number generator for various cryptographic functions
  24. */
  25. public TlsClientProtocol(Stream stream, SecureRandom secureRandom)
  26. : base(stream, secureRandom)
  27. {
  28. }
  29. /**
  30. * Constructor for blocking mode.
  31. * @param input The stream of data from the server
  32. * @param output The stream of data to the server
  33. * @param secureRandom Random number generator for various cryptographic functions
  34. */
  35. public TlsClientProtocol(Stream input, Stream output, SecureRandom secureRandom)
  36. : base(input, output, secureRandom)
  37. {
  38. }
  39. /**
  40. * Constructor for non-blocking mode.<br/>
  41. * <br/>
  42. * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to
  43. * provide the received ciphertext, then use
  44. * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.<br/>
  45. * <br/>
  46. * Similarly, when data needs to be sent, use
  47. * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use
  48. * {@link #readOutput(byte[], int, int)} to get the corresponding
  49. * ciphertext.
  50. *
  51. * @param secureRandom
  52. * Random number generator for various cryptographic functions
  53. */
  54. public TlsClientProtocol(SecureRandom secureRandom)
  55. : base(secureRandom)
  56. {
  57. }
  58. /**
  59. * Initiates a TLS handshake in the role of client.<br/>
  60. * <br/>
  61. * In blocking mode, this will not return until the handshake is complete.
  62. * In non-blocking mode, use {@link TlsPeer#NotifyHandshakeComplete()} to
  63. * receive a callback when the handshake is complete.
  64. *
  65. * @param tlsClient The {@link TlsClient} to use for the handshake.
  66. * @throws IOException If in blocking mode and handshake was not successful.
  67. */
  68. public virtual void Connect(TlsClient tlsClient)
  69. {
  70. if (tlsClient == null)
  71. throw new ArgumentNullException("tlsClient");
  72. if (this.mTlsClient != null)
  73. throw new InvalidOperationException("'Connect' can only be called once");
  74. this.mTlsClient = tlsClient;
  75. this.mSecurityParameters = new SecurityParameters();
  76. this.mSecurityParameters.entity = ConnectionEnd.client;
  77. this.mTlsClientContext = new TlsClientContextImpl(mSecureRandom, mSecurityParameters);
  78. this.mSecurityParameters.clientRandom = CreateRandomBlock(tlsClient.ShouldUseGmtUnixTime(),
  79. mTlsClientContext.NonceRandomGenerator);
  80. this.mTlsClient.Init(mTlsClientContext);
  81. this.mRecordStream.Init(mTlsClientContext);
  82. TlsSession sessionToResume = tlsClient.GetSessionToResume();
  83. if (sessionToResume != null && sessionToResume.IsResumable)
  84. {
  85. SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
  86. if (sessionParameters != null && sessionParameters.IsExtendedMasterSecret)
  87. {
  88. this.mTlsSession = sessionToResume;
  89. this.mSessionParameters = sessionParameters;
  90. }
  91. }
  92. SendClientHelloMessage();
  93. this.mConnectionState = CS_CLIENT_HELLO;
  94. BlockForHandshake();
  95. }
  96. protected override void CleanupHandshake()
  97. {
  98. base.CleanupHandshake();
  99. this.mSelectedSessionID = null;
  100. this.mKeyExchange = null;
  101. this.mAuthentication = null;
  102. this.mCertificateStatus = null;
  103. this.mCertificateRequest = null;
  104. }
  105. protected override TlsContext Context
  106. {
  107. get { return mTlsClientContext; }
  108. }
  109. internal override AbstractTlsContext ContextAdmin
  110. {
  111. get { return mTlsClientContext; }
  112. }
  113. protected override TlsPeer Peer
  114. {
  115. get { return mTlsClient; }
  116. }
  117. protected override void HandleHandshakeMessage(byte type, MemoryStream buf)
  118. {
  119. if (this.mResumedSession)
  120. {
  121. if (type != HandshakeType.finished || this.mConnectionState != CS_SERVER_HELLO)
  122. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  123. ProcessFinishedMessage(buf);
  124. this.mConnectionState = CS_SERVER_FINISHED;
  125. SendChangeCipherSpecMessage();
  126. SendFinishedMessage();
  127. this.mConnectionState = CS_CLIENT_FINISHED;
  128. CompleteHandshake();
  129. return;
  130. }
  131. switch (type)
  132. {
  133. case HandshakeType.certificate:
  134. {
  135. switch (this.mConnectionState)
  136. {
  137. case CS_SERVER_HELLO:
  138. case CS_SERVER_SUPPLEMENTAL_DATA:
  139. {
  140. if (this.mConnectionState == CS_SERVER_HELLO)
  141. {
  142. HandleSupplementalData(null);
  143. }
  144. // Parse the Certificate message and Send to cipher suite
  145. this.mPeerCertificate = Certificate.Parse(buf);
  146. AssertEmpty(buf);
  147. // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
  148. if (this.mPeerCertificate == null || this.mPeerCertificate.IsEmpty)
  149. {
  150. this.mAllowCertificateStatus = false;
  151. }
  152. this.mKeyExchange.ProcessServerCertificate(this.mPeerCertificate);
  153. this.mAuthentication = mTlsClient.GetAuthentication();
  154. this.mAuthentication.NotifyServerCertificate(this.mPeerCertificate);
  155. break;
  156. }
  157. default:
  158. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  159. }
  160. this.mConnectionState = CS_SERVER_CERTIFICATE;
  161. break;
  162. }
  163. case HandshakeType.certificate_status:
  164. {
  165. switch (this.mConnectionState)
  166. {
  167. case CS_SERVER_CERTIFICATE:
  168. {
  169. if (!this.mAllowCertificateStatus)
  170. {
  171. /*
  172. * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
  173. * server MUST have included an extension of type "status_request" with empty
  174. * "extension_data" in the extended server hello..
  175. */
  176. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  177. }
  178. this.mCertificateStatus = CertificateStatus.Parse(buf);
  179. AssertEmpty(buf);
  180. // TODO[RFC 3546] Figure out how to provide this to the client/authentication.
  181. this.mConnectionState = CS_CERTIFICATE_STATUS;
  182. break;
  183. }
  184. default:
  185. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  186. }
  187. break;
  188. }
  189. case HandshakeType.finished:
  190. {
  191. switch (this.mConnectionState)
  192. {
  193. case CS_CLIENT_FINISHED:
  194. case CS_SERVER_SESSION_TICKET:
  195. {
  196. if (this.mConnectionState == CS_CLIENT_FINISHED && this.mExpectSessionTicket)
  197. {
  198. /*
  199. * RFC 5077 3.3. This message MUST be sent if the server included a
  200. * SessionTicket extension in the ServerHello.
  201. */
  202. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  203. }
  204. ProcessFinishedMessage(buf);
  205. this.mConnectionState = CS_SERVER_FINISHED;
  206. CompleteHandshake();
  207. break;
  208. }
  209. default:
  210. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  211. }
  212. break;
  213. }
  214. case HandshakeType.server_hello:
  215. {
  216. switch (this.mConnectionState)
  217. {
  218. case CS_CLIENT_HELLO:
  219. {
  220. ReceiveServerHelloMessage(buf);
  221. this.mConnectionState = CS_SERVER_HELLO;
  222. this.mRecordStream.NotifyHelloComplete();
  223. ApplyMaxFragmentLengthExtension();
  224. if (this.mResumedSession)
  225. {
  226. this.mSecurityParameters.masterSecret = Arrays.Clone(this.mSessionParameters.MasterSecret);
  227. this.mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
  228. }
  229. else
  230. {
  231. InvalidateSession();
  232. if (this.mSelectedSessionID.Length > 0)
  233. {
  234. this.mTlsSession = new TlsSessionImpl(this.mSelectedSessionID, null);
  235. }
  236. }
  237. break;
  238. }
  239. default:
  240. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  241. }
  242. break;
  243. }
  244. case HandshakeType.supplemental_data:
  245. {
  246. switch (this.mConnectionState)
  247. {
  248. case CS_SERVER_HELLO:
  249. {
  250. HandleSupplementalData(ReadSupplementalDataMessage(buf));
  251. break;
  252. }
  253. default:
  254. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  255. }
  256. break;
  257. }
  258. case HandshakeType.server_hello_done:
  259. {
  260. switch (this.mConnectionState)
  261. {
  262. case CS_SERVER_HELLO:
  263. case CS_SERVER_SUPPLEMENTAL_DATA:
  264. case CS_SERVER_CERTIFICATE:
  265. case CS_CERTIFICATE_STATUS:
  266. case CS_SERVER_KEY_EXCHANGE:
  267. case CS_CERTIFICATE_REQUEST:
  268. {
  269. if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
  270. {
  271. HandleSupplementalData(null);
  272. }
  273. if (mConnectionState < CS_SERVER_CERTIFICATE)
  274. {
  275. // There was no server certificate message; check it's OK
  276. this.mKeyExchange.SkipServerCredentials();
  277. this.mAuthentication = null;
  278. }
  279. if (mConnectionState < CS_SERVER_KEY_EXCHANGE)
  280. {
  281. // There was no server key exchange message; check it's OK
  282. this.mKeyExchange.SkipServerKeyExchange();
  283. }
  284. AssertEmpty(buf);
  285. this.mConnectionState = CS_SERVER_HELLO_DONE;
  286. this.mRecordStream.HandshakeHash.SealHashAlgorithms();
  287. IList clientSupplementalData = mTlsClient.GetClientSupplementalData();
  288. if (clientSupplementalData != null)
  289. {
  290. SendSupplementalDataMessage(clientSupplementalData);
  291. }
  292. this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
  293. TlsCredentials clientCreds = null;
  294. if (mCertificateRequest == null)
  295. {
  296. this.mKeyExchange.SkipClientCredentials();
  297. }
  298. else
  299. {
  300. clientCreds = this.mAuthentication.GetClientCredentials(Context, mCertificateRequest);
  301. if (clientCreds == null)
  302. {
  303. this.mKeyExchange.SkipClientCredentials();
  304. /*
  305. * RFC 5246 If no suitable certificate is available, the client MUST Send a
  306. * certificate message containing no certificates.
  307. *
  308. * NOTE: In previous RFCs, this was SHOULD instead of MUST.
  309. */
  310. SendCertificateMessage(Certificate.EmptyChain);
  311. }
  312. else
  313. {
  314. this.mKeyExchange.ProcessClientCredentials(clientCreds);
  315. SendCertificateMessage(clientCreds.Certificate);
  316. }
  317. }
  318. this.mConnectionState = CS_CLIENT_CERTIFICATE;
  319. /*
  320. * Send the client key exchange message, depending on the key exchange we are using
  321. * in our CipherSuite.
  322. */
  323. SendClientKeyExchangeMessage();
  324. this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
  325. if (TlsUtilities.IsSsl(Context))
  326. {
  327. EstablishMasterSecret(Context, mKeyExchange);
  328. }
  329. TlsHandshakeHash prepareFinishHash = mRecordStream.PrepareToFinish();
  330. this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, prepareFinishHash, null);
  331. if (!TlsUtilities.IsSsl(Context))
  332. {
  333. EstablishMasterSecret(Context, mKeyExchange);
  334. }
  335. mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
  336. if (clientCreds != null && clientCreds is TlsSignerCredentials)
  337. {
  338. TlsSignerCredentials signerCredentials = (TlsSignerCredentials)clientCreds;
  339. /*
  340. * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
  341. */
  342. SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
  343. Context, signerCredentials);
  344. byte[] hash;
  345. if (signatureAndHashAlgorithm == null)
  346. {
  347. hash = mSecurityParameters.SessionHash;
  348. }
  349. else
  350. {
  351. hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
  352. }
  353. byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
  354. DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
  355. SendCertificateVerifyMessage(certificateVerify);
  356. this.mConnectionState = CS_CERTIFICATE_VERIFY;
  357. }
  358. SendChangeCipherSpecMessage();
  359. SendFinishedMessage();
  360. break;
  361. }
  362. default:
  363. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  364. }
  365. this.mConnectionState = CS_CLIENT_FINISHED;
  366. break;
  367. }
  368. case HandshakeType.server_key_exchange:
  369. {
  370. switch (this.mConnectionState)
  371. {
  372. case CS_SERVER_HELLO:
  373. case CS_SERVER_SUPPLEMENTAL_DATA:
  374. case CS_SERVER_CERTIFICATE:
  375. case CS_CERTIFICATE_STATUS:
  376. {
  377. if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
  378. {
  379. HandleSupplementalData(null);
  380. }
  381. if (mConnectionState < CS_SERVER_CERTIFICATE)
  382. {
  383. // There was no server certificate message; check it's OK
  384. this.mKeyExchange.SkipServerCredentials();
  385. this.mAuthentication = null;
  386. }
  387. this.mKeyExchange.ProcessServerKeyExchange(buf);
  388. AssertEmpty(buf);
  389. break;
  390. }
  391. default:
  392. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  393. }
  394. this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
  395. break;
  396. }
  397. case HandshakeType.certificate_request:
  398. {
  399. switch (this.mConnectionState)
  400. {
  401. case CS_SERVER_CERTIFICATE:
  402. case CS_CERTIFICATE_STATUS:
  403. case CS_SERVER_KEY_EXCHANGE:
  404. {
  405. if (this.mConnectionState != CS_SERVER_KEY_EXCHANGE)
  406. {
  407. // There was no server key exchange message; check it's OK
  408. this.mKeyExchange.SkipServerKeyExchange();
  409. }
  410. if (this.mAuthentication == null)
  411. {
  412. /*
  413. * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server
  414. * to request client identification.
  415. */
  416. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  417. }
  418. this.mCertificateRequest = CertificateRequest.Parse(Context, buf);
  419. AssertEmpty(buf);
  420. this.mKeyExchange.ValidateCertificateRequest(this.mCertificateRequest);
  421. /*
  422. * TODO Give the client a chance to immediately select the CertificateVerify hash
  423. * algorithm here to avoid tracking the other hash algorithms unnecessarily?
  424. */
  425. TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
  426. this.mCertificateRequest.SupportedSignatureAlgorithms);
  427. break;
  428. }
  429. default:
  430. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  431. }
  432. this.mConnectionState = CS_CERTIFICATE_REQUEST;
  433. break;
  434. }
  435. case HandshakeType.session_ticket:
  436. {
  437. switch (this.mConnectionState)
  438. {
  439. case CS_CLIENT_FINISHED:
  440. {
  441. if (!this.mExpectSessionTicket)
  442. {
  443. /*
  444. * RFC 5077 3.3. This message MUST NOT be sent if the server did not include a
  445. * SessionTicket extension in the ServerHello.
  446. */
  447. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  448. }
  449. /*
  450. * RFC 5077 3.4. If the client receives a session ticket from the server, then it
  451. * discards any Session ID that was sent in the ServerHello.
  452. */
  453. InvalidateSession();
  454. ReceiveNewSessionTicketMessage(buf);
  455. break;
  456. }
  457. default:
  458. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  459. }
  460. this.mConnectionState = CS_SERVER_SESSION_TICKET;
  461. break;
  462. }
  463. case HandshakeType.hello_request:
  464. {
  465. AssertEmpty(buf);
  466. /*
  467. * RFC 2246 7.4.1.1 Hello request This message will be ignored by the client if the
  468. * client is currently negotiating a session. This message may be ignored by the client
  469. * if it does not wish to renegotiate a session, or the client may, if it wishes,
  470. * respond with a no_renegotiation alert.
  471. */
  472. if (this.mConnectionState == CS_END)
  473. {
  474. RefuseRenegotiation();
  475. }
  476. break;
  477. }
  478. case HandshakeType.client_hello:
  479. case HandshakeType.client_key_exchange:
  480. case HandshakeType.certificate_verify:
  481. case HandshakeType.hello_verify_request:
  482. default:
  483. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  484. }
  485. }
  486. protected virtual void HandleSupplementalData(IList serverSupplementalData)
  487. {
  488. this.mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
  489. this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;
  490. this.mKeyExchange = mTlsClient.GetKeyExchange();
  491. this.mKeyExchange.Init(Context);
  492. }
  493. protected virtual void ReceiveNewSessionTicketMessage(MemoryStream buf)
  494. {
  495. NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);
  496. AssertEmpty(buf);
  497. mTlsClient.NotifyNewSessionTicket(newSessionTicket);
  498. }
  499. protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
  500. {
  501. {
  502. ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
  503. if (server_version.IsDtls)
  504. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  505. // Check that this matches what the server is Sending in the record layer
  506. if (!server_version.Equals(this.mRecordStream.ReadVersion))
  507. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  508. ProtocolVersion client_version = Context.ClientVersion;
  509. if (!server_version.IsEqualOrEarlierVersionOf(client_version))
  510. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  511. this.mRecordStream.SetWriteVersion(server_version);
  512. ContextAdmin.SetServerVersion(server_version);
  513. this.mTlsClient.NotifyServerVersion(server_version);
  514. }
  515. /*
  516. * Read the server random
  517. */
  518. this.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
  519. this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
  520. if (this.mSelectedSessionID.Length > 32)
  521. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  522. this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
  523. this.mResumedSession = this.mSelectedSessionID.Length > 0 && this.mTlsSession != null
  524. && Arrays.AreEqual(this.mSelectedSessionID, this.mTlsSession.SessionID);
  525. /*
  526. * Find out which CipherSuite the server has chosen and check that it was one of the offered
  527. * ones, and is a valid selection for the negotiated version.
  528. */
  529. int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
  530. if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite)
  531. || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
  532. || CipherSuite.IsScsv(selectedCipherSuite)
  533. || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
  534. {
  535. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  536. }
  537. this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite);
  538. /*
  539. * Find out which CompressionMethod the server has chosen and check that it was one of the
  540. * offered ones.
  541. */
  542. byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
  543. if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod))
  544. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  545. this.mTlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);
  546. /*
  547. * RFC 3546 2.2 The extended server hello message format MAY be sent in place of the server
  548. * hello message when the client has requested extended functionality via the extended
  549. * client hello message specified in Section 2.1. ... Note that the extended server hello
  550. * message is only sent in response to an extended client hello message. This prevents the
  551. * possibility that the extended server hello message could "break" existing TLS 1.0
  552. * clients.
  553. */
  554. this.mServerExtensions = ReadExtensions(buf);
  555. /*
  556. * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended
  557. * master secret [..]. (and see 5.2, 5.3)
  558. */
  559. this.mSecurityParameters.extendedMasterSecret = !TlsUtilities.IsSsl(mTlsClientContext)
  560. && TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mServerExtensions);
  561. if (!mSecurityParameters.IsExtendedMasterSecret
  562. && (mResumedSession || mTlsClient.RequiresExtendedMasterSecret()))
  563. {
  564. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  565. }
  566. /*
  567. * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
  568. * extended client hello message.
  569. *
  570. * However, see RFC 5746 exception below. We always include the SCSV, so an Extended Server
  571. * Hello is always allowed.
  572. */
  573. if (this.mServerExtensions != null)
  574. {
  575. foreach (int extType in this.mServerExtensions.Keys)
  576. {
  577. /*
  578. * RFC 5746 3.6. Note that Sending a "renegotiation_info" extension in response to a
  579. * ClientHello containing only the SCSV is an explicit exception to the prohibition
  580. * in RFC 5246, Section 7.4.1.4, on the server Sending unsolicited extensions and is
  581. * only allowed because the client is signaling its willingness to receive the
  582. * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
  583. */
  584. if (extType == ExtensionType.renegotiation_info)
  585. continue;
  586. /*
  587. * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
  588. * same extension type appeared in the corresponding ClientHello. If a client
  589. * receives an extension type in ServerHello that it did not request in the
  590. * associated ClientHello, it MUST abort the handshake with an unsupported_extension
  591. * fatal alert.
  592. */
  593. if (null == TlsUtilities.GetExtensionData(this.mClientExtensions, extType))
  594. throw new TlsFatalAlert(AlertDescription.unsupported_extension);
  595. /*
  596. * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
  597. * extensions appearing in the client hello, and Send a server hello containing no
  598. * extensions[.]
  599. */
  600. if (this.mResumedSession)
  601. {
  602. // TODO[compat-gnutls] GnuTLS test server Sends server extensions e.g. ec_point_formats
  603. // TODO[compat-openssl] OpenSSL test server Sends server extensions e.g. ec_point_formats
  604. // TODO[compat-polarssl] PolarSSL test server Sends server extensions e.g. ec_point_formats
  605. // throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  606. }
  607. }
  608. }
  609. /*
  610. * RFC 5746 3.4. Client Behavior: Initial Handshake
  611. */
  612. {
  613. /*
  614. * When a ServerHello is received, the client MUST check if it includes the
  615. * "renegotiation_info" extension:
  616. */
  617. byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
  618. if (renegExtData != null)
  619. {
  620. /*
  621. * If the extension is present, set the secure_renegotiation flag to TRUE. The
  622. * client MUST then verify that the length of the "renegotiated_connection"
  623. * field is zero, and if it is not, MUST abort the handshake (by Sending a fatal
  624. * handshake_failure alert).
  625. */
  626. this.mSecureRenegotiation = true;
  627. if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
  628. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  629. }
  630. }
  631. // TODO[compat-gnutls] GnuTLS test server fails to Send renegotiation_info extension when resuming
  632. this.mTlsClient.NotifySecureRenegotiation(this.mSecureRenegotiation);
  633. IDictionary sessionClientExtensions = mClientExtensions, sessionServerExtensions = mServerExtensions;
  634. if (this.mResumedSession)
  635. {
  636. if (selectedCipherSuite != this.mSessionParameters.CipherSuite
  637. || selectedCompressionMethod != this.mSessionParameters.CompressionAlgorithm)
  638. {
  639. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  640. }
  641. sessionClientExtensions = null;
  642. sessionServerExtensions = this.mSessionParameters.ReadServerExtensions();
  643. }
  644. this.mSecurityParameters.cipherSuite = selectedCipherSuite;
  645. this.mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
  646. if (sessionServerExtensions != null && sessionServerExtensions.Count > 0)
  647. {
  648. {
  649. /*
  650. * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
  651. * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
  652. * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
  653. * client.
  654. */
  655. bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
  656. if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(selectedCipherSuite))
  657. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  658. this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
  659. }
  660. this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
  661. sessionServerExtensions, AlertDescription.illegal_parameter);
  662. this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);
  663. /*
  664. * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
  665. * a session resumption handshake.
  666. */
  667. this.mAllowCertificateStatus = !this.mResumedSession
  668. && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
  669. AlertDescription.illegal_parameter);
  670. this.mExpectSessionTicket = !this.mResumedSession
  671. && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
  672. AlertDescription.illegal_parameter);
  673. }
  674. if (sessionClientExtensions != null)
  675. {
  676. this.mTlsClient.ProcessServerExtensions(sessionServerExtensions);
  677. }
  678. this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.CipherSuite);
  679. /*
  680. * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify
  681. * verify_data_length has a verify_data_length equal to 12. This includes all
  682. * existing cipher suites.
  683. */
  684. this.mSecurityParameters.verifyDataLength = 12;
  685. }
  686. protected virtual void SendCertificateVerifyMessage(DigitallySigned certificateVerify)
  687. {
  688. HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_verify);
  689. certificateVerify.Encode(message);
  690. message.WriteToRecordStream(this);
  691. }
  692. protected virtual void SendClientHelloMessage()
  693. {
  694. this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion);
  695. ProtocolVersion client_version = this.mTlsClient.ClientVersion;
  696. if (client_version.IsDtls)
  697. throw new TlsFatalAlert(AlertDescription.internal_error);
  698. ContextAdmin.SetClientVersion(client_version);
  699. /*
  700. * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a
  701. * Session ID in the TLS ClientHello.
  702. */
  703. byte[] session_id = TlsUtilities.EmptyBytes;
  704. if (this.mTlsSession != null)
  705. {
  706. session_id = this.mTlsSession.SessionID;
  707. if (session_id == null || session_id.Length > 32)
  708. {
  709. session_id = TlsUtilities.EmptyBytes;
  710. }
  711. }
  712. bool fallback = this.mTlsClient.IsFallback;
  713. this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites();
  714. this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods();
  715. if (session_id.Length > 0 && this.mSessionParameters != null)
  716. {
  717. if (!mSessionParameters.IsExtendedMasterSecret
  718. || !Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite)
  719. || !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm))
  720. {
  721. session_id = TlsUtilities.EmptyBytes;
  722. }
  723. }
  724. this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mTlsClient.GetClientExtensions());
  725. if (!client_version.IsSsl)
  726. {
  727. TlsExtensionsUtilities.AddExtendedMasterSecretExtension(this.mClientExtensions);
  728. }
  729. HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);
  730. TlsUtilities.WriteVersion(client_version, message);
  731. message.Write(this.mSecurityParameters.ClientRandom);
  732. TlsUtilities.WriteOpaque8(session_id, message);
  733. // Cipher Suites (and SCSV)
  734. {
  735. /*
  736. * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
  737. * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
  738. * ClientHello. Including both is NOT RECOMMENDED.
  739. */
  740. byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
  741. bool noRenegExt = (null == renegExtData);
  742. bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
  743. if (noRenegExt && noRenegScsv)
  744. {
  745. // TODO Consider whether to default to a client extension instead
  746. this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
  747. }
  748. /*
  749. * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value
  750. * than the latest (highest-valued) version supported by the client, it SHOULD include
  751. * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The
  752. * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
  753. * to negotiate.)
  754. */
  755. if (fallback && !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
  756. {
  757. this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
  758. }
  759. TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message);
  760. }
  761. TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message);
  762. WriteExtensions(message, mClientExtensions);
  763. message.WriteToRecordStream(this);
  764. }
  765. protected virtual void SendClientKeyExchangeMessage()
  766. {
  767. HandshakeMessage message = new HandshakeMessage(HandshakeType.client_key_exchange);
  768. this.mKeyExchange.GenerateClientKeyExchange(message);
  769. message.WriteToRecordStream(this);
  770. }
  771. }
  772. }
  773. #pragma warning restore
  774. #endif