Merge pull request #64 in ITERATE/cyberduck from feature/windows/9074 to master
[cyberduck.git] / source / ch / cyberduck / core / ssl / SSLExceptionMappingService.java
blobdd308f4fe436d299b82d4fe4e3830ac97ba720f2
1 package ch.cyberduck.core.ssl;
3 /*
4 * Copyright (c) 2002-2014 David Kocher. All rights reserved.
5 * http://cyberduck.io/
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * Bug fixes, suggestions and comments should be sent to:
18 * feedback@cyberduck.io
21 import ch.cyberduck.core.AbstractExceptionMappingService;
22 import ch.cyberduck.core.exception.BackgroundException;
23 import ch.cyberduck.core.exception.ConnectionCanceledException;
24 import ch.cyberduck.core.exception.ConnectionRefusedException;
25 import ch.cyberduck.core.exception.InteroperabilityException;
27 import org.apache.commons.lang3.StringUtils;
28 import org.apache.commons.lang3.exception.ExceptionUtils;
29 import org.apache.log4j.Logger;
31 import javax.net.ssl.SSLException;
32 import javax.net.ssl.SSLHandshakeException;
33 import java.net.SocketException;
34 import java.security.GeneralSecurityException;
35 import java.security.cert.CertificateException;
37 /**
38 * @version $Id$
40 public class SSLExceptionMappingService extends AbstractExceptionMappingService<SSLException> {
41 private static final Logger log = Logger.getLogger(SSLExceptionMappingService.class);
43 private enum Alert {
44 close_notify(0),
45 unexpected_message(10) {
46 @Override
47 public String getDescription() {
48 return String.format("%s. An inappropriate message was received.", super.getDescription());
51 bad_record_mac(20) {
52 @Override
53 public String getDescription() {
54 return String.format("%s. A record is received with an incorrect MAC.", super.getDescription());
57 decryption_failed_RESERVED(21),
58 record_overflow(22),
59 decompression_failure(30),
60 handshake_failure(40) {
61 @Override
62 public String getDescription() {
63 return String.format("%s. Unable to negotiate an acceptable set of security parameters.", super.getDescription());
66 no_certificate_RESERVED(41),
67 bad_certificate(42) {
68 @Override
69 public String getDescription() {
70 return String.format("%s. The certificate provided could not be verified by the server.", super.getDescription());
73 unsupported_certificate(43) {
74 @Override
75 public String getDescription() {
76 return String.format("%s. The certificate type provided is not supported by the server.", super.getDescription());
79 certificate_revoked(44) {
80 @Override
81 public String getDescription() {
82 return String.format("%s. The certificate provided has been revoked by its signer.", super.getDescription());
85 certificate_expired(45) {
86 @Override
87 public String getDescription() {
88 return String.format("%s. The certificate provided has expired.", super.getDescription());
91 certificate_unknown(46) {
92 @Override
93 public String getDescription() {
94 return String.format("%s. The certificate provided was not accepted by the server.", super.getDescription());
97 illegal_parameter(47),
98 unknown_ca(48) {
99 @Override
100 public String getDescription() {
101 return String.format("%s. A valid certificate chain or partial chain was received, but " +
102 "the certificate was not accepted because the certificate authority certificate could not be located " +
103 "or couldn't be matched with a known, trusted certificate authority.", super.getDescription());
106 access_denied(49) {
107 @Override
108 public String getDescription() {
109 return String.format("%s. A valid certificate was received, but when access control was " +
110 "applied, the server decided not to proceed with negotiation.", super.getDescription());
113 decode_error(50),
114 decrypt_error(51),
115 export_restriction_RESERVED(60),
116 protocol_version(70) {
117 @Override
118 public String getDescription() {
119 return String.format("%s. The protocol version attempted to negotiate is recognized but not supported.", super.getDescription());
122 insufficient_security(71) {
123 @Override
124 public String getDescription() {
125 return String.format("%s. The server requires ciphers more secure than those supported.", super.getDescription());
128 internal_error(80),
129 user_canceled(90),
130 no_renegotiation(100),
131 unsupported_extension(110);
133 private int code;
135 private Alert(int code) {
136 this.code = code;
139 public int getCode() {
140 return code;
143 public String getDescription() {
144 return StringUtils.capitalize(StringUtils.replaceChars(this.name(), '_', ' '));
149 * close_notify(0),
150 * unexpected_message(10),
151 * bad_record_mac(20),
152 * decryption_failed_RESERVED(21),
153 * record_overflow(22),
154 * decompression_failure(30),
155 * handshake_failure(40),
156 * no_certificate_RESERVED(41),
157 * bad_certificate(42),
158 * unsupported_certificate(43),
159 * certificate_revoked(44),
160 * certificate_expired(45),
161 * certificate_unknown(46),
162 * illegal_parameter(47),
163 * unknown_ca(48),
164 * access_denied(49),
165 * decode_error(50),
166 * decrypt_error(51),
167 * export_restriction_RESERVED(60),
168 * protocol_version(70),
169 * insufficient_security(71),
170 * internal_error(80),
171 * user_canceled(90),
172 * no_renegotiation(100),
173 * unsupported_extension(110),
175 @Override
176 public BackgroundException map(final SSLException failure) {
177 final StringBuilder buffer = new StringBuilder();
178 if(ExceptionUtils.getRootCause(failure) instanceof SocketException) {
179 // Map Connection has been shutdown: javax.net.ssl.SSLException: java.net.SocketException: Broken pipe
180 this.append(buffer, ExceptionUtils.getRootCause(failure).getMessage());
181 return new ConnectionRefusedException(buffer.toString(), failure);
183 if(failure instanceof SSLHandshakeException) {
184 if(ExceptionUtils.getRootCause(failure) instanceof CertificateException) {
185 log.warn(String.format("Ignore certificate failure %s and drop connection", failure.getMessage()));
186 // Server certificate not accepted
187 return new ConnectionCanceledException(failure);
190 if(ExceptionUtils.getRootCause(failure) instanceof GeneralSecurityException) {
191 this.append(buffer, ExceptionUtils.getRootCause(failure).getMessage());
192 return new InteroperabilityException(buffer.toString(), failure);
194 final String message = failure.getMessage();
195 for(Alert alert : Alert.values()) {
196 if(StringUtils.contains(message, alert.name())) {
197 this.append(buffer, alert.getDescription());
198 break;
201 if(buffer.length() == 0) {
202 this.append(buffer, message);
204 return new InteroperabilityException(buffer.toString(), failure);