Bug 1312306 - Update expires handling on RTCCertificate to match spec, r=jib,bkelly
MozReview-Commit-ID: Idnigs48DpY
--- a/dom/media/webrtc/RTCCertificate.cpp
+++ b/dom/media/webrtc/RTCCertificate.cpp
@@ -41,47 +41,24 @@ NS_INTERFACE_MAP_END
const size_t RTCCertificateCommonNameLength = 16;
const size_t RTCCertificateMinRsaSize = 1024;
class GenerateRTCCertificateTask : public GenerateAsymmetricKeyTask
{
public:
GenerateRTCCertificateTask(nsIGlobalObject* aGlobal, JSContext* aCx,
const ObjectOrString& aAlgorithm,
- const Sequence<nsString>& aKeyUsages)
+ const Sequence<nsString>& aKeyUsages,
+ PRTime expires)
: GenerateAsymmetricKeyTask(aGlobal, aCx, aAlgorithm, true, aKeyUsages),
- mExpires(0),
+ mExpires(expires),
mAuthType(ssl_kea_null),
mCertificate(nullptr),
mSignatureAlg(SEC_OID_UNKNOWN)
{
- // Expiry is 30 days after by default.
- // This is a sort of arbitrary range designed to be valid
- // now with some slack in case the other side expects
- // some before expiry.
- //
-
- mExpires = EXPIRATION_DEFAULT;
- if (!aAlgorithm.IsObject()) {
- return;
- }
-
- // Load the "expires" attribute from the algorithm dictionary. This is
- // (currently) non-standard; it exists to support testing of certificate
- // expiration, since one month is too long to wait for a test to run.
- JS::Rooted<JS::Value> exp(aCx, JS::UndefinedValue());
- JS::Rooted<JSObject*> jsval(aCx, aAlgorithm.GetAsObject());
- bool ok = JS_GetProperty(aCx, jsval, "expires", &exp);
- int64_t expval;
- if (ok) {
- ok = JS::ToInt64(aCx, exp, &expval);
- }
- if (ok && expval > 0) {
- mExpires = std::min(expval, EXPIRATION_MAX);
- }
}
private:
PRTime mExpires;
SSLKEAType mAuthType;
ScopedCERTCertificate mCertificate;
SECOidTag mSignatureAlg;
@@ -244,33 +221,67 @@ private:
CERTCertificate* cert = CERT_DupCertificate(mCertificate);
RefPtr<RTCCertificate> result =
new RTCCertificate(mResultPromise->GetParentObject(),
key, cert, mAuthType, mExpires);
mResultPromise->MaybeResolve(result);
}
};
+static PRTime
+ReadExpires(JSContext* aCx, const ObjectOrString& aOptions,
+ ErrorResult& aRv)
+{
+ // This conversion might fail, but we don't really care; use the default.
+ // If this isn't an object, or it doesn't coerce into the right type,
+ // then we won't get the |expires| value. Either will be caught later.
+ RTCCertificateExpiration expiration;
+ if (!aOptions.IsObject()) {
+ return EXPIRATION_DEFAULT;
+ }
+ JS::RootedValue value(aCx, JS::ObjectValue(*aOptions.GetAsObject()));
+ if (!expiration.Init(aCx, value)) {
+ aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+ return 0;
+ }
+
+ if (!expiration.mExpires.WasPassed()) {
+ return EXPIRATION_DEFAULT;
+ }
+ static const uint64_t max =
+ static_cast<uint64_t>(EXPIRATION_MAX / PR_USEC_PER_MSEC);
+ if (expiration.mExpires.Value() > max) {
+ return EXPIRATION_MAX;
+ }
+ return static_cast<PRTime>(expiration.mExpires.Value() * PR_USEC_PER_MSEC);
+}
+
already_AddRefed<Promise>
RTCCertificate::GenerateCertificate(
- const GlobalObject& aGlobal, const ObjectOrString& aKeygenAlgorithm,
+ const GlobalObject& aGlobal, const ObjectOrString& aOptions,
ErrorResult& aRv, JSCompartment* aCompartment)
{
nsIGlobalObject* global = xpc::NativeGlobal(aGlobal.Get());
RefPtr<Promise> p = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
Sequence<nsString> usages;
if (!usages.AppendElement(NS_LITERAL_STRING("sign"), fallible)) {
+ aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return nullptr;
+ }
+
+ PRTime expires = ReadExpires(aGlobal.Context(), aOptions, aRv);
+ if (aRv.Failed()) {
return nullptr;
}
RefPtr<WebCryptoTask> task =
new GenerateRTCCertificateTask(global, aGlobal.Context(),
- aKeygenAlgorithm, usages);
+ aOptions, usages, expires);
task->DispatchWithPromise(p);
return p.forget();
}
RTCCertificate::RTCCertificate(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal),
mPrivateKey(nullptr),
mCertificate(nullptr),
--- a/dom/media/webrtc/RTCCertificate.h
+++ b/dom/media/webrtc/RTCCertificate.h
@@ -14,16 +14,17 @@
#include "prtime.h"
#include "sslt.h"
#include "ScopedNSSTypes.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/RefPtr.h"
#include "mozilla/dom/CryptoKey.h"
+#include "mozilla/dom/RTCCertificateBinding.h"
#include "mtransport/dtlsidentity.h"
#include "js/StructuredClone.h"
#include "js/TypeDecls.h"
namespace mozilla {
namespace dom {
class ObjectOrString;
@@ -34,17 +35,17 @@ class RTCCertificate final
public nsNSSShutDownObject
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(RTCCertificate)
// WebIDL method that implements RTCPeerConnection.generateCertificate.
static already_AddRefed<Promise> GenerateCertificate(
- const GlobalObject& global, const ObjectOrString& keygenAlgorithm,
+ const GlobalObject& aGlobal, const ObjectOrString& aOptions,
ErrorResult& aRv, JSCompartment* aCompartment = nullptr);
explicit RTCCertificate(nsIGlobalObject* aGlobal);
RTCCertificate(nsIGlobalObject* aGlobal, SECKEYPrivateKey* aPrivateKey,
CERTCertificate* aCertificate, SSLKEAType aAuthType,
PRTime aExpires);
nsIGlobalObject* GetParentObject() const { return mGlobal; }
--- a/dom/webidl/RTCCertificate.webidl
+++ b/dom/webidl/RTCCertificate.webidl
@@ -1,12 +1,17 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/.
*
* Specification: http://w3c.github.io/webrtc-pc/#certificate-management
*/
+dictionary RTCCertificateExpiration {
+ [EnforceRange]
+ DOMTimeStamp expires;
+};
+
[Pref="media.peerconnection.enabled"]
interface RTCCertificate {
readonly attribute DOMTimeStamp expires;
};