# Copyright (c) 2015 The Johns Hopkins University/Applied Physics Laboratory # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import abc import six import ssl @six.add_metaclass(abc.ABCMeta) class AuthenticationSuite(object): """ An authentication suite used to establish secure network connections. Acts as the base of the suite hierarchy. """ # OpenSSL cipher suites # Explicitly listed suites for Basic and TLSv1.2 authentication for KMIP # profiles. # # Obtained from: # https://www.openssl.org/docs/man1.1.0/apps/ciphers.html # https://www.openssl.org/docs/man1.0.2/apps/ciphers.html openssl_cipher_suite_map = { # TLS v1.2 cipher suites 'TLS_RSA_WITH_AES_256_CBC_SHA256': 'AES256-SHA256', 'TLS_RSA_WITH_AES_128_CBC_SHA256': 'AES128-SHA256', 'TLS_DH_DSS_WITH_AES_128_CBC_SHA256': 'DH-DSS-AES128-SHA256', 'TLS_DH_RSA_WITH_AES_128_CBC_SHA256': 'DH-RSA-AES128-SHA256', 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA256': 'DHE-DSS-AES128-SHA256', 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA256': 'DHE-RSA-AES128-SHA256', 'TLS_DH_DSS_WITH_AES_256_CBC_SHA256': 'DH-DSS-AES256-SHA256', 'TLS_DH_RSA_WITH_AES_256_CBC_SHA256': 'DH-RSA-AES256-SHA256', 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA256': 'DHE-DSS-AES256-SHA256', 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA256': 'DHE-RSA-AES256-SHA256', 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256': 'ECDHE-ECDSA-AES128-SHA256', 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384': 'ECDHE-ECDSA-AES256-SHA384', 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256': 'ECDHE-RSA-AES128-SHA256', 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384': 'ECDHE-RSA-AES256-SHA384', 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256': 'ECDHE-ECDSA-AES128-GCM-SHA256', 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384': 'ECDHE-ECDSA-AES256-GCM-SHA384', 'TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256': 'ECDH-ECDSA-AES128-SHA256', 'TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384': 'ECDH-ECDSA-AES256-SHA384', 'TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256': 'ECDH-RSA-AES128-SHA256', 'TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384': 'ECDH-RSA-AES256-SHA384', # AES ciphersuites from RFC3268, extending TLS v1.0 'TLS_RSA_WITH_AES_128_CBC_SHA': 'AES128-SHA', 'TLS_RSA_WITH_AES_256_CBC_SHA': 'AES256-SHA', 'TLS_DH_DSS_WITH_AES_128_CBC_SHA': 'DH-DSS-AES128-SHA', 'TLS_DH_RSA_WITH_AES_128_CBC_SHA': 'DH-RSA-AES128-SHA', 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA': 'DHE-DSS-AES128-SHA', 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA': 'DHE-RSA-AES128-SHA', 'TLS_DH_DSS_WITH_AES_256_CBC_SHA': 'DH-DSS-AES256-SHA', 'TLS_DH_RSA_WITH_AES_256_CBC_SHA': 'DH-RSA-AES256-SHA', 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA': 'DHE-DSS-AES256-SHA', 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA': 'DHE-RSA-AES256-SHA', # Elliptic curve cipher suites. 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA': 'ECDHE-ECDSA-AES128-SHA', 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA': 'ECDHE-RSA-AES128-SHA', # Pre shared keying (PSK) cipheruites 'TLS_PSK_WITH_AES_128_CBC_SHA': 'PSK-AES128-CBC-SHA', 'TLS_PSK_WITH_AES_256_CBC_SHA': 'PSK-AES256-CBC-SHA', # No OpenSSL support 'TLS_DHE_PSK_WITH_AES_128_CBC_SHA': None, 'TLS_DHE_PSK_WITH_AES_256_CBC_SHA': None, 'TLS_RSA_PSK_WITH_AES_128_CBC_SHA': None, 'TLS_RSA_PSK_WITH_AES_256_CBC_SHA': None } _default_cipher_suites = [] @abc.abstractmethod def __init__(self, cipher_suites=None): """ Create an AuthenticationSuite object. Args: cipher_suites (list): A list of strings representing the names of cipher suites to use. Overrides the default set of cipher suites. Optional, defaults to None. """ self._custom_suites = [] # Compose a unique list of custom cipher suites if any were provided. # Translate each suite name into its corresponding OpenSSL suite name, # allowing for both specification and OpenSSL suite names in the # provided list. if cipher_suites: for cipher_suite in cipher_suites: if cipher_suite in self.openssl_cipher_suite_map.keys(): suite = self.openssl_cipher_suite_map.get(cipher_suite) if suite: self._custom_suites.append(suite) elif cipher_suite in self.openssl_cipher_suite_map.values(): if cipher_suite: self._custom_suites.append(cipher_suite) self._custom_suites = list(set(self._custom_suites)) # Filter the custom suites to only include those from the default # cipher suite list (provided for each subclass authentication suite). # If no custom suites were specified, use the default cipher suites. suites = [] if self._custom_suites: for suite in self._custom_suites: if suite in self._default_cipher_suites: suites.append(suite) else: suites = self._default_cipher_suites self._cipher_suites = ':'.join(suites) if self._cipher_suites == '': self._cipher_suites = ':'.join(self._default_cipher_suites) @property def protocol(self): """ Get the authentication suite protocol. Returns: int: The value of the ssl.PROTOCOL_* setting for this suite. """ return self._protocol @property def ciphers(self): """ Get the authentication suite cipher string. Returns: string: A colon delimited string listing the valid ciphers for the suite protocol. """ return self._cipher_suites class BasicAuthenticationSuite(AuthenticationSuite): """ An authentication suite used to establish secure network connections. Supports TLS 1.0 and a subset of TLS 1.0 compliant cipher suites, defined in NIST 800-57, as defined by the KMIP specification. """ _default_cipher_suites = [ 'AES128-SHA', 'DES-CBC3-SHA', 'AES256-SHA', 'DHE-DSS-DES-CBC3-SHA', 'DHE-RSA-DES-CBC3-SHA', 'DH-DSS-AES128-SHA', 'DH-RSA-AES128-SHA', 'DHE-DSS-AES128-SHA', 'DHE-RSA-AES128-SHA', 'DH-RSA-AES256-SHA', 'DHE-DSS-AES256-SHA', 'DHE-RSA-AES256-SHA' ] def __init__(self, cipher_suites=None): """ Create a BasicAuthenticationSuite object. Args: cipher_suites (list): A list of strings representing the names of cipher suites to use. Overrides the default set of cipher suites. Optional, defaults to None. """ super(BasicAuthenticationSuite, self).__init__(cipher_suites) self._protocol = ssl.PROTOCOL_TLSv1 class TLS12AuthenticationSuite(AuthenticationSuite): """ An authentication suite used to establish secure network connections. Supports TLS 1.2 and a subset of TLS 1.2 compliant cipher suites, defined in NIST 800-57, as defined by the KMIP specification. """ _default_cipher_suites = [ 'AES128-SHA256', 'AES256-SHA256', 'DH-DSS-AES256-SHA256', 'DH-DSS-AES128-SHA256', 'DH-RSA-AES128-SHA256', 'DHE-DSS-AES128-SHA256', 'DHE-RSA-AES128-SHA256', 'DH-DSS-AES256-SHA256', 'DH-RSA-AES256-SHA256', 'DHE-DSS-AES256-SHA256', 'DHE-RSA-AES256-SHA256', 'ECDH-ECDSA-AES128-SHA256', 'ECDH-ECDSA-AES256-SHA256', 'ECDHE-ECDSA-AES128-SHA256', 'ECDHE-ECDSA-AES256-SHA384', 'ECDH-RSA-AES128-SHA256', 'ECDH-RSA-AES256-SHA384', 'ECDHE-RSA-AES128-SHA256', 'ECDHE-RSA-AES256-SHA384', 'ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-ECDSA-AES128-SHA256', 'ECDHE-ECDSA-AES256-SHA384' ] def __init__(self, cipher_suites=None): """ Create a TLS12AuthenticationSuite object. Args: cipher_suites (list): A list of strings representing the names of cipher suites to use. Overrides the default set of cipher suites. Optional, defaults to None. """ super(TLS12AuthenticationSuite, self).__init__(cipher_suites) self._protocol = ssl.PROTOCOL_TLSv1_2