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