summaryrefslogtreecommitdiffstats
path: root/examples/tests/ngtcp2test/env.py
blob: 9699d552cc5bab69dd4cef61f25428b9ee6a9c5f (plain)
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