Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java
41159 views
1
/*
2
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.net.httpserver;
27
28
import java.net.*;
29
import java.nio.*;
30
import java.io.*;
31
import java.nio.channels.*;
32
import java.util.concurrent.locks.*;
33
import javax.net.ssl.*;
34
import javax.net.ssl.SSLEngineResult.*;
35
import com.sun.net.httpserver.*;
36
37
/**
38
* given a non-blocking SocketChannel, it produces
39
* (blocking) streams which encrypt/decrypt the SSL content
40
* and handle the SSL handshaking automatically.
41
*/
42
43
class SSLStreams {
44
45
SSLContext sslctx;
46
SocketChannel chan;
47
TimeSource time;
48
ServerImpl server;
49
SSLEngine engine;
50
EngineWrapper wrapper;
51
OutputStream os;
52
InputStream is;
53
54
/* held by thread doing the hand-shake on this connection */
55
Lock handshaking = new ReentrantLock();
56
57
SSLStreams (ServerImpl server, SSLContext sslctx, SocketChannel chan) throws IOException {
58
this.server = server;
59
this.time= (TimeSource)server;
60
this.sslctx= sslctx;
61
this.chan= chan;
62
InetSocketAddress addr =
63
(InetSocketAddress)chan.socket().getRemoteSocketAddress();
64
engine = sslctx.createSSLEngine (addr.getHostName(), addr.getPort());
65
engine.setUseClientMode (false);
66
HttpsConfigurator cfg = server.getHttpsConfigurator();
67
configureEngine (cfg, addr);
68
wrapper = new EngineWrapper (chan, engine);
69
}
70
71
private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr){
72
if (cfg != null) {
73
Parameters params = new Parameters (cfg, addr);
74
//BEGIN_TIGER_EXCLUDE
75
cfg.configure (params);
76
SSLParameters sslParams = params.getSSLParameters();
77
if (sslParams != null) {
78
engine.setSSLParameters (sslParams);
79
} else
80
//END_TIGER_EXCLUDE
81
{
82
/* tiger compatibility */
83
if (params.getCipherSuites() != null) {
84
try {
85
engine.setEnabledCipherSuites (
86
params.getCipherSuites()
87
);
88
} catch (IllegalArgumentException e) { /* LOG */}
89
}
90
engine.setNeedClientAuth (params.getNeedClientAuth());
91
engine.setWantClientAuth (params.getWantClientAuth());
92
if (params.getProtocols() != null) {
93
try {
94
engine.setEnabledProtocols (
95
params.getProtocols()
96
);
97
} catch (IllegalArgumentException e) { /* LOG */}
98
}
99
}
100
}
101
}
102
103
class Parameters extends HttpsParameters {
104
InetSocketAddress addr;
105
HttpsConfigurator cfg;
106
107
Parameters (HttpsConfigurator cfg, InetSocketAddress addr) {
108
this.addr = addr;
109
this.cfg = cfg;
110
}
111
public InetSocketAddress getClientAddress () {
112
return addr;
113
}
114
public HttpsConfigurator getHttpsConfigurator() {
115
return cfg;
116
}
117
//BEGIN_TIGER_EXCLUDE
118
SSLParameters params;
119
public void setSSLParameters (SSLParameters p) {
120
params = p;
121
}
122
SSLParameters getSSLParameters () {
123
return params;
124
}
125
//END_TIGER_EXCLUDE
126
}
127
128
/**
129
* cleanup resources allocated inside this object
130
*/
131
void close () throws IOException {
132
wrapper.close();
133
}
134
135
/**
136
* return the SSL InputStream
137
*/
138
InputStream getInputStream () throws IOException {
139
if (is == null) {
140
is = new InputStream();
141
}
142
return is;
143
}
144
145
/**
146
* return the SSL OutputStream
147
*/
148
OutputStream getOutputStream () throws IOException {
149
if (os == null) {
150
os = new OutputStream();
151
}
152
return os;
153
}
154
155
SSLEngine getSSLEngine () {
156
return engine;
157
}
158
159
/**
160
* request the engine to repeat the handshake on this session
161
* the handshake must be driven by reads/writes on the streams
162
* Normally, not necessary to call this.
163
*/
164
void beginHandshake() throws SSLException {
165
engine.beginHandshake();
166
}
167
168
class WrapperResult {
169
SSLEngineResult result;
170
171
/* if passed in buffer was not big enough then the
172
* a reallocated buffer is returned here
173
*/
174
ByteBuffer buf;
175
}
176
177
int app_buf_size;
178
int packet_buf_size;
179
180
enum BufType {
181
PACKET, APPLICATION
182
};
183
184
private ByteBuffer allocate (BufType type) {
185
return allocate (type, -1);
186
}
187
188
private ByteBuffer allocate (BufType type, int len) {
189
assert engine != null;
190
synchronized (this) {
191
int size;
192
if (type == BufType.PACKET) {
193
if (packet_buf_size == 0) {
194
SSLSession sess = engine.getSession();
195
packet_buf_size = sess.getPacketBufferSize();
196
}
197
if (len > packet_buf_size) {
198
packet_buf_size = len;
199
}
200
size = packet_buf_size;
201
} else {
202
if (app_buf_size == 0) {
203
SSLSession sess = engine.getSession();
204
app_buf_size = sess.getApplicationBufferSize();
205
}
206
if (len > app_buf_size) {
207
app_buf_size = len;
208
}
209
size = app_buf_size;
210
}
211
return ByteBuffer.allocate (size);
212
}
213
}
214
215
/* reallocates the buffer by :-
216
* 1. creating a new buffer double the size of the old one
217
* 2. putting the contents of the old buffer into the new one
218
* 3. set xx_buf_size to the new size if it was smaller than new size
219
*
220
* flip is set to true if the old buffer needs to be flipped
221
* before it is copied.
222
*/
223
private ByteBuffer realloc (ByteBuffer b, boolean flip, BufType type) {
224
synchronized (this) {
225
int nsize = 2 * b.capacity();
226
ByteBuffer n = allocate (type, nsize);
227
if (flip) {
228
b.flip();
229
}
230
n.put(b);
231
b = n;
232
}
233
return b;
234
}
235
/**
236
* This is a thin wrapper over SSLEngine and the SocketChannel,
237
* which guarantees the ordering of wraps/unwraps with respect to the underlying
238
* channel read/writes. It handles the UNDER/OVERFLOW status codes
239
* It does not handle the handshaking status codes, or the CLOSED status code
240
* though once the engine is closed, any attempt to read/write to it
241
* will get an exception. The overall result is returned.
242
* It functions synchronously/blocking
243
*/
244
class EngineWrapper {
245
246
SocketChannel chan;
247
SSLEngine engine;
248
Object wrapLock, unwrapLock;
249
ByteBuffer unwrap_src, wrap_dst;
250
boolean closed = false;
251
int u_remaining; // the number of bytes left in unwrap_src after an unwrap()
252
253
EngineWrapper (SocketChannel chan, SSLEngine engine) throws IOException {
254
this.chan = chan;
255
this.engine = engine;
256
wrapLock = new Object();
257
unwrapLock = new Object();
258
unwrap_src = allocate(BufType.PACKET);
259
wrap_dst = allocate(BufType.PACKET);
260
}
261
262
void close () throws IOException {
263
}
264
265
/* try to wrap and send the data in src. Handles OVERFLOW.
266
* Might block if there is an outbound blockage or if another
267
* thread is calling wrap(). Also, might not send any data
268
* if an unwrap is needed.
269
*/
270
WrapperResult wrapAndSend(ByteBuffer src) throws IOException {
271
return wrapAndSendX(src, false);
272
}
273
274
WrapperResult wrapAndSendX(ByteBuffer src, boolean ignoreClose) throws IOException {
275
if (closed && !ignoreClose) {
276
throw new IOException ("Engine is closed");
277
}
278
Status status;
279
WrapperResult r = new WrapperResult();
280
synchronized (wrapLock) {
281
wrap_dst.clear();
282
do {
283
r.result = engine.wrap (src, wrap_dst);
284
status = r.result.getStatus();
285
if (status == Status.BUFFER_OVERFLOW) {
286
wrap_dst = realloc (wrap_dst, true, BufType.PACKET);
287
}
288
} while (status == Status.BUFFER_OVERFLOW);
289
if (status == Status.CLOSED && !ignoreClose) {
290
closed = true;
291
return r;
292
}
293
if (r.result.bytesProduced() > 0) {
294
wrap_dst.flip();
295
int l = wrap_dst.remaining();
296
assert l == r.result.bytesProduced();
297
while (l>0) {
298
l -= chan.write (wrap_dst);
299
}
300
}
301
}
302
return r;
303
}
304
305
/* block until a complete message is available and return it
306
* in dst, together with the Result. dst may have been re-allocated
307
* so caller should check the returned value in Result
308
* If handshaking is in progress then, possibly no data is returned
309
*/
310
WrapperResult recvAndUnwrap(ByteBuffer dst) throws IOException {
311
Status status = Status.OK;
312
WrapperResult r = new WrapperResult();
313
r.buf = dst;
314
if (closed) {
315
throw new IOException ("Engine is closed");
316
}
317
boolean needData;
318
if (u_remaining > 0) {
319
unwrap_src.compact();
320
unwrap_src.flip();
321
needData = false;
322
} else {
323
unwrap_src.clear();
324
needData = true;
325
}
326
synchronized (unwrapLock) {
327
int x;
328
do {
329
if (needData) {
330
do {
331
x = chan.read (unwrap_src);
332
} while (x == 0);
333
if (x == -1) {
334
throw new IOException ("connection closed for reading");
335
}
336
unwrap_src.flip();
337
}
338
r.result = engine.unwrap (unwrap_src, r.buf);
339
status = r.result.getStatus();
340
if (status == Status.BUFFER_UNDERFLOW) {
341
if (unwrap_src.limit() == unwrap_src.capacity()) {
342
/* buffer not big enough */
343
unwrap_src = realloc (
344
unwrap_src, false, BufType.PACKET
345
);
346
} else {
347
/* Buffer not full, just need to read more
348
* data off the channel. Reset pointers
349
* for reading off SocketChannel
350
*/
351
unwrap_src.position (unwrap_src.limit());
352
unwrap_src.limit (unwrap_src.capacity());
353
}
354
needData = true;
355
} else if (status == Status.BUFFER_OVERFLOW) {
356
r.buf = realloc (r.buf, true, BufType.APPLICATION);
357
needData = false;
358
} else if (status == Status.CLOSED) {
359
closed = true;
360
r.buf.flip();
361
return r;
362
}
363
} while (status != Status.OK);
364
}
365
u_remaining = unwrap_src.remaining();
366
return r;
367
}
368
}
369
370
/**
371
* send the data in the given ByteBuffer. If a handshake is needed
372
* then this is handled within this method. When this call returns,
373
* all of the given user data has been sent and any handshake has been
374
* completed. Caller should check if engine has been closed.
375
*/
376
public WrapperResult sendData (ByteBuffer src) throws IOException {
377
WrapperResult r=null;
378
while (src.remaining() > 0) {
379
r = wrapper.wrapAndSend(src);
380
Status status = r.result.getStatus();
381
if (status == Status.CLOSED) {
382
doClosure ();
383
return r;
384
}
385
HandshakeStatus hs_status = r.result.getHandshakeStatus();
386
if (hs_status != HandshakeStatus.FINISHED &&
387
hs_status != HandshakeStatus.NOT_HANDSHAKING)
388
{
389
doHandshake(hs_status);
390
}
391
}
392
return r;
393
}
394
395
/**
396
* read data thru the engine into the given ByteBuffer. If the
397
* given buffer was not large enough, a new one is allocated
398
* and returned. This call handles handshaking automatically.
399
* Caller should check if engine has been closed.
400
*/
401
public WrapperResult recvData (ByteBuffer dst) throws IOException {
402
/* we wait until some user data arrives */
403
WrapperResult r = null;
404
assert dst.position() == 0;
405
while (dst.position() == 0) {
406
r = wrapper.recvAndUnwrap (dst);
407
dst = (r.buf != dst) ? r.buf: dst;
408
Status status = r.result.getStatus();
409
if (status == Status.CLOSED) {
410
doClosure ();
411
return r;
412
}
413
414
HandshakeStatus hs_status = r.result.getHandshakeStatus();
415
if (hs_status != HandshakeStatus.FINISHED &&
416
hs_status != HandshakeStatus.NOT_HANDSHAKING)
417
{
418
doHandshake (hs_status);
419
}
420
}
421
dst.flip();
422
return r;
423
}
424
425
/* we've received a close notify. Need to call wrap to send
426
* the response
427
*/
428
void doClosure () throws IOException {
429
try {
430
handshaking.lock();
431
ByteBuffer tmp = allocate(BufType.APPLICATION);
432
WrapperResult r;
433
Status st;
434
HandshakeStatus hs;
435
do {
436
tmp.clear();
437
tmp.flip ();
438
r = wrapper.wrapAndSendX (tmp, true);
439
hs = r.result.getHandshakeStatus();
440
st = r.result.getStatus();
441
} while (st != Status.CLOSED &&
442
!(st == Status.OK && hs == HandshakeStatus.NOT_HANDSHAKING));
443
} finally {
444
handshaking.unlock();
445
}
446
}
447
448
/* do the (complete) handshake after acquiring the handshake lock.
449
* If two threads call this at the same time, then we depend
450
* on the wrapper methods being idempotent. eg. if wrapAndSend()
451
* is called with no data to send then there must be no problem
452
*/
453
@SuppressWarnings("fallthrough")
454
void doHandshake (HandshakeStatus hs_status) throws IOException {
455
try {
456
handshaking.lock();
457
ByteBuffer tmp = allocate(BufType.APPLICATION);
458
while (hs_status != HandshakeStatus.FINISHED &&
459
hs_status != HandshakeStatus.NOT_HANDSHAKING)
460
{
461
WrapperResult r = null;
462
switch (hs_status) {
463
case NEED_TASK:
464
Runnable task;
465
while ((task = engine.getDelegatedTask()) != null) {
466
/* run in current thread, because we are already
467
* running an external Executor
468
*/
469
task.run();
470
}
471
/* fall thru - call wrap again */
472
case NEED_WRAP:
473
tmp.clear();
474
tmp.flip();
475
r = wrapper.wrapAndSend(tmp);
476
break;
477
478
case NEED_UNWRAP:
479
tmp.clear();
480
r = wrapper.recvAndUnwrap (tmp);
481
if (r.buf != tmp) {
482
tmp = r.buf;
483
}
484
assert tmp.position() == 0;
485
break;
486
}
487
hs_status = r.result.getHandshakeStatus();
488
}
489
} finally {
490
handshaking.unlock();
491
}
492
}
493
494
/**
495
* represents an SSL input stream. Multiple https requests can
496
* be sent over one stream. closing this stream causes an SSL close
497
* input.
498
*/
499
class InputStream extends java.io.InputStream {
500
501
ByteBuffer bbuf;
502
boolean closed = false;
503
504
/* this stream eof */
505
boolean eof = false;
506
507
boolean needData = true;
508
509
InputStream () {
510
bbuf = allocate (BufType.APPLICATION);
511
}
512
513
public int read (byte[] buf, int off, int len) throws IOException {
514
if (closed) {
515
throw new IOException ("SSL stream is closed");
516
}
517
if (eof) {
518
return 0;
519
}
520
int available=0;
521
if (!needData) {
522
available = bbuf.remaining();
523
needData = (available==0);
524
}
525
if (needData) {
526
bbuf.clear();
527
WrapperResult r = recvData (bbuf);
528
bbuf = r.buf== bbuf? bbuf: r.buf;
529
if ((available=bbuf.remaining()) == 0) {
530
eof = true;
531
return 0;
532
} else {
533
needData = false;
534
}
535
}
536
/* copy as much as possible from buf into users buf */
537
if (len > available) {
538
len = available;
539
}
540
bbuf.get (buf, off, len);
541
return len;
542
}
543
544
public int available () throws IOException {
545
return bbuf.remaining();
546
}
547
548
public boolean markSupported () {
549
return false; /* not possible with SSLEngine */
550
}
551
552
public void reset () throws IOException {
553
throw new IOException ("mark/reset not supported");
554
}
555
556
public long skip (long s) throws IOException {
557
int n = (int)s;
558
if (closed) {
559
throw new IOException ("SSL stream is closed");
560
}
561
if (eof) {
562
return 0;
563
}
564
int ret = n;
565
while (n > 0) {
566
if (bbuf.remaining() >= n) {
567
bbuf.position (bbuf.position()+n);
568
return ret;
569
} else {
570
n -= bbuf.remaining();
571
bbuf.clear();
572
WrapperResult r = recvData (bbuf);
573
bbuf = r.buf==bbuf? bbuf: r.buf;
574
}
575
}
576
return ret; /* not reached */
577
}
578
579
/**
580
* close the SSL connection. All data must have been consumed
581
* before this is called. Otherwise an exception will be thrown.
582
* [Note. May need to revisit this. not quite the normal close() symantics
583
*/
584
public void close () throws IOException {
585
eof = true;
586
engine.closeInbound ();
587
}
588
589
public int read (byte[] buf) throws IOException {
590
return read (buf, 0, buf.length);
591
}
592
593
byte single[] = new byte [1];
594
595
public int read () throws IOException {
596
int n = read (single, 0, 1);
597
if (n == 0) {
598
return -1;
599
} else {
600
return single[0] & 0xFF;
601
}
602
}
603
}
604
605
/**
606
* represents an SSL output stream. plain text data written to this stream
607
* is encrypted by the stream. Multiple HTTPS responses can be sent on
608
* one stream. closing this stream initiates an SSL closure
609
*/
610
class OutputStream extends java.io.OutputStream {
611
ByteBuffer buf;
612
boolean closed = false;
613
byte single[] = new byte[1];
614
615
OutputStream() {
616
buf = allocate(BufType.APPLICATION);
617
}
618
619
public void write(int b) throws IOException {
620
single[0] = (byte)b;
621
write (single, 0, 1);
622
}
623
624
public void write(byte b[]) throws IOException {
625
write (b, 0, b.length);
626
}
627
public void write(byte b[], int off, int len) throws IOException {
628
if (closed) {
629
throw new IOException ("output stream is closed");
630
}
631
while (len > 0) {
632
int l = len > buf.capacity() ? buf.capacity() : len;
633
buf.clear();
634
buf.put (b, off, l);
635
len -= l;
636
off += l;
637
buf.flip();
638
WrapperResult r = sendData (buf);
639
if (r.result.getStatus() == Status.CLOSED) {
640
closed = true;
641
if (len > 0) {
642
throw new IOException ("output stream is closed");
643
}
644
}
645
}
646
}
647
648
public void flush() throws IOException {
649
/* no-op */
650
}
651
652
public void close() throws IOException {
653
WrapperResult r=null;
654
engine.closeOutbound();
655
closed = true;
656
HandshakeStatus stat = HandshakeStatus.NEED_WRAP;
657
buf.clear();
658
while (stat == HandshakeStatus.NEED_WRAP) {
659
r = wrapper.wrapAndSend (buf);
660
stat = r.result.getHandshakeStatus();
661
}
662
assert r.result.getStatus() == Status.CLOSED
663
: "status is: " + r.result.getStatus()
664
+ ", handshakeStatus is: " + stat;
665
}
666
}
667
}
668
669