tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RTCCertificate.html (10740B)


      1 <!doctype html>
      2 <meta charset="utf-8">
      3 <title>RTCCertificate Tests</title>
      4 <script src="/resources/testharness.js"></script>
      5 <script src="/resources/testharnessreport.js"></script>
      6 <script>
      7  'use strict';
      8 
      9  // Test is based on the Candidate Recommendation:
     10  // https://www.w3.org/TR/webrtc/
     11 
     12  /*
     13    4.2.1. RTCConfiguration Dictionary
     14      dictionary RTCConfiguration {
     15        sequence<RTCCertificate> certificates;
     16        ...
     17      };
     18 
     19      certificates of type sequence<RTCCertificate>
     20        If this value is absent, then a default set of certificates is
     21        generated for each RTCPeerConnection instance.
     22 
     23        The value for this configuration option cannot change after its
     24        value is initially selected.
     25 
     26    4.10.2. RTCCertificate Interface
     27      interface RTCCertificate {
     28        readonly attribute DOMTimeStamp expires;
     29        static sequence<AlgorithmIdentifier> getSupportedAlgorithms();
     30        sequence<RTCDtlsFingerprint>    getFingerprints();
     31      };
     32 
     33    5.5.1 The RTCDtlsFingerprint Dictionary
     34      dictionary RTCDtlsFingerprint {
     35        DOMString algorithm;
     36        DOMString value;
     37      };
     38 
     39    [RFC4572] Comedia over TLS in SDP
     40    5.  Fingerprint Attribute
     41      Figure 2. Augmented Backus-Naur Syntax for the Fingerprint Attribute
     42 
     43        attribute              =/ fingerprint-attribute
     44 
     45        fingerprint-attribute  =  "fingerprint" ":" hash-func SP fingerprint
     46 
     47        hash-func              =  "sha-1" / "sha-224" / "sha-256" /
     48                                  "sha-384" / "sha-512" /
     49                                  "md5" / "md2" / token
     50                                  ; Additional hash functions can only come
     51                                  ; from updates to RFC 3279
     52 
     53        fingerprint            =  2UHEX *(":" 2UHEX)
     54                                  ; Each byte in upper-case hex, separated
     55                                  ; by colons.
     56 
     57        UHEX                   =  DIGIT / %x41-46 ; A-F uppercase
     58   */
     59 
     60  // Helper function to generate certificate with a set of
     61  // default parameters
     62  function generateCertificate() {
     63    return RTCPeerConnection.generateCertificate({
     64      name: 'ECDSA',
     65      namedCurve: 'P-256'
     66    });
     67  }
     68 
     69  // Helper function that takes in an RTCDtlsFingerprint
     70  // and return an a=fingerprint SDP line
     71  function fingerprintToSdpLine(fingerprint) {
     72    return `\r\na=fingerprint:${fingerprint.algorithm} ${fingerprint.value.toUpperCase()}\r\n`;
     73  }
     74 
     75  // Assert that an SDP string has fingerprint line for all the cert's fingerprints
     76  function assert_sdp_has_cert_fingerprints(sdp, cert) {
     77    for(const fingerprint of cert.getFingerprints()) {
     78      const fingerprintLine = fingerprintToSdpLine(fingerprint);
     79      assert_true(sdp.includes(fingerprintLine),
     80        'Expect fingerprint line to be found in SDP');
     81    }
     82  }
     83 
     84  /*
     85    4.3.1. Operation
     86      When the RTCPeerConnection() constructor is invoked
     87        2.  If the certificates value in configuration is non-empty,
     88            check that the expires on each value is in the future.
     89            If a certificate has expired, throw an InvalidAccessError;
     90            otherwise, store the certificates. If no certificates value
     91            was specified, one or more new RTCCertificate instances are
     92            generated for use with this RTCPeerConnection instance.
     93            This may happen asynchronously and the value of certificates
     94            remains undefined for the subsequent steps.
     95   */
     96  promise_test(t => {
     97    return RTCPeerConnection.generateCertificate({
     98      name: 'ECDSA',
     99      namedCurve: 'P-256',
    100      expires: 0
    101    }).then(cert => {
    102      assert_less_than_equal(cert.expires, Date.now());
    103      assert_throws_dom('InvalidAccessError', () =>
    104        new RTCPeerConnection({ certificates: [cert] }));
    105    });
    106  }, 'Constructing RTCPeerConnection with expired certificate should reject with InvalidAccessError');
    107 
    108  /*
    109    4.3.2 Interface Definition
    110      setConfiguration
    111        4.  If configuration.certificates is set and the set of
    112            certificates differs from the ones used when connection
    113            was constructed, throw an InvalidModificationError.
    114   */
    115  promise_test(t => {
    116    return Promise.all([
    117      generateCertificate(),
    118      generateCertificate()
    119    ]).then(([cert1, cert2]) => {
    120      const pc = new RTCPeerConnection({
    121        certificates: [cert1]
    122      });
    123 
    124      // should not throw
    125      pc.setConfiguration({
    126        certificates: [cert1]
    127      });
    128 
    129      assert_throws_dom('InvalidModificationError', () =>
    130        pc.setConfiguration({
    131          certificates: [cert2]
    132        }));
    133 
    134      assert_throws_dom('InvalidModificationError', () =>
    135        pc.setConfiguration({
    136          certificates: [cert1, cert2]
    137        }));
    138    });
    139  }, 'Calling setConfiguration with different set of certs should reject with InvalidModificationError');
    140 
    141  /*
    142    4.10.2. RTCCertificate Interface
    143      getFingerprints
    144        Returns the list of certificate fingerprints, one of which is
    145        computed with the digest algorithm used in the certificate signature.
    146 
    147    5.5.1 The RTCDtlsFingerprint Dictionary
    148      algorithm of type DOMString
    149        One of the hash function algorithms defined in the 'Hash function
    150        Textual Names' registry, initially specified in [RFC4572] Section 8.
    151        As noted in [JSEP] Section 5.2.1, the digest algorithm used for the
    152        fingerprint matches that used in the certificate signature.
    153 
    154      value of type DOMString
    155        The value of the certificate fingerprint in lowercase hex string as
    156        expressed utilizing the syntax of 'fingerprint' in [ RFC4572] Section 5.
    157 
    158   */
    159  promise_test(t => {
    160    return generateCertificate()
    161    .then(cert => {
    162      assert_idl_attribute(cert, 'getFingerprints');
    163 
    164      const fingerprints = cert.getFingerprints();
    165      assert_true(Array.isArray(fingerprints),
    166        'Expect fingerprints to return an array');
    167 
    168      assert_greater_than_equal(fingerprints.length, 1,
    169        'Expect at last one fingerprint in array');
    170 
    171      for(const fingerprint of fingerprints) {
    172        assert_equals(typeof fingerprint, 'object',
    173          'Expect fingerprint to be an object (dictionary)');
    174 
    175        // https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml
    176        const algorithms = ['md2', 'md5', 'sha-1', 'sha-224', 'sha-256', 'sha-384', 'sha-512'];
    177        assert_in_array(fingerprint.algorithm, algorithms,
    178          'Expect fingerprint.algorithm to be string of algorithm identifier');
    179 
    180        assert_true(/^([0-9a-f]{2}\:)+[0-9a-f]{2}$/.test(fingerprint.value),
    181          'Expect fingerprint.value to be lowercase hexadecimal separated by colon');
    182      }
    183    });
    184  }, 'RTCCertificate should have at least one fingerprint');
    185 
    186  /*
    187    4.3.2 Interface Definition
    188      createOffer
    189        The value for certificates in the RTCConfiguration for the
    190        RTCPeerConnection is used to produce a set of certificate
    191        fingerprints. These certificate fingerprints are used in the
    192        construction of SDP and as input to requests for identity
    193        assertions.
    194 
    195    [JSEP]
    196    5.2.1.  Initial Offers
    197      For DTLS, all m= sections MUST use all the certificate(s) that have
    198      been specified for the PeerConnection; as a result, they MUST all
    199      have the same [I-D.ietf-mmusic-4572-update] fingerprint value(s), or
    200      these value(s) MUST be session-level attributes.
    201 
    202      The following attributes, which are of category IDENTICAL or
    203      TRANSPORT, MUST appear only in "m=" sections which either have a
    204      unique address or which are associated with the bundle-tag.  (In
    205      initial offers, this means those "m=" sections which do not contain
    206      an "a=bundle-only" attribute.)
    207 
    208        - An "a=fingerprint" line for each of the endpoint's certificates,
    209          as specified in [RFC4572], Section 5; the digest algorithm used
    210          for the fingerprint MUST match that used in the certificate
    211          signature.
    212 
    213      Each m= section which is not bundled into another m= section, MUST
    214      contain the following attributes (which are of category IDENTICAL or
    215      TRANSPORT):
    216 
    217        - An "a=fingerprint" line for each of the endpoint's certificates,
    218          as specified in [RFC4572], Section 5; the digest algorithm used
    219          for the fingerprint MUST match that used in the certificate
    220          signature.
    221   */
    222  promise_test(t => {
    223    return generateCertificate()
    224    .then(cert => {
    225      const pc = new RTCPeerConnection({
    226        certificates: [cert]
    227      });
    228      pc.createDataChannel('test');
    229 
    230      return pc.createOffer()
    231      .then(offer => {
    232        assert_sdp_has_cert_fingerprints(offer.sdp, cert);
    233      });
    234    });
    235  }, 'RTCPeerConnection({ certificates }) should generate offer SDP with fingerprint of provided certificate');
    236 
    237  promise_test(t => {
    238    return Promise.all([
    239      generateCertificate(),
    240      generateCertificate()
    241    ]).then(certs => {
    242      const pc = new RTCPeerConnection({
    243        certificates: certs
    244      });
    245      pc.createDataChannel('test');
    246 
    247      return pc.createOffer()
    248      .then(offer => {
    249        for(const cert of certs) {
    250          assert_sdp_has_cert_fingerprints(offer.sdp, cert);
    251        }
    252      });
    253    });
    254  }, 'RTCPeerConnection({ certificates }) should generate offer SDP with fingerprint of all provided certificates');
    255 
    256  /*
    257    TODO
    258 
    259    4.10.2. RTCCertificate Interface
    260      getSupportedAlgorithms
    261           Returns a sequence providing a representative set of supported
    262           certificate algorithms. At least one algorithm MUST be returned.
    263 
    264      The RTCCertificate object can be stored and retrieved from persistent
    265      storage by an application. When a user agent is required to obtain a
    266      structured clone [HTML5] of a RTCCertificate object, it performs the
    267      following steps:
    268        1.  Let input and memory be the corresponding inputs defined by the
    269            internal structured cloning algorithm, where input represents a
    270            RTCCertificate object to be cloned.
    271        2.  Let output be a newly constructed RTCCertificate object.
    272        3.  Copy the value of the expires attribute from input to output.
    273        4.  Let the [[certificate]] internal slot of output be set to the
    274            result of invoking the internal structured clone algorithm
    275            recursively on the corresponding internal slots of input, with
    276            the slot contents as the new " input" argument and memory as
    277            the new " memory" argument.
    278        5.  Let the [[handle]] internal slot of output refer to the same
    279            private keying material represented by the [[handle]] internal
    280            slot of input.
    281   */
    282 
    283 </script>