tor-browser

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

RTCPeerConnection-generateCertificate.html (6229B)


      1 <!doctype html>
      2 <meta charset="utf-8">
      3 <meta name="timeout" content="long">
      4 <title>Test RTCPeerConnection.generateCertificate</title>
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="./third_party/sdp/sdp.js"></script>
      8 <script>
      9  'use strict';
     10 
     11  // Test is based on the following editor draft:
     12  // https://w3c.github.io/webrtc-pc/archives/20170515/webrtc.html
     13 
     14  /*
     15   *  4.10. Certificate Management
     16   *    partial interface RTCPeerConnection {
     17   *      static Promise<RTCCertificate> generateCertificate(
     18   *        AlgorithmIdentifier keygenAlgorithm);
     19   *    };
     20   *
     21   *  4.10.2. RTCCertificate Interface
     22   *    interface RTCCertificate {
     23   *      readonly attribute DOMTimeStamp expires;
     24   *      ...
     25   *    };
     26   *
     27   *  [WebCrypto]
     28   *  11. Algorithm Dictionary
     29   *    typedef (object or DOMString) AlgorithmIdentifier;
     30   */
     31 
     32  /*
     33   *  4.10. The following values must be supported by a user agent:
     34   *        { name: "RSASSA-PKCS1-v1_5", modulusLength: 2048,
     35   *          publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" },
     36   *        and { name: "ECDSA", namedCurve: "P-256" }.
     37   */
     38  [1024, 2048].forEach(modulusLength => {
     39    promise_test(t =>
     40      // Test common RSA key sizes. Only 2048 is mandatory to support.
     41      RTCPeerConnection.generateCertificate({
     42        name: 'RSASSA-PKCS1-v1_5',
     43        modulusLength,
     44        publicExponent: new Uint8Array([1, 0, 1]),
     45        hash: 'SHA-256'
     46      }).then(cert => {
     47        assert_true(cert instanceof RTCCertificate,
     48          'Expect cert to be instance of RTCCertificate');
     49 
     50        assert_greater_than(cert.expires, Date.now(),
     51          'Expect generated certificate to expire reasonably long after current time');
     52      }),
     53      `generateCertificate({modulusLength: ${modulusLength}}) with RSASSA-PKCS1-v1_5 parameters should succeed`);
     54  });
     55 
     56  promise_test(t =>
     57    RTCPeerConnection.generateCertificate({
     58      name: 'ECDSA',
     59      namedCurve: 'P-256'
     60    }).then(cert => {
     61      assert_true(cert instanceof RTCCertificate,
     62        'Expect cert to be instance of RTCCertificate');
     63 
     64      assert_greater_than(cert.expires, Date.now(),
     65        'Expect generated certificate to expire reasonably long after current time');
     66    }),
     67    'generateCertificate() with compulsary ECDSA parameters should succeed');
     68 
     69  /*
     70   *  4.10. A user agent must reject a call to generateCertificate() with a
     71   *        DOMException of type NotSupportedError if the keygenAlgorithm
     72   *        parameter identifies an algorithm that the user agent cannot or
     73   *        will not use to generate a certificate for RTCPeerConnection.
     74   */
     75  promise_test(t =>
     76    promise_rejects_dom(t, 'NotSupportedError',
     77      RTCPeerConnection.generateCertificate('invalid-algo')),
     78    'generateCertificate() with invalid string algorithm should reject with NotSupportedError');
     79 
     80  promise_test(t =>
     81    promise_rejects_dom(t, 'NotSupportedError',
     82      RTCPeerConnection.generateCertificate({
     83        name: 'invalid-algo'
     84      })),
     85    'generateCertificate() with invalid algorithm dict should reject with NotSupportedError');
     86 
     87  promise_test(t =>
     88    promise_rejects_dom(t, 'NotSupportedError',
     89      RTCPeerConnection.generateCertificate({
     90        name: 'RSASSA-PKCS1-v1_5',
     91        modulusLength: 2048,
     92        publicExponent: new Uint8Array([1, 0, 1]),
     93        hash: 'SHA-1'
     94      })),
     95    'generateCertificate with RSASSA-PKCS1-v1_5 parameters and SHA-1 signature should reject with NotSupportedError');
     96 
     97  /*
     98   *  4.10.1. Dictionary RTCCertificateExpiration
     99   *    dictionary RTCCertificateExpiration {
    100   *      [EnforceRange]
    101   *      DOMTimeStamp expires;
    102   *    };
    103   *
    104   *    If this parameter is present it indicates the maximum time that
    105   *    the RTCCertificate is valid for relative to the current time.
    106   *
    107   *    When generateCertificate is called with an object argument,
    108   *    the user agent attempts to convert the object into a
    109   *    RTCCertificateExpiration. If this is unsuccessful, immediately
    110   *    return a promise that is rejected with a newly created TypeError
    111   *    and abort processing.
    112   */
    113 
    114  promise_test(t => {
    115    const start = Date.now();
    116    return RTCPeerConnection.generateCertificate({
    117      name: 'ECDSA',
    118      namedCurve: 'P-256',
    119      expires: 2000
    120    }).then(cert => {
    121      assert_approx_equals(cert.expires, start+2000, 1000);
    122    })
    123  }, 'generateCertificate() with valid expires parameter should succeed');
    124 
    125  promise_test(t => {
    126    return RTCPeerConnection.generateCertificate({
    127      name: 'ECDSA',
    128      namedCurve: 'P-256',
    129      expires: 0
    130    }).then(cert => {
    131      assert_less_than_equal(cert.expires, Date.now());
    132    })
    133  }, 'generateCertificate() with 0 expires parameter should generate expired cert');
    134 
    135  promise_test(t => {
    136    return promise_rejects_js(t, TypeError,
    137      RTCPeerConnection.generateCertificate({
    138        name: 'ECDSA',
    139        namedCurve: 'P-256',
    140        expires: -1
    141      }))
    142  }, 'generateCertificate() with invalid range for expires should reject with TypeError');
    143 
    144  promise_test(t => {
    145    return promise_rejects_js(t, TypeError,
    146      RTCPeerConnection.generateCertificate({
    147        name: 'ECDSA',
    148        namedCurve: 'P-256',
    149        expires: 'invalid'
    150      }))
    151  }, 'generateCertificate() with invalid type for expires should reject with TypeError');
    152 
    153  promise_test(t => {
    154    return RTCPeerConnection.generateCertificate({
    155      name: 'ECDSA',
    156      namedCurve: 'P-256',
    157    }).then(async cert => {
    158      const pc = new RTCPeerConnection({certificates: [cert]});
    159      pc.createDataChannel('wpt');
    160      const offer = await pc.createOffer();
    161      const sections = SDPUtils.splitSections(offer.sdp);
    162      const dtlsParameters = SDPUtils.getDtlsParameters(sections[1], sections[0]);
    163      assert_equals(dtlsParameters.fingerprints[0].algorithm, cert.getFingerprints()[0].algorithm);
    164      // https://www.rfc-editor.org/rfc/rfc4572#section-5 requires uppercase hex in the SDP.
    165      assert_equals(dtlsParameters.fingerprints[0].value, cert.getFingerprints()[0].value.toUpperCase());
    166    })
    167  }, 'generateCertificate() certificate fingerprint shows up in the SDP');
    168 
    169 </script>