summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webrtc/RTCCertificate.html
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--testing/web-platform/tests/webrtc/RTCCertificate.html283
1 files changed, 283 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCCertificate.html b/testing/web-platform/tests/webrtc/RTCCertificate.html
new file mode 100644
index 0000000000..6b7626c92e
--- /dev/null
+++ b/testing/web-platform/tests/webrtc/RTCCertificate.html
@@ -0,0 +1,283 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>RTCCertificate Tests</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the Candidate Recommendation:
+ // https://www.w3.org/TR/webrtc/
+
+ /*
+ 4.2.1. RTCConfiguration Dictionary
+ dictionary RTCConfiguration {
+ sequence<RTCCertificate> certificates;
+ ...
+ };
+
+ certificates of type sequence<RTCCertificate>
+ If this value is absent, then a default set of certificates is
+ generated for each RTCPeerConnection instance.
+
+ The value for this configuration option cannot change after its
+ value is initially selected.
+
+ 4.10.2. RTCCertificate Interface
+ interface RTCCertificate {
+ readonly attribute DOMTimeStamp expires;
+ static sequence<AlgorithmIdentifier> getSupportedAlgorithms();
+ sequence<RTCDtlsFingerprint> getFingerprints();
+ };
+
+ 5.5.1 The RTCDtlsFingerprint Dictionary
+ dictionary RTCDtlsFingerprint {
+ DOMString algorithm;
+ DOMString value;
+ };
+
+ [RFC4572] Comedia over TLS in SDP
+ 5. Fingerprint Attribute
+ Figure 2. Augmented Backus-Naur Syntax for the Fingerprint Attribute
+
+ attribute =/ fingerprint-attribute
+
+ fingerprint-attribute = "fingerprint" ":" hash-func SP fingerprint
+
+ hash-func = "sha-1" / "sha-224" / "sha-256" /
+ "sha-384" / "sha-512" /
+ "md5" / "md2" / token
+ ; Additional hash functions can only come
+ ; from updates to RFC 3279
+
+ fingerprint = 2UHEX *(":" 2UHEX)
+ ; Each byte in upper-case hex, separated
+ ; by colons.
+
+ UHEX = DIGIT / %x41-46 ; A-F uppercase
+ */
+
+ // Helper function to generate certificate with a set of
+ // default parameters
+ function generateCertificate() {
+ return RTCPeerConnection.generateCertificate({
+ name: 'ECDSA',
+ namedCurve: 'P-256'
+ });
+ }
+
+ // Helper function that takes in an RTCDtlsFingerprint
+ // and return an a=fingerprint SDP line
+ function fingerprintToSdpLine(fingerprint) {
+ return `\r\na=fingerprint:${fingerprint.algorithm} ${fingerprint.value.toUpperCase()}\r\n`;
+ }
+
+ // Assert that an SDP string has fingerprint line for all the cert's fingerprints
+ function assert_sdp_has_cert_fingerprints(sdp, cert) {
+ for(const fingerprint of cert.getFingerprints()) {
+ const fingerprintLine = fingerprintToSdpLine(fingerprint);
+ assert_true(sdp.includes(fingerprintLine),
+ 'Expect fingerprint line to be found in SDP');
+ }
+ }
+
+ /*
+ 4.3.1. Operation
+ When the RTCPeerConnection() constructor is invoked
+ 2. If the certificates value in configuration is non-empty,
+ check that the expires on each value is in the future.
+ If a certificate has expired, throw an InvalidAccessError;
+ otherwise, store the certificates. If no certificates value
+ was specified, one or more new RTCCertificate instances are
+ generated for use with this RTCPeerConnection instance.
+ This may happen asynchronously and the value of certificates
+ remains undefined for the subsequent steps.
+ */
+ promise_test(t => {
+ return RTCPeerConnection.generateCertificate({
+ name: 'ECDSA',
+ namedCurve: 'P-256',
+ expires: 0
+ }).then(cert => {
+ assert_less_than_equal(cert.expires, Date.now());
+ assert_throws_dom('InvalidAccessError', () =>
+ new RTCPeerConnection({ certificates: [cert] }));
+ });
+ }, 'Constructing RTCPeerConnection with expired certificate should reject with InvalidAccessError');
+
+ /*
+ 4.3.2 Interface Definition
+ setConfiguration
+ 4. If configuration.certificates is set and the set of
+ certificates differs from the ones used when connection
+ was constructed, throw an InvalidModificationError.
+ */
+ promise_test(t => {
+ return Promise.all([
+ generateCertificate(),
+ generateCertificate()
+ ]).then(([cert1, cert2]) => {
+ const pc = new RTCPeerConnection({
+ certificates: [cert1]
+ });
+
+ // should not throw
+ pc.setConfiguration({
+ certificates: [cert1]
+ });
+
+ assert_throws_dom('InvalidModificationError', () =>
+ pc.setConfiguration({
+ certificates: [cert2]
+ }));
+
+ assert_throws_dom('InvalidModificationError', () =>
+ pc.setConfiguration({
+ certificates: [cert1, cert2]
+ }));
+ });
+ }, 'Calling setConfiguration with different set of certs should reject with InvalidModificationError');
+
+ /*
+ 4.10.2. RTCCertificate Interface
+ getFingerprints
+ Returns the list of certificate fingerprints, one of which is
+ computed with the digest algorithm used in the certificate signature.
+
+ 5.5.1 The RTCDtlsFingerprint Dictionary
+ algorithm of type DOMString
+ One of the the hash function algorithms defined in the 'Hash function
+ Textual Names' registry, initially specified in [RFC4572] Section 8.
+ As noted in [JSEP] Section 5.2.1, the digest algorithm used for the
+ fingerprint matches that used in the certificate signature.
+
+ value of type DOMString
+ The value of the certificate fingerprint in lowercase hex string as
+ expressed utilizing the syntax of 'fingerprint' in [ RFC4572] Section 5.
+
+ */
+ promise_test(t => {
+ return generateCertificate()
+ .then(cert => {
+ assert_idl_attribute(cert, 'getFingerprints');
+
+ const fingerprints = cert.getFingerprints();
+ assert_true(Array.isArray(fingerprints),
+ 'Expect fingerprints to return an array');
+
+ assert_greater_than_equal(fingerprints.length, 1,
+ 'Expect at last one fingerprint in array');
+
+ for(const fingerprint of fingerprints) {
+ assert_equals(typeof fingerprint, 'object',
+ 'Expect fingerprint to be an object (dictionary)');
+
+ // https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml
+ const algorithms = ['md2', 'md5', 'sha-1', 'sha-224', 'sha-256', 'sha-384', 'sha-512'];
+ assert_in_array(fingerprint.algorithm, algorithms,
+ 'Expect fingerprint.algorithm to be string of algorithm identifier');
+
+ assert_true(/^([0-9a-f]{2}\:)+[0-9a-f]{2}$/.test(fingerprint.value),
+ 'Expect fingerprint.value to be lowercase hexadecimal separated by colon');
+ }
+ });
+ }, 'RTCCertificate should have at least one fingerprint');
+
+ /*
+ 4.3.2 Interface Definition
+ createOffer
+ The value for certificates in the RTCConfiguration for the
+ RTCPeerConnection is used to produce a set of certificate
+ fingerprints. These certificate fingerprints are used in the
+ construction of SDP and as input to requests for identity
+ assertions.
+
+ [JSEP]
+ 5.2.1. Initial Offers
+ For DTLS, all m= sections MUST use all the certificate(s) that have
+ been specified for the PeerConnection; as a result, they MUST all
+ have the same [I-D.ietf-mmusic-4572-update] fingerprint value(s), or
+ these value(s) MUST be session-level attributes.
+
+ The following attributes, which are of category IDENTICAL or
+ TRANSPORT, MUST appear only in "m=" sections which either have a
+ unique address or which are associated with the bundle-tag. (In
+ initial offers, this means those "m=" sections which do not contain
+ an "a=bundle-only" attribute.)
+
+ - An "a=fingerprint" line for each of the endpoint's certificates,
+ as specified in [RFC4572], Section 5; the digest algorithm used
+ for the fingerprint MUST match that used in the certificate
+ signature.
+
+ Each m= section which is not bundled into another m= section, MUST
+ contain the following attributes (which are of category IDENTICAL or
+ TRANSPORT):
+
+ - An "a=fingerprint" line for each of the endpoint's certificates,
+ as specified in [RFC4572], Section 5; the digest algorithm used
+ for the fingerprint MUST match that used in the certificate
+ signature.
+ */
+ promise_test(t => {
+ return generateCertificate()
+ .then(cert => {
+ const pc = new RTCPeerConnection({
+ certificates: [cert]
+ });
+ pc.createDataChannel('test');
+
+ return pc.createOffer()
+ .then(offer => {
+ assert_sdp_has_cert_fingerprints(offer.sdp, cert);
+ });
+ });
+ }, 'RTCPeerConnection({ certificates }) should generate offer SDP with fingerprint of provided certificate');
+
+ promise_test(t => {
+ return Promise.all([
+ generateCertificate(),
+ generateCertificate()
+ ]).then(certs => {
+ const pc = new RTCPeerConnection({
+ certificates: certs
+ });
+ pc.createDataChannel('test');
+
+ return pc.createOffer()
+ .then(offer => {
+ for(const cert of certs) {
+ assert_sdp_has_cert_fingerprints(offer.sdp, cert);
+ }
+ });
+ });
+ }, 'RTCPeerConnection({ certificates }) should generate offer SDP with fingerprint of all provided certificates');
+
+ /*
+ TODO
+
+ 4.10.2. RTCCertificate Interface
+ getSupportedAlgorithms
+ Returns a sequence providing a representative set of supported
+ certificate algorithms. At least one algorithm MUST be returned.
+
+ The RTCCertificate object can be stored and retrieved from persistent
+ storage by an application. When a user agent is required to obtain a
+ structured clone [HTML5] of a RTCCertificate object, it performs the
+ following steps:
+ 1. Let input and memory be the corresponding inputs defined by the
+ internal structured cloning algorithm, where input represents a
+ RTCCertificate object to be cloned.
+ 2. Let output be a newly constructed RTCCertificate object.
+ 3. Copy the value of the expires attribute from input to output.
+ 4. Let the [[certificate]] internal slot of output be set to the
+ result of invoking the internal structured clone algorithm
+ recursively on the corresponding internal slots of input, with
+ the slot contents as the new " input" argument and memory as
+ the new " memory" argument.
+ 5. Let the [[handle]] internal slot of output refer to the same
+ private keying material represented by the [[handle]] internal
+ slot of input.
+ */
+
+</script>