1'''
2Test requiring certificate from user agent
3'''
4#  Licensed to the Apache Software Foundation (ASF) under one
5#  or more contributor license agreements.  See the NOTICE file
6#  distributed with this work for additional information
7#  regarding copyright ownership.  The ASF licenses this file
8#  to you under the Apache License, Version 2.0 (the
9#  "License"); you may not use this file except in compliance
10#  with the License.  You may obtain a copy of the License at
11#
12#      http://www.apache.org/licenses/LICENSE-2.0
13#
14#  Unless required by applicable law or agreed to in writing, software
15#  distributed under the License is distributed on an "AS IS" BASIS,
16#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17#  See the License for the specific language governing permissions and
18#  limitations under the License.
19
20
21Test.Summary = '''
22Test various options for requiring certificate from client for mutual authentication TLS
23'''
24
25ts = Test.MakeATSProcess("ts", command="traffic_manager", select_ports=True, enable_tls=True)
26cafile = "{0}/signer.pem".format(Test.RunDirectory)
27cafile2 = "{0}/signer2.pem".format(Test.RunDirectory)
28server = Test.MakeOriginServer("server")
29server2 = Test.MakeOriginServer("server2")
30
31request_header = {"headers": "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
32response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
33server.addResponse("sessionlog.json", request_header, response_header)
34request_header = {"headers": "GET / HTTP/1.1\r\nHost: bar.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
35response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
36server.addResponse("sessionlog.json", request_header, response_header)
37
38ts.addSSLfile("ssl/server.pem")
39ts.addSSLfile("ssl/server.key")
40ts.addSSLfile("ssl/signer.pem")
41
42ts.Disk.records_config.update({
43    'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
44    'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
45    'proxy.config.ssl.server.cipher_suite': 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:RC4-MD5:AES128-SHA:AES256-SHA:DES-CBC3-SHA!SRP:!DSS:!PSK:!aNULL:!eNULL:!SSLv2',
46    'proxy.config.url_remap.pristine_host_hdr': 1,
47    'proxy.config.ssl.client.certification_level': 2,
48    'proxy.config.ssl.CA.cert.filename': '{0}/signer.pem'.format(ts.Variables.SSLDir),
49    'proxy.config.exec_thread.autoconfig.scale': 1.0,
50    'proxy.config.ssl.TLSv1_3': 0
51})
52
53ts.Disk.ssl_multicert_config.AddLine(
54    'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key'
55)
56
57# Just map everything through to origin.  This test is concentratign on the user-agent side
58ts.Disk.remap_config.AddLine(
59    'map / http://127.0.0.1:{0}/'.format(server.Variables.Port)
60)
61
62# Scenario 1:  Default no client cert required.  cert required for bar.com
63ts.Disk.sni_yaml.AddLines([
64    'sni:',
65    '- fqdn: bob.bar.com',
66    '  verify_client: NONE',
67    '- fqdn: "bob.com"',
68    '  verify_client: STRICT',
69    '- fqdn: bob.*.com',
70    '  verify_client: NONE',
71    '- fqdn: "*bar.com"',
72    '  verify_client: STRICT',
73])
74
75ts.Disk.logging_yaml.AddLines(
76    '''
77logging:
78  formats:
79    - name: testformat
80      format: '%<pssc> %<cquc> %<pscert> %<cscert>'
81  logs:
82    - mode: ascii
83      format: testformat
84      filename: squid
85'''.split("\n")
86)
87
88# to foo.com w/o client cert.  Should fail
89tr = Test.AddTestRun("Connect to foo.com without cert")
90tr.Processes.Default.StartBefore(Test.Processes.ts)
91tr.Processes.Default.StartBefore(server)
92tr.StillRunningAfter = ts
93tr.StillRunningAfter = server
94tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'foo.com:{0}:127.0.0.1' https://foo.com:{0}/case1".format(
95    ts.Variables.ssl_port)
96tr.Processes.Default.ReturnCode = 35
97
98tr = Test.AddTestRun("Connect to foo.com with bad cert")
99tr.Setup.Copy("ssl/server.pem")
100tr.Setup.Copy("ssl/server.key")
101tr.StillRunningAfter = ts
102tr.StillRunningAfter = server
103tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'foo.com:{0}:127.0.0.1' https://foo.com:{0}/case2".format(
104    ts.Variables.ssl_port)
105# Should fail with badly signed certs
106tr.Processes.Default.ReturnCode = 35
107
108tr = Test.AddTestRun("Connect to foo.com with cert")
109tr.Setup.Copy("ssl/signed-foo.pem")
110tr.Setup.Copy("ssl/signed-foo.key")
111tr.StillRunningAfter = ts
112tr.StillRunningAfter = server
113tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-foo.pem --key ./signed-foo.key --resolve 'foo.com:{0}:127.0.0.1' https://foo.com:{0}/case3".format(
114    ts.Variables.ssl_port)
115tr.Processes.Default.ReturnCode = 0
116tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "Check response")
117
118tr = Test.AddTestRun("Connect to bob.bar.com without cert")
119tr.StillRunningAfter = ts
120tr.StillRunningAfter = server
121tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.bar.com:{0}:127.0.0.1' https://bob.bar.com:{0}/case4".format(
122    ts.Variables.ssl_port)
123tr.Processes.Default.ReturnCode = 0
124tr.Processes.Default.Streams.All = Testers.ExcludesExpression("alert", "TLS handshake should succeed")
125
126tr = Test.AddTestRun("Connect to bob.bar.com with cert")
127tr.Setup.Copy("ssl/signed-bob-bar.pem")
128tr.Setup.Copy("ssl/signed-bar.key")
129tr.StillRunningAfter = ts
130tr.StillRunningAfter = server
131tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-bob-bar.pem --key ./signed-bar.key --resolve 'bob.bar.com:{0}:127.0.0.1' https://bob.bar.com:{0}/case5".format(
132    ts.Variables.ssl_port)
133tr.Processes.Default.ReturnCode = 0
134tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "Check response")
135
136tr = Test.AddTestRun("Connect to bob.bar.com with bad cert")
137tr.Setup.Copy("ssl/server.pem")
138tr.Setup.Copy("ssl/server.key")
139tr.StillRunningAfter = ts
140tr.StillRunningAfter = server
141tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'bob.bar.com:{0}:127.0.0.1' https://bob.bar.com:{0}/case6".format(
142    ts.Variables.ssl_port)
143tr.Processes.Default.ReturnCode = 0
144tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "Check response")
145
146tr = Test.AddTestRun("Connect to bob.foo.com without cert")
147tr.StillRunningAfter = ts
148tr.StillRunningAfter = server
149tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.foo.com:{0}:127.0.0.1' https://bob.foo.com:{0}/case7".format(
150    ts.Variables.ssl_port)
151tr.Processes.Default.ReturnCode = 0
152tr.Processes.Default.Streams.All = Testers.ExcludesExpression("alert", "TLS handshake should succeed")
153
154tr = Test.AddTestRun("Connect to bob.foo.com with cert")
155tr.Setup.Copy("ssl/signed-bob-foo.pem")
156tr.Setup.Copy("ssl/signed-foo.key")
157tr.StillRunningAfter = ts
158tr.StillRunningAfter = server
159tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-bob-foo.pem --key ./signed-foo.key --resolve 'bob.foo.com:{0}:127.0.0.1' https://bob.foo.com:{0}/case8".format(
160    ts.Variables.ssl_port)
161tr.Processes.Default.ReturnCode = 0
162tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "Check response")
163
164tr = Test.AddTestRun("Connect to bob.foo.com with bad cert")
165tr.Setup.Copy("ssl/server.pem")
166tr.Setup.Copy("ssl/server.key")
167tr.StillRunningAfter = ts
168tr.StillRunningAfter = server
169tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'bob.foo.com:{0}:127.0.0.1' https://bob.foo.com:{0}/case9".format(
170    ts.Variables.ssl_port)
171tr.Processes.Default.ReturnCode = 0
172tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "Check response")
173
174tr = Test.AddTestRun("Connect to bar.com without cert")
175tr.StillRunningAfter = ts
176tr.StillRunningAfter = server
177tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bar.com:{0}:127.0.0.1' https://bar.com:{0}/case10".format(
178    ts.Variables.ssl_port)
179tr.Processes.Default.ReturnCode = 35
180
181tr = Test.AddTestRun("Connect to bar.com with cert")
182tr.Setup.Copy("ssl/signed-bar.pem")
183tr.Setup.Copy("ssl/signed-bar.key")
184tr.StillRunningAfter = ts
185tr.StillRunningAfter = server
186tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-bar.pem --key ./signed-bar.key --resolve 'bar.com:{0}:127.0.0.1' https://bar.com:{0}/case11".format(
187    ts.Variables.ssl_port)
188tr.Processes.Default.ReturnCode = 0
189tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "TLS handshake should succeed")
190
191tr = Test.AddTestRun("Connect to bar.com with bad cert")
192tr.Setup.Copy("ssl/server.pem")
193tr.Setup.Copy("ssl/server.key")
194tr.StillRunningAfter = ts
195tr.StillRunningAfter = server
196tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'bar.com:{0}:127.0.0.1' https://bar.com:{0}/case12".format(
197    ts.Variables.ssl_port)
198tr.Processes.Default.ReturnCode = 35
199
200
201# Test that the fqdn's match completely.  bob.com should require client certificate. bob.com.com should not
202tr = Test.AddTestRun("Connect to bob.com without cert, should fail")
203tr.StillRunningAfter = ts
204tr.StillRunningAfter = server
205tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.com:{0}:127.0.0.1' https://bob.com:{0}/case13".format(
206    ts.Variables.ssl_port)
207tr.Processes.Default.ReturnCode = 35
208
209tr = Test.AddTestRun("Connect to bob.com.com without cert, should succeed")
210tr.StillRunningAfter = ts
211tr.StillRunningAfter = server
212tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.com.com:{0}:127.0.0.1' https://bob.com.com:{0}/case14".format(
213    ts.Variables.ssl_port)
214tr.Processes.Default.ReturnCode = 0
215
216tr = Test.AddTestRun("Wait for the access log to write out")
217tr.Processes.Default.StartBefore(server2, ready=When.FileExists(ts.Disk.squid_log))
218tr.StillRunningAfter = ts
219tr.StillRunningAfter = server
220tr.StillRunningAfter = server2
221tr.Processes.Default.Command = 'echo "Log file exists"'
222tr.Processes.Default.ReturnCode = 0
223
224ts.Disk.squid_log.Content = "gold/clientcert-accesslog.gold"
225