SSLEngineImpl.java 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. /* SSLEngineImpl.java -- implementation of SSLEngine.
  2. Copyright (C) 2006 Free Software Foundation, Inc.
  3. This file is a part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or (at
  7. your option) any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  15. USA
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package gnu.javax.net.ssl.provider;
  32. import gnu.classpath.debug.Component;
  33. import gnu.classpath.debug.SystemLogger;
  34. import gnu.java.security.util.ByteBufferOutputStream;
  35. import gnu.javax.net.ssl.Session;
  36. import gnu.javax.net.ssl.SSLRecordHandler;
  37. import java.nio.BufferOverflowException;
  38. import java.nio.ByteBuffer;
  39. import java.nio.ByteOrder;
  40. import java.security.NoSuchAlgorithmException;
  41. import java.util.ArrayList;
  42. import java.util.List;
  43. import java.util.zip.DataFormatException;
  44. import javax.crypto.IllegalBlockSizeException;
  45. import javax.crypto.ShortBufferException;
  46. import javax.net.ssl.SSLEngine;
  47. import javax.net.ssl.SSLEngineResult;
  48. import javax.net.ssl.SSLException;
  49. import javax.net.ssl.SSLSession;
  50. import javax.net.ssl.SSLEngineResult.HandshakeStatus;
  51. import javax.net.ssl.SSLEngineResult.Status;
  52. public final class SSLEngineImpl extends SSLEngine
  53. {
  54. final SSLContextImpl contextImpl;
  55. private SSLRecordHandler[] handlers;
  56. private static final SystemLogger logger = SystemLogger.SYSTEM;
  57. private SessionImpl session;
  58. private InputSecurityParameters insec;
  59. private OutputSecurityParameters outsec;
  60. private boolean inClosed;
  61. private boolean outClosed;
  62. private boolean createSessions;
  63. private boolean needClientAuth;
  64. private boolean wantClientAuth;
  65. private boolean initialHandshakeDone;
  66. private AbstractHandshake handshake;
  67. private Alert lastAlert;
  68. private SSLEngineResult.HandshakeStatus handshakeStatus;
  69. private boolean changeCipherSpec;
  70. private String[] enabledSuites;
  71. private String[] enabledProtocols;
  72. /**
  73. * We can receive any message chunked across multiple records,
  74. * including alerts, even though all alert messages are only two
  75. * bytes long. Handshake messages are de-chunked in the handshake
  76. * handler, change-cipher-spec messages are always empty, and we
  77. * don't care about chunking of application messages.
  78. *
  79. * This buffer will hold the incomplete alert that we receive, if
  80. * any.
  81. */
  82. private final ByteBuffer alertBuffer;
  83. private Mode mode;
  84. private enum Mode { SERVER, CLIENT }
  85. SSLEngineImpl (SSLContextImpl contextImpl, String host, int port)
  86. {
  87. super(host, port);
  88. this.contextImpl = contextImpl;
  89. handlers = new SSLRecordHandler[256];
  90. session = new SessionImpl();
  91. session.suite = CipherSuite.TLS_NULL_WITH_NULL_NULL;
  92. session.version = ProtocolVersion.TLS_1_1;
  93. byte[] sid = new byte[32];
  94. contextImpl.random.nextBytes(sid);
  95. session.setId(new Session.ID(sid));
  96. session.setRandom(contextImpl.random);
  97. if (Debug.DEBUG)
  98. logger.logv(Component.SSL_RECORD_LAYER, "generated session ID {0} with random {1}",
  99. session.id(), contextImpl.random);
  100. // Begin with no encryption.
  101. insec = new InputSecurityParameters (null, null, null, session,
  102. CipherSuite.TLS_NULL_WITH_NULL_NULL);
  103. outsec = new OutputSecurityParameters (null, null, null, session,
  104. CipherSuite.TLS_NULL_WITH_NULL_NULL);
  105. inClosed = false;
  106. outClosed = false;
  107. needClientAuth = false;
  108. wantClientAuth = false;
  109. createSessions = true;
  110. initialHandshakeDone = false;
  111. alertBuffer = ByteBuffer.wrap (new byte[2]);
  112. mode = null;
  113. lastAlert = null;
  114. handshakeStatus = SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
  115. changeCipherSpec = false;
  116. // Set up default protocols and suites.
  117. enabledProtocols = new String[] {
  118. ProtocolVersion.TLS_1_1.toString(),
  119. ProtocolVersion.TLS_1.toString(),
  120. ProtocolVersion.SSL_3.toString()
  121. };
  122. enabledSuites = defaultSuites();
  123. }
  124. static String[] defaultSuites()
  125. {
  126. return new String[] {
  127. CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA.toString(),
  128. CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA.toString(),
  129. CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA.toString(),
  130. CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA.toString(),
  131. CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA.toString(),
  132. CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA.toString(),
  133. CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA.toString(),
  134. CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA.toString(),
  135. CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA.toString(),
  136. CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.toString(),
  137. CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA.toString(),
  138. CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
  139. CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA.toString(),
  140. CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
  141. CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
  142. CipherSuite.TLS_RSA_WITH_RC4_128_MD5.toString(),
  143. CipherSuite.TLS_RSA_WITH_RC4_128_SHA.toString(),
  144. CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA.toString(),
  145. CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA.toString(),
  146. CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA.toString(),
  147. CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA.toString(),
  148. CipherSuite.TLS_RSA_WITH_DES_CBC_SHA.toString(),
  149. CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA.toString(),
  150. CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
  151. CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
  152. CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5.toString(),
  153. CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA.toString(),
  154. CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
  155. CipherSuite.TLS_RSA_WITH_NULL_MD5.toString(),
  156. CipherSuite.TLS_RSA_WITH_NULL_SHA.toString()
  157. };
  158. }
  159. // XXX implement?
  160. /*public void registerHandler (final int contentType,
  161. SSLRecordHandler handler)
  162. throws SSLException
  163. {
  164. if (type.equals (ContentType.CHANGE_CIPHER_SPEC)
  165. || type.equals (ContentType.ALERT)
  166. || type.equals (ContentType.HANDSHAKE)
  167. || type.equals (ContentType.APPLICATION_DATA))
  168. throw new SSLException ("can't override handler for content type " + type);
  169. int i = type.getValue ();
  170. if (i < 0 || i > 255)
  171. throw new SSLException ("illegal content type: " + type);
  172. handlers[i] = handler;
  173. }*/
  174. @Override
  175. public void beginHandshake () throws SSLException
  176. {
  177. if (Debug.DEBUG)
  178. logger.log(Component.SSL_HANDSHAKE, "{0} handshake begins", mode);
  179. if (mode == null)
  180. throw new IllegalStateException("setUseClientMode was never used");
  181. switch (mode)
  182. {
  183. case SERVER:
  184. if (getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
  185. throw new SSLException("handshake already in progress");
  186. try
  187. {
  188. handshake = new ServerHandshake(initialHandshakeDone, this);
  189. }
  190. catch (NoSuchAlgorithmException nsae)
  191. {
  192. throw new SSLException(nsae);
  193. }
  194. break;
  195. case CLIENT:
  196. try
  197. {
  198. handshake = new ClientHandshake(this);
  199. }
  200. catch (NoSuchAlgorithmException nsae)
  201. {
  202. throw new SSLException(nsae);
  203. }
  204. break;
  205. }
  206. }
  207. @Override
  208. public void closeInbound()
  209. {
  210. inClosed = true;
  211. }
  212. @Override
  213. public void closeOutbound()
  214. {
  215. lastAlert = new Alert(Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY);
  216. }
  217. @Override
  218. public Runnable getDelegatedTask()
  219. {
  220. if (handshake == null)
  221. return null;
  222. return handshake.getTask();
  223. }
  224. @Override
  225. public String[] getEnabledCipherSuites()
  226. {
  227. return (String[]) enabledSuites.clone();
  228. }
  229. @Override
  230. public String[] getEnabledProtocols()
  231. {
  232. return (String[]) enabledProtocols.clone();
  233. }
  234. @Override
  235. public boolean getEnableSessionCreation()
  236. {
  237. return createSessions;
  238. }
  239. @Override
  240. public HandshakeStatus getHandshakeStatus()
  241. {
  242. if (handshake == null)
  243. return HandshakeStatus.NOT_HANDSHAKING;
  244. return handshake.status();
  245. }
  246. @Override
  247. public boolean getNeedClientAuth()
  248. {
  249. return needClientAuth;
  250. }
  251. @Override
  252. public SSLSession getSession()
  253. {
  254. return session;
  255. }
  256. @Override
  257. public boolean getUseClientMode ()
  258. {
  259. return (mode == Mode.CLIENT);
  260. }
  261. @Override
  262. public boolean getWantClientAuth()
  263. {
  264. return wantClientAuth;
  265. }
  266. @Override
  267. public boolean isInboundDone()
  268. {
  269. return inClosed;
  270. }
  271. @Override
  272. public boolean isOutboundDone()
  273. {
  274. return outClosed;
  275. }
  276. @Override
  277. public void setEnableSessionCreation(final boolean createSessions)
  278. {
  279. this.createSessions = createSessions;
  280. }
  281. @Override
  282. public void setEnabledCipherSuites(final String[] suites)
  283. {
  284. if (suites.length == 0)
  285. throw new IllegalArgumentException("need at least one suite");
  286. enabledSuites = (String[]) suites.clone();
  287. }
  288. @Override
  289. public void setEnabledProtocols(final String[] protocols)
  290. {
  291. if (protocols.length == 0)
  292. throw new IllegalArgumentException("need at least one protocol");
  293. enabledProtocols = (String[]) protocols.clone();
  294. }
  295. @Override
  296. public String[] getSupportedCipherSuites()
  297. {
  298. // XXX if we ever want to support "pluggable" cipher suites, we'll need
  299. // to figure this out.
  300. return CipherSuite.availableSuiteNames().toArray(new String[0]);
  301. }
  302. @Override
  303. public String[] getSupportedProtocols()
  304. {
  305. return new String[] { ProtocolVersion.SSL_3.toString(),
  306. ProtocolVersion.TLS_1.toString(),
  307. ProtocolVersion.TLS_1_1.toString() };
  308. }
  309. @Override
  310. public void setNeedClientAuth(final boolean needClientAuth)
  311. {
  312. this.needClientAuth = needClientAuth;
  313. }
  314. @Override
  315. public void setUseClientMode (final boolean clientMode)
  316. {
  317. if (clientMode)
  318. mode = Mode.CLIENT;
  319. else
  320. mode = Mode.SERVER;
  321. }
  322. public @Override void setWantClientAuth(final boolean wantClientAuth)
  323. {
  324. this.wantClientAuth = wantClientAuth;
  325. }
  326. public @Override SSLEngineResult unwrap (final ByteBuffer source,
  327. final ByteBuffer[] sinks,
  328. final int offset, final int length)
  329. throws SSLException
  330. {
  331. if (mode == null)
  332. throw new IllegalStateException ("setUseClientMode was never called");
  333. if (inClosed)
  334. return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
  335. handshakeStatus, 0, 0);
  336. if (source.remaining() < 5)
  337. {
  338. return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW,
  339. handshakeStatus, 0, 0);
  340. }
  341. Record record = null;
  342. boolean helloV2 = false;
  343. // XXX: messages may be chunked across multiple records; does this
  344. // include the SSLv2 message? I don't think it does, but we should
  345. // make sure.
  346. if (!getUseClientMode() && (source.get(source.position()) & 0x80) == 0x80)
  347. {
  348. if (handshake == null)
  349. beginHandshake();
  350. int hellolen = source.getShort(source.position()) & 0x7FFF;
  351. this.handshake.handleV2Hello(source.slice());
  352. if (!insec.cipherSuite().equals (CipherSuite.TLS_NULL_WITH_NULL_NULL))
  353. throw new SSLException ("received SSLv2 client hello in encrypted "
  354. + "session; this is invalid.");
  355. if (Debug.DEBUG)
  356. logger.log (Component.SSL_RECORD_LAYER,
  357. "converting SSLv2 client hello to version 3 hello");
  358. source.getShort(); // skip length
  359. ClientHelloV2 v2 = new ClientHelloV2(source.slice());
  360. if (Debug.DEBUG)
  361. logger.log(Component.SSL_RECORD_LAYER, "v2 hello: {0}", v2);
  362. List<CipherSuite> suites = v2.cipherSpecs();
  363. ClientHelloBuilder hello = new ClientHelloBuilder();
  364. hello.setVersion(v2.version ());
  365. Random random = hello.random();
  366. byte[] challenge = v2.challenge();
  367. if (challenge.length < 32)
  368. {
  369. byte[] b = new byte[32];
  370. System.arraycopy(challenge, 0, b, b.length - challenge.length,
  371. challenge.length);
  372. challenge = b;
  373. }
  374. random.setGmtUnixTime((challenge[0] & 0xFF) << 24
  375. | (challenge[1] & 0xFF) << 16
  376. | (challenge[2] & 0xFF) << 8
  377. | (challenge[3] & 0xFF));
  378. random.setRandomBytes(challenge, 4);
  379. byte[] sessionId = v2.sessionId();
  380. hello.setSessionId(sessionId, 0, sessionId.length);
  381. hello.setCipherSuites(suites);
  382. ArrayList<CompressionMethod> comps = new ArrayList<CompressionMethod>(1);
  383. comps.add(CompressionMethod.NULL);
  384. hello.setCompressionMethods(comps);
  385. record = new Record(ByteBuffer.allocate(hello.length() + 9));
  386. record.setContentType(ContentType.HANDSHAKE);
  387. record.setVersion(v2.version());
  388. record.setLength(hello.length() + 4);
  389. Handshake handshake = new Handshake(record.fragment());
  390. handshake.setLength(hello.length());
  391. handshake.setType(Handshake.Type.CLIENT_HELLO);
  392. handshake.bodyBuffer().put(hello.buffer());
  393. source.position(source.position() + hellolen);
  394. helloV2 = true;
  395. }
  396. else
  397. record = new Record(source);
  398. ContentType type = record.contentType ();
  399. if (Debug.DEBUG)
  400. logger.log(Component.SSL_RECORD_LAYER, "input record:\n{0}", record);
  401. if (record.length() > session.getPacketBufferSize() - 5)
  402. {
  403. lastAlert = new Alert(Alert.Level.FATAL,
  404. Alert.Description.RECORD_OVERFLOW);
  405. throw new AlertException(lastAlert);
  406. }
  407. ByteBufferOutputStream sysMsg = null;
  408. ByteBuffer msg = null;
  409. int produced = 0;
  410. try
  411. {
  412. // Application data will get decrypted directly into the user's
  413. // output buffers.
  414. if (record.contentType() == ContentType.APPLICATION_DATA)
  415. produced = insec.decrypt(record, sinks, offset, length);
  416. else
  417. {
  418. if (insec.cipherSuite() == CipherSuite.TLS_NULL_WITH_NULL_NULL)
  419. msg = record.fragment();
  420. else
  421. {
  422. sysMsg = new ByteBufferOutputStream();
  423. insec.decrypt(record, sysMsg);
  424. }
  425. }
  426. // Advance the input buffer past the record we just read.
  427. if (!helloV2)
  428. source.position(source.position() + record.length() + 5);
  429. }
  430. catch (BufferOverflowException boe)
  431. {
  432. // We throw this if the output buffers are not large enough; signal
  433. // the caller about this.
  434. logger.log(Component.SSL_RECORD_LAYER, "buffer overflow when decrypting", boe);
  435. return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW,
  436. handshakeStatus, 0, 0);
  437. }
  438. catch (IllegalBlockSizeException ibse)
  439. {
  440. lastAlert = new Alert(Alert.Level.FATAL,
  441. Alert.Description.BAD_RECORD_MAC);
  442. throw new AlertException(lastAlert, ibse);
  443. }
  444. catch (DataFormatException dfe)
  445. {
  446. lastAlert = new Alert(Alert.Level.FATAL,
  447. Alert.Description.DECOMPRESSION_FAILURE);
  448. throw new AlertException(lastAlert, dfe);
  449. }
  450. catch (MacException me)
  451. {
  452. lastAlert = new Alert(Alert.Level.FATAL,
  453. Alert.Description.BAD_RECORD_MAC);
  454. throw new AlertException(lastAlert, me);
  455. }
  456. catch (ShortBufferException sbe)
  457. {
  458. // We've messed up if this happens.
  459. lastAlert = new Alert(Alert.Level.FATAL,
  460. Alert.Description.INTERNAL_ERROR);
  461. throw new AlertException(lastAlert, sbe);
  462. }
  463. SSLEngineResult result = null;
  464. // If we need to handle the output here, do it. Otherwise, the output
  465. // has been stored in the supplied output buffers.
  466. if (sysMsg != null)
  467. {
  468. if (Debug.DEBUG)
  469. logger.logv(Component.SSL_RECORD_LAYER, "sysmessage {0}", sysMsg);
  470. msg = sysMsg.buffer();
  471. }
  472. if (type == ContentType.CHANGE_CIPHER_SPEC)
  473. {
  474. // We *may* get a partial message, even though the message is only
  475. // one byte long.
  476. if (msg.remaining() == 0)
  477. {
  478. result = new SSLEngineResult (SSLEngineResult.Status.OK,
  479. handshakeStatus,
  480. record.length() + 5, 0);
  481. }
  482. else
  483. {
  484. byte b = msg.get();
  485. if (b != 1)
  486. throw new SSLException ("unknown ChangeCipherSpec value: " + (b & 0xFF));
  487. InputSecurityParameters params = handshake.getInputParams();
  488. logger.log (Component.SSL_RECORD_LAYER,
  489. "switching to input security parameters {0}",
  490. params.cipherSuite());
  491. insec = params;
  492. result = new SSLEngineResult (SSLEngineResult.Status.OK,
  493. handshakeStatus,
  494. record.length() + 5, 0);
  495. }
  496. }
  497. else if (type == ContentType.ALERT)
  498. {
  499. int len = 0;
  500. if (alertBuffer.position() > 0)
  501. {
  502. alertBuffer.put(msg.get());
  503. len = 1;
  504. }
  505. if (Debug.DEBUG)
  506. logger.logv(Component.SSL_RECORD_LAYER, "processing alerts {0}",
  507. Util.wrapBuffer(msg));
  508. len += msg.remaining() / 2;
  509. Alert[] alerts = new Alert[len];
  510. int i = 0;
  511. if (alertBuffer.position() > 0)
  512. {
  513. alertBuffer.flip();
  514. alerts[0] = new Alert(alertBuffer);
  515. i++;
  516. }
  517. while (i < alerts.length)
  518. {
  519. alerts[i++] = new Alert(msg.duplicate());
  520. msg.position(msg.position() + 2);
  521. }
  522. if (Debug.DEBUG)
  523. logger.logv(Component.SSL_RECORD_LAYER, "alerts: {0}", alerts.length);
  524. for (i = 0; i < alerts.length; i++)
  525. {
  526. if (alerts[i].level() == Alert.Level.FATAL)
  527. throw new AlertException(alerts[i], false);
  528. if (alerts[i].description() != Alert.Description.CLOSE_NOTIFY)
  529. logger.log(java.util.logging.Level.WARNING,
  530. "received alert: {0}", alerts[i]);
  531. if (alerts[i].description() == Alert.Description.CLOSE_NOTIFY)
  532. inClosed = true;
  533. }
  534. if (msg.hasRemaining())
  535. alertBuffer.position(0).limit(2);
  536. result = new SSLEngineResult (SSLEngineResult.Status.OK,
  537. handshakeStatus,
  538. record.length() + 5, 0);
  539. }
  540. else if (type == ContentType.HANDSHAKE)
  541. {
  542. if (handshake == null)
  543. beginHandshake();
  544. try
  545. {
  546. handshakeStatus = handshake.handleInput(msg);
  547. }
  548. catch (AlertException ae)
  549. {
  550. lastAlert = ae.alert();
  551. return new SSLEngineResult(SSLEngineResult.Status.OK,
  552. SSLEngineResult.HandshakeStatus.NEED_WRAP,
  553. 0, 0);
  554. }
  555. if (Debug.DEBUG)
  556. logger.logv(Component.SSL_HANDSHAKE, "handshake status {0}", handshakeStatus);
  557. result = new SSLEngineResult(SSLEngineResult.Status.OK,
  558. handshakeStatus,
  559. record.length() + 5,
  560. 0);
  561. if (handshakeStatus == HandshakeStatus.FINISHED)
  562. {
  563. handshake = null;
  564. handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
  565. }
  566. }
  567. else if (type == ContentType.APPLICATION_DATA)
  568. {
  569. // Do nothing more; the application data has been put into
  570. // the output buffers.
  571. result = new SSLEngineResult(SSLEngineResult.Status.OK,
  572. handshakeStatus,
  573. record.length() + 5,
  574. produced);
  575. }
  576. else
  577. {
  578. SSLRecordHandler handler = handlers[type.getValue()];
  579. if (handler != null)
  580. {
  581. result = new SSLEngineResult(SSLEngineResult.Status.OK,
  582. handshakeStatus,
  583. record.length() + 5,
  584. 0);
  585. }
  586. else
  587. throw new SSLException ("unknown content type: " + type);
  588. }
  589. if (Debug.DEBUG)
  590. logger.logv(Component.SSL_RECORD_LAYER, "return result: {0}", result);
  591. return result;
  592. }
  593. public @Override SSLEngineResult wrap (ByteBuffer[] sources, int offset, int length,
  594. ByteBuffer sink)
  595. throws SSLException
  596. {
  597. if (mode == null)
  598. throw new IllegalStateException ("setUseClientMode was never called");
  599. if (outClosed)
  600. return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
  601. handshakeStatus, 0, 0);
  602. ContentType type = null;
  603. ByteBuffer sysMessage = null;
  604. if (Debug.DEBUG)
  605. logger.logv(Component.SSL_RECORD_LAYER, "wrap {0} {1} {2} {3} / {4}",
  606. sources, offset, length, sink, getHandshakeStatus());
  607. if (lastAlert != null)
  608. {
  609. type = ContentType.ALERT;
  610. sysMessage = ByteBuffer.allocate(2);
  611. Alert alert = new Alert(sysMessage);
  612. alert.setDescription(lastAlert.description());
  613. alert.setLevel(lastAlert.level());
  614. if (lastAlert.description() == Alert.Description.CLOSE_NOTIFY)
  615. outClosed = true;
  616. }
  617. else if (changeCipherSpec)
  618. {
  619. type = ContentType.CHANGE_CIPHER_SPEC;
  620. sysMessage = ByteBuffer.allocate(1);
  621. sysMessage.put(0, (byte) 1);
  622. }
  623. else if (getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP)
  624. {
  625. // If we are not encrypting, optimize the handshake to fill
  626. // the buffer directly.
  627. if (outsec.suite() == CipherSuite.TLS_NULL_WITH_NULL_NULL)
  628. {
  629. int orig = sink.position();
  630. sink.order(ByteOrder.BIG_ENDIAN);
  631. sink.put((byte) ContentType.HANDSHAKE.getValue());
  632. sink.putShort((short) session.version.rawValue());
  633. sink.putShort((short) 0);
  634. handshakeStatus = handshake.handleOutput(sink);
  635. int produced = sink.position() - orig;
  636. sink.putShort(orig + 3, (short) (produced - 5));
  637. if (Debug.DEBUG)
  638. logger.logv(Component.SSL_RECORD_LAYER, "emitting record:\n{0}",
  639. new Record((ByteBuffer) sink.duplicate().position(orig)));
  640. SSLEngineResult result = new SSLEngineResult(SSLEngineResult.Status.OK,
  641. handshakeStatus, 0, produced);
  642. // Note, this will only happen if we transition from
  643. // TLS_NULL_WITH_NULL_NULL *to* TLS_NULL_WITH_NULL_NULL, which
  644. // doesn't make a lot of sense, but we support it anyway.
  645. if (handshakeStatus == HandshakeStatus.FINISHED)
  646. {
  647. handshake = null; // finished with it.
  648. handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
  649. }
  650. return result;
  651. }
  652. // Rough guideline; XXX.
  653. sysMessage = ByteBuffer.allocate(sink.remaining() - 2048);
  654. type = ContentType.HANDSHAKE;
  655. try
  656. {
  657. handshakeStatus = handshake.handleOutput(sysMessage);
  658. }
  659. catch (AlertException ae)
  660. {
  661. lastAlert = ae.alert();
  662. return new SSLEngineResult(Status.OK,
  663. HandshakeStatus.NEED_WRAP, 0, 0);
  664. }
  665. sysMessage.flip();
  666. if (Debug.DEBUG)
  667. logger.logv(Component.SSL_HANDSHAKE, "handshake status {0}",
  668. handshakeStatus);
  669. }
  670. int produced = 0;
  671. int consumed = 0;
  672. try
  673. {
  674. int orig = sink.position();
  675. int[] inout = null;
  676. if (sysMessage != null)
  677. {
  678. if (Debug.DEBUG)
  679. logger.logv(Component.SSL_RECORD_LAYER, "encrypt system message {0} to {1}", sysMessage, sink);
  680. inout = outsec.encrypt(new ByteBuffer[] { sysMessage }, 0, 1,
  681. type, sink);
  682. produced = inout[1];
  683. }
  684. else
  685. {
  686. if (outsec.needToSplitPayload())
  687. {
  688. inout = outsec.encrypt(sources, offset, 1,
  689. ContentType.APPLICATION_DATA, sink);
  690. consumed = inout[0];
  691. produced = inout[1];
  692. if (length > 1)
  693. {
  694. inout = outsec.encrypt(sources, offset+1, length-1,
  695. ContentType.APPLICATION_DATA, sink);
  696. consumed += inout[0];
  697. produced += inout[1];
  698. }
  699. }
  700. else
  701. {
  702. inout = outsec.encrypt(sources, offset, length,
  703. ContentType.APPLICATION_DATA, sink);
  704. consumed = inout[0];
  705. produced = inout[1];
  706. }
  707. }
  708. if (Debug.DEBUG)
  709. logger.logv(Component.SSL_RECORD_LAYER, "emitting record:\n{0}",
  710. new Record((ByteBuffer) sink.duplicate().position(orig).limit(produced)));
  711. }
  712. catch (ShortBufferException sbe)
  713. {
  714. // We don't expect this to happen, except for bugs; signal an
  715. // internal error.
  716. lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
  717. return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
  718. }
  719. catch (IllegalBlockSizeException ibse)
  720. {
  721. // We don't expect this to happen, except for bugs; signal an
  722. // internal error.
  723. lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
  724. return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
  725. }
  726. catch (DataFormatException dfe)
  727. {
  728. // We don't expect this to happen; signal an internal error.
  729. lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
  730. return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
  731. }
  732. if (lastAlert != null && lastAlert.level() == Alert.Level.FATAL)
  733. {
  734. AlertException ae = new AlertException(lastAlert);
  735. lastAlert = null;
  736. throw ae;
  737. }
  738. if (changeCipherSpec)
  739. {
  740. outsec = handshake.getOutputParams();
  741. changeCipherSpec = false;
  742. }
  743. SSLEngineResult result
  744. = new SSLEngineResult(outClosed ? SSLEngineResult.Status.CLOSED
  745. : SSLEngineResult.Status.OK,
  746. handshakeStatus, consumed, produced);
  747. if (handshakeStatus == HandshakeStatus.FINISHED)
  748. {
  749. handshake = null; // done with it.
  750. handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
  751. }
  752. return result;
  753. }
  754. // Package-private methods.
  755. SessionImpl session ()
  756. {
  757. return session;
  758. }
  759. void setSession(SessionImpl session)
  760. {
  761. this.session = session;
  762. }
  763. void changeCipherSpec()
  764. {
  765. changeCipherSpec = true;
  766. }
  767. }