/android/upstream/org/apache/harmony/xnet/provider/jsse/SSLSocketImpl.java

https://bitbucket.org/festevezga/xobotos · Java · 810 lines · 460 code · 58 blank · 292 comment · 73 complexity · d5c7713d916d2ec6cc070b65794cad32 MD5 · raw file

  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.harmony.xnet.provider.jsse;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.OutputStream;
  21. import java.net.InetAddress;
  22. import java.net.SocketAddress;
  23. import java.net.SocketException;
  24. import java.net.UnknownHostException;
  25. import java.util.ArrayList;
  26. import javax.net.ssl.HandshakeCompletedEvent;
  27. import javax.net.ssl.HandshakeCompletedListener;
  28. import javax.net.ssl.SSLEngineResult;
  29. import javax.net.ssl.SSLException;
  30. import javax.net.ssl.SSLSession;
  31. import javax.net.ssl.SSLSocket;
  32. /**
  33. * SSLSocket implementation.
  34. * @see javax.net.ssl.SSLSocket class documentation for more information.
  35. */
  36. public class SSLSocketImpl extends SSLSocket {
  37. // indicates if handshake has been started
  38. private boolean handshake_started = false;
  39. // record protocol to be used
  40. protected SSLRecordProtocol recordProtocol;
  41. // handshake protocol to be used
  42. private HandshakeProtocol handshakeProtocol;
  43. // alert protocol to be used
  44. private AlertProtocol alertProtocol;
  45. // application data input stream, this stream is presented by
  46. // ssl socket as an input stream. Additionally this object is a
  47. // place where application data will be stored by record protocol
  48. private SSLSocketInputStream appDataIS;
  49. // outgoing application data stream
  50. private SSLSocketOutputStream appDataOS;
  51. // active session object
  52. private SSLSessionImpl session;
  53. private boolean socket_was_closed = false;
  54. // the sslParameters object encapsulates all the info
  55. // about supported and enabled cipher suites and protocols,
  56. // as well as the information about client/server mode of
  57. // ssl socket, whether it require/want client authentication or not,
  58. // and controls whether new SSL sessions may be established by this
  59. // socket or not.
  60. protected SSLParametersImpl sslParameters;
  61. // super's streams to be wrapped:
  62. protected InputStream input;
  63. protected OutputStream output;
  64. // handshake complete listeners
  65. private ArrayList<HandshakeCompletedListener> listeners;
  66. // logger
  67. private Logger.Stream logger = Logger.getStream("socket");
  68. // ----------------- Constructors and initializers --------------------
  69. /**
  70. * Constructor
  71. * @param sslParameters: SSLParametersImpl
  72. * @see javax.net.ssl.SSLSocket#SSLSocket() method documentation
  73. * for more information.
  74. */
  75. protected SSLSocketImpl(SSLParametersImpl sslParameters) {
  76. this.sslParameters = sslParameters;
  77. // init should be called after creation!
  78. }
  79. /**
  80. * Constructor
  81. * @param host: String
  82. * @param port: int
  83. * @param sslParameters: SSLParametersImpl
  84. * @throws IOException
  85. * @throws UnknownHostException
  86. * @see javax.net.ssl.SSLSocket#SSLSocket(String,int)
  87. * method documentation for more information.
  88. */
  89. protected SSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
  90. throws IOException, UnknownHostException {
  91. super(host, port);
  92. this.sslParameters = sslParameters;
  93. init();
  94. }
  95. /**
  96. * Constructor
  97. * @param host: String
  98. * @param port: int
  99. * @param localHost: InetAddress
  100. * @param localPort: int
  101. * @param sslParameters: SSLParametersImpl
  102. * @throws IOException
  103. * @throws UnknownHostException
  104. * @see javax.net.ssl.SSLSocket#SSLSocket(String,int,InetAddress,int)
  105. * method documentation for more information.
  106. */
  107. protected SSLSocketImpl(String host, int port,
  108. InetAddress localHost, int localPort,
  109. SSLParametersImpl sslParameters) throws IOException,
  110. UnknownHostException {
  111. super(host, port, localHost, localPort);
  112. this.sslParameters = sslParameters;
  113. init();
  114. }
  115. /**
  116. * Constructor
  117. * @param host: InetAddress
  118. * @param port: int
  119. * @param sslParameters: SSLParametersImpl
  120. * @return
  121. * @throws IOException
  122. * @see javax.net.ssl.SSLSocket#SSLSocket(InetAddress,int)
  123. * method documentation for more information.
  124. */
  125. protected SSLSocketImpl(InetAddress host, int port,
  126. SSLParametersImpl sslParameters) throws IOException {
  127. super(host, port);
  128. this.sslParameters = sslParameters;
  129. init();
  130. }
  131. /**
  132. * Constructor
  133. * @param address: InetAddress
  134. * @param port: int
  135. * @param localAddress: InetAddress
  136. * @param localPort: int
  137. * @param sslParameters: SSLParametersImpl
  138. * @return
  139. * @throws IOException
  140. * @see javax.net.ssl.SSLSocket#SSLSocket(InetAddress,int,InetAddress,int)
  141. * method documentation for more information.
  142. */
  143. protected SSLSocketImpl(InetAddress address, int port,
  144. InetAddress localAddress, int localPort,
  145. SSLParametersImpl sslParameters) throws IOException {
  146. super(address, port, localAddress, localPort);
  147. this.sslParameters = sslParameters;
  148. init();
  149. }
  150. /**
  151. * Initialize the SSL socket.
  152. */
  153. protected void init() throws IOException {
  154. if (appDataIS != null) {
  155. // already initialized
  156. return;
  157. }
  158. initTransportLayer();
  159. appDataIS = new SSLSocketInputStream(this);
  160. appDataOS = new SSLSocketOutputStream(this);
  161. }
  162. /**
  163. * Initialize the transport data streams.
  164. */
  165. protected void initTransportLayer() throws IOException {
  166. input = super.getInputStream();
  167. output = super.getOutputStream();
  168. }
  169. /**
  170. * Closes the transport data streams.
  171. */
  172. protected void closeTransportLayer() throws IOException {
  173. super.close();
  174. if (input != null) {
  175. input.close();
  176. output.close();
  177. }
  178. }
  179. // --------------- SSLParameters based methods ---------------------
  180. /**
  181. * This method works according to the specification of implemented class.
  182. * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites()
  183. * method documentation for more information
  184. */
  185. @Override
  186. public String[] getSupportedCipherSuites() {
  187. return CipherSuite.getSupportedCipherSuiteNames();
  188. }
  189. /**
  190. * This method works according to the specification of implemented class.
  191. * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites()
  192. * method documentation for more information
  193. */
  194. @Override
  195. public String[] getEnabledCipherSuites() {
  196. return sslParameters.getEnabledCipherSuites();
  197. }
  198. /**
  199. * This method works according to the specification of implemented class.
  200. * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(String[])
  201. * method documentation for more information
  202. */
  203. @Override
  204. public void setEnabledCipherSuites(String[] suites) {
  205. sslParameters.setEnabledCipherSuites(suites);
  206. }
  207. /**
  208. * This method works according to the specification of implemented class.
  209. * @see javax.net.ssl.SSLSocket#getSupportedProtocols()
  210. * method documentation for more information
  211. */
  212. @Override
  213. public String[] getSupportedProtocols() {
  214. return ProtocolVersion.supportedProtocols.clone();
  215. }
  216. /**
  217. * This method works according to the specification of implemented class.
  218. * @see javax.net.ssl.SSLSocket#getEnabledProtocols()
  219. * method documentation for more information
  220. */
  221. @Override
  222. public String[] getEnabledProtocols() {
  223. return sslParameters.getEnabledProtocols();
  224. }
  225. /**
  226. * This method works according to the specification of implemented class.
  227. * @see javax.net.ssl.SSLSocket#setEnabledProtocols(String[])
  228. * method documentation for more information
  229. */
  230. @Override
  231. public void setEnabledProtocols(String[] protocols) {
  232. sslParameters.setEnabledProtocols(protocols);
  233. }
  234. /**
  235. * This method works according to the specification of implemented class.
  236. * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean)
  237. * method documentation for more information
  238. */
  239. @Override
  240. public void setUseClientMode(boolean mode) {
  241. if (handshake_started) {
  242. throw new IllegalArgumentException(
  243. "Could not change the mode after the initial handshake has begun.");
  244. }
  245. sslParameters.setUseClientMode(mode);
  246. }
  247. /**
  248. * This method works according to the specification of implemented class.
  249. * @see javax.net.ssl.SSLSocket#getUseClientMode()
  250. * method documentation for more information
  251. */
  252. @Override
  253. public boolean getUseClientMode() {
  254. return sslParameters.getUseClientMode();
  255. }
  256. /**
  257. * This method works according to the specification of implemented class.
  258. * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean)
  259. * method documentation for more information
  260. */
  261. @Override
  262. public void setNeedClientAuth(boolean need) {
  263. sslParameters.setNeedClientAuth(need);
  264. }
  265. /**
  266. * This method works according to the specification of implemented class.
  267. * @see javax.net.ssl.SSLSocket#getNeedClientAuth()
  268. * method documentation for more information
  269. */
  270. @Override
  271. public boolean getNeedClientAuth() {
  272. return sslParameters.getNeedClientAuth();
  273. }
  274. /**
  275. * This method works according to the specification of implemented class.
  276. * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean)
  277. * method documentation for more information
  278. */
  279. @Override
  280. public void setWantClientAuth(boolean want) {
  281. sslParameters.setWantClientAuth(want);
  282. }
  283. /**
  284. * This method works according to the specification of implemented class.
  285. * @see javax.net.ssl.SSLSocket#getWantClientAuth()
  286. * method documentation for more information
  287. */
  288. @Override
  289. public boolean getWantClientAuth() {
  290. return sslParameters.getWantClientAuth();
  291. }
  292. /**
  293. * This method works according to the specification of implemented class.
  294. * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean)
  295. * method documentation for more information
  296. */
  297. @Override
  298. public void setEnableSessionCreation(boolean flag) {
  299. sslParameters.setEnableSessionCreation(flag);
  300. }
  301. /**
  302. * This method works according to the specification of implemented class.
  303. * @see javax.net.ssl.SSLSocket#getEnableSessionCreation()
  304. * method documentation for more information
  305. */
  306. @Override
  307. public boolean getEnableSessionCreation() {
  308. return sslParameters.getEnableSessionCreation();
  309. }
  310. // -----------------------------------------------------------------
  311. /**
  312. * This method works according to the specification of implemented class.
  313. * @see javax.net.ssl.SSLSocket#getSession()
  314. * method documentation for more information
  315. */
  316. @Override
  317. public SSLSession getSession() {
  318. if (!handshake_started) {
  319. try {
  320. startHandshake();
  321. } catch (IOException e) {
  322. // return an invalid session with
  323. // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
  324. return SSLSessionImpl.NULL_SESSION;
  325. }
  326. }
  327. return session;
  328. }
  329. /**
  330. * This method works according to the specification of implemented class.
  331. * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(HandshakeCompletedListener)
  332. * method documentation for more information
  333. */
  334. @Override
  335. public void addHandshakeCompletedListener(
  336. HandshakeCompletedListener listener) {
  337. if (listener == null) {
  338. throw new IllegalArgumentException("Provided listener is null");
  339. }
  340. if (listeners == null) {
  341. listeners = new ArrayList<HandshakeCompletedListener>();
  342. }
  343. listeners.add(listener);
  344. }
  345. /**
  346. * This method works according to the specification of implemented class.
  347. * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(HandshakeCompletedListener)
  348. * method documentation for more information
  349. */
  350. @Override
  351. public void removeHandshakeCompletedListener(
  352. HandshakeCompletedListener listener) {
  353. if (listener == null) {
  354. throw new IllegalArgumentException("Provided listener is null");
  355. }
  356. if (listeners == null) {
  357. throw new IllegalArgumentException(
  358. "Provided listener is not registered");
  359. }
  360. if (!listeners.remove(listener)) {
  361. throw new IllegalArgumentException(
  362. "Provided listener is not registered");
  363. }
  364. }
  365. /**
  366. * Performs the handshake process over the SSL/TLS connection
  367. * as described in rfc 2246, TLS v1 specification
  368. * http://www.ietf.org/rfc/rfc2246.txt. If the initial handshake
  369. * has been already done, this method initiates rehandshake.
  370. * This method works according to the specification of implemented class.
  371. * @see javax.net.ssl.SSLSocket#startHandshake()
  372. * method documentation for more information
  373. */
  374. @Override
  375. public void startHandshake() throws IOException {
  376. if (appDataIS == null) {
  377. throw new IOException("Socket is not connected.");
  378. }
  379. if (socket_was_closed) {
  380. throw new IOException("Socket has already been closed.");
  381. }
  382. if (!handshake_started) {
  383. handshake_started = true;
  384. if (sslParameters.getUseClientMode()) {
  385. if (logger != null) {
  386. logger.println("SSLSocketImpl: CLIENT");
  387. }
  388. handshakeProtocol = new ClientHandshakeImpl(this);
  389. } else {
  390. if (logger != null) {
  391. logger.println("SSLSocketImpl: SERVER");
  392. }
  393. handshakeProtocol = new ServerHandshakeImpl(this);
  394. }
  395. alertProtocol = new AlertProtocol();
  396. recordProtocol = new SSLRecordProtocol(handshakeProtocol,
  397. alertProtocol, new SSLStreamedInput(input),
  398. appDataIS.dataPoint);
  399. }
  400. if (logger != null) {
  401. logger.println("SSLSocketImpl.startHandshake");
  402. }
  403. handshakeProtocol.start();
  404. doHandshake();
  405. if (logger != null) {
  406. logger.println("SSLSocketImpl.startHandshake: END");
  407. }
  408. }
  409. /**
  410. * This method works according to the specification of implemented class.
  411. * @see javax.net.ssl.SSLSocket#getInputStream()
  412. * method documentation for more information
  413. */
  414. @Override
  415. public InputStream getInputStream() throws IOException {
  416. if (socket_was_closed) {
  417. throw new IOException("Socket has already been closed.");
  418. }
  419. return appDataIS;
  420. }
  421. /**
  422. * This method works according to the specification of implemented class.
  423. * @see javax.net.ssl.SSLSocket#getOutputStream()
  424. * method documentation for more information
  425. */
  426. @Override
  427. public OutputStream getOutputStream() throws IOException {
  428. if (socket_was_closed) {
  429. throw new IOException("Socket has already been closed.");
  430. }
  431. return appDataOS;
  432. }
  433. /**
  434. * This method works according to the specification of implemented class.
  435. * @see java.net.Socket#connect(SocketAddress)
  436. * method documentation for more information
  437. */
  438. @Override
  439. public void connect(SocketAddress endpoint) throws IOException {
  440. super.connect(endpoint);
  441. init();
  442. }
  443. /**
  444. * This method works according to the specification of implemented class.
  445. * @see java.net.Socket#connect(SocketAddress,int)
  446. * method documentation for more information
  447. */
  448. @Override
  449. public void connect(SocketAddress endpoint, int timeout)
  450. throws IOException {
  451. super.connect(endpoint, timeout);
  452. init();
  453. }
  454. /**
  455. * This method works according to the specification of implemented class.
  456. * @see javax.net.ssl.SSLSocket#close()
  457. * method documentation for more information
  458. */
  459. @Override
  460. public void close() throws IOException {
  461. if (logger != null) {
  462. logger.println("SSLSocket.close "+socket_was_closed);
  463. }
  464. if (!socket_was_closed) {
  465. if (handshake_started) {
  466. alertProtocol.alert(AlertProtocol.WARNING,
  467. AlertProtocol.CLOSE_NOTIFY);
  468. try {
  469. output.write(alertProtocol.wrap());
  470. } catch (IOException ex) { }
  471. alertProtocol.setProcessed();
  472. }
  473. shutdown();
  474. closeTransportLayer();
  475. socket_was_closed = true;
  476. }
  477. }
  478. /**
  479. * This method is not supported for SSLSocket implementation.
  480. */
  481. @Override
  482. public void sendUrgentData(int data) throws IOException {
  483. throw new SocketException(
  484. "Method sendUrgentData() is not supported.");
  485. }
  486. /**
  487. * This method is not supported for SSLSocket implementation.
  488. */
  489. @Override
  490. public void setOOBInline(boolean on) throws SocketException {
  491. throw new SocketException(
  492. "Methods sendUrgentData, setOOBInline are not supported.");
  493. }
  494. // -----------------------------------------------------------------
  495. private void shutdown() {
  496. if (handshake_started) {
  497. alertProtocol.shutdown();
  498. alertProtocol = null;
  499. handshakeProtocol.shutdown();
  500. handshakeProtocol = null;
  501. recordProtocol.shutdown();
  502. recordProtocol = null;
  503. }
  504. socket_was_closed = true;
  505. }
  506. /**
  507. * This method is called by SSLSocketInputStream class
  508. * when client application tries to read application data from
  509. * the stream, but there is no data in its underlying buffer.
  510. * @throws IOException
  511. */
  512. protected void needAppData() throws IOException {
  513. if (!handshake_started) {
  514. startHandshake();
  515. }
  516. int type;
  517. if (logger != null) {
  518. logger.println("SSLSocket.needAppData..");
  519. }
  520. try {
  521. while(appDataIS.available() == 0) {
  522. // read and unwrap the record contained in the transport
  523. // input stream (SSLStreamedInput), pass it
  524. // to appropriate client protocol (alert, handshake, or app)
  525. // and retrieve the type of unwrapped data
  526. switch (type = recordProtocol.unwrap()) {
  527. case ContentType.HANDSHAKE:
  528. if (!handshakeProtocol.getStatus().equals(
  529. SSLEngineResult.HandshakeStatus
  530. .NOT_HANDSHAKING)) {
  531. // handshake protocol got addressed to it message
  532. // and did not ignore it, so it's a rehandshake
  533. doHandshake();
  534. }
  535. break;
  536. case ContentType.ALERT:
  537. processAlert();
  538. if (socket_was_closed) {
  539. return;
  540. }
  541. break;
  542. case ContentType.APPLICATION_DATA:
  543. if (logger != null) {
  544. logger.println(
  545. "SSLSocket.needAppData: got the data");
  546. }
  547. break;
  548. default:
  549. // will throw exception
  550. reportFatalAlert(AlertProtocol.UNEXPECTED_MESSAGE,
  551. new SSLException("Unexpected message of type "
  552. + type + " has been got"));
  553. }
  554. if (alertProtocol.hasAlert()) {
  555. // warning alert occurred during wrap or unwrap
  556. // (note: fatal alert causes AlertException
  557. // to be thrown)
  558. output.write(alertProtocol.wrap());
  559. alertProtocol.setProcessed();
  560. }
  561. if (socket_was_closed) {
  562. appDataIS.setEnd();
  563. return;
  564. }
  565. }
  566. } catch (AlertException e) {
  567. // will throw exception
  568. reportFatalAlert(e.getDescriptionCode(), e.getReason());
  569. } catch (EndOfSourceException e) {
  570. // end of socket's input stream has been reached
  571. appDataIS.setEnd();
  572. }
  573. if (logger != null) {
  574. logger.println("SSLSocket.needAppData: app data len: "
  575. + appDataIS.available());
  576. }
  577. }
  578. /**
  579. * This method is called by SSLSocketOutputStream when a client application
  580. * tries to send the data over ssl protocol.
  581. */
  582. protected void writeAppData(byte[] data, int offset, int len) throws IOException {
  583. if (!handshake_started) {
  584. startHandshake();
  585. }
  586. if (logger != null) {
  587. logger.println("SSLSocket.writeAppData: " +
  588. len + " " + SSLRecordProtocol.MAX_DATA_LENGTH);
  589. //logger.println(new String(data, offset, len));
  590. }
  591. try {
  592. if (len < SSLRecordProtocol.MAX_DATA_LENGTH) {
  593. output.write(recordProtocol.wrap(ContentType.APPLICATION_DATA,
  594. data, offset, len));
  595. } else {
  596. while (len >= SSLRecordProtocol.MAX_DATA_LENGTH) {
  597. output.write(recordProtocol.wrap(
  598. ContentType.APPLICATION_DATA, data, offset,
  599. SSLRecordProtocol.MAX_DATA_LENGTH));
  600. offset += SSLRecordProtocol.MAX_DATA_LENGTH;
  601. len -= SSLRecordProtocol.MAX_DATA_LENGTH;
  602. }
  603. if (len > 0) {
  604. output.write(
  605. recordProtocol.wrap(ContentType.APPLICATION_DATA,
  606. data, offset, len));
  607. }
  608. }
  609. } catch (AlertException e) {
  610. // will throw exception
  611. reportFatalAlert(e.getDescriptionCode(), e.getReason());
  612. }
  613. }
  614. /*
  615. * Performs handshake process over this connection. The handshake
  616. * process is directed by the handshake status code provided by
  617. * handshake protocol. If this status is NEED_WRAP, method retrieves
  618. * handshake message from handshake protocol and sends it to another peer.
  619. * If this status is NEED_UNWRAP, method receives and processes handshake
  620. * message from another peer. Each of this stages (wrap/unwrap) change
  621. * the state of handshake protocol and this process is performed
  622. * until handshake status is FINISHED. After handshake process is finished
  623. * handshake completed event are sent to the registered listeners.
  624. * For more information about the handshake process see
  625. * TLS v1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 7.3.
  626. */
  627. private void doHandshake() throws IOException {
  628. SSLEngineResult.HandshakeStatus status;
  629. int type;
  630. try {
  631. while (!(status = handshakeProtocol.getStatus()).equals(
  632. SSLEngineResult.HandshakeStatus.FINISHED)) {
  633. if (logger != null) {
  634. String s = (status.equals(
  635. SSLEngineResult.HandshakeStatus.NEED_WRAP))
  636. ? "NEED_WRAP"
  637. : (status.equals(
  638. SSLEngineResult.HandshakeStatus.NEED_UNWRAP))
  639. ? "NEED_UNWRAP"
  640. : "STATUS: OTHER!";
  641. logger.println("SSLSocketImpl: HS status: "+s+" "+status);
  642. }
  643. if (status.equals(SSLEngineResult.HandshakeStatus.NEED_WRAP)) {
  644. output.write(handshakeProtocol.wrap());
  645. } else if (status.equals(
  646. SSLEngineResult.HandshakeStatus.NEED_UNWRAP)) {
  647. // read and unwrap the record contained in the transport
  648. // input stream (SSLStreamedInput), pass it
  649. // to appropriate client protocol (alert, handshake, or app)
  650. // and retrieve the type of unwrapped data
  651. switch (type = recordProtocol.unwrap()) {
  652. case ContentType.HANDSHAKE:
  653. case ContentType.CHANGE_CIPHER_SPEC:
  654. break;
  655. case ContentType.APPLICATION_DATA:
  656. // So it's rehandshake and
  657. // if app data buffer will be overloaded
  658. // it will throw alert exception.
  659. // Probably we should count the number of
  660. // not handshaking data and make additional
  661. // constraints (do not expect buffer overflow).
  662. break;
  663. case ContentType.ALERT:
  664. processAlert();
  665. if (socket_was_closed) {
  666. return;
  667. }
  668. break;
  669. default:
  670. // will throw exception
  671. reportFatalAlert(AlertProtocol.UNEXPECTED_MESSAGE,
  672. new SSLException(
  673. "Unexpected message of type "
  674. + type + " has been got"));
  675. }
  676. } else {
  677. // will throw exception
  678. reportFatalAlert(AlertProtocol.INTERNAL_ERROR,
  679. new SSLException(
  680. "Handshake passed unexpected status: "+status));
  681. }
  682. if (alertProtocol.hasAlert()) {
  683. // warning alert occurred during wrap or unwrap
  684. // (note: fatal alert causes AlertException
  685. // to be thrown)
  686. output.write(alertProtocol.wrap());
  687. alertProtocol.setProcessed();
  688. }
  689. }
  690. } catch (EndOfSourceException e) {
  691. appDataIS.setEnd();
  692. throw new IOException("Connection was closed");
  693. } catch (AlertException e) {
  694. // will throw exception
  695. reportFatalAlert(e.getDescriptionCode(), e.getReason());
  696. }
  697. session = recordProtocol.getSession();
  698. if (listeners != null) {
  699. // notify the listeners
  700. HandshakeCompletedEvent event =
  701. new HandshakeCompletedEvent(this, session);
  702. int size = listeners.size();
  703. for (int i=0; i<size; i++) {
  704. listeners.get(i)
  705. .handshakeCompleted(event);
  706. }
  707. }
  708. }
  709. /*
  710. * Process received alert message
  711. */
  712. private void processAlert() throws IOException {
  713. if (!alertProtocol.hasAlert()) {
  714. return;
  715. }
  716. if (alertProtocol.isFatalAlert()) {
  717. alertProtocol.setProcessed();
  718. String description = "Fatal alert received "
  719. + alertProtocol.getAlertDescription();
  720. shutdown();
  721. throw new SSLException(description);
  722. }
  723. if (logger != null) {
  724. logger.println("Warning alert received: "
  725. + alertProtocol.getAlertDescription());
  726. }
  727. switch(alertProtocol.getDescriptionCode()) {
  728. case AlertProtocol.CLOSE_NOTIFY:
  729. alertProtocol.setProcessed();
  730. appDataIS.setEnd();
  731. close();
  732. return;
  733. default:
  734. alertProtocol.setProcessed();
  735. // TODO: process other warning messages
  736. }
  737. }
  738. /*
  739. * Sends fatal alert message and throws exception
  740. */
  741. private void reportFatalAlert(byte description_code,
  742. SSLException reason) throws IOException {
  743. alertProtocol.alert(AlertProtocol.FATAL, description_code);
  744. try {
  745. // the output stream can be closed
  746. output.write(alertProtocol.wrap());
  747. } catch (IOException ex) { }
  748. alertProtocol.setProcessed();
  749. shutdown();
  750. throw reason;
  751. }
  752. }