ScriptPromise SubtleCrypto::unwrapKey(ScriptState* scriptState, const String& rawFormat, const DOMArrayPiece& wrappedKey, CryptoKey* unwrappingKey, const AlgorithmIdentifier& rawUnwrapAlgorithm, const AlgorithmIdentifier& rawUnwrappedKeyAlgorithm, bool extractable, const Vector<String>& rawKeyUsages) { RefPtrWillBeRawPtr<CryptoResultImpl> result = CryptoResultImpl::create(scriptState); ScriptPromise promise = result->promise(); if (!canAccessWebCrypto(scriptState, result.get())) return promise; WebCryptoKeyFormat format; if (!CryptoKey::parseFormat(rawFormat, format, result.get())) return promise; WebCryptoKeyUsageMask keyUsages; if (!CryptoKey::parseUsageMask(rawKeyUsages, keyUsages, result.get())) return promise; WebCryptoAlgorithm unwrapAlgorithm; if (!parseAlgorithm(rawUnwrapAlgorithm, WebCryptoOperationUnwrapKey, unwrapAlgorithm, result.get())) return promise; WebCryptoAlgorithm unwrappedKeyAlgorithm; if (!parseAlgorithm(rawUnwrappedKeyAlgorithm, WebCryptoOperationImportKey, unwrappedKeyAlgorithm, result.get())) return promise; if (!unwrappingKey->canBeUsedForAlgorithm(unwrapAlgorithm, WebCryptoKeyUsageUnwrapKey, result.get())) return promise; histogramAlgorithmAndKey(scriptState->executionContext(), unwrapAlgorithm, unwrappingKey->key()); histogramAlgorithm(scriptState->executionContext(), unwrappedKeyAlgorithm); Platform::current()->crypto()->unwrapKey(format, wrappedKey.bytes(), wrappedKey.byteLength(), unwrappingKey->key(), unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages, result->result()); return promise; }
ScriptPromise MediaKeys::setServerCertificate(ScriptState* scriptState, const DOMArrayPiece& serverCertificate) { // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-setservercertificate: // The setServerCertificate(serverCertificate) method provides a server // certificate to be used to encrypt messages to the license server. // It must run the following steps: // 1. If serverCertificate is an empty array, return a promise rejected // with a new DOMException whose name is "InvalidAccessError". if (!serverCertificate.byteLength()) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(InvalidAccessError, "The serverCertificate parameter is empty.")); } // 2. If the keySystem does not support server certificates, return a // promise rejected with a new DOMException whose name is // "NotSupportedError". // (Let the CDM decide whether to support this or not.) // 3. Let certificate be a copy of the contents of the serverCertificate // parameter. RefPtr<DOMArrayBuffer> serverCertificateBuffer = DOMArrayBuffer::create(serverCertificate.data(), serverCertificate.byteLength()); // 4. Let promise be a new promise. SimpleContentDecryptionModuleResultPromise* result = new SimpleContentDecryptionModuleResultPromise(scriptState); ScriptPromise promise = result->promise(); // 5. Run the following steps asynchronously (documented in timerFired()). m_pendingActions.append(PendingAction::CreatePendingSetServerCertificate(result, serverCertificateBuffer.release())); if (!m_timer.isActive()) m_timer.startOneShot(0, FROM_HERE); // 6. Return promise. return promise; }
ScriptPromise SubtleCrypto::digest(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, const DOMArrayPiece& data) { RefPtrWillBeRawPtr<CryptoResultImpl> result = CryptoResultImpl::create(scriptState); ScriptPromise promise = result->promise(); if (!canAccessWebCrypto(scriptState, result.get())) return promise; WebCryptoAlgorithm algorithm; if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationDigest, algorithm, result.get())) return promise; histogramAlgorithm(scriptState->executionContext(), algorithm); Platform::current()->crypto()->digest(algorithm, data.bytes(), data.byteLength(), result->result()); return promise; }
ScriptPromise SubtleCrypto::sign(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, CryptoKey* key, const DOMArrayPiece& data) { RefPtrWillBeRawPtr<CryptoResultImpl> result = CryptoResultImpl::create(scriptState); ScriptPromise promise = result->promise(); if (!canAccessWebCrypto(scriptState, result.get())) return promise; WebCryptoAlgorithm algorithm; if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationSign, algorithm, result.get())) return promise; if (!key->canBeUsedForAlgorithm(algorithm, WebCryptoKeyUsageSign, result.get())) return promise; histogramAlgorithmAndKey(scriptState->executionContext(), algorithm, key->key()); Platform::current()->crypto()->sign(algorithm, key->key(), data.bytes(), data.byteLength(), result->result()); return promise; }
ScriptPromise MediaKeys::setServerCertificate( ScriptState* scriptState, const DOMArrayPiece& serverCertificate) { // From https://w3c.github.io/encrypted-media/#setServerCertificate // The setServerCertificate(serverCertificate) method provides a server // certificate to be used to encrypt messages to the license server. // It must run the following steps: // 1. If the Key System implementation represented by this object's cdm // implementation value does not support server certificates, return // a promise resolved with false. // TODO(jrummell): Provide a way to determine if the CDM supports this. // http://crbug.com/647816. // // 2. If serverCertificate is an empty array, return a promise rejected // with a new a newly created TypeError. if (!serverCertificate.byteLength()) { return ScriptPromise::reject( scriptState, V8ThrowException::createTypeError( scriptState->isolate(), "The serverCertificate parameter is empty.")); } // 3. Let certificate be a copy of the contents of the serverCertificate // parameter. DOMArrayBuffer* serverCertificateBuffer = DOMArrayBuffer::create( serverCertificate.data(), serverCertificate.byteLength()); // 4. Let promise be a new promise. SetCertificateResultPromise* result = new SetCertificateResultPromise(scriptState, this); ScriptPromise promise = result->promise(); // 5. Run the following steps asynchronously (documented in timerFired()). m_pendingActions.append(PendingAction::CreatePendingSetServerCertificate( result, serverCertificateBuffer)); if (!m_timer.isActive()) m_timer.startOneShot(0, BLINK_FROM_HERE); // 6. Return promise. return promise; }
ScriptPromise BluetoothGATTCharacteristic::writeValue(ScriptState* scriptState, const DOMArrayPiece& value) { WebBluetooth* webbluetooth = BluetoothSupplement::fromScriptState(scriptState); // Partial implementation of writeValue algorithm: // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattcharacteristic-writevalue // If bytes is more than 512 bytes long (the maximum length of an attribute // value, per Long Attribute Values) return a promise rejected with an // InvalidModificationError and abort. if (value.byteLength() > 512) return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(InvalidModificationError, "Value can't exceed 512 bytes.")); // Let valueVector be a copy of the bytes held by value. WebVector<uint8_t> valueVector(value.bytes(), value.byteLength()); ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); webbluetooth->writeValue(m_webCharacteristic->characteristicInstanceID, valueVector, new CallbackPromiseAdapter<void, BluetoothError>(resolver)); return promise; }
ScriptPromise MediaKeySession::update(ScriptState* scriptState, const DOMArrayPiece& response) { WTF_LOG(Media, "MediaKeySession(%p)::update", this); ASSERT(!m_isClosed); // From https://w3c.github.io/encrypted-media/#update: // Provides messages, including licenses, to the CDM. When this method is // invoked, the user agent must run the following steps: // 1. If this object's callable value is false, return a promise rejected // with a new DOMException whose name is InvalidStateError. if (!m_isCallable) return CreateRejectedPromiseNotCallable(scriptState); // 2. If response is an empty array, return a promise rejected with a // new DOMException whose name is InvalidAccessError. if (!response.byteLength()) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(InvalidAccessError, "The response parameter is empty.")); } // 3. Let response copy be a copy of the contents of the response parameter. RefPtr<DOMArrayBuffer> responseCopy = DOMArrayBuffer::create(response.data(), response.byteLength()); // 4. Let promise be a new promise. SimpleContentDecryptionModuleResultPromise* result = new SimpleContentDecryptionModuleResultPromise(scriptState); ScriptPromise promise = result->promise(); // 5. Run the following steps asynchronously (documented in // actionTimerFired()) m_pendingActions.append(PendingAction::CreatePendingUpdate(result, responseCopy.release())); if (!m_actionTimer.isActive()) m_actionTimer.startOneShot(0, BLINK_FROM_HERE); // 6. Return promise. return promise; }
ScriptPromise SubtleCrypto::verifySignature(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, CryptoKey* key, const DOMArrayPiece& signature, const DOMArrayPiece& data) { CryptoResultImpl* result = CryptoResultImpl::create(scriptState); ScriptPromise promise = result->promise(); if (!canAccessWebCrypto(scriptState, result)) return promise; WebCryptoAlgorithm algorithm; if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationVerify, algorithm, result)) return promise; if (!key->canBeUsedForAlgorithm(algorithm, WebCryptoKeyUsageVerify, result)) return promise; histogramAlgorithmAndKey(scriptState->executionContext(), algorithm, key->key()); Platform::current()->crypto()->verifySignature(algorithm, key->key(), signature.bytes(), signature.byteLength(), data.bytes(), data.byteLength(), result->result()); return promise; }
ScriptPromise MediaKeySession::generateRequest(ScriptState* scriptState, const String& initDataTypeString, const DOMArrayPiece& initData) { WTF_LOG(Media, "MediaKeySession(%p)::generateRequest %s", this, initDataTypeString.ascii().data()); // From https://w3c.github.io/encrypted-media/#generateRequest: // Generates a request based on the initData. When this method is invoked, // the user agent must run the following steps: // 1. If this object's uninitialized value is false, return a promise // rejected with a new DOMException whose name is "InvalidStateError". if (!m_isUninitialized) return CreateRejectedPromiseAlreadyInitialized(scriptState); // 2. Let this object's uninitialized be false. m_isUninitialized = false; // 3. If initDataType is an empty string, return a promise rejected with a // new DOMException whose name is "InvalidAccessError". if (initDataTypeString.isEmpty()) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(InvalidAccessError, "The initDataType parameter is empty.")); } // 4. If initData is an empty array, return a promise rejected with a new // DOMException whose name is"InvalidAccessError". if (!initData.byteLength()) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(InvalidAccessError, "The initData parameter is empty.")); } // 5. If the Key System implementation represented by this object's cdm // implementation value does not support initDataType as an // Initialization Data Type, return a promise rejected with a new // DOMException whose name is NotSupportedError. String comparison // is case-sensitive. // (blink side doesn't know what the CDM supports, so the proper check // will be done on the Chromium side. However, we can verify that // |initDataType| is one of the registered values.) WebEncryptedMediaInitDataType initDataType = EncryptedMediaUtils::convertToInitDataType(initDataTypeString); if (initDataType == WebEncryptedMediaInitDataType::Unknown) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(NotSupportedError, "The initialization data type '" + initDataTypeString + "' is not supported.")); } // 6. Let init data be a copy of the contents of the initData parameter. RefPtr<DOMArrayBuffer> initDataBuffer = DOMArrayBuffer::create(initData.data(), initData.byteLength()); // 7. Let session type be this object's session type. // (Done in constructor.) // 8. Let promise be a new promise. NewSessionResultPromise* result = new NewSessionResultPromise(scriptState, this); ScriptPromise promise = result->promise(); // 9. Run the following steps asynchronously (documented in // actionTimerFired()) m_pendingActions.append(PendingAction::CreatePendingGenerateRequest(result, initDataType, initDataBuffer.release())); ASSERT(!m_actionTimer.isActive()); m_actionTimer.startOneShot(0, BLINK_FROM_HERE); // 10. Return promise. return promise; }