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; */