1 // ======================================================================== 2 // Copyright (c) 2000-2009 Mort Bay Consulting Pty. Ltd. 3 // ------------------------------------------------------------------------ 4 // All rights reserved. This program and the accompanying materials 5 // are made available under the terms of the Eclipse Public License v1.0 6 // and Apache License v2.0 which accompanies this distribution. 7 // The Eclipse Public License is available at 8 // http://www.eclipse.org/legal/epl-v10.html 9 // The Apache License v2.0 is available at 10 // http://www.opensource.org/licenses/apache2.0.php 11 // You may elect to redistribute this code under either of these licenses. 12 // ======================================================================== 13 14 package org.eclipse.jetty.server.ssl; 15 16 import java.io.IOException; 17 import java.net.InetAddress; 18 import java.net.ServerSocket; 19 import java.net.Socket; 20 21 import javax.net.ssl.HandshakeCompletedEvent; 22 import javax.net.ssl.HandshakeCompletedListener; 23 import javax.net.ssl.SSLContext; 24 import javax.net.ssl.SSLException; 25 import javax.net.ssl.SSLServerSocket; 26 import javax.net.ssl.SSLServerSocketFactory; 27 import javax.net.ssl.SSLSession; 28 import javax.net.ssl.SSLSocket; 29 30 import org.eclipse.jetty.http.HttpSchemes; 31 import org.eclipse.jetty.http.ssl.SslContextFactory; 32 import org.eclipse.jetty.io.EndPoint; 33 import org.eclipse.jetty.io.bio.SocketEndPoint; 34 import org.eclipse.jetty.server.Request; 35 import org.eclipse.jetty.server.bio.SocketConnector; 36 import org.eclipse.jetty.util.log.Log; 37 38 /* ------------------------------------------------------------ */ 39 /** 40 * SSL Socket Connector. 41 * 42 * This specialization of SocketConnector is an abstract listener that can be used as the basis for a 43 * specific JSSE listener. 44 * 45 * The original of this class was heavily based on the work from Court Demas, which in turn is 46 * based on the work from Forge Research. Since JSSE, this class has evolved significantly from 47 * that early work. 48 * 49 * @org.apache.xbean.XBean element="sslSocketConnector" description="Creates an ssl socket connector" 50 * 51 * 52 */ 53 public class SslSocketConnector extends SocketConnector implements SslConnector 54 { 55 private final SslContextFactory _sslContextFactory; 56 private int _handshakeTimeout = 0; //0 means use maxIdleTime 57 58 /* ------------------------------------------------------------ */ 59 /** 60 * Constructor. 61 */ 62 public SslSocketConnector() 63 { 64 this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH)); 65 } 66 67 public SslSocketConnector(SslContextFactory sslContextFactory) 68 { 69 _sslContextFactory = sslContextFactory; 70 } 71 72 /* ------------------------------------------------------------ */ 73 /** 74 * @return True if SSL re-negotiation is allowed (default false) 75 */ 76 public boolean isAllowRenegotiate() 77 { 78 return _sslContextFactory.isAllowRenegotiate(); 79 } 80 81 /* ------------------------------------------------------------ */ 82 /** 83 * Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered 84 * a vulnerability in SSL/TLS with re-negotiation. If your JVM 85 * does not have CVE-2009-3555 fixed, then re-negotiation should 86 * not be allowed. 87 * @param allowRenegotiate true if re-negotiation is allowed (default false) 88 */ 89 public void setAllowRenegotiate(boolean allowRenegotiate) 90 { 91 _sslContextFactory.setAllowRenegotiate(allowRenegotiate); 92 } 93 94 /* ------------------------------------------------------------ */ 95 @Override 96 public void accept(int acceptorID) 97 throws IOException, InterruptedException 98 { 99 Socket socket = _serverSocket.accept(); 100 configure(socket); 101 102 ConnectorEndPoint connection=new SslConnectorEndPoint(socket); 103 connection.dispatch(); 104 } 105 106 /* ------------------------------------------------------------ */ 107 @Override 108 protected void configure(Socket socket) 109 throws IOException 110 { 111 super.configure(socket); 112 } 113 114 /* ------------------------------------------------------------ */ 115 /** 116 * Allow the Listener a chance to customise the request. before the server does its stuff. <br> 117 * This allows the required attributes to be set for SSL requests. <br> 118 * The requirements of the Servlet specs are: 119 * <ul> 120 * <li> an attribute named "javax.servlet.request.ssl_id" of type String (since Spec 3.0).</li> 121 * <li> an attribute named "javax.servlet.request.cipher_suite" of type String.</li> 122 * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li> 123 * <li> an attribute named "javax.servlet.request.X509Certificate" of type 124 * java.security.cert.X509Certificate[]. This is an array of objects of type X509Certificate, 125 * the order of this array is defined as being in ascending order of trust. The first 126 * certificate in the chain is the one set by the client, the next is the one used to 127 * authenticate the first, and so on. </li> 128 * </ul> 129 * 130 * @param endpoint The Socket the request arrived on. 131 * This should be a {@link SocketEndPoint} wrapping a {@link SSLSocket}. 132 * @param request HttpRequest to be customised. 133 */ 134 @Override 135 public void customize(EndPoint endpoint, Request request) 136 throws IOException 137 { 138 super.customize(endpoint, request); 139 request.setScheme(HttpSchemes.HTTPS); 140 141 SocketEndPoint socket_end_point = (SocketEndPoint)endpoint; 142 SSLSocket sslSocket = (SSLSocket)socket_end_point.getTransport(); 143 SSLSession sslSession = sslSocket.getSession(); 144 145 SslCertificates.customize(sslSession,endpoint,request); 146 } 147 148 /* ------------------------------------------------------------ */ 149 /** 150 * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites() 151 * @deprecated 152 */ 153 @Deprecated 154 public String[] getExcludeCipherSuites() { 155 return _sslContextFactory.getExcludeCipherSuites(); 156 } 157 158 /* ------------------------------------------------------------ */ 159 /** 160 * @see org.eclipse.jetty.server.ssl.SslConnector#getIncludeCipherSuites() 161 * @deprecated 162 */ 163 @Deprecated 164 public String[] getIncludeCipherSuites() 165 { 166 return _sslContextFactory.getIncludeCipherSuites(); 167 } 168 169 /* ------------------------------------------------------------ */ 170 /** 171 * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystore() 172 * @deprecated 173 */ 174 @Deprecated 175 public String getKeystore() 176 { 177 return _sslContextFactory.getKeyStore(); 178 } 179 180 /* ------------------------------------------------------------ */ 181 /** 182 * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystoreType() 183 * @deprecated 184 */ 185 @Deprecated 186 public String getKeystoreType() 187 { 188 return _sslContextFactory.getKeyStoreType(); 189 } 190 191 /* ------------------------------------------------------------ */ 192 /** 193 * @see org.eclipse.jetty.server.ssl.SslConnector#getNeedClientAuth() 194 * @deprecated 195 */ 196 @Deprecated 197 public boolean getNeedClientAuth() 198 { 199 return _sslContextFactory.getNeedClientAuth(); 200 } 201 202 /* ------------------------------------------------------------ */ 203 /** 204 * @see org.eclipse.jetty.server.ssl.SslConnector#getProtocol() 205 * @deprecated 206 */ 207 @Deprecated 208 public String getProtocol() 209 { 210 return _sslContextFactory.getProtocol(); 211 } 212 213 /* ------------------------------------------------------------ */ 214 /** 215 * @see org.eclipse.jetty.server.ssl.SslConnector#getProvider() 216 * @deprecated 217 */ 218 @Deprecated 219 public String getProvider() { 220 return _sslContextFactory.getProvider(); 221 } 222 223 /* ------------------------------------------------------------ */ 224 /** 225 * @see org.eclipse.jetty.server.ssl.SslConnector#getSecureRandomAlgorithm() 226 * @deprecated 227 */ 228 @Deprecated 229 public String getSecureRandomAlgorithm() 230 { 231 return _sslContextFactory.getSecureRandomAlgorithm(); 232 } 233 234 /* ------------------------------------------------------------ */ 235 /** 236 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslKeyManagerFactoryAlgorithm() 237 * @deprecated 238 */ 239 @Deprecated 240 public String getSslKeyManagerFactoryAlgorithm() 241 { 242 return _sslContextFactory.getSslKeyManagerFactoryAlgorithm(); 243 } 244 245 /* ------------------------------------------------------------ */ 246 /** 247 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslTrustManagerFactoryAlgorithm() 248 * @deprecated 249 */ 250 @Deprecated 251 public String getSslTrustManagerFactoryAlgorithm() 252 { 253 return _sslContextFactory.getTrustManagerFactoryAlgorithm(); 254 } 255 256 /* ------------------------------------------------------------ */ 257 /** 258 * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststore() 259 * @deprecated 260 */ 261 @Deprecated 262 public String getTruststore() 263 { 264 return _sslContextFactory.getTrustStore(); 265 } 266 267 /* ------------------------------------------------------------ */ 268 /** 269 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslContextFactory() 270 */ 271 // @Override 272 public SslContextFactory getSslContextFactory() 273 { 274 return _sslContextFactory; 275 } 276 277 /* ------------------------------------------------------------ */ 278 /** 279 * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststoreType() 280 * @deprecated 281 */ 282 @Deprecated 283 public String getTruststoreType() 284 { 285 return _sslContextFactory.getTrustStoreType(); 286 } 287 288 /* ------------------------------------------------------------ */ 289 /** 290 * @see org.eclipse.jetty.server.ssl.SslConnector#getWantClientAuth() 291 * @deprecated 292 */ 293 @Deprecated 294 public boolean getWantClientAuth() 295 { 296 return _sslContextFactory.getWantClientAuth(); 297 } 298 299 /* ------------------------------------------------------------ */ 300 /** 301 * By default, we're confidential, given we speak SSL. But, if we've been told about an 302 * confidential port, and said port is not our port, then we're not. This allows separation of 303 * listeners providing INTEGRAL versus CONFIDENTIAL constraints, such as one SSL listener 304 * configured to require client certs providing CONFIDENTIAL, whereas another SSL listener not 305 * requiring client certs providing mere INTEGRAL constraints. 306 */ 307 @Override 308 public boolean isConfidential(Request request) 309 { 310 final int confidentialPort = getConfidentialPort(); 311 return confidentialPort == 0 || confidentialPort == request.getServerPort(); 312 } 313 314 /* ------------------------------------------------------------ */ 315 /** 316 * By default, we're integral, given we speak SSL. But, if we've been told about an integral 317 * port, and said port is not our port, then we're not. This allows separation of listeners 318 * providing INTEGRAL versus CONFIDENTIAL constraints, such as one SSL listener configured to 319 * require client certs providing CONFIDENTIAL, whereas another SSL listener not requiring 320 * client certs providing mere INTEGRAL constraints. 321 */ 322 @Override 323 public boolean isIntegral(Request request) 324 { 325 final int integralPort = getIntegralPort(); 326 return integralPort == 0 || integralPort == request.getServerPort(); 327 } 328 329 /* ------------------------------------------------------------ */ 330 /** 331 * {@inheritDoc} 332 */ 333 @Override 334 protected void doStart() throws Exception 335 { 336 if (!_sslContextFactory.checkConfig()) 337 { 338 throw new IllegalStateException("SSL context is not configured correctly."); 339 } 340 341 _sslContextFactory.start(); 342 343 super.doStart(); 344 } 345 346 /* ------------------------------------------------------------ */ 347 /** 348 * @see org.eclipse.jetty.server.bio.SocketConnector#doStop() 349 */ 350 @Override 351 protected void doStop() throws Exception 352 { 353 _sslContextFactory.stop(); 354 355 super.doStop(); 356 } 357 358 /* ------------------------------------------------------------ */ 359 /** 360 * @param host The host name that this server should listen on 361 * @param port the port that this server should listen on 362 * @param backlog See {@link ServerSocket#bind(java.net.SocketAddress, int)} 363 * @return A new {@link ServerSocket socket object} bound to the supplied address with all other 364 * settings as per the current configuration of this connector. 365 * @see #setWantClientAuth(boolean) 366 * @see #setNeedClientAuth(boolean) 367 * @exception IOException 368 */ 369 @Override 370 protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException 371 { 372 SSLServerSocketFactory factory = _sslContextFactory.getSslContext().getServerSocketFactory(); 373 374 SSLServerSocket socket = 375 (SSLServerSocket) (host==null ? 376 factory.createServerSocket(port,backlog): 377 factory.createServerSocket(port,backlog,InetAddress.getByName(host))); 378 379 if (_sslContextFactory.getWantClientAuth()) 380 socket.setWantClientAuth(_sslContextFactory.getWantClientAuth()); 381 if (_sslContextFactory.getNeedClientAuth()) 382 socket.setNeedClientAuth(_sslContextFactory.getNeedClientAuth()); 383 384 socket.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites( 385 socket.getEnabledCipherSuites(), 386 socket.getSupportedCipherSuites())); 387 return socket; 388 } 389 390 /* ------------------------------------------------------------ */ 391 /** 392 * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[]) 393 * @deprecated 394 */ 395 @Deprecated 396 public void setExcludeCipherSuites(String[] cipherSuites) 397 { 398 _sslContextFactory.setExcludeCipherSuites(cipherSuites); 399 } 400 401 /* ------------------------------------------------------------ */ 402 /** 403 * @see org.eclipse.jetty.server.ssl.SslConnector#setIncludeCipherSuites(java.lang.String[]) 404 * @deprecated 405 */ 406 @Deprecated 407 public void setIncludeCipherSuites(String[] cipherSuites) 408 { 409 _sslContextFactory.setIncludeCipherSuites(cipherSuites); 410 } 411 412 /* ------------------------------------------------------------ */ 413 /** 414 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeyPassword(java.lang.String) 415 * @deprecated 416 */ 417 @Deprecated 418 public void setKeyPassword(String password) 419 { 420 _sslContextFactory.setKeyManagerPassword(password); 421 } 422 423 /* ------------------------------------------------------------ */ 424 /** 425 * @param keystore The resource path to the keystore, or null for built in keystores. 426 * @deprecated 427 */ 428 @Deprecated 429 public void setKeystore(String keystore) 430 { 431 _sslContextFactory.setKeyStore(keystore); 432 } 433 434 /* ------------------------------------------------------------ */ 435 /** 436 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystoreType(java.lang.String) 437 * @deprecated 438 */ 439 @Deprecated 440 public void setKeystoreType(String keystoreType) 441 { 442 _sslContextFactory.setKeyStoreType(keystoreType); 443 } 444 445 /* ------------------------------------------------------------ */ 446 /** 447 * Set the value of the needClientAuth property 448 * 449 * @param needClientAuth true iff we require client certificate authentication. 450 * @deprecated 451 */ 452 @Deprecated 453 public void setNeedClientAuth(boolean needClientAuth) 454 { 455 _sslContextFactory.setNeedClientAuth(needClientAuth); 456 } 457 458 /* ------------------------------------------------------------ */ 459 /** 460 * @see org.eclipse.jetty.server.ssl.SslConnector#setPassword(java.lang.String) 461 * @deprecated 462 */ 463 @Deprecated 464 public void setPassword(String password) 465 { 466 _sslContextFactory.setKeyStorePassword(password); 467 } 468 469 /* ------------------------------------------------------------ */ 470 /** 471 * @see org.eclipse.jetty.server.ssl.SslConnector#setTrustPassword(java.lang.String) 472 * @deprecated 473 */ 474 @Deprecated 475 public void setTrustPassword(String password) 476 { 477 _sslContextFactory.setTrustStorePassword(password); 478 } 479 480 /* ------------------------------------------------------------ */ 481 /** 482 * @see org.eclipse.jetty.server.ssl.SslConnector#setProtocol(java.lang.String) 483 * @deprecated 484 */ 485 @Deprecated 486 public void setProtocol(String protocol) 487 { 488 _sslContextFactory.setProtocol(protocol); 489 } 490 491 /* ------------------------------------------------------------ */ 492 /** 493 * @see org.eclipse.jetty.server.ssl.SslConnector#setProvider(java.lang.String) 494 * @deprecated 495 */ 496 @Deprecated 497 public void setProvider(String provider) { 498 _sslContextFactory.setProvider(provider); 499 } 500 501 /* ------------------------------------------------------------ */ 502 /** 503 * @see org.eclipse.jetty.server.ssl.SslConnector#setSecureRandomAlgorithm(java.lang.String) 504 * @deprecated 505 */ 506 @Deprecated 507 public void setSecureRandomAlgorithm(String algorithm) 508 { 509 _sslContextFactory.setSecureRandomAlgorithm(algorithm); 510 } 511 512 /* ------------------------------------------------------------ */ 513 /** 514 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslKeyManagerFactoryAlgorithm(java.lang.String) 515 * @deprecated 516 */ 517 @Deprecated 518 public void setSslKeyManagerFactoryAlgorithm(String algorithm) 519 { 520 _sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm); 521 } 522 523 /* ------------------------------------------------------------ */ 524 /** 525 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslTrustManagerFactoryAlgorithm(java.lang.String) 526 * @deprecated 527 */ 528 @Deprecated 529 public void setSslTrustManagerFactoryAlgorithm(String algorithm) 530 { 531 _sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm); 532 } 533 534 /* ------------------------------------------------------------ */ 535 /** 536 * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststore(java.lang.String) 537 * @deprecated 538 */ 539 @Deprecated 540 public void setTruststore(String truststore) 541 { 542 _sslContextFactory.setTrustStore(truststore); 543 } 544 545 /* ------------------------------------------------------------ */ 546 /** 547 * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststoreType(java.lang.String) 548 * @deprecated 549 */ 550 @Deprecated 551 public void setTruststoreType(String truststoreType) 552 { 553 _sslContextFactory.setTrustStoreType(truststoreType); 554 } 555 556 /* ------------------------------------------------------------ */ 557 /** 558 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext) 559 * @deprecated 560 */ 561 @Deprecated 562 public void setSslContext(SSLContext sslContext) 563 { 564 _sslContextFactory.setSslContext(sslContext); 565 } 566 567 /* ------------------------------------------------------------ */ 568 /** 569 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext) 570 * @deprecated 571 */ 572 @Deprecated 573 public SSLContext getSslContext() 574 { 575 return _sslContextFactory.getSslContext(); 576 } 577 578 /* ------------------------------------------------------------ */ 579 /** 580 * Set the value of the _wantClientAuth property. This property is used 581 * internally when opening server sockets. 582 * 583 * @param wantClientAuth true if we want client certificate authentication. 584 * @see SSLServerSocket#setWantClientAuth 585 * @deprecated 586 */ 587 @Deprecated 588 public void setWantClientAuth(boolean wantClientAuth) 589 { 590 _sslContextFactory.setWantClientAuth(wantClientAuth); 591 } 592 593 /* ------------------------------------------------------------ */ 594 /** 595 * Set the time in milliseconds for so_timeout during ssl handshaking 596 * @param msec a non-zero value will be used to set so_timeout during 597 * ssl handshakes. A zero value means the maxIdleTime is used instead. 598 */ 599 public void setHandshakeTimeout (int msec) 600 { 601 _handshakeTimeout = msec; 602 } 603 604 605 /* ------------------------------------------------------------ */ 606 public int getHandshakeTimeout () 607 { 608 return _handshakeTimeout; 609 } 610 611 /* ------------------------------------------------------------ */ 612 public class SslConnectorEndPoint extends ConnectorEndPoint 613 { 614 public SslConnectorEndPoint(Socket socket) throws IOException 615 { 616 super(socket); 617 } 618 619 @Override 620 public void shutdownOutput() throws IOException 621 { 622 close(); 623 } 624 625 @Override 626 public void shutdownInput() throws IOException 627 { 628 close(); 629 } 630 631 @Override 632 public void run() 633 { 634 try 635 { 636 int handshakeTimeout = getHandshakeTimeout(); 637 int oldTimeout = _socket.getSoTimeout(); 638 if (handshakeTimeout > 0) 639 _socket.setSoTimeout(handshakeTimeout); 640 641 final SSLSocket ssl=(SSLSocket)_socket; 642 ssl.addHandshakeCompletedListener(new HandshakeCompletedListener() 643 { 644 boolean handshook=false; 645 public void handshakeCompleted(HandshakeCompletedEvent event) 646 { 647 if (handshook) 648 { 649 if (!_sslContextFactory.isAllowRenegotiate()) 650 { 651 Log.warn("SSL renegotiate denied: "+ssl); 652 try{ssl.close();}catch(IOException e){Log.warn(e);} 653 } 654 } 655 else 656 handshook=true; 657 } 658 }); 659 ssl.startHandshake(); 660 661 if (handshakeTimeout>0) 662 _socket.setSoTimeout(oldTimeout); 663 664 super.run(); 665 } 666 catch (SSLException e) 667 { 668 Log.debug(e); 669 try{close();} 670 catch(IOException e2){Log.ignore(e2);} 671 } 672 catch (IOException e) 673 { 674 Log.debug(e); 675 try{close();} 676 catch(IOException e2){Log.ignore(e2);} 677 } 678 } 679 } 680 681 /* ------------------------------------------------------------ */ 682 /** 683 * Unsupported. 684 * 685 * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) 686 * @deprecated 687 */ 688 @Deprecated 689 public String getAlgorithm() 690 { 691 throw new UnsupportedOperationException(); 692 } 693 694 /* ------------------------------------------------------------ */ 695 /** 696 * Unsupported. 697 * 698 * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) 699 * @deprecated 700 */ 701 @Deprecated 702 public void setAlgorithm(String algorithm) 703 { 704 throw new UnsupportedOperationException(); 705 } 706 }