Changeset 159644 in webkit


Ignore:
Timestamp:
Nov 21, 2013 1:55:20 PM (10 years ago)
Author:
ap@apple.com
Message:

Implement WebCrypto wrapKey
https://bugs.webkit.org/show_bug.cgi?id=124738

Reviewed by Anders Carlsson.

Source/WebCore:

Tests: crypto/subtle/aes-cbc-wrap-rsa-non-extractable.html

crypto/subtle/aes-cbc-wrap-rsa.html

  • bindings/js/JSSubtleCryptoCustom.cpp:

(WebCore::exportKey): Factored out the actual operation that can be chained with
encryption for wrapKey.
(WebCore::JSSubtleCrypto::exportKey):
(WebCore::JSSubtleCrypto::wrapKey):
(WebCore::JSSubtleCrypto::unwrapKey): Fixed a memory leak in failure code path.

  • crypto/SubtleCrypto.idl: Added wrapKey.

LayoutTests:

  • crypto/subtle/aes-cbc-wrap-rsa-expected.txt: Added.
  • crypto/subtle/aes-cbc-wrap-rsa-non-extractable-expected.txt: Added.
  • crypto/subtle/aes-cbc-wrap-rsa-non-extractable.html: Added.
  • crypto/subtle/aes-cbc-wrap-rsa.html: Added.
  • crypto/subtle/aes-export-key-expected.txt:
  • crypto/subtle/hmac-export-key-expected.txt:

There is no longer a console message, the error is in an exception.

Location:
trunk
Files:
4 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r159640 r159644  
     12013-11-21  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Implement WebCrypto wrapKey
     4        https://bugs.webkit.org/show_bug.cgi?id=124738
     5
     6        Reviewed by Anders Carlsson.
     7
     8        * crypto/subtle/aes-cbc-wrap-rsa-expected.txt: Added.
     9        * crypto/subtle/aes-cbc-wrap-rsa-non-extractable-expected.txt: Added.
     10        * crypto/subtle/aes-cbc-wrap-rsa-non-extractable.html: Added.
     11        * crypto/subtle/aes-cbc-wrap-rsa.html: Added.
     12
     13        * crypto/subtle/aes-export-key-expected.txt:
     14        * crypto/subtle/hmac-export-key-expected.txt:
     15        There is no longer a console message, the error is in an exception.
     16
    1172013-11-21  Radu Stavila  <stavila@adobe.com>
    218
  • trunk/LayoutTests/crypto/subtle/aes-export-key-expected.txt

    r159377 r159644  
    1 CONSOLE MESSAGE: Key is not extractable
    2 CONSOLE MESSAGE: Key is not extractable
    31Test exporting an AES key.
    42
  • trunk/LayoutTests/crypto/subtle/hmac-export-key-expected.txt

    r159377 r159644  
    1 CONSOLE MESSAGE: Key is not extractable
    2 CONSOLE MESSAGE: Key is not extractable
    31Test exporting an AES key.
    42
  • trunk/Source/WebCore/ChangeLog

    r159637 r159644  
     12013-11-21  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Implement WebCrypto wrapKey
     4        https://bugs.webkit.org/show_bug.cgi?id=124738
     5
     6        Reviewed by Anders Carlsson.
     7
     8        Tests: crypto/subtle/aes-cbc-wrap-rsa-non-extractable.html
     9               crypto/subtle/aes-cbc-wrap-rsa.html
     10
     11        * bindings/js/JSSubtleCryptoCustom.cpp:
     12        (WebCore::exportKey): Factored out the actual operation that can be chained with
     13        encryption for wrapKey.
     14        (WebCore::JSSubtleCrypto::exportKey):
     15        (WebCore::JSSubtleCrypto::wrapKey):
     16        (WebCore::JSSubtleCrypto::unwrapKey): Fixed a memory leak in failure code path.
     17
     18        * crypto/SubtleCrypto.idl: Added wrapKey.
     19
    1202013-11-21  Alexey Proskuryakov  <ap@apple.com>
    221
  • trunk/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp

    r159637 r159644  
    564564}
    565565
     566static void exportKey(ExecState* exec, CryptoKeyFormat keyFormat, const CryptoKey& key, CryptoAlgorithm::VectorCallback callback, CryptoAlgorithm::VoidCallback failureCallback)
     567{
     568    if (!key.extractable()) {
     569        throwTypeError(exec, "Key is not extractable");
     570        return;
     571    }
     572
     573    switch (keyFormat) {
     574    case CryptoKeyFormat::Raw: {
     575        Vector<uint8_t> result;
     576        if (CryptoKeySerializationRaw::serialize(key, result))
     577            callback(result);
     578        else
     579            failureCallback();
     580        break;
     581    }
     582    case CryptoKeyFormat::JWK: {
     583        String result = JSCryptoKeySerializationJWK::serialize(exec, key);
     584        if (exec->hadException())
     585            return;
     586        CString utf8String = result.utf8(StrictConversion);
     587        Vector<uint8_t> resultBuffer;
     588        resultBuffer.append(utf8String.data(), utf8String.length());
     589        callback(resultBuffer);
     590        break;
     591    }
     592    default:
     593        throwTypeError(exec, "Unsupported key format for export");
     594        break;
     595    }
     596}
     597
    566598JSValue JSSubtleCrypto::exportKey(ExecState* exec)
    567599{
     
    582614    PromiseWrapper promiseWrapper(globalObject(), promise);
    583615
    584     if (!key->extractable()) {
    585         m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key is not extractable");
    586         promiseWrapper.reject(nullptr);
    587         return promise;
    588     }
    589 
    590     switch (keyFormat) {
    591     case CryptoKeyFormat::Raw: {
    592         Vector<uint8_t> result;
    593         if (CryptoKeySerializationRaw::serialize(*key, result))
    594             promiseWrapper.fulfill(result);
    595         else {
    596             m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key cannot be exported to raw format");
     616    auto successCallback = [promiseWrapper](const Vector<uint8_t>& result) mutable {
     617        promiseWrapper.fulfill(result);
     618    };
     619    auto failureCallback = [promiseWrapper]() mutable {
     620        promiseWrapper.reject(nullptr);
     621    };
     622
     623    WebCore::exportKey(exec, keyFormat, *key, successCallback, failureCallback);
     624    if (exec->hadException())
     625        return jsUndefined();
     626
     627    return promise;
     628}
     629
     630JSValue JSSubtleCrypto::wrapKey(ExecState* exec)
     631{
     632    if (exec->argumentCount() < 4)
     633        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
     634
     635    CryptoKeyFormat keyFormat;
     636    if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
     637        ASSERT(exec->hadException());
     638        return jsUndefined();
     639    }
     640
     641    RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
     642    if (!key)
     643        return throwTypeError(exec);
     644
     645    RefPtr<CryptoKey> wrappingKey = toCryptoKey(exec->uncheckedArgument(2));
     646    if (!key)
     647        return throwTypeError(exec);
     648
     649
     650    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3));
     651    if (!algorithm) {
     652        ASSERT(exec->hadException());
     653        return jsUndefined();
     654    }
     655
     656    auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(exec, algorithm->identifier(), exec->uncheckedArgument(3));
     657    if (!parameters) {
     658        ASSERT(exec->hadException());
     659        return jsUndefined();
     660    }
     661
     662    JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
     663    PromiseWrapper promiseWrapper(globalObject(), promise);
     664
     665    CryptoAlgorithm* algorithmPtr = algorithm.release();
     666    CryptoAlgorithmParameters* parametersPtr = parameters.release();
     667
     668    auto exportSuccessCallback = [keyFormat, algorithmPtr, parametersPtr, wrappingKey, promiseWrapper](const Vector<uint8_t>& exportedKeyData) mutable {
     669        auto encryptSuccessCallback = [promiseWrapper](const Vector<uint8_t>& encryptedData) mutable {
     670            promiseWrapper.fulfill(encryptedData);
     671        };
     672        auto encryptFailureCallback = [promiseWrapper]() mutable {
    597673            promiseWrapper.reject(nullptr);
    598         }
    599         break;
    600     }
    601     case CryptoKeyFormat::JWK: {
    602         String result = JSCryptoKeySerializationJWK::serialize(exec, *key);
    603         if (exec->hadException())
    604             return jsUndefined();
    605         CString utf8String = result.utf8(StrictConversion);
    606         Vector<uint8_t> resultBuffer;
    607         resultBuffer.append(utf8String.data(), utf8String.length());
    608         promiseWrapper.fulfill(resultBuffer);
    609         break;
    610     }
    611     default:
    612         throwTypeError(exec, "Unsupported key format for export");
     674        };
     675        ExceptionCode ec = 0;
     676        algorithmPtr->encryptForWrapKey(*parametersPtr, *wrappingKey, std::make_pair(exportedKeyData.data(), exportedKeyData.size()), std::move(encryptSuccessCallback), std::move(encryptFailureCallback), ec);
     677        if (ec) {
     678            // FIXME: Report failure details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions.
     679            encryptFailureCallback();
     680        }
     681    };
     682
     683    auto exportFailureCallback = [promiseWrapper, algorithmPtr, parametersPtr]() mutable {
     684        delete algorithmPtr;
     685        delete parametersPtr;
     686        promiseWrapper.reject(nullptr);
     687    };
     688
     689    ExceptionCode ec = 0;
     690    WebCore::exportKey(exec, keyFormat, *key, exportSuccessCallback, exportFailureCallback);
     691    if (ec) {
     692        setDOMException(exec, ec);
    613693        return jsUndefined();
    614694    }
     
    694774    CryptoAlgorithmParameters* unwrappedKeyAlgorithmParametersPtr = unwrappedKeyAlgorithmParameters.release();
    695775
    696     auto failureCallback = [promiseWrapper]() mutable {
    697         promiseWrapper.reject(nullptr);
    698     };
    699 
    700     auto successCallback = [domGlobalObject, keyFormat, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, promiseWrapper, failureCallback](const Vector<uint8_t>& result) mutable {
     776    auto decryptSuccessCallback = [domGlobalObject, keyFormat, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, promiseWrapper](const Vector<uint8_t>& result) mutable {
    701777        auto importSuccessCallback = [promiseWrapper](CryptoKey& key) mutable {
    702778            promiseWrapper.fulfill(&key);
    703779        };
     780        auto importFailureCallback = [promiseWrapper]() mutable {
     781            promiseWrapper.reject(nullptr);
     782        };
    704783        ExecState* exec = domGlobalObject->globalExec();
    705         WebCore::importKey(exec, keyFormat, std::make_pair(result.data(), result.size()), unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, importSuccessCallback, failureCallback);
     784        WebCore::importKey(exec, keyFormat, std::make_pair(result.data(), result.size()), unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, importSuccessCallback, importFailureCallback);
    706785        if (exec->hadException()) {
    707786            // FIXME: Report exception details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions.
    708787            exec->clearException();
    709             failureCallback();
    710         }
     788            importFailureCallback();
     789        }
     790    };
     791
     792    auto decryptFailureCallback = [promiseWrapper, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr]() mutable {
     793        delete unwrappedKeyAlgorithmPtr;
     794        delete unwrappedKeyAlgorithmParametersPtr;
     795        promiseWrapper.reject(nullptr);
    711796    };
    712797
    713798    ExceptionCode ec = 0;
    714     unwrapAlgorithm->decryptForUnwrapKey(*unwrapAlgorithmParameters, *unwrappingKey, wrappedKeyData, std::move(successCallback), std::move(failureCallback), ec);
     799    unwrapAlgorithm->decryptForUnwrapKey(*unwrapAlgorithmParameters, *unwrappingKey, wrappedKeyData, std::move(decryptSuccessCallback), std::move(decryptFailureCallback), ec);
    715800    if (ec) {
    716801        setDOMException(exec, ec);
  • trunk/Source/WebCore/crypto/SubtleCrypto.idl

    r159637 r159644  
    3838    [Custom] Promise importKey(KeyFormat format, CryptoOperationData keyData, AlgorithmIdentifier? algorithm, optional boolean extractable, optional KeyUsage[] keyUsages);
    3939    [Custom] Promise exportKey(KeyFormat format, Key key);
     40    [Custom] Promise wrapKey(KeyFormat format, Key key, Key wrappingKey, AlgorithmIdentifier wrapAlgorithm);
    4041    [Custom] Promise unwrapKey(KeyFormat format, CryptoOperationData wrappedKey, Key unwrappingKey, AlgorithmIdentifier unwrapAlgorithm, AlgorithmIdentifier? unwrappedKeyAlgorithm, optional boolean extractable, optional KeyUsage[] keyUsages);
    4142};
Note: See TracChangeset for help on using the changeset viewer.