summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/encryptedmedia/legacy/LegacyCDMSessionClearKey.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/Modules/encryptedmedia/legacy/LegacyCDMSessionClearKey.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/Modules/encryptedmedia/legacy/LegacyCDMSessionClearKey.cpp')
-rw-r--r--Source/WebCore/Modules/encryptedmedia/legacy/LegacyCDMSessionClearKey.cpp209
1 files changed, 209 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/encryptedmedia/legacy/LegacyCDMSessionClearKey.cpp b/Source/WebCore/Modules/encryptedmedia/legacy/LegacyCDMSessionClearKey.cpp
new file mode 100644
index 000000000..e08a368bc
--- /dev/null
+++ b/Source/WebCore/Modules/encryptedmedia/legacy/LegacyCDMSessionClearKey.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LegacyCDMSessionClearKey.h"
+
+#include "JSMainThreadExecState.h"
+#include "Logging.h"
+#include "TextEncoding.h"
+#include "UUID.h"
+#include "WebKitMediaKeyError.h"
+#include <runtime/JSGlobalObject.h>
+#include <runtime/JSLock.h>
+#include <runtime/JSONObject.h>
+#include <runtime/VM.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/Base64.h>
+
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+
+using namespace JSC;
+
+namespace WebCore {
+
+static VM& clearKeyVM()
+{
+ static NeverDestroyed<RefPtr<VM>> vm;
+ if (!vm.get())
+ vm.get() = VM::create();
+
+ return *vm.get();
+}
+
+CDMSessionClearKey::CDMSessionClearKey(CDMSessionClient* client)
+ : m_client(client)
+ , m_sessionId(createCanonicalUUIDString())
+{
+}
+
+CDMSessionClearKey::~CDMSessionClearKey()
+{
+}
+
+RefPtr<Uint8Array> CDMSessionClearKey::generateKeyRequest(const String& mimeType, Uint8Array* initData, String& destinationURL, unsigned short& errorCode, uint32_t& systemCode)
+{
+ UNUSED_PARAM(mimeType);
+ UNUSED_PARAM(destinationURL);
+ UNUSED_PARAM(systemCode);
+
+ if (!initData) {
+ errorCode = WebKitMediaKeyError::MEDIA_KEYERR_CLIENT;
+ return nullptr;
+ }
+ m_initData = initData;
+
+ bool sawError = false;
+ String keyID = UTF8Encoding().decode(reinterpret_cast_ptr<char*>(m_initData->baseAddress()), m_initData->byteLength(), true, sawError);
+ if (sawError) {
+ errorCode = WebKitMediaKeyError::MEDIA_KEYERR_CLIENT;
+ return nullptr;
+ }
+
+ return initData;
+}
+
+void CDMSessionClearKey::releaseKeys()
+{
+ m_cachedKeys.clear();
+}
+
+bool CDMSessionClearKey::update(Uint8Array* rawKeysData, RefPtr<Uint8Array>& nextMessage, unsigned short& errorCode, uint32_t& systemCode)
+{
+ UNUSED_PARAM(nextMessage);
+ UNUSED_PARAM(systemCode);
+ ASSERT(rawKeysData);
+
+ do {
+ auto rawKeysString = String::fromUTF8(rawKeysData->data(), rawKeysData->length());
+ if (rawKeysString.isEmpty()) {
+ LOG(Media, "CDMSessionClearKey::update(%p) - failed: empty message", this);
+ continue;
+ }
+
+ auto& vm = clearKeyVM();
+ JSLockHolder lock(vm);
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ auto* globalObject = JSGlobalObject::create(vm, JSGlobalObject::createStructure(vm, jsNull()));
+ auto& state = *globalObject->globalExec();
+
+ auto keysDataValue = JSONParse(&state, rawKeysString);
+ if (scope.exception() || !keysDataValue.isObject()) {
+ LOG(Media, "CDMSessionClearKey::update(%p) - failed: invalid JSON", this);
+ break;
+ }
+
+ auto keysArrayValue = asObject(keysDataValue)->get(&state, Identifier::fromString(&state, "keys"));
+ if (scope.exception() || !isJSArray(keysArrayValue)) {
+ LOG(Media, "CDMSessionClearKey::update(%p) - failed: keys array missing or empty", this);
+ break;
+ }
+
+ auto keysArray = asArray(keysArrayValue);
+ auto length = keysArray->length();
+ if (!length) {
+ LOG(Media, "CDMSessionClearKey::update(%p) - failed: keys array missing or empty", this);
+ break;
+ }
+
+ bool foundValidKey = false;
+ for (unsigned i = 0; i < length; ++i) {
+ auto keyValue = keysArray->getIndex(&state, i);
+
+ if (scope.exception() || !keyValue.isObject()) {
+ LOG(Media, "CDMSessionClearKey::update(%p) - failed: null keyDictionary", this);
+ continue;
+ }
+
+ auto keyObject = asObject(keyValue);
+
+ auto getStringProperty = [&scope, &state, &keyObject](const char* name) -> String {
+ auto value = keyObject->get(&state, Identifier::fromString(&state, name));
+ if (scope.exception() || !value.isString())
+ return { };
+
+ auto string = asString(value)->value(&state);
+ if (scope.exception())
+ return { };
+
+ return string;
+ };
+
+ auto algorithm = getStringProperty("alg");
+ if (!equalLettersIgnoringASCIICase(algorithm, "a128kw")) {
+ LOG(Media, "CDMSessionClearKey::update(%p) - failed: algorithm unsupported", this);
+ continue;
+ }
+
+ auto keyType = getStringProperty("kty");
+ if (!equalLettersIgnoringASCIICase(keyType, "oct")) {
+ LOG(Media, "CDMSessionClearKey::update(%p) - failed: keyType unsupported", this);
+ continue;
+ }
+
+ auto keyId = getStringProperty("kid");
+ if (keyId.isEmpty()) {
+ LOG(Media, "CDMSessionClearKey::update(%p) - failed: keyId missing or empty", this);
+ continue;
+ }
+
+ auto rawKeyData = getStringProperty("k");
+ if (rawKeyData.isEmpty()) {
+ LOG(Media, "CDMSessionClearKey::update(%p) - failed: key missing or empty", this);
+ continue;
+ }
+
+ Vector<uint8_t> keyData;
+ if (!base64Decode(rawKeyData, keyData) || keyData.isEmpty()) {
+ LOG(Media, "CDMSessionClearKey::update(%p) - failed: unable to base64 decode key", this);
+ continue;
+ }
+
+ m_cachedKeys.set(keyId, WTFMove(keyData));
+ foundValidKey = true;
+ }
+
+ if (foundValidKey)
+ return true;
+
+ } while (false);
+
+ errorCode = WebKitMediaKeyError::MEDIA_KEYERR_CLIENT;
+ return false;
+}
+
+RefPtr<ArrayBuffer> CDMSessionClearKey::cachedKeyForKeyID(const String& keyId) const
+{
+ if (!m_cachedKeys.contains(keyId))
+ return nullptr;
+
+ auto keyData = m_cachedKeys.get(keyId);
+ RefPtr<Uint8Array> keyDataArray = Uint8Array::create(keyData.data(), keyData.size());
+ return keyDataArray->unsharedBuffer();
+}
+
+}
+
+#endif