Showing the changes to java/pkg/sun/security/ssl/SSLSocketImpl.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,2493 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1996, 2011, 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 | |||
| 27 | package sun.security.ssl; | ||
| 28 | |||
| 29 | import java.io.*; | ||
| 30 | import java.net.*; | ||
| 31 | import java.security.GeneralSecurityException; | ||
| 32 | import java.security.AccessController; | ||
| 33 | import java.security.AccessControlContext; | ||
| 34 | import java.security.PrivilegedAction; | ||
| 35 | import java.security.AlgorithmConstraints; | ||
| 36 | import java.util.*; | ||
| 37 | import java.util.concurrent.TimeUnit; | ||
| 38 | import java.util.concurrent.locks.ReentrantLock; | ||
| 39 | |||
| 40 | import javax.crypto.BadPaddingException; | ||
| 41 | |||
| 42 | import javax.net.ssl.*; | ||
| 43 | |||
| 44 | import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Implementation of an SSL socket. This is a normal connection type | ||
| 48 | * socket, implementing SSL over some lower level socket, such as TCP. | ||
| 49 | * Because it is layered over some lower level socket, it MUST override | ||
| 50 | * all default socket methods. | ||
| 51 | * | ||
| 52 | * <P> This API offers a non-traditional option for establishing SSL | ||
| 53 | * connections. You may first establish the connection directly, then pass | ||
| 54 | * that connection to the SSL socket constructor with a flag saying which | ||
| 55 | * role should be taken in the handshake protocol. (The two ends of the | ||
| 56 | * connection must not choose the same role!) This allows setup of SSL | ||
| 57 | * proxying or tunneling, and also allows the kind of "role reversal" | ||
| 58 | * that is required for most FTP data transfers. | ||
| 59 | * | ||
| 60 | * @see javax.net.ssl.SSLSocket | ||
| 61 | * @see SSLServerSocket | ||
| 62 | * | ||
| 63 | * @author David Brownell | ||
| 64 | */ | ||
| 65 | final public class SSLSocketImpl extends BaseSSLSocketImpl { | ||
| 66 | |||
| 67 | /* | ||
| 68 | * ERROR HANDLING GUIDELINES | ||
| 69 | * (which exceptions to throw and catch and which not to throw and catch) | ||
| 70 | * | ||
| 71 | * . if there is an IOException (SocketException) when accessing the | ||
| 72 | * underlying Socket, pass it through | ||
| 73 | * | ||
| 74 | * . do not throw IOExceptions, throw SSLExceptions (or a subclass) | ||
| 75 | * | ||
| 76 | * . for internal errors (things that indicate a bug in JSSE or a | ||
| 77 | * grossly misconfigured J2RE), throw either an SSLException or | ||
| 78 | * a RuntimeException at your convenience. | ||
| 79 | * | ||
| 80 | * . handshaking code (Handshaker or HandshakeMessage) should generally | ||
| 81 | * pass through exceptions, but can handle them if they know what to | ||
| 82 | * do. | ||
| 83 | * | ||
| 84 | * . exception chaining should be used for all new code. If you happen | ||
| 85 | * to touch old code that does not use chaining, you should change it. | ||
| 86 | * | ||
| 87 | * . there is a top level exception handler that sits at all entry | ||
| 88 | * points from application code to SSLSocket read/write code. It | ||
| 89 | * makes sure that all errors are handled (see handleException()). | ||
| 90 | * | ||
| 91 | * . JSSE internal code should generally not call close(), call | ||
| 92 | * closeInternal(). | ||
| 93 | */ | ||
| 94 | |||
| 95 | /* | ||
| 96 | * There's a state machine associated with each connection, which | ||
| 97 | * among other roles serves to negotiate session changes. | ||
| 98 | * | ||
| 99 | * - START with constructor, until the TCP connection's around. | ||
| 100 | * - HANDSHAKE picks session parameters before allowing traffic. | ||
| 101 | * There are many substates due to sequencing requirements | ||
| 102 | * for handshake messages. | ||
| 103 | * - DATA may be transmitted. | ||
| 104 | * - RENEGOTIATE state allows concurrent data and handshaking | ||
| 105 | * traffic ("same" substates as HANDSHAKE), and terminates | ||
| 106 | * in selection of new session (and connection) parameters | ||
| 107 | * - ERROR state immediately precedes abortive disconnect. | ||
| 108 | * - SENT_CLOSE sent a close_notify to the peer. For layered, | ||
| 109 | * non-autoclose socket, must now read close_notify | ||
| 110 | * from peer before closing the connection. For nonlayered or | ||
| 111 | * non-autoclose socket, close connection and go onto | ||
| 112 | * cs_CLOSED state. | ||
| 113 | * - CLOSED after sending close_notify alert, & socket is closed. | ||
| 114 | * SSL connection objects are not reused. | ||
| 115 | * - APP_CLOSED once the application calls close(). Then it behaves like | ||
| 116 | * a closed socket, e.g.. getInputStream() throws an Exception. | ||
| 117 | * | ||
| 118 | * State affects what SSL record types may legally be sent: | ||
| 119 | * | ||
| 120 | * - Handshake ... only in HANDSHAKE and RENEGOTIATE states | ||
| 121 | * - App Data ... only in DATA and RENEGOTIATE states | ||
| 122 | * - Alert ... in HANDSHAKE, DATA, RENEGOTIATE | ||
| 123 | * | ||
| 124 | * Re what may be received: same as what may be sent, except that | ||
| 125 | * HandshakeRequest handshaking messages can come from servers even | ||
| 126 | * in the application data state, to request entry to RENEGOTIATE. | ||
| 127 | * | ||
| 128 | * The state machine within HANDSHAKE and RENEGOTIATE states controls | ||
| 129 | * the pending session, not the connection state, until the change | ||
| 130 | * cipher spec and "Finished" handshake messages are processed and | ||
| 131 | * make the "new" session become the current one. | ||
| 132 | * | ||
| 133 | * NOTE: details of the SMs always need to be nailed down better. | ||
| 134 | * The text above illustrates the core ideas. | ||
| 135 | * | ||
| 136 | * +---->-------+------>--------->-------+ | ||
| 137 | * | | | | ||
| 138 | * <-----< ^ ^ <-----< v | ||
| 139 | *START>----->HANDSHAKE>----->DATA>----->RENEGOTIATE SENT_CLOSE | ||
| 140 | * v v v | | | ||
| 141 | * | | | | v | ||
| 142 | * +------------+---------------+ v ERROR | ||
| 143 | * | | | | ||
| 144 | * v | | | ||
| 145 | * ERROR>------>----->CLOSED<--------<----+-- + | ||
| 146 | * | | ||
| 147 | * v | ||
| 148 | * APP_CLOSED | ||
| 149 | * | ||
| 150 | * ALSO, note that the the purpose of handshaking (renegotiation is | ||
| 151 | * included) is to assign a different, and perhaps new, session to | ||
| 152 | * the connection. The SSLv3 spec is a bit confusing on that new | ||
| 153 | * protocol feature. | ||
| 154 | */ | ||
| 155 | private static final int cs_START = 0; | ||
| 156 | private static final int cs_HANDSHAKE = 1; | ||
| 157 | private static final int cs_DATA = 2; | ||
| 158 | private static final int cs_RENEGOTIATE = 3; | ||
| 159 | private static final int cs_ERROR = 4; | ||
| 160 | private static final int cs_SENT_CLOSE = 5; | ||
| 161 | private static final int cs_CLOSED = 6; | ||
| 162 | private static final int cs_APP_CLOSED = 7; | ||
| 163 | |||
| 164 | |||
| 165 | /* | ||
| 166 | * Client authentication be off, requested, or required. | ||
| 167 | * | ||
| 168 | * Migrated to SSLEngineImpl: | ||
| 169 | * clauth_none/cl_auth_requested/clauth_required | ||
| 170 | */ | ||
| 171 | |||
| 172 | /* | ||
| 173 | * Drives the protocol state machine. | ||
| 174 | */ | ||
| 175 | private int connectionState; | ||
| 176 | |||
| 177 | /* | ||
| 178 | * Flag indicating if the next record we receive MUST be a Finished | ||
| 179 | * message. Temporarily set during the handshake to ensure that | ||
| 180 | * a change cipher spec message is followed by a finished message. | ||
| 181 | */ | ||
| 182 | private boolean expectingFinished; | ||
| 183 | |||
| 184 | /* | ||
| 185 | * For improved diagnostics, we detail connection closure | ||
| 186 | * If the socket is closed (connectionState >= cs_ERROR), | ||
| 187 | * closeReason != null indicates if the socket was closed | ||
| 188 | * because of an error or because or normal shutdown. | ||
| 189 | */ | ||
| 190 | private SSLException closeReason; | ||
| 191 | |||
| 192 | /* | ||
| 193 | * Per-connection private state that doesn't change when the | ||
| 194 | * session is changed. | ||
| 195 | */ | ||
| 196 | private byte doClientAuth; | ||
| 197 | private boolean roleIsServer; | ||
| 198 | private boolean enableSessionCreation = true; | ||
| 199 | private String host; | ||
| 200 | private boolean autoClose = true; | ||
| 201 | private AccessControlContext acc; | ||
| 202 | |||
| 203 | /* | ||
| 204 | * We cannot use the hostname resolved from name services. For | ||
| 205 | * virtual hosting, multiple hostnames may be bound to the same IP | ||
| 206 | * address, so the hostname resolved from name services is not | ||
| 207 | * reliable. | ||
| 208 | */ | ||
| 209 | private String rawHostname; | ||
| 210 | |||
| 211 | // The cipher suites enabled for use on this connection. | ||
| 212 | private CipherSuiteList enabledCipherSuites; | ||
| 213 | |||
| 214 | // The endpoint identification protocol | ||
| 215 | private String identificationProtocol = null; | ||
| 216 | |||
| 217 | // The cryptographic algorithm constraints | ||
| 218 | private AlgorithmConstraints algorithmConstraints = null; | ||
| 219 | |||
| 220 | /* | ||
| 221 | * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME * | ||
| 222 | * IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES. | ||
| 223 | * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME * | ||
| 224 | * | ||
| 225 | * There are several locks here. | ||
| 226 | * | ||
| 227 | * The primary lock is the per-instance lock used by | ||
| 228 | * synchronized(this) and the synchronized methods. It controls all | ||
| 229 | * access to things such as the connection state and variables which | ||
| 230 | * affect handshaking. If we are inside a synchronized method, we | ||
| 231 | * can access the state directly, otherwise, we must use the | ||
| 232 | * synchronized equivalents. | ||
| 233 | * | ||
| 234 | * The handshakeLock is used to ensure that only one thread performs | ||
| 235 | * the *complete initial* handshake. If someone is handshaking, any | ||
| 236 | * stray application or startHandshake() requests who find the | ||
| 237 | * connection state is cs_HANDSHAKE will stall on handshakeLock | ||
| 238 | * until handshaking is done. Once the handshake is done, we either | ||
| 239 | * succeeded or failed, but we can never go back to the cs_HANDSHAKE | ||
| 240 | * or cs_START state again. | ||
| 241 | * | ||
| 242 | * Note that the read/write() calls here in SSLSocketImpl are not | ||
| 243 | * obviously synchronized. In fact, it's very nonintuitive, and | ||
| 244 | * requires careful examination of code paths. Grab some coffee, | ||
| 245 | * and be careful with any code changes. | ||
| 246 | * | ||
| 247 | * There can be only three threads active at a time in the I/O | ||
| 248 | * subsection of this class. | ||
| 249 | * 1. startHandshake | ||
| 250 | * 2. AppInputStream | ||
| 251 | * 3. AppOutputStream | ||
| 252 | * One thread could call startHandshake(). | ||
| 253 | * AppInputStream/AppOutputStream read() and write() calls are each | ||
| 254 | * synchronized on 'this' in their respective classes, so only one | ||
| 255 | * app. thread will be doing a SSLSocketImpl.read() or .write()'s at | ||
| 256 | * a time. | ||
| 257 | * | ||
| 258 | * If handshaking is required (state cs_HANDSHAKE), and | ||
| 259 | * getConnectionState() for some/all threads returns cs_HANDSHAKE, | ||
| 260 | * only one can grab the handshakeLock, and the rest will stall | ||
| 261 | * either on getConnectionState(), or on the handshakeLock if they | ||
| 262 | * happen to successfully race through the getConnectionState(). | ||
| 263 | * | ||
| 264 | * If a writer is doing the initial handshaking, it must create a | ||
| 265 | * temporary reader to read the responses from the other side. As a | ||
| 266 | * side-effect, the writer's reader will have priority over any | ||
| 267 | * other reader. However, the writer's reader is not allowed to | ||
| 268 | * consume any application data. When handshakeLock is finally | ||
| 269 | * released, we either have a cs_DATA connection, or a | ||
| 270 | * cs_CLOSED/cs_ERROR socket. | ||
| 271 | * | ||
| 272 | * The writeLock is held while writing on a socket connection and | ||
| 273 | * also to protect the MAC and cipher for their direction. The | ||
| 274 | * writeLock is package private for Handshaker which holds it while | ||
| 275 | * writing the ChangeCipherSpec message. | ||
| 276 | * | ||
| 277 | * To avoid the problem of a thread trying to change operational | ||
| 278 | * modes on a socket while handshaking is going on, we synchronize | ||
| 279 | * on 'this'. If handshaking has not started yet, we tell the | ||
| 280 | * handshaker to change its mode. If handshaking has started, | ||
| 281 | * we simply store that request until the next pending session | ||
| 282 | * is created, at which time the new handshaker's state is set. | ||
| 283 | * | ||
| 284 | * The readLock is held during readRecord(), which is responsible | ||
| 285 | * for reading an InputRecord, decrypting it, and processing it. | ||
| 286 | * The readLock ensures that these three steps are done atomically | ||
| 287 | * and that once started, no other thread can block on InputRecord.read. | ||
| 288 | * This is necessary so that processing of close_notify alerts | ||
| 289 | * from the peer are handled properly. | ||
| 290 | */ | ||
| 291 | final private Object handshakeLock = new Object(); | ||
| 292 | final ReentrantLock writeLock = new ReentrantLock(); | ||
| 293 | final private Object readLock = new Object(); | ||
| 294 | |||
| 295 | private InputRecord inrec; | ||
| 296 | |||
| 297 | /* | ||
| 298 | * Crypto state that's reinitialized when the session changes. | ||
| 299 | */ | ||
| 300 | private MAC readMAC, writeMAC; | ||
| 301 | private CipherBox readCipher, writeCipher; | ||
| 302 | // NOTE: compression state would be saved here | ||
| 303 | |||
| 304 | /* | ||
| 305 | * security parameters for secure renegotiation. | ||
| 306 | */ | ||
| 307 | private boolean secureRenegotiation; | ||
| 308 | private byte[] clientVerifyData; | ||
| 309 | private byte[] serverVerifyData; | ||
| 310 | |||
| 311 | /* | ||
| 312 | * The authentication context holds all information used to establish | ||
| 313 | * who this end of the connection is (certificate chains, private keys, | ||
| 314 | * etc) and who is trusted (e.g. as CAs or websites). | ||
| 315 | */ | ||
| 316 | private SSLContextImpl sslContext; | ||
| 317 | |||
| 318 | |||
| 319 | /* | ||
| 320 | * This connection is one of (potentially) many associated with | ||
| 321 | * any given session. The output of the handshake protocol is a | ||
| 322 | * new session ... although all the protocol description talks | ||
| 323 | * about changing the cipher spec (and it does change), in fact | ||
| 324 | * that's incidental since it's done by changing everything that | ||
| 325 | * is associated with a session at the same time. (TLS/IETF may | ||
| 326 | * change that to add client authentication w/o new key exchg.) | ||
| 327 | */ | ||
| 328 | private Handshaker handshaker; | ||
| 329 | private SSLSessionImpl sess; | ||
| 330 | private volatile SSLSessionImpl handshakeSession; | ||
| 331 | |||
| 332 | |||
| 333 | /* | ||
| 334 | * If anyone wants to get notified about handshake completions, | ||
| 335 | * they'll show up on this list. | ||
| 336 | */ | ||
| 337 | private HashMap<HandshakeCompletedListener, AccessControlContext> | ||
| 338 | handshakeListeners; | ||
| 339 | |||
| 340 | /* | ||
| 341 | * Reuse the same internal input/output streams. | ||
| 342 | */ | ||
| 343 | private InputStream sockInput; | ||
| 344 | private OutputStream sockOutput; | ||
| 345 | |||
| 346 | |||
| 347 | /* | ||
| 348 | * These input and output streams block their data in SSL records, | ||
| 349 | * and usually arrange integrity and privacy protection for those | ||
| 350 | * records. The guts of the SSL protocol are wrapped up in these | ||
| 351 | * streams, and in the handshaking that establishes the details of | ||
| 352 | * that integrity and privacy protection. | ||
| 353 | */ | ||
| 354 | private AppInputStream input; | ||
| 355 | private AppOutputStream output; | ||
| 356 | |||
| 357 | /* | ||
| 358 | * The protocol versions enabled for use on this connection. | ||
| 359 | * | ||
| 360 | * Note: we support a pseudo protocol called SSLv2Hello which when | ||
| 361 | * set will result in an SSL v2 Hello being sent with SSL (version 3.0) | ||
| 362 | * or TLS (version 3.1, 3.2, etc.) version info. | ||
| 363 | */ | ||
| 364 | private ProtocolList enabledProtocols; | ||
| 365 | |||
| 366 | /* | ||
| 367 | * The SSL version associated with this connection. | ||
| 368 | */ | ||
| 369 | private ProtocolVersion protocolVersion = ProtocolVersion.DEFAULT; | ||
| 370 | |||
| 371 | /* Class and subclass dynamic debugging support */ | ||
| 372 | private static final Debug debug = Debug.getInstance("ssl"); | ||
| 373 | |||
| 374 | // | ||
| 375 | // CONSTRUCTORS AND INITIALIZATION CODE | ||
| 376 | // | ||
| 377 | |||
| 378 | /** | ||
| 379 | * Constructs an SSL connection to a named host at a specified port, | ||
| 380 | * using the authentication context provided. This endpoint acts as | ||
| 381 | * the client, and may rejoin an existing SSL session if appropriate. | ||
| 382 | * | ||
| 383 | * @param context authentication context to use | ||
| 384 | * @param host name of the host with which to connect | ||
| 385 | * @param port number of the server's port | ||
| 386 | */ | ||
| 387 | SSLSocketImpl(SSLContextImpl context, String host, int port) | ||
| 388 | throws IOException, UnknownHostException { | ||
| 389 | super(); | ||
| 390 | this.host = host; | ||
| 391 | this.rawHostname = host; | ||
| 392 | init(context, false); | ||
| 393 | SocketAddress socketAddress = | ||
| 394 | host != null ? new InetSocketAddress(host, port) : | ||
| 395 | new InetSocketAddress(InetAddress.getByName(null), port); | ||
| 396 | connect(socketAddress, 0); | ||
| 397 | } | ||
| 398 | |||
| 399 | |||
| 400 | /** | ||
| 401 | * Constructs an SSL connection to a server at a specified address. | ||
| 402 | * and TCP port, using the authentication context provided. This | ||
| 403 | * endpoint acts as the client, and may rejoin an existing SSL session | ||
| 404 | * if appropriate. | ||
| 405 | * | ||
| 406 | * @param context authentication context to use | ||
| 407 | * @param address the server's host | ||
| 408 | * @param port its port | ||
| 409 | */ | ||
| 410 | SSLSocketImpl(SSLContextImpl context, InetAddress host, int port) | ||
| 411 | throws IOException { | ||
| 412 | super(); | ||
| 413 | init(context, false); | ||
| 414 | SocketAddress socketAddress = new InetSocketAddress(host, port); | ||
| 415 | connect(socketAddress, 0); | ||
| 416 | } | ||
| 417 | |||
| 418 | /** | ||
| 419 | * Constructs an SSL connection to a named host at a specified port, | ||
| 420 | * using the authentication context provided. This endpoint acts as | ||
| 421 | * the client, and may rejoin an existing SSL session if appropriate. | ||
| 422 | * | ||
| 423 | * @param context authentication context to use | ||
| 424 | * @param host name of the host with which to connect | ||
| 425 | * @param port number of the server's port | ||
| 426 | * @param localAddr the local address the socket is bound to | ||
| 427 | * @param localPort the local port the socket is bound to | ||
| 428 | */ | ||
| 429 | SSLSocketImpl(SSLContextImpl context, String host, int port, | ||
| 430 | InetAddress localAddr, int localPort) | ||
| 431 | throws IOException, UnknownHostException { | ||
| 432 | super(); | ||
| 433 | this.host = host; | ||
| 434 | this.rawHostname = host; | ||
| 435 | init(context, false); | ||
| 436 | bind(new InetSocketAddress(localAddr, localPort)); | ||
| 437 | SocketAddress socketAddress = | ||
| 438 | host != null ? new InetSocketAddress(host, port) : | ||
| 439 | new InetSocketAddress(InetAddress.getByName(null), port); | ||
| 440 | connect(socketAddress, 0); | ||
| 441 | } | ||
| 442 | |||
| 443 | |||
| 444 | /** | ||
| 445 | * Constructs an SSL connection to a server at a specified address. | ||
| 446 | * and TCP port, using the authentication context provided. This | ||
| 447 | * endpoint acts as the client, and may rejoin an existing SSL session | ||
| 448 | * if appropriate. | ||
| 449 | * | ||
| 450 | * @param context authentication context to use | ||
| 451 | * @param address the server's host | ||
| 452 | * @param port its port | ||
| 453 | * @param localAddr the local address the socket is bound to | ||
| 454 | * @param localPort the local port the socket is bound to | ||
| 455 | */ | ||
| 456 | SSLSocketImpl(SSLContextImpl context, InetAddress host, int port, | ||
| 457 | InetAddress localAddr, int localPort) | ||
| 458 | throws IOException { | ||
| 459 | super(); | ||
| 460 | init(context, false); | ||
| 461 | bind(new InetSocketAddress(localAddr, localPort)); | ||
| 462 | SocketAddress socketAddress = new InetSocketAddress(host, port); | ||
| 463 | connect(socketAddress, 0); | ||
| 464 | } | ||
| 465 | |||
| 466 | /* | ||
| 467 | * Package-private constructor used ONLY by SSLServerSocket. The | ||
| 468 | * java.net package accepts the TCP connection after this call is | ||
| 469 | * made. This just initializes handshake state to use "server mode", | ||
| 470 | * giving control over the use of SSL client authentication. | ||
| 471 | */ | ||
| 472 | SSLSocketImpl(SSLContextImpl context, boolean serverMode, | ||
| 473 | CipherSuiteList suites, byte clientAuth, | ||
| 474 | boolean sessionCreation, ProtocolList protocols, | ||
| 475 | String identificationProtocol, | ||
| 476 | AlgorithmConstraints algorithmConstraints) throws IOException { | ||
| 477 | |||
| 478 | super(); | ||
| 479 | doClientAuth = clientAuth; | ||
| 480 | enableSessionCreation = sessionCreation; | ||
| 481 | this.identificationProtocol = identificationProtocol; | ||
| 482 | this.algorithmConstraints = algorithmConstraints; | ||
| 483 | init(context, serverMode); | ||
| 484 | |||
| 485 | /* | ||
| 486 | * Override what was picked out for us. | ||
| 487 | */ | ||
| 488 | enabledCipherSuites = suites; | ||
| 489 | enabledProtocols = protocols; | ||
| 490 | } | ||
| 491 | |||
| 492 | |||
| 493 | /** | ||
| 494 | * Package-private constructor used to instantiate an unconnected | ||
| 495 | * socket. The java.net package will connect it, either when the | ||
| 496 | * connect() call is made by the application. This instance is | ||
| 497 | * meant to set handshake state to use "client mode". | ||
| 498 | */ | ||
| 499 | SSLSocketImpl(SSLContextImpl context) { | ||
| 500 | super(); | ||
| 501 | init(context, false); | ||
| 502 | } | ||
| 503 | |||
| 504 | |||
| 505 | /** | ||
| 506 | * Layer SSL traffic over an existing connection, rather than creating | ||
| 507 | * a new connection. The existing connection may be used only for SSL | ||
| 508 | * traffic (using this SSLSocket) until the SSLSocket.close() call | ||
| 509 | * returns. However, if a protocol error is detected, that existing | ||
| 510 | * connection is automatically closed. | ||
| 511 | * | ||
| 512 | * <P> This particular constructor always uses the socket in the | ||
| 513 | * role of an SSL client. It may be useful in cases which start | ||
| 514 | * using SSL after some initial data transfers, for example in some | ||
| 515 | * SSL tunneling applications or as part of some kinds of application | ||
| 516 | * protocols which negotiate use of a SSL based security. | ||
| 517 | * | ||
| 518 | * @param sock the existing connection | ||
| 519 | * @param context the authentication context to use | ||
| 520 | */ | ||
| 521 | SSLSocketImpl(SSLContextImpl context, Socket sock, String host, | ||
| 522 | int port, boolean autoClose) throws IOException { | ||
| 523 | super(sock); | ||
| 524 | // We always layer over a connected socket | ||
| 525 | if (!sock.isConnected()) { | ||
| 526 | throw new SocketException("Underlying socket is not connected"); | ||
| 527 | } | ||
| 528 | this.host = host; | ||
| 529 | this.rawHostname = host; | ||
| 530 | init(context, false); | ||
| 531 | this.autoClose = autoClose; | ||
| 532 | doneConnect(); | ||
| 533 | } | ||
| 534 | |||
| 535 | /** | ||
| 536 | * Initializes the client socket. | ||
| 537 | */ | ||
| 538 | private void init(SSLContextImpl context, boolean isServer) { | ||
| 539 | sslContext = context; | ||
| 540 | sess = SSLSessionImpl.nullSession; | ||
| 541 | handshakeSession = null; | ||
| 542 | |||
| 543 | /* | ||
| 544 | * role is as specified, state is START until after | ||
| 545 | * the low level connection's established. | ||
| 546 | */ | ||
| 547 | roleIsServer = isServer; | ||
| 548 | connectionState = cs_START; | ||
| 549 | |||
| 550 | /* | ||
| 551 | * default read and write side cipher and MAC support | ||
| 552 | * | ||
| 553 | * Note: compression support would go here too | ||
| 554 | */ | ||
| 555 | readCipher = CipherBox.NULL; | ||
| 556 | readMAC = MAC.NULL; | ||
| 557 | writeCipher = CipherBox.NULL; | ||
| 558 | writeMAC = MAC.NULL; | ||
| 559 | |||
| 560 | // initial security parameters for secure renegotiation | ||
| 561 | secureRenegotiation = false; | ||
| 562 | clientVerifyData = new byte[0]; | ||
| 563 | serverVerifyData = new byte[0]; | ||
| 564 | |||
| 565 | enabledCipherSuites = | ||
| 566 | sslContext.getDefaultCipherSuiteList(roleIsServer); | ||
| 567 | enabledProtocols = | ||
| 568 | sslContext.getDefaultProtocolList(roleIsServer); | ||
| 569 | |||
| 570 | inrec = null; | ||
| 571 | |||
| 572 | // save the acc | ||
| 573 | acc = AccessController.getContext(); | ||
| 574 | |||
| 575 | input = new AppInputStream(this); | ||
| 576 | output = new AppOutputStream(this); | ||
| 577 | } | ||
| 578 | |||
| 579 | /** | ||
| 580 | * Connects this socket to the server with a specified timeout | ||
| 581 | * value. | ||
| 582 | * | ||
| 583 | * This method is either called on an unconnected SSLSocketImpl by the | ||
| 584 | * application, or it is called in the constructor of a regular | ||
| 585 | * SSLSocketImpl. If we are layering on top on another socket, then | ||
| 586 | * this method should not be called, because we assume that the | ||
| 587 | * underlying socket is already connected by the time it is passed to | ||
| 588 | * us. | ||
| 589 | * | ||
| 590 | * @param endpoint the <code>SocketAddress</code> | ||
| 591 | * @param timeout the timeout value to be used, 0 is no timeout | ||
| 592 | * @throws IOException if an error occurs during the connection | ||
| 593 | * @throws SocketTimeoutException if timeout expires before connecting | ||
| 594 | */ | ||
| 595 | public void connect(SocketAddress endpoint, int timeout) | ||
| 596 | throws IOException { | ||
| 597 | |||
| 598 | if (self != this) { | ||
| 599 | throw new SocketException("Already connected"); | ||
| 600 | } | ||
| 601 | |||
| 602 | if (!(endpoint instanceof InetSocketAddress)) { | ||
| 603 | throw new SocketException( | ||
| 604 | "Cannot handle non-Inet socket addresses."); | ||
| 605 | } | ||
| 606 | |||
| 607 | super.connect(endpoint, timeout); | ||
| 608 | doneConnect(); | ||
| 609 | } | ||
| 610 | |||
| 611 | /** | ||
| 612 | * Initialize the handshaker and socket streams. | ||
| 613 | * | ||
| 614 | * Called by connect, the layered constructor, and SSLServerSocket. | ||
| 615 | */ | ||
| 616 | void doneConnect() throws IOException { | ||
| 617 | /* | ||
| 618 | * Save the input and output streams. May be done only after | ||
| 619 | * java.net actually connects using the socket "self", else | ||
| 620 | * we get some pretty bizarre failure modes. | ||
| 621 | */ | ||
| 622 | if (self == this) { | ||
| 623 | sockInput = super.getInputStream(); | ||
| 624 | sockOutput = super.getOutputStream(); | ||
| 625 | } else { | ||
| 626 | sockInput = self.getInputStream(); | ||
| 627 | sockOutput = self.getOutputStream(); | ||
| 628 | } | ||
| 629 | |||
| 630 | /* | ||
| 631 | * Move to handshaking state, with pending session initialized | ||
| 632 | * to defaults and the appropriate kind of handshaker set up. | ||
| 633 | */ | ||
| 634 | initHandshaker(); | ||
| 635 | } | ||
| 636 | |||
| 637 | synchronized private int getConnectionState() { | ||
| 638 | return connectionState; | ||
| 639 | } | ||
| 640 | |||
| 641 | synchronized private void setConnectionState(int state) { | ||
| 642 | connectionState = state; | ||
| 643 | } | ||
| 644 | |||
| 645 | AccessControlContext getAcc() { | ||
| 646 | return acc; | ||
| 647 | } | ||
| 648 | |||
| 649 | // | ||
| 650 | // READING AND WRITING RECORDS | ||
| 651 | // | ||
| 652 | |||
| 653 | /* | ||
| 654 | * Record Output. Application data can't be sent until the first | ||
| 655 | * handshake establishes a session. | ||
| 656 | * | ||
| 657 | * NOTE: we let empty records be written as a hook to force some | ||
| 658 | * TCP-level activity, notably handshaking, to occur. | ||
| 659 | */ | ||
| 660 | void writeRecord(OutputRecord r) throws IOException { | ||
| 661 | /* | ||
| 662 | * The loop is in case of HANDSHAKE --> ERROR transitions, etc | ||
| 663 | */ | ||
| 664 | loop: | ||
| 665 | while (r.contentType() == Record.ct_application_data) { | ||
| 666 | /* | ||
| 667 | * Not all states support passing application data. We | ||
| 668 | * synchronize access to the connection state, so that | ||
| 669 | * synchronous handshakes can complete cleanly. | ||
| 670 | */ | ||
| 671 | switch (getConnectionState()) { | ||
| 672 | |||
| 673 | /* | ||
| 674 | * We've deferred the initial handshaking till just now, | ||
| 675 | * when presumably a thread's decided it's OK to block for | ||
| 676 | * longish periods of time for I/O purposes (as well as | ||
| 677 | * configured the cipher suites it wants to use). | ||
| 678 | */ | ||
| 679 | case cs_HANDSHAKE: | ||
| 680 | performInitialHandshake(); | ||
| 681 | break; | ||
| 682 | |||
| 683 | case cs_DATA: | ||
| 684 | case cs_RENEGOTIATE: | ||
| 685 | break loop; | ||
| 686 | |||
| 687 | case cs_ERROR: | ||
| 688 | fatal(Alerts.alert_close_notify, | ||
| 689 | "error while writing to socket"); | ||
| 690 | break; // dummy | ||
| 691 | |||
| 692 | case cs_SENT_CLOSE: | ||
| 693 | case cs_CLOSED: | ||
| 694 | case cs_APP_CLOSED: | ||
| 695 | // we should never get here (check in AppOutputStream) | ||
| 696 | // this is just a fallback | ||
| 697 | if (closeReason != null) { | ||
| 698 | throw closeReason; | ||
| 699 | } else { | ||
| 700 | throw new SocketException("Socket closed"); | ||
| 701 | } | ||
| 702 | |||
| 703 | /* | ||
| 704 | * Else something's goofy in this state machine's use. | ||
| 705 | */ | ||
| 706 | default: | ||
| 707 | throw new SSLProtocolException("State error, send app data"); | ||
| 708 | } | ||
| 709 | } | ||
| 710 | |||
| 711 | // | ||
| 712 | // Don't bother to really write empty records. We went this | ||
| 713 | // far to drive the handshake machinery, for correctness; not | ||
| 714 | // writing empty records improves performance by cutting CPU | ||
| 715 | // time and network resource usage. However, some protocol | ||
| 716 | // implementations are fragile and don't like to see empty | ||
| 717 | // records, so this also increases robustness. | ||
| 718 | // | ||
| 719 | if (!r.isEmpty()) { | ||
| 720 | |||
| 721 | // If the record is a close notify alert, we need to honor | ||
| 722 | // socket option SO_LINGER. Note that we will try to send | ||
| 723 | // the close notify even if the SO_LINGER set to zero. | ||
| 724 | if (r.isAlert(Alerts.alert_close_notify) && getSoLinger() >= 0) { | ||
| 725 | |||
| 726 | // keep and clear the current thread interruption status. | ||
| 727 | boolean interrupted = Thread.interrupted(); | ||
| 728 | try { | ||
| 729 | if (writeLock.tryLock(getSoLinger(), TimeUnit.SECONDS)) { | ||
| 730 | try { | ||
| 731 | writeRecordInternal(r); | ||
| 732 | } finally { | ||
| 733 | writeLock.unlock(); | ||
| 734 | } | ||
| 735 | } else { | ||
| 736 | SSLException ssle = new SSLException( | ||
| 737 | "SO_LINGER timeout," + | ||
| 738 | " close_notify message cannot be sent."); | ||
| 739 | |||
| 740 | |||
| 741 | // For layered, non-autoclose sockets, we are not | ||
| 742 | // able to bring them into a usable state, so we | ||
| 743 | // treat it as fatal error. | ||
| 744 | if (self != this && !autoClose) { | ||
| 745 | // Note that the alert description is | ||
| 746 | // specified as -1, so no message will be send | ||
| 747 | // to peer anymore. | ||
| 748 | fatal((byte)(-1), ssle); | ||
| 749 | } else if ((debug != null) && Debug.isOn("ssl")) { | ||
| 750 | System.out.println(threadName() + | ||
| 751 | ", received Exception: " + ssle); | ||
| 752 | } | ||
| 753 | |||
| 754 | // RFC2246 requires that the session becomes | ||
| 755 | // unresumable if any connection is terminated | ||
| 756 | // without proper close_notify messages with | ||
| 757 | // level equal to warning. | ||
| 758 | // | ||
| 759 | // RFC4346 no longer requires that a session not be | ||
| 760 | // resumed if failure to properly close a connection. | ||
| 761 | // | ||
| 762 | // We choose to make the session unresumable if | ||
| 763 | // failed to send the close_notify message. | ||
| 764 | // | ||
| 765 | sess.invalidate(); | ||
| 766 | } | ||
| 767 | } catch (InterruptedException ie) { | ||
| 768 | // keep interrupted status | ||
| 769 | interrupted = true; | ||
| 770 | } | ||
| 771 | |||
| 772 | // restore the interrupted status | ||
| 773 | if (interrupted) { | ||
| 774 | Thread.currentThread().interrupt(); | ||
| 775 | } | ||
| 776 | } else { | ||
| 777 | writeLock.lock(); | ||
| 778 | try { | ||
| 779 | writeRecordInternal(r); | ||
| 780 | } finally { | ||
| 781 | writeLock.unlock(); | ||
| 782 | } | ||
| 783 | } | ||
| 784 | } | ||
| 785 | } | ||
| 786 | |||
| 787 | private void writeRecordInternal(OutputRecord r) throws IOException { | ||
| 788 | // r.compress(c); | ||
| 789 | r.addMAC(writeMAC); | ||
| 790 | r.encrypt(writeCipher); | ||
| 791 | r.write(sockOutput); | ||
| 792 | |||
| 793 | /* | ||
| 794 | * Check the sequence number state | ||
| 795 | * | ||
| 796 | * Note that in order to maintain the connection I/O | ||
| 797 | * properly, we check the sequence number after the last | ||
| 798 | * record writing process. As we request renegotiation | ||
| 799 | * or close the connection for wrapped sequence number | ||
| 800 | * when there is enough sequence number space left to | ||
| 801 | * handle a few more records, so the sequence number | ||
| 802 | * of the last record cannot be wrapped. | ||
| 803 | */ | ||
| 804 | if (connectionState < cs_ERROR) { | ||
| 805 | checkSequenceNumber(writeMAC, r.contentType()); | ||
| 806 | } | ||
| 807 | } | ||
| 808 | |||
| 809 | |||
| 810 | /* | ||
| 811 | * Read an application data record. Alerts and handshake | ||
| 812 | * messages are handled directly. | ||
| 813 | */ | ||
| 814 | void readDataRecord(InputRecord r) throws IOException { | ||
| 815 | if (getConnectionState() == cs_HANDSHAKE) { | ||
| 816 | performInitialHandshake(); | ||
| 817 | } | ||
| 818 | readRecord(r, true); | ||
| 819 | } | ||
| 820 | |||
| 821 | |||
| 822 | /* | ||
| 823 | * Clear the pipeline of records from the peer, optionally returning | ||
| 824 | * application data. Caller is responsible for knowing that it's | ||
| 825 | * possible to do this kind of clearing, if they don't want app | ||
| 826 | * data -- e.g. since it's the initial SSL handshake. | ||
| 827 | * | ||
| 828 | * Don't synchronize (this) during a blocking read() since it | ||
| 829 | * protects data which is accessed on the write side as well. | ||
| 830 | */ | ||
| 831 | private void readRecord(InputRecord r, boolean needAppData) | ||
| 832 | throws IOException { | ||
| 833 | int state; | ||
| 834 | |||
| 835 | // readLock protects reading and processing of an InputRecord. | ||
| 836 | // It keeps the reading from sockInput and processing of the record | ||
| 837 | // atomic so that no two threads can be blocked on the | ||
| 838 | // read from the same input stream at the same time. | ||
| 839 | // This is required for example when a reader thread is | ||
| 840 | // blocked on the read and another thread is trying to | ||
| 841 | // close the socket. For a non-autoclose, layered socket, | ||
| 842 | // the thread performing the close needs to read the close_notify. | ||
| 843 | // | ||
| 844 | // Use readLock instead of 'this' for locking because | ||
| 845 | // 'this' also protects data accessed during writing. | ||
| 846 | synchronized (readLock) { | ||
| 847 | /* | ||
| 848 | * Read and handle records ... return application data | ||
| 849 | * ONLY if it's needed. | ||
| 850 | */ | ||
| 851 | |||
| 852 | while (((state = getConnectionState()) != cs_CLOSED) && | ||
| 853 | (state != cs_ERROR) && (state != cs_APP_CLOSED)) { | ||
| 854 | /* | ||
| 855 | * Read a record ... maybe emitting an alert if we get a | ||
| 856 | * comprehensible but unsupported "hello" message during | ||
| 857 | * format checking (e.g. V2). | ||
| 858 | */ | ||
| 859 | try { | ||
| 860 | r.setAppDataValid(false); | ||
| 861 | r.read(sockInput, sockOutput); | ||
| 862 | } catch (SSLProtocolException e) { | ||
| 863 | try { | ||
| 864 | fatal(Alerts.alert_unexpected_message, e); | ||
| 865 | } catch (IOException x) { | ||
| 866 | // discard this exception | ||
| 867 | } | ||
| 868 | throw e; | ||
| 869 | } catch (EOFException eof) { | ||
| 870 | boolean handshaking = (getConnectionState() <= cs_HANDSHAKE); | ||
| 871 | boolean rethrow = requireCloseNotify || handshaking; | ||
| 872 | if ((debug != null) && Debug.isOn("ssl")) { | ||
| 873 | System.out.println(threadName() + | ||
| 874 | ", received EOFException: " | ||
| 875 | + (rethrow ? "error" : "ignored")); | ||
| 876 | } | ||
| 877 | if (rethrow) { | ||
| 878 | SSLException e; | ||
| 879 | if (handshaking) { | ||
| 880 | e = new SSLHandshakeException | ||
| 881 | ("Remote host closed connection during handshake"); | ||
| 882 | } else { | ||
| 883 | e = new SSLProtocolException | ||
| 884 | ("Remote host closed connection incorrectly"); | ||
| 885 | } | ||
| 886 | e.initCause(eof); | ||
| 887 | throw e; | ||
| 888 | } else { | ||
| 889 | // treat as if we had received a close_notify | ||
| 890 | closeInternal(false); | ||
| 891 | continue; | ||
| 892 | } | ||
| 893 | } | ||
| 894 | |||
| 895 | |||
| 896 | /* | ||
| 897 | * The basic SSLv3 record protection involves (optional) | ||
| 898 | * encryption for privacy, and an integrity check ensuring | ||
| 899 | * data origin authentication. We do them both here, and | ||
| 900 | * throw a fatal alert if the integrity check fails. | ||
| 901 | */ | ||
| 902 | try { | ||
| 903 | r.decrypt(readCipher); | ||
| 904 | } catch (BadPaddingException e) { | ||
| 905 | // RFC 2246 states that decryption_failed should be used | ||
| 906 | // for this purpose. However, that allows certain attacks, | ||
| 907 | // so we just send bad record MAC. We also need to make | ||
| 908 | // sure to always check the MAC to avoid a timing attack | ||
| 909 | // for the same issue. See paper by Vaudenay et al. | ||
| 910 | r.checkMAC(readMAC); | ||
| 911 | // use the same alert types as for MAC failure below | ||
| 912 | byte alertType = (r.contentType() == Record.ct_handshake) | ||
| 913 | ? Alerts.alert_handshake_failure | ||
| 914 | : Alerts.alert_bad_record_mac; | ||
| 915 | fatal(alertType, "Invalid padding", e); | ||
| 916 | } | ||
| 917 | if (!r.checkMAC(readMAC)) { | ||
| 918 | if (r.contentType() == Record.ct_handshake) { | ||
| 919 | fatal(Alerts.alert_handshake_failure, | ||
| 920 | "bad handshake record MAC"); | ||
| 921 | } else { | ||
| 922 | fatal(Alerts.alert_bad_record_mac, "bad record MAC"); | ||
| 923 | } | ||
| 924 | } | ||
| 925 | |||
| 926 | |||
| 927 | // if (!r.decompress(c)) | ||
| 928 | // fatal(Alerts.alert_decompression_failure, | ||
| 929 | // "decompression failure"); | ||
| 930 | |||
| 931 | /* | ||
| 932 | * Process the record. | ||
| 933 | */ | ||
| 934 | synchronized (this) { | ||
| 935 | switch (r.contentType()) { | ||
| 936 | case Record.ct_handshake: | ||
| 937 | /* | ||
| 938 | * Handshake messages always go to a pending session | ||
| 939 | * handshaker ... if there isn't one, create one. This | ||
| 940 | * must work asynchronously, for renegotiation. | ||
| 941 | * | ||
| 942 | * NOTE that handshaking will either resume a session | ||
| 943 | * which was in the cache (and which might have other | ||
| 944 | * connections in it already), or else will start a new | ||
| 945 | * session (new keys exchanged) with just this connection | ||
| 946 | * in it. | ||
| 947 | */ | ||
| 948 | initHandshaker(); | ||
| 949 | if (!handshaker.activated()) { | ||
| 950 | // prior to handshaking, activate the handshake | ||
| 951 | if (connectionState == cs_RENEGOTIATE) { | ||
| 952 | // don't use SSLv2Hello when renegotiating | ||
| 953 | handshaker.activate(protocolVersion); | ||
| 954 | } else { | ||
| 955 | handshaker.activate(null); | ||
| 956 | } | ||
| 957 | } | ||
| 958 | |||
| 959 | /* | ||
| 960 | * process the handshake record ... may contain just | ||
| 961 | * a partial handshake message or multiple messages. | ||
| 962 | * | ||
| 963 | * The handshaker state machine will ensure that it's | ||
| 964 | * a finished message. | ||
| 965 | */ | ||
| 966 | handshaker.process_record(r, expectingFinished); | ||
| 967 | expectingFinished = false; | ||
| 968 | |||
| 969 | if (handshaker.invalidated) { | ||
| 970 | handshaker = null; | ||
| 971 | // if state is cs_RENEGOTIATE, revert it to cs_DATA | ||
| 972 | if (connectionState == cs_RENEGOTIATE) { | ||
| 973 | connectionState = cs_DATA; | ||
| 974 | } | ||
| 975 | } else if (handshaker.isDone()) { | ||
| 976 | // reset the parameters for secure renegotiation. | ||
| 977 | secureRenegotiation = | ||
| 978 | handshaker.isSecureRenegotiation(); | ||
| 979 | clientVerifyData = handshaker.getClientVerifyData(); | ||
| 980 | serverVerifyData = handshaker.getServerVerifyData(); | ||
| 981 | |||
| 982 | sess = handshaker.getSession(); | ||
| 983 | handshakeSession = null; | ||
| 984 | handshaker = null; | ||
| 985 | connectionState = cs_DATA; | ||
| 986 | |||
| 987 | // | ||
| 988 | // Tell folk about handshake completion, but do | ||
| 989 | // it in a separate thread. | ||
| 990 | // | ||
| 991 | if (handshakeListeners != null) { | ||
| 992 | HandshakeCompletedEvent event = | ||
| 993 | new HandshakeCompletedEvent(this, sess); | ||
| 994 | |||
| 995 | Thread t = new NotifyHandshakeThread( | ||
| 996 | handshakeListeners.entrySet(), event); | ||
| 997 | t.start(); | ||
| 998 | } | ||
| 999 | } | ||
| 1000 | |||
| 1001 | if (needAppData || connectionState != cs_DATA) { | ||
| 1002 | continue; | ||
| 1003 | } | ||
| 1004 | break; | ||
| 1005 | |||
| 1006 | case Record.ct_application_data: | ||
| 1007 | // Pass this right back up to the application. | ||
| 1008 | if (connectionState != cs_DATA | ||
| 1009 | && connectionState != cs_RENEGOTIATE | ||
| 1010 | && connectionState != cs_SENT_CLOSE) { | ||
| 1011 | throw new SSLProtocolException( | ||
| 1012 | "Data received in non-data state: " + | ||
| 1013 | connectionState); | ||
| 1014 | } | ||
| 1015 | if (expectingFinished) { | ||
| 1016 | throw new SSLProtocolException | ||
| 1017 | ("Expecting finished message, received data"); | ||
| 1018 | } | ||
| 1019 | if (!needAppData) { | ||
| 1020 | throw new SSLException("Discarding app data"); | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | r.setAppDataValid(true); | ||
| 1024 | break; | ||
| 1025 | |||
| 1026 | case Record.ct_alert: | ||
| 1027 | recvAlert(r); | ||
| 1028 | continue; | ||
| 1029 | |||
| 1030 | case Record.ct_change_cipher_spec: | ||
| 1031 | if ((connectionState != cs_HANDSHAKE | ||
| 1032 | && connectionState != cs_RENEGOTIATE) | ||
| 1033 | || r.available() != 1 | ||
| 1034 | || r.read() != 1) { | ||
| 1035 | fatal(Alerts.alert_unexpected_message, | ||
| 1036 | "illegal change cipher spec msg, state = " | ||
| 1037 | + connectionState); | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | // | ||
| 1041 | // The first message after a change_cipher_spec | ||
| 1042 | // record MUST be a "Finished" handshake record, | ||
| 1043 | // else it's a protocol violation. We force this | ||
| 1044 | // to be checked by a minor tweak to the state | ||
| 1045 | // machine. | ||
| 1046 | // | ||
| 1047 | changeReadCiphers(); | ||
| 1048 | // next message MUST be a finished message | ||
| 1049 | expectingFinished = true; | ||
| 1050 | continue; | ||
| 1051 | |||
| 1052 | default: | ||
| 1053 | // | ||
| 1054 | // TLS requires that unrecognized records be ignored. | ||
| 1055 | // | ||
| 1056 | if (debug != null && Debug.isOn("ssl")) { | ||
| 1057 | System.out.println(threadName() + | ||
| 1058 | ", Received record type: " | ||
| 1059 | + r.contentType()); | ||
| 1060 | } | ||
| 1061 | continue; | ||
| 1062 | } // switch | ||
| 1063 | |||
| 1064 | /* | ||
| 1065 | * Check the sequence number state | ||
| 1066 | * | ||
| 1067 | * Note that in order to maintain the connection I/O | ||
| 1068 | * properly, we check the sequence number after the last | ||
| 1069 | * record reading process. As we request renegotiation | ||
| 1070 | * or close the connection for wrapped sequence number | ||
| 1071 | * when there is enough sequence number space left to | ||
| 1072 | * handle a few more records, so the sequence number | ||
| 1073 | * of the last record cannot be wrapped. | ||
| 1074 | */ | ||
| 1075 | if (connectionState < cs_ERROR) { | ||
| 1076 | checkSequenceNumber(readMAC, r.contentType()); | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | return; | ||
| 1080 | } // synchronized (this) | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | // | ||
| 1084 | // couldn't read, due to some kind of error | ||
| 1085 | // | ||
| 1086 | r.close(); | ||
| 1087 | return; | ||
| 1088 | } // synchronized (readLock) | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | /** | ||
| 1092 | * Check the sequence number state | ||
| 1093 | * | ||
| 1094 | * RFC 4346 states that, "Sequence numbers are of type uint64 and | ||
| 1095 | * may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS | ||
| 1096 | * implementation would need to wrap a sequence number, it must | ||
| 1097 | * renegotiate instead." | ||
| 1098 | */ | ||
| 1099 | private void checkSequenceNumber(MAC mac, byte type) | ||
| 1100 | throws IOException { | ||
| 1101 | |||
| 1102 | /* | ||
| 1103 | * Don't bother to check the sequence number for error or | ||
| 1104 | * closed connections, or NULL MAC. | ||
| 1105 | */ | ||
| 1106 | if (connectionState >= cs_ERROR || mac == MAC.NULL) { | ||
| 1107 | return; | ||
| 1108 | } | ||
| 1109 | |||
| 1110 | /* | ||
| 1111 | * Conservatively, close the connection immediately when the | ||
| 1112 | * sequence number is close to overflow | ||
| 1113 | */ | ||
| 1114 | if (mac.seqNumOverflow()) { | ||
| 1115 | /* | ||
| 1116 | * TLS protocols do not define a error alert for sequence | ||
| 1117 | * number overflow. We use handshake_failure error alert | ||
| 1118 | * for handshaking and bad_record_mac for other records. | ||
| 1119 | */ | ||
| 1120 | if (debug != null && Debug.isOn("ssl")) { | ||
| 1121 | System.out.println(threadName() + | ||
| 1122 | ", sequence number extremely close to overflow " + | ||
| 1123 | "(2^64-1 packets). Closing connection."); | ||
| 1124 | |||
| 1125 | } | ||
| 1126 | |||
| 1127 | fatal(Alerts.alert_handshake_failure, "sequence number overflow"); | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | /* | ||
| 1131 | * Ask for renegotiation when need to renew sequence number. | ||
| 1132 | * | ||
| 1133 | * Don't bother to kickstart the renegotiation when the local is | ||
| 1134 | * asking for it. | ||
| 1135 | */ | ||
| 1136 | if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) { | ||
| 1137 | if (debug != null && Debug.isOn("ssl")) { | ||
| 1138 | System.out.println(threadName() + ", request renegotiation " + | ||
| 1139 | "to avoid sequence number overflow"); | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | startHandshake(); | ||
| 1143 | } | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | // | ||
| 1147 | // HANDSHAKE RELATED CODE | ||
| 1148 | // | ||
| 1149 | |||
| 1150 | /** | ||
| 1151 | * Return the AppInputStream. For use by Handshaker only. | ||
| 1152 | */ | ||
| 1153 | AppInputStream getAppInputStream() { | ||
| 1154 | return input; | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | /** | ||
| 1158 | * Return the AppOutputStream. For use by Handshaker only. | ||
| 1159 | */ | ||
| 1160 | AppOutputStream getAppOutputStream() { | ||
| 1161 | return output; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | /** | ||
| 1165 | * Initialize the handshaker object. This means: | ||
| 1166 | * | ||
| 1167 | * . if a handshake is already in progress (state is cs_HANDSHAKE | ||
| 1168 | * or cs_RENEGOTIATE), do nothing and return | ||
| 1169 | * | ||
| 1170 | * . if the socket is already closed, throw an Exception (internal error) | ||
| 1171 | * | ||
| 1172 | * . otherwise (cs_START or cs_DATA), create the appropriate handshaker | ||
| 1173 | * object, and advance the connection state (to cs_HANDSHAKE or | ||
| 1174 | * cs_RENEGOTIATE, respectively). | ||
| 1175 | * | ||
| 1176 | * This method is called right after a new socket is created, when | ||
| 1177 | * starting renegotiation, or when changing client/ server mode of the | ||
| 1178 | * socket. | ||
| 1179 | */ | ||
| 1180 | private void initHandshaker() { | ||
| 1181 | switch (connectionState) { | ||
| 1182 | |||
| 1183 | // | ||
| 1184 | // Starting a new handshake. | ||
| 1185 | // | ||
| 1186 | case cs_START: | ||
| 1187 | case cs_DATA: | ||
| 1188 | break; | ||
| 1189 | |||
| 1190 | // | ||
| 1191 | // We're already in the middle of a handshake. | ||
| 1192 | // | ||
| 1193 | case cs_HANDSHAKE: | ||
| 1194 | case cs_RENEGOTIATE: | ||
| 1195 | return; | ||
| 1196 | |||
| 1197 | // | ||
| 1198 | // Anyone allowed to call this routine is required to | ||
| 1199 | // do so ONLY if the connection state is reasonable... | ||
| 1200 | // | ||
| 1201 | default: | ||
| 1202 | throw new IllegalStateException("Internal error"); | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | // state is either cs_START or cs_DATA | ||
| 1206 | if (connectionState == cs_START) { | ||
| 1207 | connectionState = cs_HANDSHAKE; | ||
| 1208 | } else { // cs_DATA | ||
| 1209 | connectionState = cs_RENEGOTIATE; | ||
| 1210 | } | ||
| 1211 | if (roleIsServer) { | ||
| 1212 | handshaker = new ServerHandshaker(this, sslContext, | ||
| 1213 | enabledProtocols, doClientAuth, | ||
| 1214 | protocolVersion, connectionState == cs_HANDSHAKE, | ||
| 1215 | secureRenegotiation, clientVerifyData, serverVerifyData); | ||
| 1216 | } else { | ||
| 1217 | handshaker = new ClientHandshaker(this, sslContext, | ||
| 1218 | enabledProtocols, | ||
| 1219 | protocolVersion, connectionState == cs_HANDSHAKE, | ||
| 1220 | secureRenegotiation, clientVerifyData, serverVerifyData); | ||
| 1221 | } | ||
| 1222 | handshaker.setEnabledCipherSuites(enabledCipherSuites); | ||
| 1223 | handshaker.setEnableSessionCreation(enableSessionCreation); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | /** | ||
| 1227 | * Synchronously perform the initial handshake. | ||
| 1228 | * | ||
| 1229 | * If the handshake is already in progress, this method blocks until it | ||
| 1230 | * is completed. If the initial handshake has already been completed, | ||
| 1231 | * it returns immediately. | ||
| 1232 | */ | ||
| 1233 | private void performInitialHandshake() throws IOException { | ||
| 1234 | // use handshakeLock and the state check to make sure only | ||
| 1235 | // one thread performs the handshake | ||
| 1236 | synchronized (handshakeLock) { | ||
| 1237 | if (getConnectionState() == cs_HANDSHAKE) { | ||
| 1238 | kickstartHandshake(); | ||
| 1239 | |||
| 1240 | /* | ||
| 1241 | * All initial handshaking goes through this | ||
| 1242 | * InputRecord until we have a valid SSL connection. | ||
| 1243 | * Once initial handshaking is finished, AppInputStream's | ||
| 1244 | * InputRecord can handle any future renegotiation. | ||
| 1245 | * | ||
| 1246 | * Keep this local so that it goes out of scope and is | ||
| 1247 | * eventually GC'd. | ||
| 1248 | */ | ||
| 1249 | if (inrec == null) { | ||
| 1250 | inrec = new InputRecord(); | ||
| 1251 | |||
| 1252 | /* | ||
| 1253 | * Grab the characteristics already assigned to | ||
| 1254 | * AppInputStream's InputRecord. Enable checking for | ||
| 1255 | * SSLv2 hellos on this first handshake. | ||
| 1256 | */ | ||
| 1257 | inrec.setHandshakeHash(input.r.getHandshakeHash()); | ||
| 1258 | inrec.setHelloVersion(input.r.getHelloVersion()); | ||
| 1259 | inrec.enableFormatChecks(); | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | readRecord(inrec, false); | ||
| 1263 | inrec = null; | ||
| 1264 | } | ||
| 1265 | } | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | /** | ||
| 1269 | * Starts an SSL handshake on this connection. | ||
| 1270 | */ | ||
| 1271 | public void startHandshake() throws IOException { | ||
| 1272 | // start an ssl handshake that could be resumed from timeout exception | ||
| 1273 | startHandshake(true); | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | /** | ||
| 1277 | * Starts an ssl handshake on this connection. | ||
| 1278 | * | ||
| 1279 | * @param resumable indicates the handshake process is resumable from a | ||
| 1280 | * certain exception. If <code>resumable</code>, the socket will | ||
| 1281 | * be reserved for exceptions like timeout; otherwise, the socket | ||
| 1282 | * will be closed, no further communications could be done. | ||
| 1283 | */ | ||
| 1284 | private void startHandshake(boolean resumable) throws IOException { | ||
| 1285 | checkWrite(); | ||
| 1286 | try { | ||
| 1287 | if (getConnectionState() == cs_HANDSHAKE) { | ||
| 1288 | // do initial handshake | ||
| 1289 | performInitialHandshake(); | ||
| 1290 | } else { | ||
| 1291 | // start renegotiation | ||
| 1292 | kickstartHandshake(); | ||
| 1293 | } | ||
| 1294 | } catch (Exception e) { | ||
| 1295 | // shutdown and rethrow (wrapped) exception as appropriate | ||
| 1296 | handleException(e, resumable); | ||
| 1297 | } | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | /** | ||
| 1301 | * Kickstart the handshake if it is not already in progress. | ||
| 1302 | * This means: | ||
| 1303 | * | ||
| 1304 | * . if handshaking is already underway, do nothing and return | ||
| 1305 | * | ||
| 1306 | * . if the socket is not connected or already closed, throw an | ||
| 1307 | * Exception. | ||
| 1308 | * | ||
| 1309 | * . otherwise, call initHandshake() to initialize the handshaker | ||
| 1310 | * object and progress the state. Then, send the initial | ||
| 1311 | * handshaking message if appropriate (always on clients and | ||
| 1312 | * on servers when renegotiating). | ||
| 1313 | */ | ||
| 1314 | private synchronized void kickstartHandshake() throws IOException { | ||
| 1315 | |||
| 1316 | switch (connectionState) { | ||
| 1317 | |||
| 1318 | case cs_HANDSHAKE: | ||
| 1319 | // handshaker already setup, proceed | ||
| 1320 | break; | ||
| 1321 | |||
| 1322 | case cs_DATA: | ||
| 1323 | if (!secureRenegotiation && !Handshaker.allowUnsafeRenegotiation) { | ||
| 1324 | throw new SSLHandshakeException( | ||
| 1325 | "Insecure renegotiation is not allowed"); | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | if (!secureRenegotiation) { | ||
| 1329 | if (debug != null && Debug.isOn("handshake")) { | ||
| 1330 | System.out.println( | ||
| 1331 | "Warning: Using insecure renegotiation"); | ||
| 1332 | } | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | // initialize the handshaker, move to cs_RENEGOTIATE | ||
| 1336 | initHandshaker(); | ||
| 1337 | break; | ||
| 1338 | |||
| 1339 | case cs_RENEGOTIATE: | ||
| 1340 | // handshaking already in progress, return | ||
| 1341 | return; | ||
| 1342 | |||
| 1343 | /* | ||
| 1344 | * The only way to get a socket in the state is when | ||
| 1345 | * you have an unconnected socket. | ||
| 1346 | */ | ||
| 1347 | case cs_START: | ||
| 1348 | throw new SocketException( | ||
| 1349 | "handshaking attempted on unconnected socket"); | ||
| 1350 | |||
| 1351 | default: | ||
| 1352 | throw new SocketException("connection is closed"); | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | // | ||
| 1356 | // Kickstart handshake state machine if we need to ... | ||
| 1357 | // | ||
| 1358 | // Note that handshaker.kickstart() writes the message | ||
| 1359 | // to its HandshakeOutStream, which calls back into | ||
| 1360 | // SSLSocketImpl.writeRecord() to send it. | ||
| 1361 | // | ||
| 1362 | if (!handshaker.activated()) { | ||
| 1363 | // prior to handshaking, activate the handshake | ||
| 1364 | if (connectionState == cs_RENEGOTIATE) { | ||
| 1365 | // don't use SSLv2Hello when renegotiating | ||
| 1366 | handshaker.activate(protocolVersion); | ||
| 1367 | } else { | ||
| 1368 | handshaker.activate(null); | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | if (handshaker instanceof ClientHandshaker) { | ||
| 1372 | // send client hello | ||
| 1373 | handshaker.kickstart(); | ||
| 1374 | } else { | ||
| 1375 | if (connectionState == cs_HANDSHAKE) { | ||
| 1376 | // initial handshake, no kickstart message to send | ||
| 1377 | } else { | ||
| 1378 | // we want to renegotiate, send hello request | ||
| 1379 | handshaker.kickstart(); | ||
| 1380 | // hello request is not included in the handshake | ||
| 1381 | // hashes, reset them | ||
| 1382 | handshaker.handshakeHash.reset(); | ||
| 1383 | } | ||
| 1384 | } | ||
| 1385 | } | ||
| 1386 | } | ||
| 1387 | |||
| 1388 | // | ||
| 1389 | // CLOSURE RELATED CALLS | ||
| 1390 | // | ||
| 1391 | |||
| 1392 | /** | ||
| 1393 | * Return whether the socket has been explicitly closed by the application. | ||
| 1394 | */ | ||
| 1395 | public boolean isClosed() { | ||
| 1396 | return getConnectionState() == cs_APP_CLOSED; | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | /** | ||
| 1400 | * Return whether we have reached end-of-file. | ||
| 1401 | * | ||
| 1402 | * If the socket is not connected, has been shutdown because of an error | ||
| 1403 | * or has been closed, throw an Exception. | ||
| 1404 | */ | ||
| 1405 | boolean checkEOF() throws IOException { | ||
| 1406 | switch (getConnectionState()) { | ||
| 1407 | case cs_START: | ||
| 1408 | throw new SocketException("Socket is not connected"); | ||
| 1409 | |||
| 1410 | case cs_HANDSHAKE: | ||
| 1411 | case cs_DATA: | ||
| 1412 | case cs_RENEGOTIATE: | ||
| 1413 | case cs_SENT_CLOSE: | ||
| 1414 | return false; | ||
| 1415 | |||
| 1416 | case cs_APP_CLOSED: | ||
| 1417 | throw new SocketException("Socket is closed"); | ||
| 1418 | |||
| 1419 | case cs_ERROR: | ||
| 1420 | case cs_CLOSED: | ||
| 1421 | default: | ||
| 1422 | // either closed because of error, or normal EOF | ||
| 1423 | if (closeReason == null) { | ||
| 1424 | return true; | ||
| 1425 | } | ||
| 1426 | IOException e = new SSLException | ||
| 1427 | ("Connection has been shutdown: " + closeReason); | ||
| 1428 | e.initCause(closeReason); | ||
| 1429 | throw e; | ||
| 1430 | |||
| 1431 | } | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | /** | ||
| 1435 | * Check if we can write data to this socket. If not, throw an IOException. | ||
| 1436 | */ | ||
| 1437 | void checkWrite() throws IOException { | ||
| 1438 | if (checkEOF() || (getConnectionState() == cs_SENT_CLOSE)) { | ||
| 1439 | // we are at EOF, write must throw Exception | ||
| 1440 | throw new SocketException("Connection closed by remote host"); | ||
| 1441 | } | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | protected void closeSocket() throws IOException { | ||
| 1445 | |||
| 1446 | if ((debug != null) && Debug.isOn("ssl")) { | ||
| 1447 | System.out.println(threadName() + ", called closeSocket()"); | ||
| 1448 | } | ||
| 1449 | if (self == this) { | ||
| 1450 | super.close(); | ||
| 1451 | } else { | ||
| 1452 | self.close(); | ||
| 1453 | } | ||
| 1454 | } | ||
| 1455 | |||
| 1456 | private void closeSocket(boolean selfInitiated) throws IOException { | ||
| 1457 | if ((debug != null) && Debug.isOn("ssl")) { | ||
| 1458 | System.out.println(threadName() + ", called closeSocket(selfInitiated)"); | ||
| 1459 | } | ||
| 1460 | if (self == this) { | ||
| 1461 | super.close(); | ||
| 1462 | } else if (autoClose) { | ||
| 1463 | self.close(); | ||
| 1464 | } else if (selfInitiated) { | ||
| 1465 | // layered && non-autoclose | ||
| 1466 | // read close_notify alert to clear input stream | ||
| 1467 | waitForClose(false); | ||
| 1468 | } | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | /* | ||
| 1472 | * Closing the connection is tricky ... we can't officially close the | ||
| 1473 | * connection until we know the other end is ready to go away too, | ||
| 1474 | * and if ever the connection gets aborted we must forget session | ||
| 1475 | * state (it becomes invalid). | ||
| 1476 | */ | ||
| 1477 | |||
| 1478 | /** | ||
| 1479 | * Closes the SSL connection. SSL includes an application level | ||
| 1480 | * shutdown handshake; you should close SSL sockets explicitly | ||
| 1481 | * rather than leaving it for finalization, so that your remote | ||
| 1482 | * peer does not experience a protocol error. | ||
| 1483 | */ | ||
| 1484 | public void close() throws IOException { | ||
| 1485 | if ((debug != null) && Debug.isOn("ssl")) { | ||
| 1486 | System.out.println(threadName() + ", called close()"); | ||
| 1487 | } | ||
| 1488 | closeInternal(true); // caller is initiating close | ||
| 1489 | setConnectionState(cs_APP_CLOSED); | ||
| 1490 | } | ||
| 1491 | |||
| 1492 | /** | ||
| 1493 | * Don't synchronize the whole method because waitForClose() | ||
| 1494 | * (which calls readRecord()) might be called. | ||
| 1495 | * | ||
| 1496 | * @param selfInitiated Indicates which party initiated the close. | ||
| 1497 | * If selfInitiated, this side is initiating a close; for layered and | ||
| 1498 | * non-autoclose socket, wait for close_notify response. | ||
| 1499 | * If !selfInitiated, peer sent close_notify; we reciprocate but | ||
| 1500 | * no need to wait for response. | ||
| 1501 | */ | ||
| 1502 | private void closeInternal(boolean selfInitiated) throws IOException { | ||
| 1503 | if ((debug != null) && Debug.isOn("ssl")) { | ||
| 1504 | System.out.println(threadName() + ", called closeInternal(" | ||
| 1505 | + selfInitiated + ")"); | ||
| 1506 | } | ||
| 1507 | |||
| 1508 | int state = getConnectionState(); | ||
| 1509 | boolean closeSocketCalled = false; | ||
| 1510 | Throwable cachedThrowable = null; | ||
| 1511 | try { | ||
| 1512 | switch (state) { | ||
| 1513 | /* | ||
| 1514 | * java.net code sometimes closes sockets "early", when | ||
| 1515 | * we can't actually do I/O on them. | ||
| 1516 | */ | ||
| 1517 | case cs_START: | ||
| 1518 | break; | ||
| 1519 | |||
| 1520 | /* | ||
| 1521 | * If we're closing down due to error, we already sent (or else | ||
| 1522 | * received) the fatal alert ... no niceties, blow the connection | ||
| 1523 | * away as quickly as possible (even if we didn't allocate the | ||
| 1524 | * socket ourselves; it's unusable, regardless). | ||
| 1525 | */ | ||
| 1526 | case cs_ERROR: | ||
| 1527 | closeSocket(); | ||
| 1528 | break; | ||
| 1529 | |||
| 1530 | /* | ||
| 1531 | * Sometimes close() gets called more than once. | ||
| 1532 | */ | ||
| 1533 | case cs_CLOSED: | ||
| 1534 | case cs_APP_CLOSED: | ||
| 1535 | break; | ||
| 1536 | |||
| 1537 | /* | ||
| 1538 | * Otherwise we indicate clean termination. | ||
| 1539 | */ | ||
| 1540 | // case cs_HANDSHAKE: | ||
| 1541 | // case cs_DATA: | ||
| 1542 | // case cs_RENEGOTIATE: | ||
| 1543 | // case cs_SENT_CLOSE: | ||
| 1544 | default: | ||
| 1545 | synchronized (this) { | ||
| 1546 | if (((state = getConnectionState()) == cs_CLOSED) || | ||
| 1547 | (state == cs_ERROR) || (state == cs_APP_CLOSED)) { | ||
| 1548 | return; // connection was closed while we waited | ||
| 1549 | } | ||
| 1550 | if (state != cs_SENT_CLOSE) { | ||
| 1551 | try { | ||
| 1552 | warning(Alerts.alert_close_notify); | ||
| 1553 | connectionState = cs_SENT_CLOSE; | ||
| 1554 | } catch (Throwable th) { | ||
| 1555 | // we need to ensure socket is closed out | ||
| 1556 | // if we encounter any errors. | ||
| 1557 | connectionState = cs_ERROR; | ||
| 1558 | // cache this for later use | ||
| 1559 | cachedThrowable = th; | ||
| 1560 | closeSocketCalled = true; | ||
| 1561 | closeSocket(selfInitiated); | ||
| 1562 | } | ||
| 1563 | } | ||
| 1564 | } | ||
| 1565 | // If state was cs_SENT_CLOSE before, we don't do the actual | ||
| 1566 | // closing since it is already in progress. | ||
| 1567 | if (state == cs_SENT_CLOSE) { | ||
| 1568 | if (debug != null && Debug.isOn("ssl")) { | ||
| 1569 | System.out.println(threadName() + | ||
| 1570 | ", close invoked again; state = " + | ||
| 1571 | getConnectionState()); | ||
| 1572 | } | ||
| 1573 | if (selfInitiated == false) { | ||
| 1574 | // We were called because a close_notify message was | ||
| 1575 | // received. This may be due to another thread calling | ||
| 1576 | // read() or due to our call to waitForClose() below. | ||
| 1577 | // In either case, just return. | ||
| 1578 | return; | ||
| 1579 | } | ||
| 1580 | // Another thread explicitly called close(). We need to | ||
| 1581 | // wait for the closing to complete before returning. | ||
| 1582 | synchronized (this) { | ||
| 1583 | while (connectionState < cs_CLOSED) { | ||
| 1584 | try { | ||
| 1585 | this.wait(); | ||
| 1586 | } catch (InterruptedException e) { | ||
| 1587 | // ignore | ||
| 1588 | } | ||
| 1589 | } | ||
| 1590 | } | ||
| 1591 | if ((debug != null) && Debug.isOn("ssl")) { | ||
| 1592 | System.out.println(threadName() + | ||
| 1593 | ", after primary close; state = " + | ||
| 1594 | getConnectionState()); | ||
| 1595 | } | ||
| 1596 | return; | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | if (!closeSocketCalled) { | ||
| 1600 | closeSocketCalled = true; | ||
| 1601 | closeSocket(selfInitiated); | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | break; | ||
| 1605 | } | ||
| 1606 | } finally { | ||
| 1607 | synchronized (this) { | ||
| 1608 | // Upon exit from this method, the state is always >= cs_CLOSED | ||
| 1609 | connectionState = (connectionState == cs_APP_CLOSED) | ||
| 1610 | ? cs_APP_CLOSED : cs_CLOSED; | ||
| 1611 | // notify any threads waiting for the closing to finish | ||
| 1612 | this.notifyAll(); | ||
| 1613 | } | ||
| 1614 | if (closeSocketCalled) { | ||
| 1615 | // Dispose of ciphers since we've closed socket | ||
| 1616 | disposeCiphers(); | ||
| 1617 | } | ||
| 1618 | if (cachedThrowable != null) { | ||
| 1619 | /* | ||
| 1620 | * Rethrow the error to the calling method | ||
| 1621 | * The Throwable caught can only be an Error or RuntimeException | ||
| 1622 | */ | ||
| 1623 | if (cachedThrowable instanceof Error) | ||
| 1624 | throw (Error) cachedThrowable; | ||
| 1625 | if (cachedThrowable instanceof RuntimeException) | ||
| 1626 | throw (RuntimeException) cachedThrowable; | ||
| 1627 | } | ||
| 1628 | } | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | /** | ||
| 1632 | * Reads a close_notify or a fatal alert from the input stream. | ||
| 1633 | * Keep reading records until we get a close_notify or until | ||
| 1634 | * the connection is otherwise closed. The close_notify or alert | ||
| 1635 | * might be read by another reader, | ||
| 1636 | * which will then process the close and set the connection state. | ||
| 1637 | */ | ||
| 1638 | void waitForClose(boolean rethrow) throws IOException { | ||
| 1639 | if (debug != null && Debug.isOn("ssl")) { | ||
| 1640 | System.out.println(threadName() + | ||
| 1641 | ", waiting for close_notify or alert: state " | ||
| 1642 | + getConnectionState()); | ||
| 1643 | } | ||
| 1644 | |||
| 1645 | try { | ||
| 1646 | int state; | ||
| 1647 | |||
| 1648 | while (((state = getConnectionState()) != cs_CLOSED) && | ||
| 1649 | (state != cs_ERROR) && (state != cs_APP_CLOSED)) { | ||
| 1650 | // create the InputRecord if it isn't intialized. | ||
| 1651 | if (inrec == null) { | ||
| 1652 | inrec = new InputRecord(); | ||
| 1653 | } | ||
| 1654 | |||
| 1655 | // Ask for app data and then throw it away | ||
| 1656 | try { | ||
| 1657 | readRecord(inrec, true); | ||
| 1658 | } catch (SocketTimeoutException e) { | ||
| 1659 | // if time out, ignore the exception and continue | ||
| 1660 | } | ||
| 1661 | } | ||
| 1662 | inrec = null; | ||
| 1663 | } catch (IOException e) { | ||
| 1664 | if (debug != null && Debug.isOn("ssl")) { | ||
| 1665 | System.out.println(threadName() + | ||
| 1666 | ", Exception while waiting for close " +e); | ||
| 1667 | } | ||
| 1668 | if (rethrow) { | ||
| 1669 | throw e; // pass exception up | ||
| 1670 | } | ||
| 1671 | } | ||
| 1672 | } | ||
| 1673 | |||
| 1674 | /** | ||
| 1675 | * Called by closeInternal() only. Be sure to consider the | ||
| 1676 | * synchronization locks carefully before calling it elsewhere. | ||
| 1677 | */ | ||
| 1678 | private void disposeCiphers() { | ||
| 1679 | // See comment in changeReadCiphers() | ||
| 1680 | synchronized (readLock) { | ||
| 1681 | readCipher.dispose(); | ||
| 1682 | } | ||
| 1683 | // See comment in changeReadCiphers() | ||
| 1684 | writeLock.lock(); | ||
| 1685 | try { | ||
| 1686 | writeCipher.dispose(); | ||
| 1687 | } finally { | ||
| 1688 | writeLock.unlock(); | ||
| 1689 | } | ||
| 1690 | } | ||
| 1691 | |||
| 1692 | // | ||
| 1693 | // EXCEPTION AND ALERT HANDLING | ||
| 1694 | // | ||
| 1695 | |||
| 1696 | /** | ||
| 1697 | * Handle an exception. This method is called by top level exception | ||
| 1698 | * handlers (in read(), write()) to make sure we always shutdown the | ||
| 1699 | * connection correctly and do not pass runtime exception to the | ||
| 1700 | * application. | ||
| 1701 | */ | ||
| 1702 | void handleException(Exception e) throws IOException { | ||
| 1703 | handleException(e, true); | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | /** | ||
| 1707 | * Handle an exception. This method is called by top level exception | ||
| 1708 | * handlers (in read(), write(), startHandshake()) to make sure we | ||
| 1709 | * always shutdown the connection correctly and do not pass runtime | ||
| 1710 | * exception to the application. | ||
| 1711 | * | ||
| 1712 | * This method never returns normally, it always throws an IOException. | ||
| 1713 | * | ||
| 1714 | * We first check if the socket has already been shutdown because of an | ||
| 1715 | * error. If so, we just rethrow the exception. If the socket has not | ||
| 1716 | * been shutdown, we sent a fatal alert and remember the exception. | ||
| 1717 | * | ||
| 1718 | * @param e the Exception | ||
| 1719 | * @param resumable indicates the caller process is resumable from the | ||
| 1720 | * exception. If <code>resumable</code>, the socket will be | ||
| 1721 | * reserved for exceptions like timeout; otherwise, the socket | ||
| 1722 | * will be closed, no further communications could be done. | ||
| 1723 | */ | ||
| 1724 | synchronized private void handleException(Exception e, boolean resumable) | ||
| 1725 | throws IOException { | ||
| 1726 | if ((debug != null) && Debug.isOn("ssl")) { | ||
| 1727 | System.out.println(threadName() | ||
| 1728 | + ", handling exception: " + e.toString()); | ||
| 1729 | } | ||
| 1730 | |||
| 1731 | // don't close the Socket in case of timeouts or interrupts if | ||
| 1732 | // the process is resumable. | ||
| 1733 | if (e instanceof InterruptedIOException && resumable) { | ||
| 1734 | throw (IOException)e; | ||
| 1735 | } | ||
| 1736 | |||
| 1737 | // if we've already shutdown because of an error, | ||
| 1738 | // there is nothing to do except rethrow the exception | ||
| 1739 | if (closeReason != null) { | ||
| 1740 | if (e instanceof IOException) { // includes SSLException | ||
| 1741 | throw (IOException)e; | ||
| 1742 | } else { | ||
| 1743 | // this is odd, not an IOException. | ||
| 1744 | // normally, this should not happen | ||
| 1745 | // if closeReason has been already been set | ||
| 1746 | throw Alerts.getSSLException(Alerts.alert_internal_error, e, | ||
| 1747 | "Unexpected exception"); | ||
| 1748 | } | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | // need to perform error shutdown | ||
| 1752 | boolean isSSLException = (e instanceof SSLException); | ||
| 1753 | if ((isSSLException == false) && (e instanceof IOException)) { | ||
| 1754 | // IOException from the socket | ||
| 1755 | // this means the TCP connection is already dead | ||
| 1756 | // we call fatal just to set the error status | ||
| 1757 | try { | ||
| 1758 | fatal(Alerts.alert_unexpected_message, e); | ||
| 1759 | } catch (IOException ee) { | ||
| 1760 | // ignore (IOException wrapped in SSLException) | ||
| 1761 | } | ||
| 1762 | // rethrow original IOException | ||
| 1763 | throw (IOException)e; | ||
| 1764 | } | ||
| 1765 | |||
| 1766 | // must be SSLException or RuntimeException | ||
| 1767 | byte alertType; | ||
| 1768 | if (isSSLException) { | ||
| 1769 | if (e instanceof SSLHandshakeException) { | ||
| 1770 | alertType = Alerts.alert_handshake_failure; | ||
| 1771 | } else { | ||
| 1772 | alertType = Alerts.alert_unexpected_message; | ||
| 1773 | } | ||
| 1774 | } else { | ||
| 1775 | alertType = Alerts.alert_internal_error; | ||
| 1776 | } | ||
| 1777 | fatal(alertType, e); | ||
| 1778 | } | ||
| 1779 | |||
| 1780 | /* | ||
| 1781 | * Send a warning alert. | ||
| 1782 | */ | ||
| 1783 | void warning(byte description) { | ||
| 1784 | sendAlert(Alerts.alert_warning, description); | ||
| 1785 | } | ||
| 1786 | |||
| 1787 | synchronized void fatal(byte description, String diagnostic) | ||
| 1788 | throws IOException { | ||
| 1789 | fatal(description, diagnostic, null); | ||
| 1790 | } | ||
| 1791 | |||
| 1792 | synchronized void fatal(byte description, Throwable cause) | ||
| 1793 | throws IOException { | ||
| 1794 | fatal(description, null, cause); | ||
| 1795 | } | ||
| 1796 | |||
| 1797 | /* | ||
| 1798 | * Send a fatal alert, and throw an exception so that callers will | ||
| 1799 | * need to stand on their heads to accidentally continue processing. | ||
| 1800 | */ | ||
| 1801 | synchronized void fatal(byte description, String diagnostic, | ||
| 1802 | Throwable cause) throws IOException { | ||
| 1803 | if ((input != null) && (input.r != null)) { | ||
| 1804 | input.r.close(); | ||
| 1805 | } | ||
| 1806 | sess.invalidate(); | ||
| 1807 | if (handshakeSession != null) { | ||
| 1808 | handshakeSession.invalidate(); | ||
| 1809 | } | ||
| 1810 | |||
| 1811 | int oldState = connectionState; | ||
| 1812 | if (connectionState < cs_ERROR) { | ||
| 1813 | connectionState = cs_ERROR; | ||
| 1814 | } | ||
| 1815 | |||
| 1816 | /* | ||
| 1817 | * Has there been an error received yet? If not, remember it. | ||
| 1818 | * By RFC 2246, we don't bother waiting for a response. | ||
| 1819 | * Fatal errors require immediate shutdown. | ||
| 1820 | */ | ||
| 1821 | if (closeReason == null) { | ||
| 1822 | /* | ||
| 1823 | * Try to clear the kernel buffer to avoid TCP connection resets. | ||
| 1824 | */ | ||
| 1825 | if (oldState == cs_HANDSHAKE) { | ||
| 1826 | sockInput.skip(sockInput.available()); | ||
| 1827 | } | ||
| 1828 | |||
| 1829 | // If the description equals -1, the alert won't be sent to peer. | ||
| 1830 | if (description != -1) { | ||
| 1831 | sendAlert(Alerts.alert_fatal, description); | ||
| 1832 | } | ||
| 1833 | if (cause instanceof SSLException) { // only true if != null | ||
| 1834 | closeReason = (SSLException)cause; | ||
| 1835 | } else { | ||
| 1836 | closeReason = | ||
| 1837 | Alerts.getSSLException(description, cause, diagnostic); | ||
| 1838 | } | ||
| 1839 | } | ||
| 1840 | |||
| 1841 | /* | ||
| 1842 | * Clean up our side. | ||
| 1843 | */ | ||
| 1844 | closeSocket(); | ||
| 1845 | // Another thread may have disposed the ciphers during closing | ||
| 1846 | if (connectionState < cs_CLOSED) { | ||
| 1847 | connectionState = (oldState == cs_APP_CLOSED) ? cs_APP_CLOSED | ||
| 1848 | : cs_CLOSED; | ||
| 1849 | |||
| 1850 | // We should lock readLock and writeLock if no deadlock risks. | ||
| 1851 | // See comment in changeReadCiphers() | ||
| 1852 | readCipher.dispose(); | ||
| 1853 | writeCipher.dispose(); | ||
| 1854 | } | ||
| 1855 | |||
| 1856 | throw closeReason; | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | |||
| 1860 | /* | ||
| 1861 | * Process an incoming alert ... caller must already have synchronized | ||
| 1862 | * access to "this". | ||
| 1863 | */ | ||
| 1864 | private void recvAlert(InputRecord r) throws IOException { | ||
| 1865 | byte level = (byte)r.read(); | ||
| 1866 | byte description = (byte)r.read(); | ||
| 1867 | if (description == -1) { // check for short message | ||
| 1868 | fatal(Alerts.alert_illegal_parameter, "Short alert message"); | ||
| 1869 | } | ||
| 1870 | |||
| 1871 | if (debug != null && (Debug.isOn("record") || | ||
| 1872 | Debug.isOn("handshake"))) { | ||
| 1873 | synchronized (System.out) { | ||
| 1874 | System.out.print(threadName()); | ||
| 1875 | System.out.print(", RECV " + protocolVersion + " ALERT: "); | ||
| 1876 | if (level == Alerts.alert_fatal) { | ||
| 1877 | System.out.print("fatal, "); | ||
| 1878 | } else if (level == Alerts.alert_warning) { | ||
| 1879 | System.out.print("warning, "); | ||
| 1880 | } else { | ||
| 1881 | System.out.print("<level " + (0x0ff & level) + ">, "); | ||
| 1882 | } | ||
| 1883 | System.out.println(Alerts.alertDescription(description)); | ||
| 1884 | } | ||
| 1885 | } | ||
| 1886 | |||
| 1887 | if (level == Alerts.alert_warning) { | ||
| 1888 | if (description == Alerts.alert_close_notify) { | ||
| 1889 | if (connectionState == cs_HANDSHAKE) { | ||
| 1890 | fatal(Alerts.alert_unexpected_message, | ||
| 1891 | "Received close_notify during handshake"); | ||
| 1892 | } else { | ||
| 1893 | closeInternal(false); // reply to close | ||
| 1894 | } | ||
| 1895 | } else { | ||
| 1896 | |||
| 1897 | // | ||
| 1898 | // The other legal warnings relate to certificates, | ||
| 1899 | // e.g. no_certificate, bad_certificate, etc; these | ||
| 1900 | // are important to the handshaking code, which can | ||
| 1901 | // also handle illegal protocol alerts if needed. | ||
| 1902 | // | ||
| 1903 | if (handshaker != null) { | ||
| 1904 | handshaker.handshakeAlert(description); | ||
| 1905 | } | ||
| 1906 | } | ||
| 1907 | } else { // fatal or unknown level | ||
| 1908 | String reason = "Received fatal alert: " | ||
| 1909 | + Alerts.alertDescription(description); | ||
| 1910 | if (closeReason == null) { | ||
| 1911 | closeReason = Alerts.getSSLException(description, reason); | ||
| 1912 | } | ||
| 1913 | fatal(Alerts.alert_unexpected_message, reason); | ||
| 1914 | } | ||
| 1915 | } | ||
| 1916 | |||
| 1917 | |||
| 1918 | /* | ||
| 1919 | * Emit alerts. Caller must have synchronized with "this". | ||
| 1920 | */ | ||
| 1921 | private void sendAlert(byte level, byte description) { | ||
| 1922 | // the connectionState cannot be cs_START | ||
| 1923 | if (connectionState >= cs_SENT_CLOSE) { | ||
| 1924 | return; | ||
| 1925 | } | ||
| 1926 | |||
| 1927 | // For initial handshaking, don't send alert message to peer if | ||
| 1928 | // handshaker has not started. | ||
| 1929 | if (connectionState == cs_HANDSHAKE && | ||
| 1930 | (handshaker == null || !handshaker.started())) { | ||
| 1931 | return; | ||
| 1932 | } | ||
| 1933 | |||
| 1934 | OutputRecord r = new OutputRecord(Record.ct_alert); | ||
| 1935 | r.setVersion(protocolVersion); | ||
| 1936 | |||
| 1937 | boolean useDebug = debug != null && Debug.isOn("ssl"); | ||
| 1938 | if (useDebug) { | ||
| 1939 | synchronized (System.out) { | ||
| 1940 | System.out.print(threadName()); | ||
| 1941 | System.out.print(", SEND " + protocolVersion + " ALERT: "); | ||
| 1942 | if (level == Alerts.alert_fatal) { | ||
| 1943 | System.out.print("fatal, "); | ||
| 1944 | } else if (level == Alerts.alert_warning) { | ||
| 1945 | System.out.print("warning, "); | ||
| 1946 | } else { | ||
| 1947 | System.out.print("<level = " + (0x0ff & level) + ">, "); | ||
| 1948 | } | ||
| 1949 | System.out.println("description = " | ||
| 1950 | + Alerts.alertDescription(description)); | ||
| 1951 | } | ||
| 1952 | } | ||
| 1953 | |||
| 1954 | r.write(level); | ||
| 1955 | r.write(description); | ||
| 1956 | try { | ||
| 1957 | writeRecord(r); | ||
| 1958 | } catch (IOException e) { | ||
| 1959 | if (useDebug) { | ||
| 1960 | System.out.println(threadName() + | ||
| 1961 | ", Exception sending alert: " + e); | ||
| 1962 | } | ||
| 1963 | } | ||
| 1964 | } | ||
| 1965 | |||
| 1966 | // | ||
| 1967 | // VARIOUS OTHER METHODS | ||
| 1968 | // | ||
| 1969 | |||
| 1970 | /* | ||
| 1971 | * When a connection finishes handshaking by enabling use of a newly | ||
| 1972 | * negotiated session, each end learns about it in two halves (read, | ||
| 1973 | * and write). When both read and write ciphers have changed, and the | ||
| 1974 | * last handshake message has been read, the connection has joined | ||
| 1975 | * (rejoined) the new session. | ||
| 1976 | * | ||
| 1977 | * NOTE: The SSLv3 spec is rather unclear on the concepts here. | ||
| 1978 | * Sessions don't change once they're established (including cipher | ||
| 1979 | * suite and master secret) but connections can join them (and leave | ||
| 1980 | * them). They're created by handshaking, though sometime handshaking | ||
| 1981 | * causes connections to join up with pre-established sessions. | ||
| 1982 | */ | ||
| 1983 | private void changeReadCiphers() throws SSLException { | ||
| 1984 | if (connectionState != cs_HANDSHAKE | ||
| 1985 | && connectionState != cs_RENEGOTIATE) { | ||
| 1986 | throw new SSLProtocolException( | ||
| 1987 | "State error, change cipher specs"); | ||
| 1988 | } | ||
| 1989 | |||
| 1990 | // ... create decompressor | ||
| 1991 | |||
| 1992 | CipherBox oldCipher = readCipher; | ||
| 1993 | |||
| 1994 | try { | ||
| 1995 | readCipher = handshaker.newReadCipher(); | ||
| 1996 | readMAC = handshaker.newReadMAC(); | ||
| 1997 | } catch (GeneralSecurityException e) { | ||
| 1998 | // "can't happen" | ||
| 1999 | throw (SSLException)new SSLException | ||
| 2000 | ("Algorithm missing: ").initCause(e); | ||
| 2001 | } | ||
| 2002 | |||
| 2003 | /* | ||
| 2004 | * Dispose of any intermediate state in the underlying cipher. | ||
| 2005 | * For PKCS11 ciphers, this will release any attached sessions, | ||
| 2006 | * and thus make finalization faster. | ||
| 2007 | * | ||
| 2008 | * Since MAC's doFinal() is called for every SSL/TLS packet, it's | ||
| 2009 | * not necessary to do the same with MAC's. | ||
| 2010 | */ | ||
| 2011 | oldCipher.dispose(); | ||
| 2012 | } | ||
| 2013 | |||
| 2014 | // used by Handshaker | ||
| 2015 | void changeWriteCiphers() throws SSLException { | ||
| 2016 | if (connectionState != cs_HANDSHAKE | ||
| 2017 | && connectionState != cs_RENEGOTIATE) { | ||
| 2018 | throw new SSLProtocolException( | ||
| 2019 | "State error, change cipher specs"); | ||
| 2020 | } | ||
| 2021 | |||
| 2022 | // ... create compressor | ||
| 2023 | |||
| 2024 | CipherBox oldCipher = writeCipher; | ||
| 2025 | |||
| 2026 | try { | ||
| 2027 | writeCipher = handshaker.newWriteCipher(); | ||
| 2028 | writeMAC = handshaker.newWriteMAC(); | ||
| 2029 | } catch (GeneralSecurityException e) { | ||
| 2030 | // "can't happen" | ||
| 2031 | throw (SSLException)new SSLException | ||
| 2032 | ("Algorithm missing: ").initCause(e); | ||
| 2033 | } | ||
| 2034 | |||
| 2035 | // See comment above. | ||
| 2036 | oldCipher.dispose(); | ||
| 2037 | } | ||
| 2038 | |||
| 2039 | /* | ||
| 2040 | * Updates the SSL version associated with this connection. | ||
| 2041 | * Called from Handshaker once it has determined the negotiated version. | ||
| 2042 | */ | ||
| 2043 | synchronized void setVersion(ProtocolVersion protocolVersion) { | ||
| 2044 | this.protocolVersion = protocolVersion; | ||
| 2045 | output.r.setVersion(protocolVersion); | ||
| 2046 | } | ||
| 2047 | |||
| 2048 | synchronized String getHost() { | ||
| 2049 | // Note that the host may be null or empty for localhost. | ||
| 2050 | if (host == null || host.length() == 0) { | ||
| 2051 | host = getInetAddress().getHostName(); | ||
| 2052 | } | ||
| 2053 | return host; | ||
| 2054 | } | ||
| 2055 | |||
| 2056 | synchronized String getRawHostname() { | ||
| 2057 | return rawHostname; | ||
| 2058 | } | ||
| 2059 | |||
| 2060 | // ONLY used by HttpsClient to setup the URI specified hostname | ||
| 2061 | synchronized public void setHost(String host) { | ||
| 2062 | this.host = host; | ||
| 2063 | this.rawHostname = host; | ||
| 2064 | } | ||
| 2065 | |||
| 2066 | /** | ||
| 2067 | * Gets an input stream to read from the peer on the other side. | ||
| 2068 | * Data read from this stream was always integrity protected in | ||
| 2069 | * transit, and will usually have been confidentiality protected. | ||
| 2070 | */ | ||
| 2071 | synchronized public InputStream getInputStream() throws IOException { | ||
| 2072 | if (isClosed()) { | ||
| 2073 | throw new SocketException("Socket is closed"); | ||
| 2074 | } | ||
| 2075 | |||
| 2076 | /* | ||
| 2077 | * Can't call isConnected() here, because the Handshakers | ||
| 2078 | * do some initialization before we actually connect. | ||
| 2079 | */ | ||
| 2080 | if (connectionState == cs_START) { | ||
| 2081 | throw new SocketException("Socket is not connected"); | ||
| 2082 | } | ||
| 2083 | |||
| 2084 | return input; | ||
| 2085 | } | ||
| 2086 | |||
| 2087 | /** | ||
| 2088 | * Gets an output stream to write to the peer on the other side. | ||
| 2089 | * Data written on this stream is always integrity protected, and | ||
| 2090 | * will usually be confidentiality protected. | ||
| 2091 | */ | ||
| 2092 | synchronized public OutputStream getOutputStream() throws IOException { | ||
| 2093 | if (isClosed()) { | ||
| 2094 | throw new SocketException("Socket is closed"); | ||
| 2095 | } | ||
| 2096 | |||
| 2097 | /* | ||
| 2098 | * Can't call isConnected() here, because the Handshakers | ||
| 2099 | * do some initialization before we actually connect. | ||
| 2100 | */ | ||
| 2101 | if (connectionState == cs_START) { | ||
| 2102 | throw new SocketException("Socket is not connected"); | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | return output; | ||
| 2106 | } | ||
| 2107 | |||
| 2108 | /** | ||
| 2109 | * Returns the the SSL Session in use by this connection. These can | ||
| 2110 | * be long lived, and frequently correspond to an entire login session | ||
| 2111 | * for some user. | ||
| 2112 | */ | ||
| 2113 | public SSLSession getSession() { | ||
| 2114 | /* | ||
| 2115 | * Force a synchronous handshake, if appropriate. | ||
| 2116 | */ | ||
| 2117 | if (getConnectionState() == cs_HANDSHAKE) { | ||
| 2118 | try { | ||
| 2119 | // start handshaking, if failed, the connection will be closed. | ||
| 2120 | startHandshake(false); | ||
| 2121 | } catch (IOException e) { | ||
| 2122 | // handshake failed. log and return a nullSession | ||
| 2123 | if (debug != null && Debug.isOn("handshake")) { | ||
| 2124 | System.out.println(threadName() + | ||
| 2125 | ", IOException in getSession(): " + e); | ||
| 2126 | } | ||
| 2127 | } | ||
| 2128 | } | ||
| 2129 | synchronized (this) { | ||
| 2130 | return sess; | ||
| 2131 | } | ||
| 2132 | } | ||
| 2133 | |||
| 2134 | @Override | ||
| 2135 | synchronized public SSLSession getHandshakeSession() { | ||
| 2136 | return handshakeSession; | ||
| 2137 | } | ||
| 2138 | |||
| 2139 | synchronized void setHandshakeSession(SSLSessionImpl session) { | ||
| 2140 | handshakeSession = session; | ||
| 2141 | } | ||
| 2142 | |||
| 2143 | /** | ||
| 2144 | * Controls whether new connections may cause creation of new SSL | ||
| 2145 | * sessions. | ||
| 2146 | * | ||
| 2147 | * As long as handshaking has not started, we can change | ||
| 2148 | * whether we enable session creations. Otherwise, | ||
| 2149 | * we will need to wait for the next handshake. | ||
| 2150 | */ | ||
| 2151 | synchronized public void setEnableSessionCreation(boolean flag) { | ||
| 2152 | enableSessionCreation = flag; | ||
| 2153 | |||
| 2154 | if ((handshaker != null) && !handshaker.activated()) { | ||
| 2155 | handshaker.setEnableSessionCreation(enableSessionCreation); | ||
| 2156 | } | ||
| 2157 | } | ||
| 2158 | |||
| 2159 | /** | ||
| 2160 | * Returns true if new connections may cause creation of new SSL | ||
| 2161 | * sessions. | ||
| 2162 | */ | ||
| 2163 | synchronized public boolean getEnableSessionCreation() { | ||
| 2164 | return enableSessionCreation; | ||
| 2165 | } | ||
| 2166 | |||
| 2167 | |||
| 2168 | /** | ||
| 2169 | * Sets the flag controlling whether a server mode socket | ||
| 2170 | * *REQUIRES* SSL client authentication. | ||
| 2171 | * | ||
| 2172 | * As long as handshaking has not started, we can change | ||
| 2173 | * whether client authentication is needed. Otherwise, | ||
| 2174 | * we will need to wait for the next handshake. | ||
| 2175 | */ | ||
| 2176 | synchronized public void setNeedClientAuth(boolean flag) { | ||
| 2177 | doClientAuth = (flag ? | ||
| 2178 | SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none); | ||
| 2179 | |||
| 2180 | if ((handshaker != null) && | ||
| 2181 | (handshaker instanceof ServerHandshaker) && | ||
| 2182 | !handshaker.activated()) { | ||
| 2183 | ((ServerHandshaker) handshaker).setClientAuth(doClientAuth); | ||
| 2184 | } | ||
| 2185 | } | ||
| 2186 | |||
| 2187 | synchronized public boolean getNeedClientAuth() { | ||
| 2188 | return (doClientAuth == SSLEngineImpl.clauth_required); | ||
| 2189 | } | ||
| 2190 | |||
| 2191 | /** | ||
| 2192 | * Sets the flag controlling whether a server mode socket | ||
| 2193 | * *REQUESTS* SSL client authentication. | ||
| 2194 | * | ||
| 2195 | * As long as handshaking has not started, we can change | ||
| 2196 | * whether client authentication is requested. Otherwise, | ||
| 2197 | * we will need to wait for the next handshake. | ||
| 2198 | */ | ||
| 2199 | synchronized public void setWantClientAuth(boolean flag) { | ||
| 2200 | doClientAuth = (flag ? | ||
| 2201 | SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none); | ||
| 2202 | |||
| 2203 | if ((handshaker != null) && | ||
| 2204 | (handshaker instanceof ServerHandshaker) && | ||
| 2205 | !handshaker.activated()) { | ||
| 2206 | ((ServerHandshaker) handshaker).setClientAuth(doClientAuth); | ||
| 2207 | } | ||
| 2208 | } | ||
| 2209 | |||
| 2210 | synchronized public boolean getWantClientAuth() { | ||
| 2211 | return (doClientAuth == SSLEngineImpl.clauth_requested); | ||
| 2212 | } | ||
| 2213 | |||
| 2214 | |||
| 2215 | /** | ||
| 2216 | * Sets the flag controlling whether the socket is in SSL | ||
| 2217 | * client or server mode. Must be called before any SSL | ||
| 2218 | * traffic has started. | ||
| 2219 | */ | ||
| 2220 | synchronized public void setUseClientMode(boolean flag) { | ||
| 2221 | switch (connectionState) { | ||
| 2222 | |||
| 2223 | case cs_START: | ||
| 2224 | /* | ||
| 2225 | * If we need to change the socket mode and the enabled | ||
| 2226 | * protocols haven't specifically been set by the user, | ||
| 2227 | * change them to the corresponding default ones. | ||
| 2228 | */ | ||
| 2229 | if (roleIsServer != (!flag) && | ||
| 2230 | sslContext.isDefaultProtocolList(enabledProtocols)) { | ||
| 2231 | enabledProtocols = sslContext.getDefaultProtocolList(!flag); | ||
| 2232 | } | ||
| 2233 | roleIsServer = !flag; | ||
| 2234 | break; | ||
| 2235 | |||
| 2236 | case cs_HANDSHAKE: | ||
| 2237 | /* | ||
| 2238 | * If we have a handshaker, but haven't started | ||
| 2239 | * SSL traffic, we can throw away our current | ||
| 2240 | * handshaker, and start from scratch. Don't | ||
| 2241 | * need to call doneConnect() again, we already | ||
| 2242 | * have the streams. | ||
| 2243 | */ | ||
| 2244 | assert(handshaker != null); | ||
| 2245 | if (!handshaker.activated()) { | ||
| 2246 | /* | ||
| 2247 | * If we need to change the socket mode and the enabled | ||
| 2248 | * protocols haven't specifically been set by the user, | ||
| 2249 | * change them to the corresponding default ones. | ||
| 2250 | */ | ||
| 2251 | if (roleIsServer != (!flag) && | ||
| 2252 | sslContext.isDefaultProtocolList(enabledProtocols)) { | ||
| 2253 | enabledProtocols = sslContext.getDefaultProtocolList(!flag); | ||
| 2254 | } | ||
| 2255 | roleIsServer = !flag; | ||
| 2256 | connectionState = cs_START; | ||
| 2257 | initHandshaker(); | ||
| 2258 | break; | ||
| 2259 | } | ||
| 2260 | |||
| 2261 | // If handshake has started, that's an error. Fall through... | ||
| 2262 | |||
| 2263 | default: | ||
| 2264 | if (debug != null && Debug.isOn("ssl")) { | ||
| 2265 | System.out.println(threadName() + | ||
| 2266 | ", setUseClientMode() invoked in state = " + | ||
| 2267 | connectionState); | ||
| 2268 | } | ||
| 2269 | throw new IllegalArgumentException( | ||
| 2270 | "Cannot change mode after SSL traffic has started"); | ||
| 2271 | } | ||
| 2272 | } | ||
| 2273 | |||
| 2274 | synchronized public boolean getUseClientMode() { | ||
| 2275 | return !roleIsServer; | ||
| 2276 | } | ||
| 2277 | |||
| 2278 | |||
| 2279 | /** | ||
| 2280 | * Returns the names of the cipher suites which could be enabled for use | ||
| 2281 | * on an SSL connection. Normally, only a subset of these will actually | ||
| 2282 | * be enabled by default, since this list may include cipher suites which | ||
| 2283 | * do not support the mutual authentication of servers and clients, or | ||
| 2284 | * which do not protect data confidentiality. Servers may also need | ||
| 2285 | * certain kinds of certificates to use certain cipher suites. | ||
| 2286 | * | ||
| 2287 | * @return an array of cipher suite names | ||
| 2288 | */ | ||
| 2289 | public String[] getSupportedCipherSuites() { | ||
| 2290 | return sslContext.getSuportedCipherSuiteList().toStringArray(); | ||
| 2291 | } | ||
| 2292 | |||
| 2293 | /** | ||
| 2294 | * Controls which particular cipher suites are enabled for use on | ||
| 2295 | * this connection. The cipher suites must have been listed by | ||
| 2296 | * getCipherSuites() as being supported. Even if a suite has been | ||
| 2297 | * enabled, it might never be used if no peer supports it or the | ||
| 2298 | * requisite certificates (and private keys) are not available. | ||
| 2299 | * | ||
| 2300 | * @param suites Names of all the cipher suites to enable. | ||
| 2301 | */ | ||
| 2302 | synchronized public void setEnabledCipherSuites(String[] suites) { | ||
| 2303 | enabledCipherSuites = new CipherSuiteList(suites); | ||
| 2304 | if ((handshaker != null) && !handshaker.activated()) { | ||
| 2305 | handshaker.setEnabledCipherSuites(enabledCipherSuites); | ||
| 2306 | } | ||
| 2307 | } | ||
| 2308 | |||
| 2309 | /** | ||
| 2310 | * Returns the names of the SSL cipher suites which are currently enabled | ||
| 2311 | * for use on this connection. When an SSL socket is first created, | ||
| 2312 | * all enabled cipher suites <em>(a)</em> protect data confidentiality, | ||
| 2313 | * by traffic encryption, and <em>(b)</em> can mutually authenticate | ||
| 2314 | * both clients and servers. Thus, in some environments, this value | ||
| 2315 | * might be empty. | ||
| 2316 | * | ||
| 2317 | * @return an array of cipher suite names | ||
| 2318 | */ | ||
| 2319 | synchronized public String[] getEnabledCipherSuites() { | ||
| 2320 | return enabledCipherSuites.toStringArray(); | ||
| 2321 | } | ||
| 2322 | |||
| 2323 | |||
| 2324 | /** | ||
| 2325 | * Returns the protocols that are supported by this implementation. | ||
| 2326 | * A subset of the supported protocols may be enabled for this connection | ||
| 2327 | * @return an array of protocol names. | ||
| 2328 | */ | ||
| 2329 | public String[] getSupportedProtocols() { | ||
| 2330 | return sslContext.getSuportedProtocolList().toStringArray(); | ||
| 2331 | } | ||
| 2332 | |||
| 2333 | /** | ||
| 2334 | * Controls which protocols are enabled for use on | ||
| 2335 | * this connection. The protocols must have been listed by | ||
| 2336 | * getSupportedProtocols() as being supported. | ||
| 2337 | * | ||
| 2338 | * @param protocols protocols to enable. | ||
| 2339 | * @exception IllegalArgumentException when one of the protocols | ||
| 2340 | * named by the parameter is not supported. | ||
| 2341 | */ | ||
| 2342 | synchronized public void setEnabledProtocols(String[] protocols) { | ||
| 2343 | enabledProtocols = new ProtocolList(protocols); | ||
| 2344 | if ((handshaker != null) && !handshaker.activated()) { | ||
| 2345 | handshaker.setEnabledProtocols(enabledProtocols); | ||
| 2346 | } | ||
| 2347 | } | ||
| 2348 | |||
| 2349 | synchronized public String[] getEnabledProtocols() { | ||
| 2350 | return enabledProtocols.toStringArray(); | ||
| 2351 | } | ||
| 2352 | |||
| 2353 | /** | ||
| 2354 | * Assigns the socket timeout. | ||
| 2355 | * @see java.net.Socket#setSoTimeout | ||
| 2356 | */ | ||
| 2357 | public void setSoTimeout(int timeout) throws SocketException { | ||
| 2358 | if ((debug != null) && Debug.isOn("ssl")) { | ||
| 2359 | System.out.println(threadName() + | ||
| 2360 | ", setSoTimeout(" + timeout + ") called"); | ||
| 2361 | } | ||
| 2362 | if (self == this) { | ||
| 2363 | super.setSoTimeout(timeout); | ||
| 2364 | } else { | ||
| 2365 | self.setSoTimeout(timeout); | ||
| 2366 | } | ||
| 2367 | } | ||
| 2368 | |||
| 2369 | /** | ||
| 2370 | * Registers an event listener to receive notifications that an | ||
| 2371 | * SSL handshake has completed on this connection. | ||
| 2372 | */ | ||
| 2373 | public synchronized void addHandshakeCompletedListener( | ||
| 2374 | HandshakeCompletedListener listener) { | ||
| 2375 | if (listener == null) { | ||
| 2376 | throw new IllegalArgumentException("listener is null"); | ||
| 2377 | } | ||
| 2378 | if (handshakeListeners == null) { | ||
| 2379 | handshakeListeners = new | ||
| 2380 | HashMap<HandshakeCompletedListener, AccessControlContext>(4); | ||
| 2381 | } | ||
| 2382 | handshakeListeners.put(listener, AccessController.getContext()); | ||
| 2383 | } | ||
| 2384 | |||
| 2385 | |||
| 2386 | /** | ||
| 2387 | * Removes a previously registered handshake completion listener. | ||
| 2388 | */ | ||
| 2389 | public synchronized void removeHandshakeCompletedListener( | ||
| 2390 | HandshakeCompletedListener listener) { | ||
| 2391 | if (handshakeListeners == null) { | ||
| 2392 | throw new IllegalArgumentException("no listeners"); | ||
| 2393 | } | ||
| 2394 | if (handshakeListeners.remove(listener) == null) { | ||
| 2395 | throw new IllegalArgumentException("listener not registered"); | ||
| 2396 | } | ||
| 2397 | if (handshakeListeners.isEmpty()) { | ||
| 2398 | handshakeListeners = null; | ||
| 2399 | } | ||
| 2400 | } | ||
| 2401 | |||
| 2402 | /** | ||
| 2403 | * Returns the SSLParameters in effect for this SSLSocket. | ||
| 2404 | */ | ||
| 2405 | synchronized public SSLParameters getSSLParameters() { | ||
| 2406 | SSLParameters params = super.getSSLParameters(); | ||
| 2407 | |||
| 2408 | // the super implementation does not handle the following parameters | ||
| 2409 | params.setEndpointIdentificationAlgorithm(identificationProtocol); | ||
| 2410 | params.setAlgorithmConstraints(algorithmConstraints); | ||
| 2411 | |||
| 2412 | return params; | ||
| 2413 | } | ||
| 2414 | |||
| 2415 | /** | ||
| 2416 | * Applies SSLParameters to this socket. | ||
| 2417 | */ | ||
| 2418 | synchronized public void setSSLParameters(SSLParameters params) { | ||
| 2419 | super.setSSLParameters(params); | ||
| 2420 | |||
| 2421 | // the super implementation does not handle the following parameters | ||
| 2422 | identificationProtocol = params.getEndpointIdentificationAlgorithm(); | ||
| 2423 | algorithmConstraints = params.getAlgorithmConstraints(); | ||
| 2424 | if ((handshaker != null) && !handshaker.started()) { | ||
| 2425 | handshaker.setIdentificationProtocol(identificationProtocol); | ||
| 2426 | handshaker.setAlgorithmConstraints(algorithmConstraints); | ||
| 2427 | } | ||
| 2428 | } | ||
| 2429 | |||
| 2430 | // | ||
| 2431 | // We allocate a separate thread to deliver handshake completion | ||
| 2432 | // events. This ensures that the notifications don't block the | ||
| 2433 | // protocol state machine. | ||
| 2434 | // | ||
| 2435 | private static class NotifyHandshakeThread extends Thread { | ||
| 2436 | |||
| 2437 | private Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>> | ||
| 2438 | targets; // who gets notified | ||
| 2439 | private HandshakeCompletedEvent event; // the notification | ||
| 2440 | |||
| 2441 | NotifyHandshakeThread( | ||
| 2442 | Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>> | ||
| 2443 | entrySet, HandshakeCompletedEvent e) { | ||
| 2444 | |||
| 2445 | super("HandshakeCompletedNotify-Thread"); | ||
| 2446 | targets = entrySet; | ||
| 2447 | event = e; | ||
| 2448 | } | ||
| 2449 | |||
| 2450 | public void run() { | ||
| 2451 | for (Map.Entry<HandshakeCompletedListener,AccessControlContext> | ||
| 2452 | entry : targets) { | ||
| 2453 | |||
| 2454 | final HandshakeCompletedListener l = entry.getKey(); | ||
| 2455 | AccessControlContext acc = entry.getValue(); | ||
| 2456 | AccessController.doPrivileged(new PrivilegedAction<Void>() { | ||
| 2457 | public Void run() { | ||
| 2458 | l.handshakeCompleted(event); | ||
| 2459 | return null; | ||
| 2460 | } | ||
| 2461 | }, acc); | ||
| 2462 | } | ||
| 2463 | } | ||
| 2464 | } | ||
| 2465 | |||
| 2466 | /** | ||
| 2467 | * Return the name of the current thread. Utility method. | ||
| 2468 | */ | ||
| 2469 | private static String threadName() { | ||
| 2470 | return Thread.currentThread().getName(); | ||
| 2471 | } | ||
| 2472 | |||
| 2473 | /** | ||
| 2474 | * Returns a printable representation of this end of the connection. | ||
| 2475 | */ | ||
| 2476 | public String toString() { | ||
| 2477 | StringBuffer retval = new StringBuffer(80); | ||
| 2478 | |||
| 2479 | retval.append(Integer.toHexString(hashCode())); | ||
| 2480 | retval.append("["); | ||
| 2481 | retval.append(sess.getCipherSuite()); | ||
| 2482 | retval.append(": "); | ||
| 2483 | |||
| 2484 | if (self == this) { | ||
| 2485 | retval.append(super.toString()); | ||
| 2486 | } else { | ||
| 2487 | retval.append(self.toString()); | ||
| 2488 | } | ||
| 2489 | retval.append("]"); | ||
| 2490 | |||
| 2491 | return retval.toString(); | ||
| 2492 | } | ||
| 2493 | } | ||