1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43:
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57:
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66:
67:
70: public class SSLSocketImpl extends SSLSocket
71: {
72: private class SocketOutputStream extends OutputStream
73: {
74: private final ByteBuffer buffer;
75: private final OutputStream out;
76:
77: SocketOutputStream() throws IOException
78: {
79: buffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
80: if (underlyingSocket != null)
81: out = underlyingSocket.getOutputStream();
82: else
83: out = SSLSocketImpl.super.getOutputStream();
84: }
85:
86: @Override public void write(byte[] buf, int off, int len) throws IOException
87: {
88: if (!initialHandshakeDone
89: || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
90: {
91: doHandshake();
92: if (handshakeException != null)
93: throw handshakeException;
94: }
95:
96: int k = 0;
97: while (k < len)
98: {
99: synchronized (engine)
100: {
101: int l = Math.min(len-k, getSession().getApplicationBufferSize());
102: ByteBuffer in = ByteBuffer.wrap(buf, off+k, l);
103: SSLEngineResult result = engine.wrap(in, buffer);
104: if (result.getStatus() == Status.CLOSED)
105: return;
106: if (result.getStatus() != Status.OK)
107: throw new SSLException("unexpected SSL state " + result.getStatus());
108: buffer.flip();
109: out.write(buffer.array(), 0, buffer.limit());
110: k += result.bytesConsumed();
111: buffer.clear();
112: }
113: }
114: }
115:
116: @Override public void write(int b) throws IOException
117: {
118: write(new byte[] { (byte) b });
119: }
120:
121: @Override public void close() throws IOException
122: {
123: SSLSocketImpl.this.close();
124: }
125: }
126:
127: private class SocketInputStream extends InputStream
128: {
129: private final ByteBuffer inBuffer;
130: private final ByteBuffer appBuffer;
131: private final DataInputStream in;
132:
133: SocketInputStream() throws IOException
134: {
135: inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
136: inBuffer.limit(0);
137: appBuffer = ByteBuffer.allocate(getSession().getApplicationBufferSize());
138: appBuffer.flip();
139: if (underlyingSocket != null)
140: in = new DataInputStream(underlyingSocket.getInputStream());
141: else
142: in = new DataInputStream(SSLSocketImpl.super.getInputStream());
143: }
144:
145: @Override public int read(byte[] buf, int off, int len) throws IOException
146: {
147: if (!initialHandshakeDone ||
148: engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
149: {
150: doHandshake();
151: if (handshakeException != null)
152: throw handshakeException;
153: }
154:
155: if (!appBuffer.hasRemaining())
156: {
157: int x = in.read();
158: if (x == -1)
159: return -1;
160: inBuffer.clear();
161: inBuffer.put((byte) x);
162: inBuffer.putInt(in.readInt());
163: int reclen = inBuffer.getShort(3) & 0xFFFF;
164: in.readFully(inBuffer.array(), 5, reclen);
165: inBuffer.position(0).limit(reclen + 5);
166: synchronized (engine)
167: {
168: appBuffer.clear();
169: SSLEngineResult result = engine.unwrap(inBuffer, appBuffer);
170: Status status = result.getStatus();
171: if (status == Status.CLOSED && result.bytesProduced() == 0)
172: return -1;
173: }
174: inBuffer.compact();
175: appBuffer.flip();
176: }
177: int l = Math.min(len, appBuffer.remaining());
178: appBuffer.get(buf, off, l);
179: return l;
180: }
181:
182: @Override public int read() throws IOException
183: {
184: byte[] b = new byte[1];
185: if (read(b) == -1)
186: return -1;
187: return b[0] & 0xFF;
188: }
189: }
190:
191: private static final SystemLogger logger = SystemLogger.getSystemLogger();
192:
193: private SSLEngineImpl engine;
194: private Set<HandshakeCompletedListener> listeners;
195: private Socket underlyingSocket;
196: private boolean isHandshaking;
197: private IOException handshakeException;
198: private boolean initialHandshakeDone = false;
199: private final boolean autoClose;
200:
201: public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port)
202: {
203: this(contextImpl, host, port, new Socket(), true);
204: }
205:
206: public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port,
207: Socket underlyingSocket, boolean autoClose)
208: {
209: engine = new SSLEngineImpl(contextImpl, host, port);
210: engine.setUseClientMode(true);
211: listeners = new HashSet<HandshakeCompletedListener>();
212: this.underlyingSocket = underlyingSocket;
213: this.autoClose = autoClose;
214: }
215:
216:
219: @Override
220: public void addHandshakeCompletedListener(HandshakeCompletedListener listener)
221: {
222: listeners.add(listener);
223: }
224:
225:
228: @Override public boolean getEnableSessionCreation()
229: {
230: return engine.getEnableSessionCreation();
231: }
232:
233:
236: @Override public String[] getEnabledCipherSuites()
237: {
238: return engine.getEnabledCipherSuites();
239: }
240:
241:
244: @Override public String[] getEnabledProtocols()
245: {
246: return engine.getEnabledProtocols();
247: }
248:
249:
252: @Override public boolean getNeedClientAuth()
253: {
254: return engine.getNeedClientAuth();
255: }
256:
257:
260: @Override public SSLSession getSession()
261: {
262: return engine.getSession();
263: }
264:
265:
268: @Override public String[] getSupportedCipherSuites()
269: {
270: return engine.getSupportedCipherSuites();
271: }
272:
273:
276: @Override public String[] getSupportedProtocols()
277: {
278: return engine.getSupportedProtocols();
279: }
280:
281:
284: @Override public boolean getUseClientMode()
285: {
286: return engine.getUseClientMode();
287: }
288:
289:
292: @Override public boolean getWantClientAuth()
293: {
294: return engine.getWantClientAuth();
295: }
296:
297:
300: @Override
301: public void removeHandshakeCompletedListener(HandshakeCompletedListener listener)
302: {
303: listeners.remove(listener);
304: }
305:
306:
309: @Override public void setEnableSessionCreation(boolean enable)
310: {
311: engine.setEnableSessionCreation(enable);
312: }
313:
314:
317: @Override public void setEnabledCipherSuites(String[] suites)
318: {
319: engine.setEnabledCipherSuites(suites);
320: }
321:
322:
325: @Override public void setEnabledProtocols(String[] protocols)
326: {
327: engine.setEnabledProtocols(protocols);
328: }
329:
330:
333: @Override public void setNeedClientAuth(boolean needAuth)
334: {
335: engine.setNeedClientAuth(needAuth);
336: }
337:
338:
341: @Override public void setUseClientMode(boolean clientMode)
342: {
343: engine.setUseClientMode(clientMode);
344: }
345:
346:
349: @Override public void setWantClientAuth(boolean wantAuth)
350: {
351: engine.setWantClientAuth(wantAuth);
352: }
353:
354:
357: @Override public void startHandshake() throws IOException
358: {
359: if (isHandshaking)
360: return;
361:
362: if (handshakeException != null)
363: throw handshakeException;
364:
365: Thread t = new Thread(new Runnable()
366: {
367: public void run()
368: {
369: try
370: {
371: doHandshake();
372: }
373: catch (IOException ioe)
374: {
375: handshakeException = ioe;
376: }
377: }
378: }, "HandshakeThread@" + System.identityHashCode(this));
379: t.start();
380: }
381:
382: void doHandshake() throws IOException
383: {
384: synchronized (engine)
385: {
386: if (isHandshaking)
387: {
388: try
389: {
390: engine.wait();
391: }
392: catch (InterruptedException ie)
393: {
394: }
395: return;
396: }
397: isHandshaking = true;
398: }
399:
400: if (initialHandshakeDone)
401: throw new SSLException("rehandshaking not yet implemented");
402:
403: long now = -System.currentTimeMillis();
404: engine.beginHandshake();
405:
406: HandshakeStatus status = engine.getHandshakeStatus();
407: assert(status != HandshakeStatus.NOT_HANDSHAKING);
408:
409: ByteBuffer inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
410: inBuffer.position(inBuffer.limit());
411: ByteBuffer outBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
412: ByteBuffer emptyBuffer = ByteBuffer.allocate(0);
413: SSLEngineResult result = null;
414:
415: DataInputStream sockIn = new DataInputStream(underlyingSocket.getInputStream());
416: OutputStream sockOut = underlyingSocket.getOutputStream();
417:
418: try
419: {
420: while (status != HandshakeStatus.NOT_HANDSHAKING
421: && status != HandshakeStatus.FINISHED)
422: {
423: logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}",
424: status);
425:
426: if (inBuffer.capacity() != getSession().getPacketBufferSize())
427: {
428: ByteBuffer b
429: = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
430: if (inBuffer.hasRemaining())
431: b.put(inBuffer).flip();
432: inBuffer = b;
433: }
434: if (outBuffer.capacity() != getSession().getPacketBufferSize())
435: outBuffer
436: = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
437:
438: switch (status)
439: {
440: case NEED_UNWRAP:
441:
442: inBuffer.clear();
443: int i = sockIn.read();
444: if (i == -1)
445: throw new EOFException();
446: if ((i & 0x80) == 0x80)
447: {
448: inBuffer.put((byte) i);
449: int v2len = (i & 0x7f) << 8;
450: i = sockIn.read();
451: v2len = v2len | (i & 0xff);
452: inBuffer.put((byte) i);
453: sockIn.readFully(inBuffer.array(), 2, v2len);
454: inBuffer.position(0).limit(v2len + 2);
455: }
456: else
457: {
458: inBuffer.put((byte) i);
459: inBuffer.putInt(sockIn.readInt());
460: int reclen = inBuffer.getShort(3) & 0xFFFF;
461: sockIn.readFully(inBuffer.array(), 5, reclen);
462: inBuffer.position(0).limit(reclen + 5);
463: }
464: result = engine.unwrap(inBuffer, emptyBuffer);
465: status = result.getHandshakeStatus();
466: if (result.getStatus() != Status.OK)
467: throw new SSLException("unexpected SSL status "
468: + result.getStatus());
469: break;
470:
471: case NEED_WRAP:
472: {
473: outBuffer.clear();
474: result = engine.wrap(emptyBuffer, outBuffer);
475: status = result.getHandshakeStatus();
476: if (result.getStatus() != Status.OK)
477: throw new SSLException("unexpected SSL status "
478: + result.getStatus());
479: outBuffer.flip();
480: sockOut.write(outBuffer.array(), outBuffer.position(),
481: outBuffer.limit());
482: }
483: break;
484:
485: case NEED_TASK:
486: {
487: Runnable task;
488: while ((task = engine.getDelegatedTask()) != null)
489: task.run();
490: status = engine.getHandshakeStatus();
491: }
492: break;
493:
494: case FINISHED:
495: break;
496: }
497: }
498:
499: initialHandshakeDone = true;
500:
501: HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession());
502: for (HandshakeCompletedListener l : listeners)
503: {
504: try
505: {
506: l.handshakeCompleted(hce);
507: }
508: catch (ThreadDeath td)
509: {
510: throw td;
511: }
512: catch (Throwable x)
513: {
514: logger.log(Component.WARNING,
515: "HandshakeCompletedListener threw exception", x);
516: }
517: }
518:
519: now += System.currentTimeMillis();
520: if (Debug.DEBUG)
521: logger.logv(Component.SSL_HANDSHAKE,
522: "handshake completed in {0}ms in thread {1}", now,
523: Thread.currentThread().getName());
524: }
525: catch (SSLException ssle)
526: {
527: handshakeException = ssle;
528: throw ssle;
529: }
530: finally
531: {
532: synchronized (engine)
533: {
534: isHandshaking = false;
535: engine.notifyAll();
536: }
537: }
538: }
539:
540:
541:
542: @Override public void bind(SocketAddress bindpoint) throws IOException
543: {
544: underlyingSocket.bind(bindpoint);
545: }
546:
547: @Override public void connect(SocketAddress endpoint) throws IOException
548: {
549: underlyingSocket.connect(endpoint);
550: }
551:
552: @Override public void connect(SocketAddress endpoint, int timeout)
553: throws IOException
554: {
555: underlyingSocket.connect(endpoint, timeout);
556: }
557:
558: @Override public InetAddress getInetAddress()
559: {
560: return underlyingSocket.getInetAddress();
561: }
562:
563: @Override public InetAddress getLocalAddress()
564: {
565: return underlyingSocket.getLocalAddress();
566: }
567:
568: @Override public int getPort()
569: {
570: return underlyingSocket.getPort();
571: }
572:
573: @Override public int getLocalPort()
574: {
575: return underlyingSocket.getLocalPort();
576: }
577:
578: @Override public SocketAddress getRemoteSocketAddress()
579: {
580: return underlyingSocket.getRemoteSocketAddress();
581: }
582:
583: public SocketAddress getLocalSocketAddress()
584: {
585: return underlyingSocket.getLocalSocketAddress();
586: }
587:
588: @Override public SocketChannel getChannel()
589: {
590: throw new UnsupportedOperationException("use javax.net.ssl.SSLEngine for NIO");
591: }
592:
593: @Override public InputStream getInputStream() throws IOException
594: {
595: return new SocketInputStream();
596: }
597:
598: @Override public OutputStream getOutputStream() throws IOException
599: {
600: return new SocketOutputStream();
601: }
602:
603: @Override public void setTcpNoDelay(boolean on) throws SocketException
604: {
605: underlyingSocket.setTcpNoDelay(on);
606: }
607:
608: @Override public boolean getTcpNoDelay() throws SocketException
609: {
610: return underlyingSocket.getTcpNoDelay();
611: }
612:
613: @Override public void setSoLinger(boolean on, int linger) throws SocketException
614: {
615: underlyingSocket.setSoLinger(on, linger);
616: }
617:
618: public int getSoLinger() throws SocketException
619: {
620: return underlyingSocket.getSoLinger();
621: }
622:
623: @Override public void sendUrgentData(int x) throws IOException
624: {
625: throw new UnsupportedOperationException("not supported");
626: }
627:
628: @Override public void setOOBInline(boolean on) throws SocketException
629: {
630: underlyingSocket.setOOBInline(on);
631: }
632:
633: @Override public boolean getOOBInline() throws SocketException
634: {
635: return underlyingSocket.getOOBInline();
636: }
637:
638: @Override public void setSoTimeout(int timeout) throws SocketException
639: {
640: underlyingSocket.setSoTimeout(timeout);
641: }
642:
643: @Override public int getSoTimeout() throws SocketException
644: {
645: return underlyingSocket.getSoTimeout();
646: }
647:
648: @Override public void setSendBufferSize(int size) throws SocketException
649: {
650: underlyingSocket.setSendBufferSize(size);
651: }
652:
653: @Override public int getSendBufferSize() throws SocketException
654: {
655: return underlyingSocket.getSendBufferSize();
656: }
657:
658: @Override public void setReceiveBufferSize(int size) throws SocketException
659: {
660: underlyingSocket.setReceiveBufferSize(size);
661: }
662:
663: @Override public int getReceiveBufferSize() throws SocketException
664: {
665: return underlyingSocket.getReceiveBufferSize();
666: }
667:
668: @Override public void setKeepAlive(boolean on) throws SocketException
669: {
670: underlyingSocket.setKeepAlive(on);
671: }
672:
673: @Override public boolean getKeepAlive() throws SocketException
674: {
675: return underlyingSocket.getKeepAlive();
676: }
677:
678: @Override public void setTrafficClass(int tc) throws SocketException
679: {
680: underlyingSocket.setTrafficClass(tc);
681: }
682:
683: @Override public int getTrafficClass() throws SocketException
684: {
685: return underlyingSocket.getTrafficClass();
686: }
687:
688: @Override public void setReuseAddress(boolean reuseAddress)
689: throws SocketException
690: {
691: underlyingSocket.setReuseAddress(reuseAddress);
692: }
693:
694: @Override public boolean getReuseAddress() throws SocketException
695: {
696: return underlyingSocket.getReuseAddress();
697: }
698:
699: @Override public void close() throws IOException
700: {
701:
702: if (autoClose)
703: underlyingSocket.close();
704: }
705:
706: @Override public void shutdownInput() throws IOException
707: {
708: underlyingSocket.shutdownInput();
709: }
710:
711: @Override public void shutdownOutput() throws IOException
712: {
713: underlyingSocket.shutdownOutput();
714: }
715:
716: @Override public boolean isConnected()
717: {
718: return underlyingSocket.isConnected();
719: }
720:
721: @Override public boolean isBound()
722: {
723: return underlyingSocket.isBound();
724: }
725:
726: @Override public boolean isClosed()
727: {
728: return underlyingSocket.isClosed();
729: }
730:
731: @Override public boolean isInputShutdown()
732: {
733: return underlyingSocket.isInputShutdown();
734: }
735:
736: @Override public boolean isOutputShutdown()
737: {
738: return underlyingSocket.isOutputShutdown();
739: }
740: }