< prev index next >

src/java.base/share/classes/sun/security/ssl/Alert.java

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 23,223 **** * questions. */ package sun.security.ssl; import javax.net.ssl.*; ! /* ! * A simple class to congregate alerts, their definitions, and common ! * support methods. */ ! final class Alerts { ! /* ! * Alerts are always a fixed two byte format (level/description). */ ! // warnings and fatal errors are package private facilities/constants ! // Alert levels (enum AlertLevel) ! static final byte alert_warning = 1; ! static final byte alert_fatal = 2; ! /* ! * Alert descriptions (enum AlertDescription) ! * ! * We may not use them all in our processing, but if someone ! * sends us one, we can at least convert it to a string for the ! * user. */ ! static final byte alert_close_notify = 0; ! static final byte alert_unexpected_message = 10; ! static final byte alert_bad_record_mac = 20; ! static final byte alert_decryption_failed = 21; ! static final byte alert_record_overflow = 22; ! static final byte alert_decompression_failure = 30; ! static final byte alert_handshake_failure = 40; ! static final byte alert_no_certificate = 41; ! static final byte alert_bad_certificate = 42; ! static final byte alert_unsupported_certificate = 43; ! static final byte alert_certificate_revoked = 44; ! static final byte alert_certificate_expired = 45; ! static final byte alert_certificate_unknown = 46; ! static final byte alert_illegal_parameter = 47; ! static final byte alert_unknown_ca = 48; ! static final byte alert_access_denied = 49; ! static final byte alert_decode_error = 50; ! static final byte alert_decrypt_error = 51; ! static final byte alert_export_restriction = 60; ! static final byte alert_protocol_version = 70; ! static final byte alert_insufficient_security = 71; ! static final byte alert_internal_error = 80; ! static final byte alert_user_canceled = 90; ! static final byte alert_no_renegotiation = 100; ! ! // from RFC 3546 (TLS Extensions) ! static final byte alert_unsupported_extension = 110; ! static final byte alert_certificate_unobtainable = 111; ! static final byte alert_unrecognized_name = 112; ! static final byte alert_bad_certificate_status_response = 113; ! static final byte alert_bad_certificate_hash_value = 114; ! ! // from RFC 7301 (TLS ALPN Extension) ! static final byte alert_no_application_protocol = 120; ! ! static String alertDescription(byte code) { ! switch (code) { ! ! case alert_close_notify: ! return "close_notify"; ! case alert_unexpected_message: ! return "unexpected_message"; ! case alert_bad_record_mac: ! return "bad_record_mac"; ! case alert_decryption_failed: ! return "decryption_failed"; ! case alert_record_overflow: ! return "record_overflow"; ! case alert_decompression_failure: ! return "decompression_failure"; ! case alert_handshake_failure: ! return "handshake_failure"; ! case alert_no_certificate: ! return "no_certificate"; ! case alert_bad_certificate: ! return "bad_certificate"; ! case alert_unsupported_certificate: ! return "unsupported_certificate"; ! case alert_certificate_revoked: ! return "certificate_revoked"; ! case alert_certificate_expired: ! return "certificate_expired"; ! case alert_certificate_unknown: ! return "certificate_unknown"; ! case alert_illegal_parameter: ! return "illegal_parameter"; ! case alert_unknown_ca: ! return "unknown_ca"; ! case alert_access_denied: ! return "access_denied"; ! case alert_decode_error: ! return "decode_error"; ! case alert_decrypt_error: ! return "decrypt_error"; ! case alert_export_restriction: ! return "export_restriction"; ! case alert_protocol_version: ! return "protocol_version"; ! case alert_insufficient_security: ! return "insufficient_security"; ! case alert_internal_error: ! return "internal_error"; ! case alert_user_canceled: ! return "user_canceled"; ! case alert_no_renegotiation: ! return "no_renegotiation"; ! case alert_unsupported_extension: ! return "unsupported_extension"; ! case alert_certificate_unobtainable: ! return "certificate_unobtainable"; ! case alert_unrecognized_name: ! return "unrecognized_name"; ! case alert_bad_certificate_status_response: ! return "bad_certificate_status_response"; ! case alert_bad_certificate_hash_value: ! return "bad_certificate_hash_value"; ! case alert_no_application_protocol: ! return "no_application_protocol"; ! ! default: ! return "<UNKNOWN ALERT: " + (code & 0x0ff) + ">"; ! } ! } ! ! static SSLException getSSLException(byte description, String reason) { ! return getSSLException(description, null, reason); ! } ! ! /* ! * Try to be a little more specific in our choice of ! * exceptions to throw. */ ! static SSLException getSSLException(byte description, Throwable cause, ! String reason) { ! SSLException e; ! // the SSLException classes do not have a no-args constructor ! // make up a message if there is none ! if (reason == null) { ! if (cause != null) { ! reason = cause.toString(); ! } else { ! reason = ""; } } ! switch (description) { ! case alert_handshake_failure: ! case alert_no_certificate: ! case alert_bad_certificate: ! case alert_unsupported_certificate: ! case alert_certificate_revoked: ! case alert_certificate_expired: ! case alert_certificate_unknown: ! case alert_unknown_ca: ! case alert_access_denied: ! case alert_decrypt_error: ! case alert_export_restriction: ! case alert_insufficient_security: ! case alert_unsupported_extension: ! case alert_certificate_unobtainable: ! case alert_unrecognized_name: ! case alert_bad_certificate_status_response: ! case alert_bad_certificate_hash_value: ! case alert_no_application_protocol: ! e = new SSLHandshakeException(reason); ! break; ! ! case alert_close_notify: ! case alert_unexpected_message: ! case alert_bad_record_mac: ! case alert_decryption_failed: ! case alert_record_overflow: ! case alert_decompression_failure: ! case alert_illegal_parameter: ! case alert_decode_error: ! case alert_protocol_version: ! case alert_internal_error: ! case alert_user_canceled: ! case alert_no_renegotiation: ! default: ! e = new SSLException(reason); ! break; } ! if (cause != null) { ! e.initCause(cause); } - return e; } } --- 23,269 ---- * questions. */ package sun.security.ssl; + import java.io.IOException; + import java.nio.ByteBuffer; + import java.text.MessageFormat; + import java.util.Locale; import javax.net.ssl.*; ! /** ! * SSL/(D)TLS Alter description */ + enum Alert { + // Please refer to TLS Alert Registry for the latest (D)TLS Alert values: + // https://www.iana.org/assignments/tls-parameters/ + CLOSE_NOTIFY ((byte)0, "close_notify", false), + UNEXPECTED_MESSAGE ((byte)10, "unexpected_message", false), + BAD_RECORD_MAC ((byte)20, "bad_record_mac", false), + DECRYPTION_FAILED ((byte)21, "decryption_failed", false), + RECORD_OVERFLOW ((byte)22, "record_overflow", false), + DECOMPRESSION_FAILURE ((byte)30, "decompression_failure", false), + HANDSHAKE_FAILURE ((byte)40, "handshake_failure", true), + NO_CERTIFICATE ((byte)41, "no_certificate", true), + BAD_CERTIFICATE ((byte)42, "bad_certificate", true), + UNSUPPORTED_CERTIFCATE ((byte)43, "unsupported_certificate", true), + CERTIFICATE_REVOKED ((byte)44, "certificate_revoked", true), + CERTIFICATE_EXPIRED ((byte)45, "certificate_expired", true), + CERTIFICATE_UNKNOWN ((byte)46, "certificate_unknown", true), + ILLEGAL_PARAMETER ((byte)47, "illegal_parameter", true), + UNKNOWN_CA ((byte)48, "unknown_ca", true), + ACCESS_DENIED ((byte)49, "access_denied", true), + DECODE_ERROR ((byte)50, "decode_error", true), + DECRYPT_ERROR ((byte)51, "decrypt_error", true), + EXPORT_RESTRICTION ((byte)60, "export_restriction", true), + PROTOCOL_VERSION ((byte)70, "protocol_version", true), + INSUFFICIENT_SECURITY ((byte)71, "insufficient_security", true), + INTERNAL_ERROR ((byte)80, "internal_error", false), + INAPPROPRIATE_FALLBACK ((byte)86, "inappropriate_fallback", false), + USER_CANCELED ((byte)90, "user_canceled", false), + NO_RENEGOTIATION ((byte)100, "no_renegotiation", true), + MISSING_EXTENSION ((byte)109, "missing_extension", true), + UNSUPPORTED_EXTENSION ((byte)110, "unsupported_extension", true), + CERT_UNOBTAINABLE ((byte)111, "certificate_unobtainable", true), + UNRECOGNIZED_NAME ((byte)112, "unrecognized_name", true), + BAD_CERT_STATUS_RESPONSE((byte)113, + "bad_certificate_status_response", true), + BAD_CERT_HASH_VALUE ((byte)114, "bad_certificate_hash_value", true), + UNKNOWN_PSK_IDENTITY ((byte)115, "unknown_psk_identity", true), + CERTIFICATE_REQUIRED ((byte)116, "certificate_required", true), + NO_APPLICATION_PROTOCOL ((byte)120, "no_application_protocol", true); + + // ordinal value of the Alert + final byte id; + + // description of the Alert + final String description; + + // Does tha alert happen during handshake only? + final boolean handshakeOnly; + + // Alert message consumer + static final SSLConsumer alertConsumer = new AlertConsumer(); + + private Alert(byte id, String description, boolean handshakeOnly) { + this.id = id; + this.description = description; + this.handshakeOnly = handshakeOnly; + } + + static Alert valueOf(byte id) { + for (Alert al : Alert.values()) { + if (al.id == id) { + return al; + } + } + + return null; + } ! static String nameOf(byte id) { ! for (Alert al : Alert.values()) { ! if (al.id == id) { ! return al.description; ! } ! } ! ! return "UNKNOWN ALERT (" + (id & 0x0FF) + ")"; ! } ! ! SSLException createSSLException(String reason) { ! return createSSLException(reason, null); ! } ! SSLException createSSLException(String reason, Throwable cause) { ! if (reason == null) { ! reason = (cause != null) ? cause.getMessage() : ""; ! } ! ! SSLException ssle = handshakeOnly ? ! new SSLHandshakeException(reason) : new SSLException(reason); ! if (cause != null) { ! ssle.initCause(cause); ! } ! ! return ssle; ! } ! ! /** ! * SSL/(D)TLS Alert level. */ + enum Level { + WARNING ((byte)1, "warning"), + FATAL ((byte)2, "fatal"); + + // ordinal value of the Alert level + final byte level; + + // description of the Alert level + final String description; + + private Level(byte level, String description) { + this.level = level; + this.description = description; + } ! static Level valueOf(byte level) { ! for (Level lv : Level.values()) { ! if (lv.level == level) { ! return lv; ! } ! } ! return null; ! } ! static String nameOf(byte level) { ! for (Level lv : Level.values()) { ! if (lv.level == level) { ! return lv.description; ! } ! } ! ! return "UNKNOWN ALERT LEVEL (" + (level & 0x0FF) + ")"; ! } ! } ! ! /** ! * The Alert message. */ ! private static final class AlertMessage { ! private final byte level; // level ! private final byte id; // description ! ! AlertMessage(TransportContext context, ! ByteBuffer m) throws IOException { ! // struct { ! // AlertLevel level; ! // AlertDescription description; ! // } Alert; ! if (m.remaining() != 2) { ! context.fatal(Alert.ILLEGAL_PARAMETER, ! "Invalid Alert message: no sufficient data"); ! } ! ! this.level = m.get(); // level ! this.id = m.get(); // description ! } ! ! @Override ! public String toString() { ! MessageFormat messageFormat = new MessageFormat( ! "\"Alert\": '{'\n" + ! " \"level\" : \"{0}\",\n" + ! " \"description\": \"{1}\"\n" + ! "'}'", ! Locale.ENGLISH); ! ! Object[] messageFields = { ! Level.nameOf(level), ! Alert.nameOf(id) ! }; ! ! return messageFormat.format(messageFields); ! } ! } ! ! /** ! * Consumer of alert messages */ ! private static final class AlertConsumer implements SSLConsumer { ! // Prevent instantiation of this class. ! private AlertConsumer() { ! // blank ! } ! @Override ! public void consume(ConnectionContext context, ! ByteBuffer m) throws IOException { ! TransportContext tc = (TransportContext)context; ! ! AlertMessage am = new AlertMessage(tc, m); ! if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { ! SSLLogger.fine("Received alert message", am); } + + Level level = Level.valueOf(am.level); + Alert alert = Alert.valueOf(am.id); + if (alert == Alert.CLOSE_NOTIFY) { + if (tc.handshakeContext != null) { + tc.fatal(Alert.UNEXPECTED_MESSAGE, + "Received close_notify during handshake"); } ! ! tc.isInputCloseNotified = true; ! tc.closeInbound(); ! } else if ((level == Level.WARNING) && (alert != null)) { ! // Terminate the connection if an alert with a level of warning ! // is received during handshaking, except the no_certificate ! // warning. ! if (alert.handshakeOnly && (tc.handshakeContext != null)) { ! // It's OK to get a no_certificate alert from a client of ! // which we requested client authentication. However, ! // if we required it, then this is not acceptable. ! if (tc.sslConfig.isClientMode || ! alert != Alert.NO_CERTIFICATE || ! (tc.sslConfig.clientAuthType != ! ClientAuthType.CLIENT_AUTH_REQUESTED)) { ! tc.fatal(Alert.HANDSHAKE_FAILURE, ! "received handshake warning: " + alert.description); ! } // Otherwise, ignore the warning ! } // Otherwise, ignore the warning. ! } else { // fatal or unknown ! String diagnostic; ! if (alert == null) { ! alert = Alert.UNEXPECTED_MESSAGE; ! diagnostic = "Unknown alert description (" + am.id + ")"; ! } else { ! diagnostic = "Received fatal alert: " + alert.description; } ! tc.fatal(alert, diagnostic, true, null); ! } } } }
< prev index next >