1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
import logging
import os
from configparser import ConfigParser, ExtendedInterpolation
from typing import Dict, Optional
from .certs import CertificateSpec, Ngtcp2TestCA, Credentials
log = logging.getLogger(__name__)
class CryptoLib:
IGNORES_CIPHER_CONFIG = [
'picotls', 'boringssl'
]
UNSUPPORTED_CIPHERS = {
'wolfssl': [
'TLS_AES_128_CCM_SHA256', # no plans to
],
'picotls': [
'TLS_AES_128_CCM_SHA256', # no plans to
],
'boringssl': [
'TLS_AES_128_CCM_SHA256', # no plans to
]
}
GNUTLS_CIPHERS = {
'TLS_AES_128_GCM_SHA256': 'AES-128-GCM',
'TLS_AES_256_GCM_SHA384': 'AES-256-GCM',
'TLS_CHACHA20_POLY1305_SHA256': 'CHACHA20-POLY1305',
'TLS_AES_128_CCM_SHA256': 'AES-128-CCM',
}
@classmethod
def uses_cipher_config(cls, crypto_lib):
return crypto_lib not in cls.IGNORES_CIPHER_CONFIG
@classmethod
def supports_cipher(cls, crypto_lib, cipher):
return crypto_lib not in cls.UNSUPPORTED_CIPHERS or \
cipher not in cls.UNSUPPORTED_CIPHERS[crypto_lib]
@classmethod
def adjust_ciphers(cls, crypto_lib, ciphers: str) -> str:
if crypto_lib == 'gnutls':
gciphers = "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL"
for cipher in ciphers.split(':'):
gciphers += f':+{cls.GNUTLS_CIPHERS[cipher]}'
return gciphers
return ciphers
def init_config_from(conf_path):
if os.path.isfile(conf_path):
config = ConfigParser(interpolation=ExtendedInterpolation())
config.read(conf_path)
return config
return None
TESTS_PATH = os.path.dirname(os.path.dirname(__file__))
EXAMPLES_PATH = os.path.dirname(TESTS_PATH)
DEF_CONFIG = init_config_from(os.path.join(TESTS_PATH, 'config.ini'))
class Env:
@classmethod
def get_crypto_libs(cls, configurable_ciphers=None):
names = [name for name in DEF_CONFIG['examples']
if DEF_CONFIG['examples'][name] == 'yes']
if configurable_ciphers is not None:
names = [n for n in names if CryptoLib.uses_cipher_config(n)]
return names
def __init__(self, examples_dir=None, tests_dir=None, config=None,
pytestconfig=None):
self._verbose = pytestconfig.option.verbose if pytestconfig is not None else 0
self._examples_dir = examples_dir if examples_dir is not None else EXAMPLES_PATH
self._tests_dir = examples_dir if tests_dir is not None else TESTS_PATH
self._gen_dir = os.path.join(self._tests_dir, 'gen')
self.config = config if config is not None else DEF_CONFIG
self._version = self.config['ngtcp2']['version']
self._crypto_libs = [name for name in self.config['examples']
if self.config['examples'][name] == 'yes']
self._clients = [self.config['clients'][lib] for lib in self._crypto_libs
if lib in self.config['clients']]
self._servers = [self.config['servers'][lib] for lib in self._crypto_libs
if lib in self.config['servers']]
self._examples_pem = {
'key': 'xxx',
'cert': 'xxx',
}
self._htdocs_dir = os.path.join(self._gen_dir, 'htdocs')
self._tld = 'tests.ngtcp2.nghttp2.org'
self._example_domain = f"one.{self._tld}"
self._ca = None
self._cert_specs = [
CertificateSpec(domains=[self._example_domain], key_type='rsa2048'),
CertificateSpec(name="clientsX", sub_specs=[
CertificateSpec(name="user1", client=True),
]),
]
def issue_certs(self):
if self._ca is None:
self._ca = Ngtcp2TestCA.create_root(name=self._tld,
store_dir=os.path.join(self.gen_dir, 'ca'),
key_type="rsa2048")
self._ca.issue_certs(self._cert_specs)
def setup(self):
os.makedirs(self._gen_dir, exist_ok=True)
os.makedirs(self._htdocs_dir, exist_ok=True)
self.issue_certs()
def get_server_credentials(self) -> Optional[Credentials]:
creds = self.ca.get_credentials_for_name(self._example_domain)
if len(creds) > 0:
return creds[0]
return None
@property
def verbose(self) -> int:
return self._verbose
@property
def version(self) -> str:
return self._version
@property
def gen_dir(self) -> str:
return self._gen_dir
@property
def ca(self):
return self._ca
@property
def htdocs_dir(self) -> str:
return self._htdocs_dir
@property
def example_domain(self) -> str:
return self._example_domain
@property
def examples_dir(self) -> str:
return self._examples_dir
@property
def examples_port(self) -> int:
return int(self.config['examples']['port'])
@property
def examples_pem(self) -> Dict[str, str]:
return self._examples_pem
@property
def crypto_libs(self):
return self._crypto_libs
@property
def clients(self):
return self._clients
@property
def servers(self):
return self._servers
def client_name(self, crypto_lib):
if crypto_lib in self.config['clients']:
return self.config['clients'][crypto_lib]
return None
def client_path(self, crypto_lib):
cname = self.client_name(crypto_lib)
if cname is not None:
return os.path.join(self.examples_dir, cname)
return None
def server_name(self, crypto_lib):
if crypto_lib in self.config['servers']:
return self.config['servers'][crypto_lib]
return None
def server_path(self, crypto_lib):
sname = self.server_name(crypto_lib)
if sname is not None:
return os.path.join(self.examples_dir, sname)
return None
|