xref: /unit/test/test_tls.py (revision 2144:b14caaedca5e)
11356St.nateldemoura@f5.comimport io
2781Szelenkov@nginx.comimport re
3781Szelenkov@nginx.comimport ssl
4781Szelenkov@nginx.comimport subprocess
51886Szelenkov@nginx.comimport time
61477Szelenkov@nginx.com
71635Szelenkov@nginx.comimport pytest
81019Szelenkov@nginx.comfrom unit.applications.tls import TestApplicationTLS
91863Szelenkov@nginx.comfrom unit.option import option
10781Szelenkov@nginx.com
111017Szelenkov@nginx.com
121019Szelenkov@nginx.comclass TestTLS(TestApplicationTLS):
131467Szelenkov@nginx.com    prerequisites = {'modules': {'python': 'any', 'openssl': 'any'}}
14781Szelenkov@nginx.com
15781Szelenkov@nginx.com    def openssl_date_to_sec_epoch(self, date):
16*2144Szelenkov@nginx.com        return self.date_to_sec_epoch(date, '%b %d %X %Y %Z')
17781Szelenkov@nginx.com
18781Szelenkov@nginx.com    def add_tls(self, application='empty', cert='default', port=7080):
191775Szelenkov@nginx.com        assert 'success' in self.conf(
201041Svbart@nginx.com            {
211041Svbart@nginx.com                "pass": "applications/" + application,
221848Szelenkov@nginx.com                "tls": {"certificate": cert},
231041Svbart@nginx.com            },
241017Szelenkov@nginx.com            'listeners/*:' + str(port),
251017Szelenkov@nginx.com        )
26781Szelenkov@nginx.com
27781Szelenkov@nginx.com    def remove_tls(self, application='empty', port=7080):
281775Szelenkov@nginx.com        assert 'success' in self.conf(
291041Svbart@nginx.com            {"pass": "applications/" + application}, 'listeners/*:' + str(port)
301041Svbart@nginx.com        )
31781Szelenkov@nginx.com
321863Szelenkov@nginx.com    def req(self, name='localhost', subject=None, x509=False):
331863Szelenkov@nginx.com        subj = subject if subject is not None else '/CN=' + name + '/'
341863Szelenkov@nginx.com
352004Szelenkov@nginx.com        subprocess.check_output(
361863Szelenkov@nginx.com            [
371863Szelenkov@nginx.com                'openssl',
381863Szelenkov@nginx.com                'req',
391863Szelenkov@nginx.com                '-new',
401863Szelenkov@nginx.com                '-subj',
411863Szelenkov@nginx.com                subj,
421863Szelenkov@nginx.com                '-config',
431863Szelenkov@nginx.com                option.temp_dir + '/openssl.conf',
441863Szelenkov@nginx.com                '-out',
451863Szelenkov@nginx.com                option.temp_dir + '/' + name + '.csr',
461863Szelenkov@nginx.com                '-keyout',
471863Szelenkov@nginx.com                option.temp_dir + '/' + name + '.key',
481863Szelenkov@nginx.com            ],
491863Szelenkov@nginx.com            stderr=subprocess.STDOUT,
501863Szelenkov@nginx.com        )
511863Szelenkov@nginx.com
521863Szelenkov@nginx.com    def generate_ca_conf(self):
531863Szelenkov@nginx.com        with open(option.temp_dir + '/ca.conf', 'w') as f:
541863Szelenkov@nginx.com            f.write(
551863Szelenkov@nginx.com                """[ ca ]
561863Szelenkov@nginx.comdefault_ca = myca
571863Szelenkov@nginx.com
581863Szelenkov@nginx.com[ myca ]
591863Szelenkov@nginx.comnew_certs_dir = %(dir)s
601863Szelenkov@nginx.comdatabase = %(database)s
611863Szelenkov@nginx.comdefault_md = sha256
621863Szelenkov@nginx.compolicy = myca_policy
631863Szelenkov@nginx.comserial = %(certserial)s
641863Szelenkov@nginx.comdefault_days = 1
651863Szelenkov@nginx.comx509_extensions = myca_extensions
661863Szelenkov@nginx.comcopy_extensions = copy
671863Szelenkov@nginx.com
681863Szelenkov@nginx.com[ myca_policy ]
691863Szelenkov@nginx.comcommonName = optional
701863Szelenkov@nginx.com
711863Szelenkov@nginx.com[ myca_extensions ]
721863Szelenkov@nginx.combasicConstraints = critical,CA:TRUE"""
731863Szelenkov@nginx.com                % {
741863Szelenkov@nginx.com                    'dir': option.temp_dir,
751863Szelenkov@nginx.com                    'database': option.temp_dir + '/certindex',
761863Szelenkov@nginx.com                    'certserial': option.temp_dir + '/certserial',
771863Szelenkov@nginx.com                }
781863Szelenkov@nginx.com            )
791863Szelenkov@nginx.com
801863Szelenkov@nginx.com        with open(option.temp_dir + '/certserial', 'w') as f:
811863Szelenkov@nginx.com            f.write('1000')
821863Szelenkov@nginx.com
831863Szelenkov@nginx.com        with open(option.temp_dir + '/certindex', 'w') as f:
841863Szelenkov@nginx.com            f.write('')
851863Szelenkov@nginx.com
861863Szelenkov@nginx.com        with open(option.temp_dir + '/certindex.attr', 'w') as f:
871863Szelenkov@nginx.com            f.write('')
881863Szelenkov@nginx.com
891863Szelenkov@nginx.com    def ca(self, cert='root', out='localhost'):
902004Szelenkov@nginx.com        subprocess.check_output(
911863Szelenkov@nginx.com            [
921863Szelenkov@nginx.com                'openssl',
931863Szelenkov@nginx.com                'ca',
941863Szelenkov@nginx.com                '-batch',
951863Szelenkov@nginx.com                '-config',
961863Szelenkov@nginx.com                option.temp_dir + '/ca.conf',
971863Szelenkov@nginx.com                '-keyfile',
981863Szelenkov@nginx.com                option.temp_dir + '/' + cert + '.key',
991863Szelenkov@nginx.com                '-cert',
1001863Szelenkov@nginx.com                option.temp_dir + '/' + cert + '.crt',
1011863Szelenkov@nginx.com                '-in',
1021863Szelenkov@nginx.com                option.temp_dir + '/' + out + '.csr',
1031863Szelenkov@nginx.com                '-out',
1041863Szelenkov@nginx.com                option.temp_dir + '/' + out + '.crt',
1051863Szelenkov@nginx.com            ],
1061863Szelenkov@nginx.com            stderr=subprocess.STDOUT,
1071863Szelenkov@nginx.com        )
1081863Szelenkov@nginx.com
1091863Szelenkov@nginx.com    def set_certificate_req_context(self, cert='root'):
1101863Szelenkov@nginx.com        self.context = ssl.create_default_context()
1111863Szelenkov@nginx.com        self.context.check_hostname = False
1121863Szelenkov@nginx.com        self.context.verify_mode = ssl.CERT_REQUIRED
1131863Szelenkov@nginx.com        self.context.load_verify_locations(
1141863Szelenkov@nginx.com            option.temp_dir + '/' + cert + '.crt'
1151863Szelenkov@nginx.com        )
1161863Szelenkov@nginx.com
117781Szelenkov@nginx.com    def test_tls_listener_option_add(self):
118781Szelenkov@nginx.com        self.load('empty')
119781Szelenkov@nginx.com
120781Szelenkov@nginx.com        self.certificate()
121781Szelenkov@nginx.com
122781Szelenkov@nginx.com        self.add_tls()
123781Szelenkov@nginx.com
1241596Szelenkov@nginx.com        assert self.get_ssl()['status'] == 200, 'add listener option'
125781Szelenkov@nginx.com
126781Szelenkov@nginx.com    def test_tls_listener_option_remove(self):
127781Szelenkov@nginx.com        self.load('empty')
128781Szelenkov@nginx.com
129781Szelenkov@nginx.com        self.certificate()
130781Szelenkov@nginx.com
131781Szelenkov@nginx.com        self.add_tls()
132781Szelenkov@nginx.com
133781Szelenkov@nginx.com        self.get_ssl()
134781Szelenkov@nginx.com
135781Szelenkov@nginx.com        self.remove_tls()
136781Szelenkov@nginx.com
1371596Szelenkov@nginx.com        assert self.get()['status'] == 200, 'remove listener option'
138781Szelenkov@nginx.com
139781Szelenkov@nginx.com    def test_tls_certificate_remove(self):
140781Szelenkov@nginx.com        self.load('empty')
141781Szelenkov@nginx.com
142781Szelenkov@nginx.com        self.certificate()
143781Szelenkov@nginx.com
1441596Szelenkov@nginx.com        assert 'success' in self.conf_delete(
1451596Szelenkov@nginx.com            '/certificates/default'
1461596Szelenkov@nginx.com        ), 'remove certificate'
147781Szelenkov@nginx.com
148781Szelenkov@nginx.com    def test_tls_certificate_remove_used(self):
149781Szelenkov@nginx.com        self.load('empty')
150781Szelenkov@nginx.com
151781Szelenkov@nginx.com        self.certificate()
152781Szelenkov@nginx.com
153781Szelenkov@nginx.com        self.add_tls()
154781Szelenkov@nginx.com
1551596Szelenkov@nginx.com        assert 'error' in self.conf_delete(
1561596Szelenkov@nginx.com            '/certificates/default'
1571596Szelenkov@nginx.com        ), 'remove certificate'
158781Szelenkov@nginx.com
159781Szelenkov@nginx.com    def test_tls_certificate_remove_nonexisting(self):
160781Szelenkov@nginx.com        self.load('empty')
161781Szelenkov@nginx.com
162781Szelenkov@nginx.com        self.certificate()
163781Szelenkov@nginx.com
164781Szelenkov@nginx.com        self.add_tls()
165781Szelenkov@nginx.com
1661596Szelenkov@nginx.com        assert 'error' in self.conf_delete(
1671596Szelenkov@nginx.com            '/certificates/blah'
1681596Szelenkov@nginx.com        ), 'remove nonexistings certificate'
169781Szelenkov@nginx.com
1701596Szelenkov@nginx.com    @pytest.mark.skip('not yet')
171781Szelenkov@nginx.com    def test_tls_certificate_update(self):
172781Szelenkov@nginx.com        self.load('empty')
173781Szelenkov@nginx.com
174781Szelenkov@nginx.com        self.certificate()
175781Szelenkov@nginx.com
176781Szelenkov@nginx.com        self.add_tls()
177781Szelenkov@nginx.com
1782066Szelenkov@nginx.com        cert_old = ssl.get_server_certificate(('127.0.0.1', 7080))
179781Szelenkov@nginx.com
180781Szelenkov@nginx.com        self.certificate()
181781Szelenkov@nginx.com
1822066Szelenkov@nginx.com        assert cert_old != ssl.get_server_certificate(
1832066Szelenkov@nginx.com            ('127.0.0.1', 7080)
1842066Szelenkov@nginx.com        ), 'update certificate'
185781Szelenkov@nginx.com
1861596Szelenkov@nginx.com    @pytest.mark.skip('not yet')
187781Szelenkov@nginx.com    def test_tls_certificate_key_incorrect(self):
188781Szelenkov@nginx.com        self.load('empty')
189781Szelenkov@nginx.com
190781Szelenkov@nginx.com        self.certificate('first', False)
191781Szelenkov@nginx.com        self.certificate('second', False)
192781Szelenkov@nginx.com
1931596Szelenkov@nginx.com        assert 'error' in self.certificate_load(
1941596Szelenkov@nginx.com            'first', 'second'
1951596Szelenkov@nginx.com        ), 'key incorrect'
196781Szelenkov@nginx.com
197781Szelenkov@nginx.com    def test_tls_certificate_change(self):
198781Szelenkov@nginx.com        self.load('empty')
199781Szelenkov@nginx.com
200781Szelenkov@nginx.com        self.certificate()
201781Szelenkov@nginx.com        self.certificate('new')
202781Szelenkov@nginx.com
203781Szelenkov@nginx.com        self.add_tls()
204781Szelenkov@nginx.com
2052066Szelenkov@nginx.com        cert_old = ssl.get_server_certificate(('127.0.0.1', 7080))
206781Szelenkov@nginx.com
207781Szelenkov@nginx.com        self.add_tls(cert='new')
208781Szelenkov@nginx.com
2092066Szelenkov@nginx.com        assert cert_old != ssl.get_server_certificate(
2102066Szelenkov@nginx.com            ('127.0.0.1', 7080)
2112066Szelenkov@nginx.com        ), 'change certificate'
212781Szelenkov@nginx.com
213781Szelenkov@nginx.com    def test_tls_certificate_key_rsa(self):
214781Szelenkov@nginx.com        self.load('empty')
215781Szelenkov@nginx.com
216781Szelenkov@nginx.com        self.certificate()
217781Szelenkov@nginx.com
2181596Szelenkov@nginx.com        assert (
2191596Szelenkov@nginx.com            self.conf_get('/certificates/default/key') == 'RSA (2048 bits)'
2201596Szelenkov@nginx.com        ), 'certificate key rsa'
221781Szelenkov@nginx.com
2221654Szelenkov@nginx.com    def test_tls_certificate_key_ec(self, temp_dir):
223807Spluknet@nginx.com        self.load('empty')
224807Spluknet@nginx.com
2251100Szelenkov@nginx.com        self.openssl_conf()
2261100Szelenkov@nginx.com
2272004Szelenkov@nginx.com        subprocess.check_output(
2281017Szelenkov@nginx.com            [
2291017Szelenkov@nginx.com                'openssl',
2301017Szelenkov@nginx.com                'ecparam',
2311017Szelenkov@nginx.com                '-noout',
2321017Szelenkov@nginx.com                '-genkey',
2331596Szelenkov@nginx.com                '-out',
2341654Szelenkov@nginx.com                temp_dir + '/ec.key',
2351596Szelenkov@nginx.com                '-name',
2361596Szelenkov@nginx.com                'prime256v1',
2371388Szelenkov@nginx.com            ],
2381388Szelenkov@nginx.com            stderr=subprocess.STDOUT,
2391017Szelenkov@nginx.com        )
240781Szelenkov@nginx.com
2412004Szelenkov@nginx.com        subprocess.check_output(
2421017Szelenkov@nginx.com            [
2431017Szelenkov@nginx.com                'openssl',
2441017Szelenkov@nginx.com                'req',
2451017Szelenkov@nginx.com                '-x509',
2461017Szelenkov@nginx.com                '-new',
2471596Szelenkov@nginx.com                '-subj',
2481596Szelenkov@nginx.com                '/CN=ec/',
2491596Szelenkov@nginx.com                '-config',
2501654Szelenkov@nginx.com                temp_dir + '/openssl.conf',
2511596Szelenkov@nginx.com                '-key',
2521654Szelenkov@nginx.com                temp_dir + '/ec.key',
2531596Szelenkov@nginx.com                '-out',
2541654Szelenkov@nginx.com                temp_dir + '/ec.crt',
2551388Szelenkov@nginx.com            ],
2561388Szelenkov@nginx.com            stderr=subprocess.STDOUT,
2571017Szelenkov@nginx.com        )
258781Szelenkov@nginx.com
259781Szelenkov@nginx.com        self.certificate_load('ec')
260781Szelenkov@nginx.com
2611596Szelenkov@nginx.com        assert (
2621596Szelenkov@nginx.com            self.conf_get('/certificates/ec/key') == 'ECDH'
2631596Szelenkov@nginx.com        ), 'certificate key ec'
264781Szelenkov@nginx.com
265781Szelenkov@nginx.com    def test_tls_certificate_chain_options(self):
266781Szelenkov@nginx.com        self.load('empty')
267781Szelenkov@nginx.com
268781Szelenkov@nginx.com        self.certificate()
269781Szelenkov@nginx.com
270781Szelenkov@nginx.com        chain = self.conf_get('/certificates/default/chain')
271781Szelenkov@nginx.com
2721596Szelenkov@nginx.com        assert len(chain) == 1, 'certificate chain length'
273781Szelenkov@nginx.com
274781Szelenkov@nginx.com        cert = chain[0]
275781Szelenkov@nginx.com
2761596Szelenkov@nginx.com        assert (
2771596Szelenkov@nginx.com            cert['subject']['common_name'] == 'default'
2781596Szelenkov@nginx.com        ), 'certificate subject common name'
2791596Szelenkov@nginx.com        assert (
2801596Szelenkov@nginx.com            cert['issuer']['common_name'] == 'default'
2811596Szelenkov@nginx.com        ), 'certificate issuer common name'
282781Szelenkov@nginx.com
2831596Szelenkov@nginx.com        assert (
2841017Szelenkov@nginx.com            abs(
2851017Szelenkov@nginx.com                self.sec_epoch()
2861017Szelenkov@nginx.com                - self.openssl_date_to_sec_epoch(cert['validity']['since'])
2871596Szelenkov@nginx.com            )
2881803Szelenkov@nginx.com            < 60
2891596Szelenkov@nginx.com        ), 'certificate validity since'
2901596Szelenkov@nginx.com        assert (
2911017Szelenkov@nginx.com            self.openssl_date_to_sec_epoch(cert['validity']['until'])
2921596Szelenkov@nginx.com            - self.openssl_date_to_sec_epoch(cert['validity']['since'])
2931596Szelenkov@nginx.com            == 2592000
2941596Szelenkov@nginx.com        ), 'certificate validity until'
295781Szelenkov@nginx.com
2961654Szelenkov@nginx.com    def test_tls_certificate_chain(self, temp_dir):
297781Szelenkov@nginx.com        self.load('empty')
298781Szelenkov@nginx.com
299781Szelenkov@nginx.com        self.certificate('root', False)
300781Szelenkov@nginx.com
3011863Szelenkov@nginx.com        self.req('int')
3021863Szelenkov@nginx.com        self.req('end')
303781Szelenkov@nginx.com
3041863Szelenkov@nginx.com        self.generate_ca_conf()
305781Szelenkov@nginx.com
3061863Szelenkov@nginx.com        self.ca(cert='root', out='int')
3071863Szelenkov@nginx.com        self.ca(cert='int', out='end')
308781Szelenkov@nginx.com
3091654Szelenkov@nginx.com        crt_path = temp_dir + '/end-int.crt'
3101654Szelenkov@nginx.com        end_path = temp_dir + '/end.crt'
3111654Szelenkov@nginx.com        int_path = temp_dir + '/int.crt'
3121017Szelenkov@nginx.com
3131596Szelenkov@nginx.com        with open(crt_path, 'wb') as crt, open(end_path, 'rb') as end, open(
3141596Szelenkov@nginx.com            int_path, 'rb'
3151596Szelenkov@nginx.com        ) as int:
3161017Szelenkov@nginx.com            crt.write(end.read() + int.read())
317781Szelenkov@nginx.com
3181863Szelenkov@nginx.com        self.set_certificate_req_context()
319781Szelenkov@nginx.com
320781Szelenkov@nginx.com        # incomplete chain
321781Szelenkov@nginx.com
3221596Szelenkov@nginx.com        assert 'success' in self.certificate_load(
3231596Szelenkov@nginx.com            'end', 'end'
3241596Szelenkov@nginx.com        ), 'certificate chain end upload'
325781Szelenkov@nginx.com
326781Szelenkov@nginx.com        chain = self.conf_get('/certificates/end/chain')
3271596Szelenkov@nginx.com        assert len(chain) == 1, 'certificate chain end length'
3281596Szelenkov@nginx.com        assert (
3291596Szelenkov@nginx.com            chain[0]['subject']['common_name'] == 'end'
3301596Szelenkov@nginx.com        ), 'certificate chain end subject common name'
3311596Szelenkov@nginx.com        assert (
3321596Szelenkov@nginx.com            chain[0]['issuer']['common_name'] == 'int'
3331596Szelenkov@nginx.com        ), 'certificate chain end issuer common name'
334781Szelenkov@nginx.com
335781Szelenkov@nginx.com        self.add_tls(cert='end')
336781Szelenkov@nginx.com
337781Szelenkov@nginx.com        try:
338781Szelenkov@nginx.com            resp = self.get_ssl()
339781Szelenkov@nginx.com        except ssl.SSLError:
340781Szelenkov@nginx.com            resp = None
341781Szelenkov@nginx.com
3421596Szelenkov@nginx.com        assert resp == None, 'certificate chain incomplete chain'
343781Szelenkov@nginx.com
344781Szelenkov@nginx.com        # intermediate
345781Szelenkov@nginx.com
3461596Szelenkov@nginx.com        assert 'success' in self.certificate_load(
3471596Szelenkov@nginx.com            'int', 'int'
3481596Szelenkov@nginx.com        ), 'certificate chain int upload'
349781Szelenkov@nginx.com
350781Szelenkov@nginx.com        chain = self.conf_get('/certificates/int/chain')
3511596Szelenkov@nginx.com        assert len(chain) == 1, 'certificate chain int length'
3521596Szelenkov@nginx.com        assert (
3531596Szelenkov@nginx.com            chain[0]['subject']['common_name'] == 'int'
3541596Szelenkov@nginx.com        ), 'certificate chain int subject common name'
3551596Szelenkov@nginx.com        assert (
3561596Szelenkov@nginx.com            chain[0]['issuer']['common_name'] == 'root'
3571596Szelenkov@nginx.com        ), 'certificate chain int issuer common name'
358781Szelenkov@nginx.com
359781Szelenkov@nginx.com        self.add_tls(cert='int')
360781Szelenkov@nginx.com
3612073Szelenkov@nginx.com        assert self.get_ssl()['status'] == 200, 'certificate chain intermediate'
362781Szelenkov@nginx.com
363781Szelenkov@nginx.com        # intermediate server
364781Szelenkov@nginx.com
3651596Szelenkov@nginx.com        assert 'success' in self.certificate_load(
3661596Szelenkov@nginx.com            'end-int', 'end'
3671596Szelenkov@nginx.com        ), 'certificate chain end-int upload'
368781Szelenkov@nginx.com
369781Szelenkov@nginx.com        chain = self.conf_get('/certificates/end-int/chain')
3701596Szelenkov@nginx.com        assert len(chain) == 2, 'certificate chain end-int length'
3711596Szelenkov@nginx.com        assert (
3721596Szelenkov@nginx.com            chain[0]['subject']['common_name'] == 'end'
3731596Szelenkov@nginx.com        ), 'certificate chain end-int int subject common name'
3741596Szelenkov@nginx.com        assert (
3751596Szelenkov@nginx.com            chain[0]['issuer']['common_name'] == 'int'
3761596Szelenkov@nginx.com        ), 'certificate chain end-int int issuer common name'
3771596Szelenkov@nginx.com        assert (
3781596Szelenkov@nginx.com            chain[1]['subject']['common_name'] == 'int'
3791596Szelenkov@nginx.com        ), 'certificate chain end-int end subject common name'
3801596Szelenkov@nginx.com        assert (
3811596Szelenkov@nginx.com            chain[1]['issuer']['common_name'] == 'root'
3821596Szelenkov@nginx.com        ), 'certificate chain end-int end issuer common name'
383781Szelenkov@nginx.com
384781Szelenkov@nginx.com        self.add_tls(cert='end-int')
385781Szelenkov@nginx.com
3861596Szelenkov@nginx.com        assert (
3871596Szelenkov@nginx.com            self.get_ssl()['status'] == 200
3881596Szelenkov@nginx.com        ), 'certificate chain intermediate server'
389781Szelenkov@nginx.com
3902071Szelenkov@nginx.com    def test_tls_certificate_chain_long(self, temp_dir):
3912071Szelenkov@nginx.com        self.load('empty')
3922071Szelenkov@nginx.com
3932071Szelenkov@nginx.com        self.generate_ca_conf()
3942071Szelenkov@nginx.com
3952071Szelenkov@nginx.com        # Minimum chain length is 3.
3962071Szelenkov@nginx.com        chain_length = 10
3972071Szelenkov@nginx.com
3982071Szelenkov@nginx.com        for i in range(chain_length):
3992071Szelenkov@nginx.com            if i == 0:
4002071Szelenkov@nginx.com                self.certificate('root', False)
4012071Szelenkov@nginx.com            elif i == chain_length - 1:
4022071Szelenkov@nginx.com                self.req('end')
4032071Szelenkov@nginx.com            else:
4042071Szelenkov@nginx.com                self.req('int{}'.format(i))
4052071Szelenkov@nginx.com
4062071Szelenkov@nginx.com        for i in range(chain_length - 1):
4072071Szelenkov@nginx.com            if i == 0:
4082071Szelenkov@nginx.com                self.ca(cert='root', out='int1')
4092071Szelenkov@nginx.com            elif i == chain_length - 2:
4102071Szelenkov@nginx.com                self.ca(cert='int{}'.format(chain_length - 2), out='end')
4112071Szelenkov@nginx.com            else:
4122071Szelenkov@nginx.com                self.ca(cert='int{}'.format(i), out='int{}'.format(i + 1))
4132071Szelenkov@nginx.com
4142071Szelenkov@nginx.com        for i in range(chain_length - 1, 0, -1):
4152071Szelenkov@nginx.com            path = temp_dir + (
4162071Szelenkov@nginx.com                '/end.crt' if i == chain_length - 1 else '/int{}.crt'.format(i)
4172071Szelenkov@nginx.com            )
4182071Szelenkov@nginx.com
4192071Szelenkov@nginx.com            with open(temp_dir + '/all.crt', 'a') as chain, open(path) as cert:
4202071Szelenkov@nginx.com                chain.write(cert.read())
4212071Szelenkov@nginx.com
4222071Szelenkov@nginx.com        self.set_certificate_req_context()
4232071Szelenkov@nginx.com
4242071Szelenkov@nginx.com        assert 'success' in self.certificate_load(
4252071Szelenkov@nginx.com            'all', 'end'
4262071Szelenkov@nginx.com        ), 'certificate chain upload'
4272071Szelenkov@nginx.com
4282071Szelenkov@nginx.com        chain = self.conf_get('/certificates/all/chain')
4292071Szelenkov@nginx.com        assert len(chain) == chain_length - 1, 'certificate chain length'
4302071Szelenkov@nginx.com
4312071Szelenkov@nginx.com        self.add_tls(cert='all')
4322071Szelenkov@nginx.com
4332071Szelenkov@nginx.com        assert self.get_ssl()['status'] == 200, 'certificate chain long'
4342071Szelenkov@nginx.com
4351863Szelenkov@nginx.com    def test_tls_certificate_empty_cn(self, temp_dir):
4361863Szelenkov@nginx.com        self.certificate('root', False)
4371863Szelenkov@nginx.com
4381863Szelenkov@nginx.com        self.req(subject='/')
4391863Szelenkov@nginx.com
4401863Szelenkov@nginx.com        self.generate_ca_conf()
4411863Szelenkov@nginx.com        self.ca()
4421863Szelenkov@nginx.com
4431863Szelenkov@nginx.com        self.set_certificate_req_context()
4441863Szelenkov@nginx.com
4451863Szelenkov@nginx.com        assert 'success' in self.certificate_load('localhost', 'localhost')
4461863Szelenkov@nginx.com
4471863Szelenkov@nginx.com        cert = self.conf_get('/certificates/localhost')
4481863Szelenkov@nginx.com        assert cert['chain'][0]['subject'] == {}, 'empty subject'
4491863Szelenkov@nginx.com        assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer'
4501863Szelenkov@nginx.com
4511863Szelenkov@nginx.com    def test_tls_certificate_empty_cn_san(self, temp_dir):
4521863Szelenkov@nginx.com        self.certificate('root', False)
4531863Szelenkov@nginx.com
4541863Szelenkov@nginx.com        self.openssl_conf(
4551863Szelenkov@nginx.com            rewrite=True, alt_names=["example.com", "www.example.net"]
4561863Szelenkov@nginx.com        )
4571863Szelenkov@nginx.com
4581863Szelenkov@nginx.com        self.req(subject='/')
4591863Szelenkov@nginx.com
4601863Szelenkov@nginx.com        self.generate_ca_conf()
4611863Szelenkov@nginx.com        self.ca()
4621863Szelenkov@nginx.com
4631863Szelenkov@nginx.com        self.set_certificate_req_context()
4641863Szelenkov@nginx.com
4651863Szelenkov@nginx.com        assert 'success' in self.certificate_load('localhost', 'localhost')
4661863Szelenkov@nginx.com
4671863Szelenkov@nginx.com        cert = self.conf_get('/certificates/localhost')
4681863Szelenkov@nginx.com        assert cert['chain'][0]['subject'] == {
4691863Szelenkov@nginx.com            'alt_names': ['example.com', 'www.example.net']
4701863Szelenkov@nginx.com        }, 'subject alt_names'
4711863Szelenkov@nginx.com        assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer'
4721863Szelenkov@nginx.com
4731866Szelenkov@nginx.com    def test_tls_certificate_empty_cn_san_ip(self):
4741866Szelenkov@nginx.com        self.certificate('root', False)
4751866Szelenkov@nginx.com
4761866Szelenkov@nginx.com        self.openssl_conf(
4771866Szelenkov@nginx.com            rewrite=True,
4781866Szelenkov@nginx.com            alt_names=['example.com', 'www.example.net', 'IP|10.0.0.1'],
4791866Szelenkov@nginx.com        )
4801866Szelenkov@nginx.com
4811866Szelenkov@nginx.com        self.req(subject='/')
4821866Szelenkov@nginx.com
4831866Szelenkov@nginx.com        self.generate_ca_conf()
4841866Szelenkov@nginx.com        self.ca()
4851866Szelenkov@nginx.com
4861866Szelenkov@nginx.com        self.set_certificate_req_context()
4871866Szelenkov@nginx.com
4881866Szelenkov@nginx.com        assert 'success' in self.certificate_load('localhost', 'localhost')
4891866Szelenkov@nginx.com
4901866Szelenkov@nginx.com        cert = self.conf_get('/certificates/localhost')
4911866Szelenkov@nginx.com        assert cert['chain'][0]['subject'] == {
4921866Szelenkov@nginx.com            'alt_names': ['example.com', 'www.example.net']
4931866Szelenkov@nginx.com        }, 'subject alt_names'
4941866Szelenkov@nginx.com        assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer'
4951866Szelenkov@nginx.com
496781Szelenkov@nginx.com    def test_tls_keepalive(self):
497781Szelenkov@nginx.com        self.load('mirror')
498781Szelenkov@nginx.com
4991596Szelenkov@nginx.com        assert self.get()['status'] == 200, 'init'
5001029Szelenkov@nginx.com
501781Szelenkov@nginx.com        self.certificate()
502781Szelenkov@nginx.com
503781Szelenkov@nginx.com        self.add_tls(application='mirror')
504781Szelenkov@nginx.com
5051017Szelenkov@nginx.com        (resp, sock) = self.post_ssl(
5061017Szelenkov@nginx.com            headers={
5071017Szelenkov@nginx.com                'Host': 'localhost',
5081017Szelenkov@nginx.com                'Connection': 'keep-alive',
5091017Szelenkov@nginx.com                'Content-Type': 'text/html',
5101017Szelenkov@nginx.com            },
5111017Szelenkov@nginx.com            start=True,
5121017Szelenkov@nginx.com            body='0123456789',
5131029Szelenkov@nginx.com            read_timeout=1,
5141017Szelenkov@nginx.com        )
515781Szelenkov@nginx.com
5161596Szelenkov@nginx.com        assert resp['body'] == '0123456789', 'keepalive 1'
517781Szelenkov@nginx.com
5181017Szelenkov@nginx.com        resp = self.post_ssl(
5191017Szelenkov@nginx.com            headers={
5201017Szelenkov@nginx.com                'Host': 'localhost',
5211017Szelenkov@nginx.com                'Connection': 'close',
5221017Szelenkov@nginx.com                'Content-Type': 'text/html',
5231017Szelenkov@nginx.com            },
5241017Szelenkov@nginx.com            sock=sock,
5251017Szelenkov@nginx.com            body='0123456789',
5261017Szelenkov@nginx.com        )
527781Szelenkov@nginx.com
5281596Szelenkov@nginx.com        assert resp['body'] == '0123456789', 'keepalive 2'
529781Szelenkov@nginx.com
5301886Szelenkov@nginx.com    def test_tls_no_close_notify(self):
5311886Szelenkov@nginx.com        self.certificate()
5321886Szelenkov@nginx.com
5331886Szelenkov@nginx.com        assert 'success' in self.conf(
5341886Szelenkov@nginx.com            {
5351886Szelenkov@nginx.com                "listeners": {
5361886Szelenkov@nginx.com                    "*:7080": {
5371886Szelenkov@nginx.com                        "pass": "routes",
5381886Szelenkov@nginx.com                        "tls": {"certificate": "default"},
5391886Szelenkov@nginx.com                    }
5401886Szelenkov@nginx.com                },
5411886Szelenkov@nginx.com                "routes": [{"action": {"return": 200}}],
5421886Szelenkov@nginx.com                "applications": {},
5431886Szelenkov@nginx.com            }
5441886Szelenkov@nginx.com        ), 'load application configuration'
5451886Szelenkov@nginx.com
5461886Szelenkov@nginx.com        (resp, sock) = self.get_ssl(start=True)
5471886Szelenkov@nginx.com
5481886Szelenkov@nginx.com        time.sleep(5)
5491886Szelenkov@nginx.com
5501886Szelenkov@nginx.com        sock.close()
5511886Szelenkov@nginx.com
5521596Szelenkov@nginx.com    @pytest.mark.skip('not yet')
553781Szelenkov@nginx.com    def test_tls_keepalive_certificate_remove(self):
554781Szelenkov@nginx.com        self.load('empty')
555781Szelenkov@nginx.com
5561596Szelenkov@nginx.com        assert self.get()['status'] == 200, 'init'
5571029Szelenkov@nginx.com
558781Szelenkov@nginx.com        self.certificate()
559781Szelenkov@nginx.com
560781Szelenkov@nginx.com        self.add_tls()
561781Szelenkov@nginx.com
5621017Szelenkov@nginx.com        (resp, sock) = self.get_ssl(
5631017Szelenkov@nginx.com            headers={'Host': 'localhost', 'Connection': 'keep-alive'},
5641017Szelenkov@nginx.com            start=True,
5651029Szelenkov@nginx.com            read_timeout=1,
5661017Szelenkov@nginx.com        )
567781Szelenkov@nginx.com
5681775Szelenkov@nginx.com        assert 'success' in self.conf(
5691775Szelenkov@nginx.com            {"pass": "applications/empty"}, 'listeners/*:7080'
5701775Szelenkov@nginx.com        )
5711775Szelenkov@nginx.com        assert 'success' in self.conf_delete('/certificates/default')
572781Szelenkov@nginx.com
573781Szelenkov@nginx.com        try:
5741017Szelenkov@nginx.com            resp = self.get_ssl(
5751017Szelenkov@nginx.com                headers={'Host': 'localhost', 'Connection': 'close'}, sock=sock
5761017Szelenkov@nginx.com            )
5771706Smax.romanov@nginx.com
5781706Smax.romanov@nginx.com        except KeyboardInterrupt:
5791706Smax.romanov@nginx.com            raise
5801706Smax.romanov@nginx.com
581781Szelenkov@nginx.com        except:
582781Szelenkov@nginx.com            resp = None
583781Szelenkov@nginx.com
5841596Szelenkov@nginx.com        assert resp == None, 'keepalive remove certificate'
585781Szelenkov@nginx.com
5861596Szelenkov@nginx.com    @pytest.mark.skip('not yet')
587781Szelenkov@nginx.com    def test_tls_certificates_remove_all(self):
588781Szelenkov@nginx.com        self.load('empty')
589781Szelenkov@nginx.com
590781Szelenkov@nginx.com        self.certificate()
591781Szelenkov@nginx.com
5921596Szelenkov@nginx.com        assert 'success' in self.conf_delete(
5931596Szelenkov@nginx.com            '/certificates'
5941596Szelenkov@nginx.com        ), 'remove all certificates'
595781Szelenkov@nginx.com
5961736Szelenkov@nginx.com    def test_tls_application_respawn(self, skip_alert):
597781Szelenkov@nginx.com        self.load('mirror')
598781Szelenkov@nginx.com
599781Szelenkov@nginx.com        self.certificate()
600781Szelenkov@nginx.com
6011775Szelenkov@nginx.com        assert 'success' in self.conf('1', 'applications/mirror/processes')
602781Szelenkov@nginx.com
603781Szelenkov@nginx.com        self.add_tls(application='mirror')
604781Szelenkov@nginx.com
6051453Szelenkov@nginx.com        (_, sock) = self.post_ssl(
6061017Szelenkov@nginx.com            headers={
6071017Szelenkov@nginx.com                'Host': 'localhost',
6081017Szelenkov@nginx.com                'Connection': 'keep-alive',
6091017Szelenkov@nginx.com                'Content-Type': 'text/html',
6101017Szelenkov@nginx.com            },
6111017Szelenkov@nginx.com            start=True,
6121017Szelenkov@nginx.com            body='0123456789',
6131029Szelenkov@nginx.com            read_timeout=1,
6141017Szelenkov@nginx.com        )
615781Szelenkov@nginx.com
616781Szelenkov@nginx.com        app_id = self.findall(r'(\d+)#\d+ "mirror" application started')[0]
617781Szelenkov@nginx.com
6182004Szelenkov@nginx.com        subprocess.check_output(['kill', '-9', app_id])
619781Szelenkov@nginx.com
6201999Smax.romanov@nginx.com        skip_alert(r'process .* %s.* exited on signal 9' % app_id)
6211453Szelenkov@nginx.com
6221017Szelenkov@nginx.com        self.wait_for_record(
6231017Szelenkov@nginx.com            re.compile(
6241635Szelenkov@nginx.com                r' (?!' + app_id + r'#)(\d+)#\d+ "mirror" application started'
6251017Szelenkov@nginx.com            )
6261017Szelenkov@nginx.com        )
627781Szelenkov@nginx.com
6281017Szelenkov@nginx.com        resp = self.post_ssl(
6291017Szelenkov@nginx.com            headers={
6301017Szelenkov@nginx.com                'Host': 'localhost',
6311017Szelenkov@nginx.com                'Connection': 'close',
6321017Szelenkov@nginx.com                'Content-Type': 'text/html',
6331017Szelenkov@nginx.com            },
6341017Szelenkov@nginx.com            sock=sock,
6351017Szelenkov@nginx.com            body='0123456789',
6361017Szelenkov@nginx.com        )
637781Szelenkov@nginx.com
6381596Szelenkov@nginx.com        assert resp['status'] == 200, 'application respawn status'
6391596Szelenkov@nginx.com        assert resp['body'] == '0123456789', 'application respawn body'
640781Szelenkov@nginx.com
6411011Smax.romanov@nginx.com    def test_tls_url_scheme(self):
6421011Smax.romanov@nginx.com        self.load('variables')
6431011Smax.romanov@nginx.com
6441596Szelenkov@nginx.com        assert (
6451017Szelenkov@nginx.com            self.post(
6461017Szelenkov@nginx.com                headers={
6471017Szelenkov@nginx.com                    'Host': 'localhost',
6481017Szelenkov@nginx.com                    'Content-Type': 'text/html',
6491017Szelenkov@nginx.com                    'Custom-Header': '',
6501017Szelenkov@nginx.com                    'Connection': 'close',
6511017Szelenkov@nginx.com                }
6521596Szelenkov@nginx.com            )['headers']['Wsgi-Url-Scheme']
6531596Szelenkov@nginx.com            == 'http'
6541596Szelenkov@nginx.com        ), 'url scheme http'
6551011Smax.romanov@nginx.com
6561011Smax.romanov@nginx.com        self.certificate()
6571011Smax.romanov@nginx.com
6581011Smax.romanov@nginx.com        self.add_tls(application='variables')
6591011Smax.romanov@nginx.com
6601596Szelenkov@nginx.com        assert (
6611017Szelenkov@nginx.com            self.post_ssl(
6621017Szelenkov@nginx.com                headers={
6631017Szelenkov@nginx.com                    'Host': 'localhost',
6641017Szelenkov@nginx.com                    'Content-Type': 'text/html',
6651017Szelenkov@nginx.com                    'Custom-Header': '',
6661017Szelenkov@nginx.com                    'Connection': 'close',
6671017Szelenkov@nginx.com                }
6681596Szelenkov@nginx.com            )['headers']['Wsgi-Url-Scheme']
6691596Szelenkov@nginx.com            == 'https'
6701596Szelenkov@nginx.com        ), 'url scheme https'
6711011Smax.romanov@nginx.com
6721356St.nateldemoura@f5.com    def test_tls_big_upload(self):
6731356St.nateldemoura@f5.com        self.load('upload')
6741356St.nateldemoura@f5.com
6751356St.nateldemoura@f5.com        self.certificate()
6761356St.nateldemoura@f5.com
6771356St.nateldemoura@f5.com        self.add_tls(application='upload')
6781356St.nateldemoura@f5.com
6791356St.nateldemoura@f5.com        filename = 'test.txt'
6801356St.nateldemoura@f5.com        data = '0123456789' * 9000
6811356St.nateldemoura@f5.com
6821596Szelenkov@nginx.com        res = self.post_ssl(
6831596Szelenkov@nginx.com            body={
6841596Szelenkov@nginx.com                'file': {
6851596Szelenkov@nginx.com                    'filename': filename,
6861596Szelenkov@nginx.com                    'type': 'text/plain',
6871596Szelenkov@nginx.com                    'data': io.StringIO(data),
6881596Szelenkov@nginx.com                }
6891356St.nateldemoura@f5.com            }
6901596Szelenkov@nginx.com        )
6911596Szelenkov@nginx.com        assert res['status'] == 200, 'status ok'
6921596Szelenkov@nginx.com        assert res['body'] == filename + data
6931904Smax.romanov@nginx.com
6941904Smax.romanov@nginx.com    def test_tls_multi_listener(self):
6951904Smax.romanov@nginx.com        self.load('empty')
6961904Smax.romanov@nginx.com
6971904Smax.romanov@nginx.com        self.certificate()
6981904Smax.romanov@nginx.com
6991904Smax.romanov@nginx.com        self.add_tls()
7001904Smax.romanov@nginx.com        self.add_tls(port=7081)
7011904Smax.romanov@nginx.com
7021904Smax.romanov@nginx.com        assert self.get_ssl()['status'] == 200, 'listener #1'
7031904Smax.romanov@nginx.com
7041904Smax.romanov@nginx.com        assert self.get_ssl(port=7081)['status'] == 200, 'listener #2'
705