mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1172785 - Using RTCCertificate for WebRTC, r=ekr
This commit is contained in:
parent
35c3c246af
commit
2402691c0f
@ -388,6 +388,7 @@ RTCPeerConnection.prototype = {
|
||||
|
||||
this._impl.initialize(this._observer, this._win, rtcConfig,
|
||||
Services.tm.currentThread);
|
||||
this._initCertificate(rtcConfig.certificates);
|
||||
this._initIdp();
|
||||
_globalPCList.notifyLifecycleObservers(this, "initialized");
|
||||
},
|
||||
@ -401,6 +402,30 @@ RTCPeerConnection.prototype = {
|
||||
return this._pc;
|
||||
},
|
||||
|
||||
_initCertificate: function(certificates) {
|
||||
let certPromise;
|
||||
if (certificates && certificates.length > 0) {
|
||||
if (certificates.length > 1) {
|
||||
throw new this._win.DOMException(
|
||||
"RTCPeerConnection does not currently support multiple certificates",
|
||||
"NotSupportedError");
|
||||
}
|
||||
let cert = certificates.find(c => c.expires.getTime() > Date.now());
|
||||
if (!cert) {
|
||||
throw new this._win.DOMException(
|
||||
"Unable to create RTCPeerConnection with an expired certificate",
|
||||
"InvalidParameterError");
|
||||
}
|
||||
certPromise = Promise.resolve(cert);
|
||||
} else {
|
||||
certPromise = this._win.mozRTCPeerConnection.generateCertificate({
|
||||
name: "ECDSA", namedCurve: "P-256"
|
||||
});
|
||||
}
|
||||
this._certificateReady = certPromise
|
||||
.then(cert => this._impl.certificate = cert);
|
||||
},
|
||||
|
||||
_initIdp: function() {
|
||||
this._peerIdentity = new this._win.Promise((resolve, reject) => {
|
||||
this._resolvePeerIdentity = resolve;
|
||||
@ -655,11 +680,13 @@ RTCPeerConnection.prototype = {
|
||||
|
||||
let origin = Cu.getWebIDLCallerPrincipal().origin;
|
||||
return this._chain(() => {
|
||||
let p = new this._win.Promise((resolve, reject) => {
|
||||
this._onCreateOfferSuccess = resolve;
|
||||
this._onCreateOfferFailure = reject;
|
||||
this._impl.createOffer(options);
|
||||
});
|
||||
let p = this._certificateReady.then(
|
||||
() => new this._win.Promise((resolve, reject) => {
|
||||
this._onCreateOfferSuccess = resolve;
|
||||
this._onCreateOfferFailure = reject;
|
||||
this._impl.createOffer(options);
|
||||
})
|
||||
);
|
||||
p = this._addIdentityAssertion(p, origin);
|
||||
return p.then(
|
||||
sdp => new this._win.mozRTCSessionDescription({ type: "offer", sdp: sdp }));
|
||||
@ -671,22 +698,24 @@ RTCPeerConnection.prototype = {
|
||||
return this._legacyCatch(onSuccess, onError, () => {
|
||||
let origin = Cu.getWebIDLCallerPrincipal().origin;
|
||||
return this._chain(() => {
|
||||
let p = new this._win.Promise((resolve, reject) => {
|
||||
// We give up line-numbers in errors by doing this here, but do all
|
||||
// state-checks inside the chain, to support the legacy feature that
|
||||
// callers don't have to wait for setRemoteDescription to finish.
|
||||
if (!this.remoteDescription) {
|
||||
throw new this._win.DOMException("setRemoteDescription not called",
|
||||
"InvalidStateError");
|
||||
}
|
||||
if (this.remoteDescription.type != "offer") {
|
||||
throw new this._win.DOMException("No outstanding offer",
|
||||
"InvalidStateError");
|
||||
}
|
||||
this._onCreateAnswerSuccess = resolve;
|
||||
this._onCreateAnswerFailure = reject;
|
||||
this._impl.createAnswer();
|
||||
});
|
||||
let p = this._certificateReady.then(
|
||||
() => new this._win.Promise((resolve, reject) => {
|
||||
// We give up line-numbers in errors by doing this here, but do all
|
||||
// state-checks inside the chain, to support the legacy feature that
|
||||
// callers don't have to wait for setRemoteDescription to finish.
|
||||
if (!this.remoteDescription) {
|
||||
throw new this._win.DOMException("setRemoteDescription not called",
|
||||
"InvalidStateError");
|
||||
}
|
||||
if (this.remoteDescription.type != "offer") {
|
||||
throw new this._win.DOMException("No outstanding offer",
|
||||
"InvalidStateError");
|
||||
}
|
||||
this._onCreateAnswerSuccess = resolve;
|
||||
this._onCreateAnswerFailure = reject;
|
||||
this._impl.createAnswer();
|
||||
})
|
||||
);
|
||||
p = this._addIdentityAssertion(p, origin);
|
||||
return p.then(sdp => {
|
||||
return new this._win.mozRTCSessionDescription({ type: "answer", sdp: sdp });
|
||||
@ -695,7 +724,6 @@ RTCPeerConnection.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
setLocalDescription: function(desc, onSuccess, onError) {
|
||||
return this._legacyCatch(onSuccess, onError, () => {
|
||||
this._localType = desc.type;
|
||||
@ -818,9 +846,11 @@ RTCPeerConnection.prototype = {
|
||||
|
||||
getIdentityAssertion: function() {
|
||||
let origin = Cu.getWebIDLCallerPrincipal().origin;
|
||||
return this._chain(() => {
|
||||
return this._localIdp.getIdentityAssertion(this._impl.fingerprint, origin);
|
||||
});
|
||||
return this._chain(
|
||||
() => this._certificateReady.then(
|
||||
() => this._localIdp.getIdentityAssertion(this._impl.fingerprint, origin)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
updateIce: function(config) {
|
||||
|
@ -94,6 +94,8 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_captureStream_canvas_webgl.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_certificates.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_close.html]
|
||||
[test_peerConnection_closeDuringIce.html]
|
||||
[test_peerConnection_errorCallbacks.html]
|
||||
|
173
dom/media/tests/mochitest/test_peerConnection_certificates.html
Normal file
173
dom/media/tests/mochitest/test_peerConnection_certificates.html
Normal file
@ -0,0 +1,173 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1172785",
|
||||
title: "Certificate management"
|
||||
});
|
||||
|
||||
function badCertificate(config, expectedError, message) {
|
||||
return mozRTCPeerConnection.generateCertificate(config)
|
||||
.then(() => ok(false, message),
|
||||
e => is(e.name, expectedError, message));
|
||||
}
|
||||
|
||||
// Checks a handful of obviously bad options to RTCCertificate.create(). Most
|
||||
// of the checking is done by the WebCrypto code underpinning this, hence the
|
||||
// baffling error codes, but a sanity check is still in order.
|
||||
function checkBadParameters() {
|
||||
return Promise.all([
|
||||
badCertificate({
|
||||
name: "RSASSA-PKCS1-v1_5",
|
||||
hash: "SHA-256",
|
||||
modulusLength: 1023,
|
||||
publicExponent: new Uint8Array([1, 0, 1])
|
||||
}, "NotSupportedError", "1023-bit is too small to succeed"),
|
||||
|
||||
badCertificate({
|
||||
name: "ECDH",
|
||||
namedCurve: "P-256"
|
||||
}, "DataError", "otherwise valid ECDH config is rejected"),
|
||||
|
||||
badCertificate({
|
||||
name: "not a valid algorithm"
|
||||
}, "SyntaxError", "not a valid algorithm"),
|
||||
|
||||
badCertificate("ECDSA", "SyntaxError", "a bare name is not enough"),
|
||||
|
||||
badCertificate({
|
||||
name: "ECDSA",
|
||||
namedCurve: "not a curve"
|
||||
}, "NotSupportedError", "ECDSA with an unknown curve")
|
||||
]);
|
||||
}
|
||||
|
||||
function createDB() {
|
||||
var openDB = indexedDB.open("genericstore");
|
||||
openDB.onupgradeneeded = e => {
|
||||
var db = e.target.result;
|
||||
db.createObjectStore("data");
|
||||
};
|
||||
return new Promise(resolve => {
|
||||
openDB.onsuccess = e => resolve(e.target.result);
|
||||
});
|
||||
}
|
||||
|
||||
function resultPromise(tx, op) {
|
||||
return new Promise((resolve, reject) => {
|
||||
op.onsuccess = e => resolve(e.target.result);
|
||||
op.onerror = () => reject(op.error);
|
||||
tx.onabort = () => reject(tx.error);
|
||||
});
|
||||
}
|
||||
|
||||
function store(db, value) {
|
||||
var tx = db.transaction("data", "readwrite");
|
||||
var store = tx.objectStore("data");
|
||||
return resultPromise(tx, store.put(value, "value"));
|
||||
}
|
||||
|
||||
function retrieve(db) {
|
||||
var tx = db.transaction("data", "readonly");
|
||||
var store = tx.objectStore("data");
|
||||
return resultPromise(tx, store.get("value"));
|
||||
}
|
||||
|
||||
// Creates a database, stores a value, retrieves it.
|
||||
function storeAndRetrieve(value) {
|
||||
return createDB().then(db => {
|
||||
return store(db, value)
|
||||
.then(() => retrieve(db))
|
||||
.then(retrieved => {
|
||||
db.close();
|
||||
return retrieved;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
var expiredCert;
|
||||
return Promise.resolve()
|
||||
.then(() => mozRTCPeerConnection.generateCertificate({
|
||||
name: "ECDSA",
|
||||
namedCurve: "P-256",
|
||||
expires: 1 // smallest possible expiration window
|
||||
}))
|
||||
.then(cert => {
|
||||
ok(cert.expires instanceof Date, 'cert has expiration time');
|
||||
info('Expires at ' + cert.expires);
|
||||
expiredCert = cert;
|
||||
})
|
||||
|
||||
.then(() => checkBadParameters())
|
||||
|
||||
.then(() => {
|
||||
var delay = expiredCert.expires.getTime() - Date.now();
|
||||
// Hopefully this delay is never needed.
|
||||
if (delay > 0) {
|
||||
return new Promise(r => setTimeout(r, delay));
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
ok(expiredCert.expires <= Date.now(), 'Cert should be at or past expiration');
|
||||
try {
|
||||
new mozRTCPeerConnection({ certificates: [expiredCert] });
|
||||
ok(false, 'Constructing peer connection with an expired cert is not allowed');
|
||||
} catch(e) {
|
||||
is(e.name, 'InvalidParameterError',
|
||||
'Constructing peer connection with an expired certs is not allowed');
|
||||
}
|
||||
})
|
||||
|
||||
.then(() => Promise.all([
|
||||
mozRTCPeerConnection.generateCertificate({
|
||||
name: "ECDSA",
|
||||
namedCurve: "P-256"
|
||||
}),
|
||||
mozRTCPeerConnection.generateCertificate({
|
||||
name: "RSASSA-PKCS1-v1_5",
|
||||
hash: "SHA-256",
|
||||
modulusLength: 2048,
|
||||
publicExponent: new Uint8Array([1, 0, 1])
|
||||
})
|
||||
]))
|
||||
|
||||
// A round trip through indexedDB should not do anything.
|
||||
.then(storeAndRetrieve)
|
||||
.then(certs => {
|
||||
try {
|
||||
new mozRTCPeerConnection({ certificates: certs });
|
||||
ok(false, 'Constructing peer connection with multiple certs is not allowed');
|
||||
} catch(e) {
|
||||
is(e.name, 'NotSupportedError',
|
||||
'Constructing peer connection with multiple certs is not allowed');
|
||||
}
|
||||
return certs;
|
||||
})
|
||||
.then(certs => {
|
||||
test = new PeerConnectionTest({
|
||||
config_local: {
|
||||
certificates: [certs[0]]
|
||||
},
|
||||
config_remote: {
|
||||
certificates: [certs[1]]
|
||||
}
|
||||
});
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
return test.run();
|
||||
})
|
||||
.catch(e => {
|
||||
console.log('test failure', e);
|
||||
ok(false, 'test failed: ' + e);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -59,11 +59,15 @@ XPIDL_SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'MediaEngineDefault.cpp',
|
||||
'PeerIdentity.cpp',
|
||||
'RTCCertificate.cpp',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'PeerIdentity.h',
|
||||
]
|
||||
EXPORTS.mozilla.dom += [
|
||||
'RTCCertificate.h',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
|
@ -4,30 +4,26 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <iomanip>
|
||||
#include "logging.h"
|
||||
#include "nspr.h"
|
||||
#include "cryptohi.h"
|
||||
#include "ssl.h"
|
||||
#include "keyhi.h"
|
||||
#include "pk11pub.h"
|
||||
#include "sechash.h"
|
||||
#include "nsError.h"
|
||||
#include "dtlsidentity.h"
|
||||
|
||||
#include "cert.h"
|
||||
#include "cryptohi.h"
|
||||
#include "keyhi.h"
|
||||
#include "nsError.h"
|
||||
#include "pk11pub.h"
|
||||
#include "prprf.h"
|
||||
#include "sechash.h"
|
||||
#include "ssl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
DtlsIdentity::~DtlsIdentity() {
|
||||
// XXX: make cert_ a smart pointer to avoid this, after we figure
|
||||
// out the linking problem.
|
||||
if (cert_)
|
||||
if (cert_) {
|
||||
CERT_DestroyCertificate(cert_);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string DtlsIdentity::DEFAULT_HASH_ALGORITHM = "sha-256";
|
||||
|
||||
already_AddRefed<DtlsIdentity> DtlsIdentity::Generate() {
|
||||
|
||||
RefPtr<DtlsIdentity> DtlsIdentity::Generate() {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
if (!slot) {
|
||||
return nullptr;
|
||||
@ -53,10 +49,16 @@ already_AddRefed<DtlsIdentity> DtlsIdentity::Generate() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PK11RSAGenParams rsaparams;
|
||||
rsaparams.keySizeInBits = 1024; // TODO: make this stronger when we
|
||||
// pre-generate.
|
||||
rsaparams.pe = 65537; // We are too paranoid to use 3 as the exponent.
|
||||
unsigned char paramBuf[12]; // OIDs are small
|
||||
SECItem ecdsaParams = { siBuffer, paramBuf, sizeof(paramBuf) };
|
||||
SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
|
||||
if (!oidData || (oidData->oid.len > (sizeof(paramBuf) - 2))) {
|
||||
return nullptr;
|
||||
}
|
||||
ecdsaParams.data[0] = SEC_ASN1_OBJECT_ID;
|
||||
ecdsaParams.data[1] = oidData->oid.len;
|
||||
memcpy(ecdsaParams.data + 2, oidData->oid.data, oidData->oid.len);
|
||||
ecdsaParams.len = oidData->oid.len + 2;
|
||||
|
||||
ScopedSECKEYPrivateKey private_key;
|
||||
ScopedSECKEYPublicKey public_key;
|
||||
@ -64,7 +66,7 @@ already_AddRefed<DtlsIdentity> DtlsIdentity::Generate() {
|
||||
|
||||
private_key =
|
||||
PK11_GenerateKeyPair(slot,
|
||||
CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaparams, &pubkey,
|
||||
CKM_EC_KEY_PAIR_GEN, &ecdsaParams, &pubkey,
|
||||
PR_FALSE, PR_TRUE, nullptr);
|
||||
if (private_key == nullptr)
|
||||
return nullptr;
|
||||
@ -120,7 +122,7 @@ already_AddRefed<DtlsIdentity> DtlsIdentity::Generate() {
|
||||
PLArenaPool *arena = certificate->arena;
|
||||
|
||||
rv = SECOID_SetAlgorithmID(arena, &certificate->signature,
|
||||
SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, 0);
|
||||
SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0);
|
||||
if (rv != SECSuccess)
|
||||
return nullptr;
|
||||
|
||||
@ -144,32 +146,34 @@ already_AddRefed<DtlsIdentity> DtlsIdentity::Generate() {
|
||||
|
||||
rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len,
|
||||
private_key,
|
||||
SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION);
|
||||
SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
|
||||
if (rv != SECSuccess) {
|
||||
return nullptr;
|
||||
}
|
||||
certificate->derCert = *signedCert;
|
||||
|
||||
RefPtr<DtlsIdentity> identity =
|
||||
new DtlsIdentity(private_key.forget(), certificate.forget());
|
||||
new DtlsIdentity(private_key.forget(), certificate.forget(), ssl_kea_ecdh);
|
||||
return identity.forget();
|
||||
}
|
||||
|
||||
const std::string DtlsIdentity::DEFAULT_HASH_ALGORITHM = "sha-256";
|
||||
|
||||
nsresult DtlsIdentity::ComputeFingerprint(const std::string algorithm,
|
||||
unsigned char *digest,
|
||||
std::size_t size,
|
||||
std::size_t *digest_length) {
|
||||
MOZ_ASSERT(cert_);
|
||||
uint8_t *digest,
|
||||
size_t size,
|
||||
size_t *digest_length) const {
|
||||
const CERTCertificate* c = cert();
|
||||
MOZ_ASSERT(c);
|
||||
|
||||
return ComputeFingerprint(cert_, algorithm, digest, size, digest_length);
|
||||
return ComputeFingerprint(c, algorithm, digest, size, digest_length);
|
||||
}
|
||||
|
||||
nsresult DtlsIdentity::ComputeFingerprint(const CERTCertificate *cert,
|
||||
const std::string algorithm,
|
||||
unsigned char *digest,
|
||||
std::size_t size,
|
||||
std::size_t *digest_length) {
|
||||
uint8_t *digest,
|
||||
size_t size,
|
||||
size_t *digest_length) {
|
||||
MOZ_ASSERT(cert);
|
||||
|
||||
HASH_HashType ht;
|
||||
@ -190,19 +194,22 @@ nsresult DtlsIdentity::ComputeFingerprint(const CERTCertificate *cert,
|
||||
|
||||
const SECHashObject *ho = HASH_GetHashObject(ht);
|
||||
MOZ_ASSERT(ho);
|
||||
if (!ho)
|
||||
if (!ho) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(ho->length >= 20); // Double check
|
||||
|
||||
if (size < ho->length)
|
||||
if (size < ho->length) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
SECStatus rv = HASH_HashBuf(ho->type, digest,
|
||||
cert->derCert.data,
|
||||
cert->derCert.len);
|
||||
if (rv != SECSuccess)
|
||||
if (rv != SECSuccess) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*digest_length = ho->length;
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "m_cpp_utils.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "sslt.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
|
||||
// All code in this module requires NSS to be live.
|
||||
@ -18,31 +19,38 @@
|
||||
// protocol.
|
||||
namespace mozilla {
|
||||
|
||||
class DtlsIdentity {
|
||||
private:
|
||||
~DtlsIdentity();
|
||||
|
||||
class DtlsIdentity final {
|
||||
public:
|
||||
// Generate an identity with a random name.
|
||||
static already_AddRefed<DtlsIdentity> Generate();
|
||||
// This constructor takes ownership of privkey and cert.
|
||||
DtlsIdentity(SECKEYPrivateKey *privkey,
|
||||
CERTCertificate *cert,
|
||||
SSLKEAType authType)
|
||||
: private_key_(privkey), cert_(cert), auth_type_(authType) {}
|
||||
|
||||
// Note: the following two functions just provide access. They
|
||||
// do not transfer ownership. If you want a pointer that lasts
|
||||
// past the lifetime of the DtlsIdentity, you must make
|
||||
// a copy yourself.
|
||||
CERTCertificate *cert() { return cert_; }
|
||||
SECKEYPrivateKey *privkey() { return privkey_; }
|
||||
// This is only for use in tests, or for external linkage. It makes a (bad)
|
||||
// instance of this class.
|
||||
static RefPtr<DtlsIdentity> Generate();
|
||||
|
||||
// These don't create copies or transfer ownership. If you want these to live
|
||||
// on, make a copy.
|
||||
CERTCertificate *cert() const { return cert_; }
|
||||
SECKEYPrivateKey *privkey() const { return private_key_; }
|
||||
// Note: this uses SSLKEAType because that is what the libssl API requires.
|
||||
// This is a giant confusing mess, but libssl indexes certificates based on a
|
||||
// key exchange type, not authentication type (as you might have reasonably
|
||||
// expected).
|
||||
SSLKEAType auth_type() const { return auth_type_; }
|
||||
|
||||
nsresult ComputeFingerprint(const std::string algorithm,
|
||||
unsigned char *digest,
|
||||
std::size_t size,
|
||||
std::size_t *digest_length);
|
||||
|
||||
uint8_t *digest,
|
||||
size_t size,
|
||||
size_t *digest_length) const;
|
||||
static nsresult ComputeFingerprint(const CERTCertificate *cert,
|
||||
const std::string algorithm,
|
||||
unsigned char *digest,
|
||||
std::size_t size,
|
||||
std::size_t *digest_length);
|
||||
uint8_t *digest,
|
||||
size_t size,
|
||||
size_t *digest_length);
|
||||
|
||||
static const std::string DEFAULT_HASH_ALGORITHM;
|
||||
enum {
|
||||
HASH_ALGORITHM_MAX_LENGTH = 64
|
||||
@ -50,14 +58,14 @@ class DtlsIdentity {
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DtlsIdentity)
|
||||
|
||||
private:
|
||||
DtlsIdentity(SECKEYPrivateKey *privkey, CERTCertificate *cert)
|
||||
: privkey_(privkey), cert_(cert) {}
|
||||
private:
|
||||
~DtlsIdentity();
|
||||
DISALLOW_COPY_ASSIGN(DtlsIdentity);
|
||||
|
||||
ScopedSECKEYPrivateKey privkey_;
|
||||
ScopedSECKEYPrivateKey private_key_;
|
||||
CERTCertificate *cert_; // TODO: Using a smart pointer here causes link
|
||||
// errors.
|
||||
SSLKEAType auth_type_;
|
||||
};
|
||||
} // close namespace
|
||||
#endif
|
||||
|
@ -497,7 +497,7 @@ bool TransportLayerDtls::Setup() {
|
||||
// Server side
|
||||
rv = SSL_ConfigSecureServer(ssl_fd, identity_->cert(),
|
||||
identity_->privkey(),
|
||||
kt_rsa);
|
||||
identity_->auth_type());
|
||||
if (rv != SECSuccess) {
|
||||
MOZ_MTLOG(ML_ERROR, "Couldn't set identity");
|
||||
return false;
|
||||
|
@ -108,4 +108,3 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
|
||||
build_for_standalone=1
|
||||
)
|
||||
GYP_DIRS['signalingstandalone'].non_unified_sources += signaling_non_unified_sources
|
||||
|
||||
|
@ -177,7 +177,7 @@ MediaPipelineFactory::CreateOrGetTransportFlow(
|
||||
? TransportLayerDtls::CLIENT
|
||||
: TransportLayerDtls::SERVER);
|
||||
|
||||
RefPtr<DtlsIdentity> pcid = mPC->GetIdentity();
|
||||
RefPtr<DtlsIdentity> pcid = mPC->Identity();
|
||||
if (!pcid) {
|
||||
MOZ_MTLOG(ML_ERROR, "Failed to get DTLS identity.");
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -74,6 +74,7 @@
|
||||
#include "nsIDOMLocation.h"
|
||||
#include "nsNullPrincipal.h"
|
||||
#include "mozilla/PeerIdentity.h"
|
||||
#include "mozilla/dom/RTCCertificate.h"
|
||||
#include "mozilla/dom/RTCConfigurationBinding.h"
|
||||
#include "mozilla/dom/RTCStatsReportBinding.h"
|
||||
#include "mozilla/dom/RTCPeerConnectionBinding.h"
|
||||
@ -372,7 +373,11 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
|
||||
, mIceGatheringState(PCImplIceGatheringState::New)
|
||||
, mDtlsConnected(false)
|
||||
, mWindow(nullptr)
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
, mCertificate(nullptr)
|
||||
#else
|
||||
, mIdentity(nullptr)
|
||||
#endif
|
||||
, mPrivacyRequested(false)
|
||||
, mSTSThread(nullptr)
|
||||
, mAllowIceLoopback(false)
|
||||
@ -424,17 +429,6 @@ PeerConnectionImpl::~PeerConnectionImpl()
|
||||
|
||||
Close();
|
||||
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
{
|
||||
// Deregister as an NSS Shutdown Object
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (!isAlreadyShutDown()) {
|
||||
destructorSafeDestroyNSSReference();
|
||||
shutdown(calledFromObject);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Since this and Initialize() occur on MainThread, they can't both be
|
||||
// running at once
|
||||
|
||||
@ -751,16 +745,6 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
|
||||
|
||||
PeerConnectionCtx::GetInstance()->mPeerConnections[mHandle] = this;
|
||||
|
||||
STAMP_TIMECARD(mTimeCard, "Generating DTLS Identity");
|
||||
// Create the DTLS Identity
|
||||
mIdentity = DtlsIdentity::Generate();
|
||||
STAMP_TIMECARD(mTimeCard, "Done Generating DTLS Identity");
|
||||
|
||||
if (!mIdentity) {
|
||||
CSFLogError(logTag, "%s: Generate returned NULL", __FUNCTION__);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mJsepSession = MakeUnique<JsepSessionImpl>(mName,
|
||||
MakeUnique<PCUuidGenerator>());
|
||||
|
||||
@ -781,17 +765,23 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
|
||||
return res;
|
||||
}
|
||||
|
||||
const std::string& fpAlg = DtlsIdentity::DEFAULT_HASH_ALGORITHM;
|
||||
std::vector<uint8_t> fingerprint;
|
||||
res = CalculateFingerprint(fpAlg, fingerprint);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
res = mJsepSession->AddDtlsFingerprint(fpAlg, fingerprint);
|
||||
if (NS_FAILED(res)) {
|
||||
CSFLogError(logTag, "%s: Couldn't set DTLS credentials, res=%u",
|
||||
__FUNCTION__,
|
||||
static_cast<unsigned>(res));
|
||||
return res;
|
||||
#if defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
{
|
||||
mIdentity = DtlsIdentity::Generate();
|
||||
if (!mIdentity) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> fingerprint;
|
||||
res = CalculateFingerprint(DtlsIdentity::DEFAULT_HASH_ALGORITHM,
|
||||
&fingerprint);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
res = mJsepSession->AddDtlsFingerprint(DtlsIdentity::DEFAULT_HASH_ALGORITHM,
|
||||
fingerprint);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
#endif
|
||||
|
||||
res = mJsepSession->SetBundlePolicy(aConfiguration.getBundlePolicy());
|
||||
if (NS_FAILED(res)) {
|
||||
@ -833,6 +823,53 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
void
|
||||
PeerConnectionImpl::SetCertificate(mozilla::dom::RTCCertificate& aCertificate)
|
||||
{
|
||||
PC_AUTO_ENTER_API_CALL_NO_CHECK();
|
||||
MOZ_ASSERT(!mCertificate, "This can only be called once");
|
||||
mCertificate = &aCertificate;
|
||||
|
||||
std::vector<uint8_t> fingerprint;
|
||||
nsresult rv = CalculateFingerprint(DtlsIdentity::DEFAULT_HASH_ALGORITHM,
|
||||
&fingerprint);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(logTag, "%s: Couldn't calculate fingerprint, rv=%u",
|
||||
__FUNCTION__, static_cast<unsigned>(rv));
|
||||
mCertificate = nullptr;
|
||||
return;
|
||||
}
|
||||
rv = mJsepSession->AddDtlsFingerprint(DtlsIdentity::DEFAULT_HASH_ALGORITHM,
|
||||
fingerprint);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(logTag, "%s: Couldn't set DTLS credentials, rv=%u",
|
||||
__FUNCTION__, static_cast<unsigned>(rv));
|
||||
mCertificate = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const nsRefPtr<mozilla::dom::RTCCertificate>&
|
||||
PeerConnectionImpl::Certificate() const
|
||||
{
|
||||
PC_AUTO_ENTER_API_CALL_NO_CHECK();
|
||||
return mCertificate;
|
||||
}
|
||||
#endif
|
||||
|
||||
mozilla::RefPtr<DtlsIdentity>
|
||||
PeerConnectionImpl::Identity() const
|
||||
{
|
||||
PC_AUTO_ENTER_API_CALL_NO_CHECK();
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
MOZ_ASSERT(mCertificate);
|
||||
return mCertificate->CreateDtlsIdentity();
|
||||
#else
|
||||
mozilla::RefPtr<DtlsIdentity> id = mIdentity;
|
||||
return id;
|
||||
#endif
|
||||
}
|
||||
|
||||
class CompareCodecPriority {
|
||||
public:
|
||||
void SetPreferredCodec(int32_t preferredCodec) {
|
||||
@ -1025,13 +1062,6 @@ PeerConnectionImpl::ConfigureJsepSessionCodecs() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<DtlsIdentity> const
|
||||
PeerConnectionImpl::GetIdentity() const
|
||||
{
|
||||
PC_AUTO_ENTER_API_CALL_NO_CHECK();
|
||||
return mIdentity;
|
||||
}
|
||||
|
||||
// Data channels won't work without a window, so in order for the C++ unit
|
||||
// tests to work (it doesn't have a window available) we ifdef the following
|
||||
// two implementations.
|
||||
@ -2206,18 +2236,27 @@ PeerConnectionImpl::ReplaceTrack(MediaStreamTrack& aThisTrack,
|
||||
nsresult
|
||||
PeerConnectionImpl::CalculateFingerprint(
|
||||
const std::string& algorithm,
|
||||
std::vector<uint8_t>& fingerprint) const {
|
||||
std::vector<uint8_t>* fingerprint) const {
|
||||
uint8_t buf[DtlsIdentity::HASH_ALGORITHM_MAX_LENGTH];
|
||||
size_t len = 0;
|
||||
nsresult rv = mIdentity->ComputeFingerprint(algorithm, &buf[0], sizeof(buf),
|
||||
&len);
|
||||
CERTCertificate* cert;
|
||||
|
||||
MOZ_ASSERT(fingerprint);
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
cert = mCertificate->Certificate();
|
||||
#else
|
||||
cert = mIdentity->cert();
|
||||
#endif
|
||||
nsresult rv = DtlsIdentity::ComputeFingerprint(cert, algorithm,
|
||||
&buf[0], sizeof(buf),
|
||||
&len);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(logTag, "Unable to calculate certificate fingerprint, rv=%u",
|
||||
static_cast<unsigned>(rv));
|
||||
return rv;
|
||||
}
|
||||
MOZ_ASSERT(len > 0 && len <= DtlsIdentity::HASH_ALGORITHM_MAX_LENGTH);
|
||||
fingerprint.assign(buf, buf + len);
|
||||
fingerprint->assign(buf, buf + len);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2225,9 +2264,11 @@ NS_IMETHODIMP
|
||||
PeerConnectionImpl::GetFingerprint(char** fingerprint)
|
||||
{
|
||||
MOZ_ASSERT(fingerprint);
|
||||
MOZ_ASSERT(mIdentity);
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
MOZ_ASSERT(mCertificate);
|
||||
#endif
|
||||
std::vector<uint8_t> fp;
|
||||
nsresult rv = CalculateFingerprint(DtlsIdentity::DEFAULT_HASH_ALGORITHM, fp);
|
||||
nsresult rv = CalculateFingerprint(DtlsIdentity::DEFAULT_HASH_ALGORITHM, &fp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
std::ostringstream os;
|
||||
os << DtlsIdentity::DEFAULT_HASH_ALGORITHM << ' '
|
||||
@ -2427,25 +2468,6 @@ PeerConnectionImpl::ShutdownMedia()
|
||||
mMedia.forget().take()->SelfDestruct();
|
||||
}
|
||||
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
// If NSS is shutting down, then we need to get rid of the DTLS
|
||||
// identity right now; otherwise, we'll cause wreckage when we do
|
||||
// finally deallocate it in our destructor.
|
||||
void
|
||||
PeerConnectionImpl::virtualDestroyNSSReference()
|
||||
{
|
||||
destructorSafeDestroyNSSReference();
|
||||
}
|
||||
|
||||
void
|
||||
PeerConnectionImpl::destructorSafeDestroyNSSReference()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
CSFLogDebug(logTag, "%s: NSS shutting down; freeing our DtlsIdentity.", __FUNCTION__);
|
||||
mIdentity = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState,
|
||||
bool rollback)
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include "mozilla/net/DataChannel.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "VideoSegment.h"
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "mozilla/dom/RTCStatsReportBinding.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "mozilla/PeerIdentity.h"
|
||||
@ -78,6 +77,7 @@ class DOMMediaStream;
|
||||
#endif
|
||||
|
||||
namespace dom {
|
||||
class RTCCertificate;
|
||||
struct RTCConfiguration;
|
||||
struct RTCIceServer;
|
||||
struct RTCOfferOptions;
|
||||
@ -242,7 +242,6 @@ class RTCStatsQuery {
|
||||
class PeerConnectionImpl final : public nsISupports,
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
public mozilla::DataChannelConnection::DataConnectionListener,
|
||||
public nsNSSShutDownObject,
|
||||
public DOMMediaStream::PrincipalChangeObserver,
|
||||
#endif
|
||||
public sigslot::has_slots<>
|
||||
@ -333,9 +332,6 @@ public:
|
||||
return mSTSThread;
|
||||
}
|
||||
|
||||
// Get the DTLS identity (local side)
|
||||
mozilla::RefPtr<DtlsIdentity> const GetIdentity() const;
|
||||
|
||||
nsPIDOMWindow* GetWindow() const {
|
||||
PC_AUTO_ENTER_API_CALL_NO_CHECK();
|
||||
return mWindow;
|
||||
@ -358,6 +354,13 @@ public:
|
||||
ErrorResult &rv);
|
||||
#endif
|
||||
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
void SetCertificate(mozilla::dom::RTCCertificate& aCertificate);
|
||||
const nsRefPtr<mozilla::dom::RTCCertificate>& Certificate() const;
|
||||
#endif
|
||||
// This is a hack to support external linkage.
|
||||
mozilla::RefPtr<DtlsIdentity> Identity() const;
|
||||
|
||||
NS_IMETHODIMP_TO_ERRORRESULT(CreateOffer, ErrorResult &rv,
|
||||
const RTCOfferOptions& aOptions)
|
||||
{
|
||||
@ -620,7 +623,7 @@ private:
|
||||
PeerConnectionImpl(const PeerConnectionImpl&rhs);
|
||||
PeerConnectionImpl& operator=(PeerConnectionImpl);
|
||||
nsresult CalculateFingerprint(const std::string& algorithm,
|
||||
std::vector<uint8_t>& fingerprint) const;
|
||||
std::vector<uint8_t>* fingerprint) const;
|
||||
nsresult ConfigureJsepSessionCodecs();
|
||||
|
||||
NS_IMETHODIMP EnsureDataConnection(uint16_t aNumstreams);
|
||||
@ -645,8 +648,6 @@ private:
|
||||
}
|
||||
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
void virtualDestroyNSSReference() final;
|
||||
void destructorSafeDestroyNSSReference();
|
||||
nsresult GetTimeSinceEpoch(DOMHighResTimeStamp *result);
|
||||
#endif
|
||||
|
||||
@ -713,11 +714,14 @@ private:
|
||||
std::string mRemoteFingerprint;
|
||||
|
||||
// identity-related fields
|
||||
mozilla::RefPtr<DtlsIdentity> mIdentity;
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
// The entity on the other end of the peer-to-peer connection;
|
||||
// void if they are not yet identified, and no identity setting has been set
|
||||
nsAutoPtr<PeerIdentity> mPeerIdentity;
|
||||
// The certificate we are using.
|
||||
nsRefPtr<mozilla::dom::RTCCertificate> mCertificate;
|
||||
#else
|
||||
mozilla::RefPtr<DtlsIdentity> mIdentity;
|
||||
#endif
|
||||
// Whether an app should be prevented from accessing media produced by the PC
|
||||
// If this is true, then media will not be sent until mPeerIdentity matches
|
||||
|
Loading…
Reference in New Issue
Block a user