Bug 1172785 - Using RTCCertificate for WebRTC, r=ekr

This commit is contained in:
Martin Thomson 2015-07-06 10:40:04 -07:00
parent 35c3c246af
commit 2402691c0f
11 changed files with 407 additions and 158 deletions

View File

@ -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) {

View File

@ -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]

View 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>

View File

@ -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')

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -108,4 +108,3 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
build_for_standalone=1
)
GYP_DIRS['signalingstandalone'].non_unified_sources += signaling_non_unified_sources

View File

@ -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;

View File

@ -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)

View File

@ -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