1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/ssl/openssl_ssl_util.h" 6 7 #include <errno.h> 8 9 #include <openssl/err.h> 10 #include <openssl/ssl.h> 11 12 #include "base/bind.h" 13 #include "base/lazy_instance.h" 14 #include "base/location.h" 15 #include "base/logging.h" 16 #include "base/values.h" 17 #include "crypto/openssl_util.h" 18 #include "net/base/net_errors.h" 19 20 namespace net { 21 22 SslSetClearMask::SslSetClearMask() 23 : set_mask(0), 24 clear_mask(0) { 25 } 26 27 void SslSetClearMask::ConfigureFlag(long flag, bool state) { 28 (state ? set_mask : clear_mask) |= flag; 29 // Make sure we haven't got any intersection in the set & clear options. 30 DCHECK_EQ(0, set_mask & clear_mask) << flag << ":" << state; 31 } 32 33 namespace { 34 35 class OpenSSLNetErrorLibSingleton { 36 public: 37 OpenSSLNetErrorLibSingleton() { 38 crypto::EnsureOpenSSLInit(); 39 40 // Allocate a new error library value for inserting net errors into 41 // OpenSSL. This does not register any ERR_STRING_DATA for the errors, so 42 // stringifying error codes through OpenSSL will return NULL. 43 net_error_lib_ = ERR_get_next_error_library(); 44 } 45 46 unsigned net_error_lib() const { return net_error_lib_; } 47 48 private: 49 unsigned net_error_lib_; 50 }; 51 52 base::LazyInstance<OpenSSLNetErrorLibSingleton>::Leaky g_openssl_net_error_lib = 53 LAZY_INSTANCE_INITIALIZER; 54 55 unsigned OpenSSLNetErrorLib() { 56 return g_openssl_net_error_lib.Get().net_error_lib(); 57 } 58 59 int MapOpenSSLErrorSSL(uint32_t error_code) { 60 DCHECK_EQ(ERR_LIB_SSL, ERR_GET_LIB(error_code)); 61 62 DVLOG(1) << "OpenSSL SSL error, reason: " << ERR_GET_REASON(error_code) 63 << ", name: " << ERR_error_string(error_code, NULL); 64 switch (ERR_GET_REASON(error_code)) { 65 case SSL_R_READ_TIMEOUT_EXPIRED: 66 return ERR_TIMED_OUT; 67 case SSL_R_UNKNOWN_CERTIFICATE_TYPE: 68 case SSL_R_UNKNOWN_CIPHER_TYPE: 69 case SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE: 70 case SSL_R_UNKNOWN_PKEY_TYPE: 71 case SSL_R_UNKNOWN_SSL_VERSION: 72 return ERR_NOT_IMPLEMENTED; 73 case SSL_R_UNSUPPORTED_SSL_VERSION: 74 case SSL_R_NO_CIPHER_MATCH: 75 case SSL_R_NO_SHARED_CIPHER: 76 case SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY: 77 case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION: 78 case SSL_R_UNSUPPORTED_PROTOCOL: 79 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; 80 case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: 81 case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE: 82 case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: 83 case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: 84 case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: 85 case SSL_R_TLSV1_ALERT_ACCESS_DENIED: 86 case SSL_R_TLSV1_ALERT_UNKNOWN_CA: 87 return ERR_BAD_SSL_CLIENT_AUTH_CERT; 88 case SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE: 89 return ERR_SSL_DECOMPRESSION_FAILURE_ALERT; 90 case SSL_R_SSLV3_ALERT_BAD_RECORD_MAC: 91 return ERR_SSL_BAD_RECORD_MAC_ALERT; 92 case SSL_R_TLSV1_ALERT_DECRYPT_ERROR: 93 return ERR_SSL_DECRYPT_ERROR_ALERT; 94 case SSL_R_TLSV1_UNRECOGNIZED_NAME: 95 return ERR_SSL_UNRECOGNIZED_NAME_ALERT; 96 case SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED: 97 return ERR_SSL_UNSAFE_NEGOTIATION; 98 case SSL_R_BAD_DH_P_LENGTH: 99 return ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY; 100 // SSL_R_UNKNOWN_PROTOCOL is reported if premature application data is 101 // received (see http://crbug.com/42538), and also if all the protocol 102 // versions supported by the server were disabled in this socket instance. 103 // Mapped to ERR_SSL_PROTOCOL_ERROR for compatibility with other SSL sockets 104 // in the former scenario. 105 case SSL_R_UNKNOWN_PROTOCOL: 106 case SSL_R_SSL_HANDSHAKE_FAILURE: 107 case SSL_R_DECRYPTION_FAILED: 108 case SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC: 109 case SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG: 110 case SSL_R_DIGEST_CHECK_FAILED: 111 case SSL_R_ENCRYPTED_LENGTH_TOO_LONG: 112 case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST: 113 case SSL_R_EXCESSIVE_MESSAGE_SIZE: 114 case SSL_R_EXTRA_DATA_IN_MESSAGE: 115 case SSL_R_GOT_A_FIN_BEFORE_A_CCS: 116 case SSL_R_INVALID_COMMAND: 117 case SSL_R_INVALID_STATUS_RESPONSE: 118 case SSL_R_INVALID_TICKET_KEYS_LENGTH: 119 // SSL_do_handshake reports this error when the server responds to a 120 // ClientHello with a fatal close_notify alert. 121 case SSL_AD_REASON_OFFSET + SSL_AD_CLOSE_NOTIFY: 122 case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE: 123 // TODO(joth): SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE may be returned from the 124 // server after receiving ClientHello if there's no common supported cipher. 125 // Ideally we'd map that specific case to ERR_SSL_VERSION_OR_CIPHER_MISMATCH 126 // to match the NSS implementation. See also http://goo.gl/oMtZW 127 case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE: 128 case SSL_R_SSLV3_ALERT_NO_CERTIFICATE: 129 case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER: 130 case SSL_R_TLSV1_ALERT_DECODE_ERROR: 131 case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: 132 case SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION: 133 case SSL_R_TLSV1_ALERT_INTERNAL_ERROR: 134 case SSL_R_TLSV1_ALERT_NO_RENEGOTIATION: 135 case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW: 136 case SSL_R_TLSV1_ALERT_USER_CANCELLED: 137 return ERR_SSL_PROTOCOL_ERROR; 138 case SSL_R_CERTIFICATE_VERIFY_FAILED: 139 // The only way that the certificate verify callback can fail is if 140 // the leaf certificate changed during a renegotiation. 141 return ERR_SSL_SERVER_CERT_CHANGED; 142 case SSL_AD_REASON_OFFSET + SSL3_AD_INAPPROPRIATE_FALLBACK: 143 return ERR_SSL_INAPPROPRIATE_FALLBACK; 144 default: 145 LOG(WARNING) << "Unmapped error reason: " << ERR_GET_REASON(error_code); 146 return ERR_SSL_PROTOCOL_ERROR; 147 } 148 } 149 150 base::Value* NetLogOpenSSLErrorCallback(int net_error, 151 int ssl_error, 152 const OpenSSLErrorInfo& error_info, 153 NetLog::LogLevel /* log_level */) { 154 base::DictionaryValue* dict = new base::DictionaryValue(); 155 dict->SetInteger("net_error", net_error); 156 dict->SetInteger("ssl_error", ssl_error); 157 if (error_info.error_code != 0) { 158 dict->SetInteger("error_lib", ERR_GET_LIB(error_info.error_code)); 159 dict->SetInteger("error_reason", ERR_GET_REASON(error_info.error_code)); 160 } 161 if (error_info.file != NULL) 162 dict->SetString("file", error_info.file); 163 if (error_info.line != 0) 164 dict->SetInteger("line", error_info.line); 165 return dict; 166 } 167 168 } // namespace 169 170 void OpenSSLPutNetError(const tracked_objects::Location& location, int err) { 171 // Net error codes are negative. Encode them as positive numbers. 172 err = -err; 173 if (err < 0 || err > 0xfff) { 174 // OpenSSL reserves 12 bits for the reason code. 175 NOTREACHED(); 176 err = ERR_INVALID_ARGUMENT; 177 } 178 ERR_put_error(OpenSSLNetErrorLib(), 0, err, 179 location.file_name(), location.line_number()); 180 } 181 182 int MapOpenSSLError(int err, const crypto::OpenSSLErrStackTracer& tracer) { 183 OpenSSLErrorInfo error_info; 184 return MapOpenSSLErrorWithDetails(err, tracer, &error_info); 185 } 186 187 int MapOpenSSLErrorWithDetails(int err, 188 const crypto::OpenSSLErrStackTracer& tracer, 189 OpenSSLErrorInfo* out_error_info) { 190 *out_error_info = OpenSSLErrorInfo(); 191 192 switch (err) { 193 case SSL_ERROR_WANT_READ: 194 case SSL_ERROR_WANT_WRITE: 195 return ERR_IO_PENDING; 196 case SSL_ERROR_SYSCALL: 197 LOG(ERROR) << "OpenSSL SYSCALL error, earliest error code in " 198 "error queue: " << ERR_peek_error() << ", errno: " 199 << errno; 200 return ERR_FAILED; 201 case SSL_ERROR_SSL: 202 // Walk down the error stack to find an SSL or net error. 203 uint32_t error_code; 204 const char* file; 205 int line; 206 do { 207 error_code = ERR_get_error_line(&file, &line); 208 if (ERR_GET_LIB(error_code) == ERR_LIB_SSL) { 209 out_error_info->error_code = error_code; 210 out_error_info->file = file; 211 out_error_info->line = line; 212 return MapOpenSSLErrorSSL(error_code); 213 } else if (ERR_GET_LIB(error_code) == OpenSSLNetErrorLib()) { 214 out_error_info->error_code = error_code; 215 out_error_info->file = file; 216 out_error_info->line = line; 217 // Net error codes are negative but encoded in OpenSSL as positive 218 // numbers. 219 return -ERR_GET_REASON(error_code); 220 } 221 } while (error_code != 0); 222 return ERR_FAILED; 223 default: 224 // TODO(joth): Implement full mapping. 225 LOG(WARNING) << "Unknown OpenSSL error " << err; 226 return ERR_SSL_PROTOCOL_ERROR; 227 } 228 } 229 230 NetLog::ParametersCallback CreateNetLogOpenSSLErrorCallback( 231 int net_error, 232 int ssl_error, 233 const OpenSSLErrorInfo& error_info) { 234 return base::Bind(&NetLogOpenSSLErrorCallback, 235 net_error, ssl_error, error_info); 236 } 237 238 } // namespace net 239