Skip to content

Commit

Permalink
Merge branch 'master' into improve-is-05-control
Browse files Browse the repository at this point in the history
  • Loading branch information
garethsb authored Aug 18, 2022
2 parents f15269f + 88034d1 commit faa50f9
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 57 deletions.
4 changes: 2 additions & 2 deletions docs/2.2. Usage - Testing BCP-003-01 TLS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

BCP-003-01 covers the use of Transport Layer Security with NMOS APIs. The BCP-003-01 Secure API Communications test suite can be run against an implementation of any of the APIs running in HTTPS mode to confirm that the full requirements of BCP-003-01 are met.

Testing of certain aspects of BCP-003-01 makes use of an external tool 'testssl.sh'. Please see [testssl/README.md](../testssl/README.md) for installation instructions.
Testing of certain aspects of BCP-003-01 makes use of an external tool 'testssl.sh'. Please see [testssl/](../testssl/) for installation instructions.

In order to ease testing of TLS with the various specifications, sample certificates are provided in this repository. Please see [test_data/BCP00301/README.md](../test_data/BCP00301/README.md) for their details and installation guidance.
In order to ease testing of TLS with the various specifications, sample certificates are provided in this repository. Please see [test_data/BCP00301/](../test_data/BCP00301/) for their details and installation guidance.

In addition to the specific test suite, each of the specification test suites can be run in HTTPS mode where applicable. When this is enabled, every request which is made by the testing tool will use HTTPS. The configuration parameter `ENABLE_HTTPS` should be set to `True` before running the Testing Tool.
9 changes: 8 additions & 1 deletion nmostesting/Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,17 @@
SDP_PREFERENCES = {
"audio_channels": 2,
"audio_sample_rate": 48000,
"audio_packet_time": 1,
"audio_max_packet_time": 1,
"video_width": 1920,
"video_height": 1080,
"video_interlace": True,
"video_exactframerate": "25"
"video_exactframerate": "25",
"video_depth": 10,
"video_sampling": "YCbCr-4:2:2",
"video_colorimetry": "BT709",
"video_transfer_characteristic": "SDR",
"video_type_parameter": "2110TPW"
}

# Test with an MQTT Broker as per AMWA IS-07
Expand Down
10 changes: 10 additions & 0 deletions nmostesting/TestHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# limitations under the License.

import asyncio
import ipaddress
import threading
import requests
import websocket
Expand Down Expand Up @@ -165,6 +166,15 @@ def get_default_ip():
return netifaces.ifaddresses(preferred_interface)[netifaces.AF_INET][0]['addr']


def is_ip_address(arg):
"""True if arg is an IPv4 or IPv6 address"""
try:
ipaddress.ip_address(arg)
return True
except ValueError:
return False


def do_request(method, url, **kwargs):
"""Perform a basic HTTP request with appropriate error handling"""
response = None
Expand Down
18 changes: 15 additions & 3 deletions nmostesting/mocks/Node.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,12 +363,19 @@ def node_sdp(stream_type):
width=CONFIG.SDP_PREFERENCES["video_width"],
height=CONFIG.SDP_PREFERENCES["video_height"],
interlace=interlace,
exactframerate=CONFIG.SDP_PREFERENCES["video_exactframerate"])
exactframerate=CONFIG.SDP_PREFERENCES["video_exactframerate"],
depth=CONFIG.SDP_PREFERENCES["video_depth"],
sampling=CONFIG.SDP_PREFERENCES["video_sampling"],
colorimetry=CONFIG.SDP_PREFERENCES["video_colorimetry"],
transfer_characteristic=CONFIG.SDP_PREFERENCES["video_transfer_characteristic"],
type_parameter=CONFIG.SDP_PREFERENCES["video_type_parameter"])
elif stream_type == "audio":
# TODO: The SDP_PREFERENCES doesn't include audio media type or sample depth
sdp_file = template.render(dst_ip=dst_ip, dst_port=dst_port, src_ip=src_ip, media_type="L24",
channels=CONFIG.SDP_PREFERENCES["audio_channels"],
sample_rate=CONFIG.SDP_PREFERENCES["audio_sample_rate"])
sample_rate=CONFIG.SDP_PREFERENCES["audio_sample_rate"],
max_packet_time=CONFIG.SDP_PREFERENCES["audio_max_packet_time"],
packet_time=CONFIG.SDP_PREFERENCES["audio_packet_time"])
elif stream_type == "data":
sdp_file = template.render(dst_ip=dst_ip, dst_port=dst_port, src_ip=src_ip)
elif stream_type == "mux":
Expand Down Expand Up @@ -577,7 +584,12 @@ def transport_file(version, resource, resource_id):
width=CONFIG.SDP_PREFERENCES["video_width"],
height=CONFIG.SDP_PREFERENCES["video_height"],
interlace=interlace,
exactframerate=CONFIG.SDP_PREFERENCES["video_exactframerate"])
exactframerate=CONFIG.SDP_PREFERENCES["video_exactframerate"],
depth=CONFIG.SDP_PREFERENCES["video_depth"],
sampling=CONFIG.SDP_PREFERENCES["video_sampling"],
colorimetry=CONFIG.SDP_PREFERENCES["video_colorimetry"],
transfer_characteristic=CONFIG.SDP_PREFERENCES["video_transfer_characteristic"],
type_parameter=CONFIG.SDP_PREFERENCES["video_type_parameter"])

response = make_response(sdp_file, 200)
response.headers["Content-Type"] = "application/sdp"
Expand Down
12 changes: 6 additions & 6 deletions nmostesting/suites/IS0401Test.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from ..MdnsListener import MdnsListener
from ..GenericTest import GenericTest, NMOSTestException, NMOS_WIKI_URL
from ..IS04Utils import IS04Utils
from ..TestHelper import get_default_ip, load_resolved_schema
from ..TestHelper import get_default_ip, is_ip_address, load_resolved_schema

NODE_API_KEY = "node"
RECEIVER_CAPS_KEY = "receiver-caps"
Expand Down Expand Up @@ -1230,7 +1230,7 @@ def test_20(self, test):
node_self = response.json()
if not node_self["href"].startswith(self.protocol + "://"):
return test.FAIL("Node 'href' does not match the current protocol")
if node_self["href"].startswith("https://") and urlparse(node_self["href"]).hostname[-1].isdigit():
if node_self["href"].startswith("https://") and is_ip_address(urlparse(node_self["href"]).hostname):
href_hostname_warn = True
if self.is04_utils.compare_api_version(api["version"], "v1.1") >= 0:
for endpoint in node_self["api"]["endpoints"]:
Expand All @@ -1246,15 +1246,15 @@ def test_20(self, test):
if self.is04_utils.compare_urls(node_self["href"], "{}://{}:{}"
.format(endpoint["protocol"], endpoint["host"], endpoint["port"])):
found_href = True
if endpoint["protocol"] == "https" and endpoint["host"][-1].isdigit():
if endpoint["protocol"] == "https" and is_ip_address(endpoint["host"]):
api_endpoint_host_warn = True
for service in node_self["services"]:
href = service["href"]
if href.startswith("http") and not href.startswith(self.protocol + "://"):
# Only warn about these at the end so that more major failures are flagged first
# Protocols other than HTTP may be used, so don't incorrectly flag those too
service_href_scheme_warn = True
if href.startswith("https://") and urlparse(href).hostname[-1].isdigit():
if href.startswith("https://") and is_ip_address(urlparse(href).hostname):
service_href_hostname_warn = True
if self.is04_utils.compare_api_version(api["version"], "v1.3") >= 0 and \
service["type"].startswith("urn:x-nmos:"):
Expand Down Expand Up @@ -1284,7 +1284,7 @@ def test_20(self, test):
# Only warn about these at the end so that more major failures are flagged first
# Protocols other than HTTP may be used, so don't incorrectly flag those too
control_href_scheme_warn = True
if href.startswith("https://") and urlparse(href).hostname[-1].isdigit():
if href.startswith("https://") and is_ip_address(urlparse(href).hostname):
control_href_hostname_warn = True
if self.is04_utils.compare_api_version(api["version"], "v1.3") >= 0 and \
control["type"].startswith("urn:x-nmos:"):
Expand All @@ -1304,7 +1304,7 @@ def test_20(self, test):
href = sender["manifest_href"]
if href is not None and href.startswith("http") and not href.startswith(self.protocol + "://"):
manifest_href_scheme_warn = True
if href is not None and href.startswith("https://") and urlparse(href).hostname[-1].isdigit():
if href is not None and href.startswith("https://") and is_ip_address(urlparse(href).hostname):
manifest_href_hostname_warn = True
except json.JSONDecodeError:
return test.FAIL("Non-JSON response returned from Node API")
Expand Down
8 changes: 4 additions & 4 deletions nmostesting/suites/IS0402Test.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from ..MdnsListener import MdnsListener
from ..GenericTest import GenericTest, NMOSTestException, NMOSInitException, NMOS_WIKI_URL
from ..IS04Utils import IS04Utils
from ..TestHelper import WebsocketWorker, load_resolved_schema
from ..TestHelper import is_ip_address, load_resolved_schema, WebsocketWorker
from ..TestResult import Test

REG_API_KEY = "registration"
Expand Down Expand Up @@ -154,7 +154,7 @@ def test_03_1(self, test):
location, timestamp = self.post_resource(test, "node", data, codes=[201])

# also check an 'https' URL in the Location header has a hostname not an IP address
if location is not None and location.startswith("https://") and urlparse(location).hostname[-1].isdigit():
if location is not None and location.startswith("https://") and is_ip_address(urlparse(location).hostname):
return test.WARNING("Registration API Location header has an IP address not a hostname")

return test.PASS()
Expand Down Expand Up @@ -966,7 +966,7 @@ def test_21_9(self, test):
if rel not in link_header:
continue

if link_header[rel].startswith("https://") and urlparse(link_header[rel]).hostname[-1].isdigit():
if link_header[rel].startswith("https://") and is_ip_address(urlparse(link_header[rel]).hostname):
return test.WARNING("Query API Link header has an IP address not a hostname")

return test.PASS()
Expand Down Expand Up @@ -1775,7 +1775,7 @@ def test_29(self, test):

# Check IP/hostname
ws_href_hostname_warn = False
if resp_json["ws_href"].startswith("wss://") and urlparse(resp_json["ws_href"]).hostname[-1].isdigit():
if resp_json["ws_href"].startswith("wss://") and is_ip_address(urlparse(resp_json["ws_href"]).hostname):
ws_href_hostname_warn = True

# Test if subscription is available
Expand Down
Loading

0 comments on commit faa50f9

Please sign in to comment.