001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.net.pop3; 019 020 import java.io.BufferedWriter; 021 import java.io.IOException; 022 import java.io.InputStreamReader; 023 import java.io.OutputStreamWriter; 024 025 import javax.net.ssl.KeyManager; 026 import javax.net.ssl.SSLContext; 027 import javax.net.ssl.SSLException; 028 import javax.net.ssl.SSLSocket; 029 import javax.net.ssl.SSLSocketFactory; 030 import javax.net.ssl.TrustManager; 031 032 import org.apache.commons.net.io.CRLFLineReader; 033 import org.apache.commons.net.util.SSLContextUtils; 034 035 /** 036 * POP3 over SSL processing. Copied from FTPSClient.java and modified to suit POP3. 037 * If implicit mode is selected (NOT the default), SSL/TLS negotiation starts right 038 * after the connection has been established. In explicit mode (the default), SSL/TLS 039 * negotiation starts when the user calls execTLS() and the server accepts the command. 040 * Implicit usage: 041 * POP3SClient c = new POP3SClient(true); 042 * c.connect("127.0.0.1", 995); 043 * Explicit usage: 044 * POP3SClient c = new POP3SClient(); 045 * c.connect("127.0.0.1", 110); 046 * if (c.execTLS()) { /rest of the commands here/ } 047 * @since 3.0 048 */ 049 public class POP3SClient extends POP3Client 050 { 051 // from http://www.iana.org/assignments/port-numbers 052 053 // pop3s 995/tcp pop3 protocol over TLS/SSL (was spop3) 054 // pop3s 995/udp pop3 protocol over TLS/SSL (was spop3) 055 056 private static final int DEFAULT_POP3S_PORT = 995; 057 058 /** Default secure socket protocol name, like TLS */ 059 private static final String DEFAULT_PROTOCOL = "TLS"; 060 061 /** The security mode. True - Implicit Mode / False - Explicit Mode. */ 062 private final boolean isImplicit; 063 /** The secure socket protocol to be used, like SSL/TLS. */ 064 private final String protocol; 065 /** The context object. */ 066 private SSLContext context = null; 067 /** The cipher suites. SSLSockets have a default set of these anyway, 068 so no initialization required. */ 069 private String[] suites = null; 070 /** The protocol versions. */ 071 private String[] protocols = //null; 072 null;//{"SSLv2", "SSLv3", "TLSv1", "TLSv1.1", "SSLv2Hello"}; 073 074 /** The FTPS {@link TrustManager} implementation, default null. */ 075 private TrustManager trustManager = null; 076 077 /** The {@link KeyManager}, default null. */ 078 private KeyManager keyManager = null; 079 080 /** 081 * Constructor for POP3SClient, using {@link #DEFAULT_PROTOCOL} i.e. TLS 082 * Sets security mode to explicit. 083 */ 084 public POP3SClient() 085 { 086 this(DEFAULT_PROTOCOL, false); 087 } 088 089 /** 090 * Constructor for POP3SClient, using {@link #DEFAULT_PROTOCOL} i.e. TLS 091 * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit 092 */ 093 public POP3SClient(boolean implicit) 094 { 095 this(DEFAULT_PROTOCOL, implicit); 096 } 097 098 /** 099 * Constructor for POP3SClient. 100 * Sets security mode to explicit. 101 * @param proto the protocol. 102 */ 103 public POP3SClient(String proto) 104 { 105 this(proto, false); 106 } 107 108 /** 109 * Constructor for POP3SClient. 110 * @param proto the protocol. 111 * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit 112 */ 113 public POP3SClient(String proto, boolean implicit) 114 { 115 this(proto, implicit, null); 116 } 117 118 /** 119 * Constructor for POP3SClient. 120 * Sets the default port to {@link #DEFAULT_POP3S_PORT} - 995 - if using implicit mode 121 * @param proto the protocol. 122 * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit 123 * @param ctx the context to be used 124 */ 125 public POP3SClient(String proto, boolean implicit, SSLContext ctx) 126 { 127 super(); 128 protocol = proto; 129 isImplicit = implicit; 130 context = ctx; 131 if (isImplicit) { 132 setDefaultPort(DEFAULT_POP3S_PORT); 133 } 134 } 135 136 /** 137 * Constructor for POP3SClient, using {@link #DEFAULT_PROTOCOL} i.e. TLS 138 * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit 139 * @param ctx A pre-configured SSL Context. 140 */ 141 public POP3SClient(boolean implicit, SSLContext ctx) 142 { 143 this(DEFAULT_PROTOCOL, implicit, ctx); 144 } 145 146 /** 147 * Constructor for POP3SClient, using {@link #DEFAULT_PROTOCOL} - TLS - and isImplicit = false 148 * @param context A pre-configured SSL Context. 149 * @see #POP3SClient(boolean, SSLContext) 150 */ 151 public POP3SClient(SSLContext context) 152 { 153 this(false, context); 154 } 155 156 /** 157 * Because there are so many connect() methods, 158 * the _connectAction_() method is provided as a means of performing 159 * some action immediately after establishing a connection, 160 * rather than reimplementing all of the connect() methods. 161 * @throws IOException If it is thrown by _connectAction_(). 162 * @see org.apache.commons.net.SocketClient#_connectAction_() 163 */ 164 @Override 165 protected void _connectAction_() throws IOException 166 { 167 // Implicit mode. 168 if (isImplicit) { 169 performSSLNegotiation(); 170 } 171 super._connectAction_(); 172 // Explicit mode - don't do anything. The user calls execTLS() 173 } 174 175 /** 176 * Performs a lazy init of the SSL context. 177 * @throws IOException When could not initialize the SSL context. 178 */ 179 private void initSSLContext() throws IOException 180 { 181 if (context == null) 182 { 183 context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager()); 184 } 185 } 186 187 /** 188 * SSL/TLS negotiation. Acquires an SSL socket of a 189 * connection and carries out handshake processing. 190 * @throws IOException If server negotiation fails. 191 */ 192 private void performSSLNegotiation() throws IOException 193 { 194 initSSLContext(); 195 196 SSLSocketFactory ssf = context.getSocketFactory(); 197 String ip = getRemoteAddress().getHostAddress(); 198 int port = getRemotePort(); 199 SSLSocket socket = 200 (SSLSocket) ssf.createSocket(_socket_, ip, port, true); 201 socket.setEnableSessionCreation(true); 202 socket.setUseClientMode(true); 203 204 if (protocols != null) { 205 socket.setEnabledProtocols(protocols); 206 } 207 if (suites != null) { 208 socket.setEnabledCipherSuites(suites); 209 } 210 socket.startHandshake(); 211 212 _socket_ = socket; 213 _input_ = socket.getInputStream(); 214 _output_ = socket.getOutputStream(); 215 _reader = new CRLFLineReader(new InputStreamReader(_input_, _DEFAULT_ENCODING)); 216 _writer = new BufferedWriter(new OutputStreamWriter(_output_, _DEFAULT_ENCODING)); 217 } 218 219 /** 220 * Get the {@link KeyManager} instance. 221 * @return The current {@link KeyManager} instance. 222 */ 223 private KeyManager getKeyManager() 224 { 225 return keyManager; 226 } 227 228 /** 229 * Set a {@link KeyManager} to use. 230 * @param newKeyManager The KeyManager implementation to set. 231 * @see org.apache.commons.net.util.KeyManagerUtils 232 */ 233 public void setKeyManager(KeyManager newKeyManager) 234 { 235 keyManager = newKeyManager; 236 } 237 238 /** 239 * Controls which particular cipher suites are enabled for use on this 240 * connection. Called before server negotiation. 241 * @param cipherSuites The cipher suites. 242 */ 243 public void setEnabledCipherSuites(String[] cipherSuites) 244 { 245 suites = new String[cipherSuites.length]; 246 System.arraycopy(cipherSuites, 0, suites, 0, cipherSuites.length); 247 } 248 249 /** 250 * Returns the names of the cipher suites which could be enabled 251 * for use on this connection. 252 * When the underlying {@link java.net.Socket Socket} is not an {@link SSLSocket} instance, returns null. 253 * @return An array of cipher suite names, or <code>null</code>. 254 */ 255 public String[] getEnabledCipherSuites() 256 { 257 if (_socket_ instanceof SSLSocket) 258 { 259 return ((SSLSocket)_socket_).getEnabledCipherSuites(); 260 } 261 return null; 262 } 263 264 /** 265 * Controls which particular protocol versions are enabled for use on this 266 * connection. I perform setting before a server negotiation. 267 * @param protocolVersions The protocol versions. 268 */ 269 public void setEnabledProtocols(String[] protocolVersions) 270 { 271 protocols = new String[protocolVersions.length]; 272 System.arraycopy(protocolVersions, 0, protocols, 0, protocolVersions.length); 273 } 274 275 /** 276 * Returns the names of the protocol versions which are currently 277 * enabled for use on this connection. 278 * When the underlying {@link java.net.Socket Socket} is not an {@link SSLSocket} instance, returns null. 279 * @return An array of protocols, or <code>null</code>. 280 */ 281 public String[] getEnabledProtocols() 282 { 283 if (_socket_ instanceof SSLSocket) 284 { 285 return ((SSLSocket)_socket_).getEnabledProtocols(); 286 } 287 return null; 288 } 289 290 /** 291 * The TLS command execution. 292 * @throws SSLException If the server reply code is not positive. 293 * @throws IOException If an I/O error occurs while sending 294 * the command or performing the negotiation. 295 * @return TRUE if the command and negotiation succeeded. 296 */ 297 public boolean execTLS() throws SSLException, IOException 298 { 299 if (sendCommand("STLS") != POP3Reply.OK) 300 { 301 return false; 302 //throw new SSLException(getReplyString()); 303 } 304 performSSLNegotiation(); 305 return true; 306 } 307 308 /** 309 * Get the currently configured {@link TrustManager}. 310 * @return A TrustManager instance. 311 */ 312 public TrustManager getTrustManager() 313 { 314 return trustManager; 315 } 316 317 /** 318 * Override the default {@link TrustManager} to use. 319 * @param newTrustManager The TrustManager implementation to set. 320 * @see org.apache.commons.net.util.TrustManagerUtils 321 */ 322 public void setTrustManager(TrustManager newTrustManager) 323 { 324 trustManager = newTrustManager; 325 } 326 } 327 328 /* kate: indent-width 4; replace-tabs on; */