Add a Mac WebCrypto implementation of HMAC importKey/sign/verify
authorap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Nov 2013 07:15:45 +0000 (07:15 +0000)
committerap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Nov 2013 07:15:45 +0000 (07:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123598

Reviewed by Anders Carlsson.

Source/WebCore:

Test: crypto/subtle/hmac-sign-verify.html

* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSSubtleCryptoCustom.cpp: Added property svn:eol-style.
(WebCore::createAlgorithmFromJSValue):
(WebCore::cryptoOperationDataFromJSValue):
(WebCore::cryptoKeyFormatFromJSValue):
(WebCore::cryptoKeyUsagesFromJSValue):
(WebCore::JSSubtleCrypto::sign):
(WebCore::JSSubtleCrypto::verify):
(WebCore::JSSubtleCrypto::digest):
(WebCore::JSSubtleCrypto::importKey):
* crypto/SubtleCrypto.idl:
* crypto/algorithms/CryptoAlgorithmHMAC.cpp: Added.
(WebCore::CryptoAlgorithmHMAC::CryptoAlgorithmHMAC):
(WebCore::CryptoAlgorithmHMAC::~CryptoAlgorithmHMAC):
(WebCore::CryptoAlgorithmHMAC::create):
(WebCore::CryptoAlgorithmHMAC::identifier):
(WebCore::CryptoAlgorithmHMAC::importKey):
(WebCore::CryptoAlgorithmHMAC::exportKey):
* crypto/algorithms/CryptoAlgorithmHMAC.h: Added.
* crypto/keys: Added.
* crypto/keys/CryptoKeyHMAC.cpp: Added.
(WebCore::CryptoKeyHMAC::CryptoKeyHMAC):
(WebCore::CryptoKeyHMAC::~CryptoKeyHMAC):
(WebCore::CryptoKeyHMAC::buildAlgorithmDescription):
* crypto/keys/CryptoKeyHMAC.h: Added.
* crypto/mac/CryptoAlgorithmHMACMac.cpp: Added.
(WebCore::getCommonCryptoAlgorithm):
(WebCore::calculateSignature):
(WebCore::CryptoAlgorithmHMAC::sign):
(WebCore::CryptoAlgorithmHMAC::verify):
(WebCore::CryptoAlgorithmHMAC::generateKey):
* crypto/mac/CryptoAlgorithmRegistryMac.cpp:
(WebCore::CryptoAlgorithmRegistry::platformRegisterAlgorithms):

LayoutTests:

* crypto/subtle/hmac-sign-verify-expected.txt: Added.
* crypto/subtle/hmac-sign-verify.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@158427 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/ChangeLog
LayoutTests/crypto/subtle/hmac-sign-verify-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/hmac-sign-verify.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp
Source/WebCore/crypto/SubtleCrypto.idl
Source/WebCore/crypto/algorithms/CryptoAlgorithmHMAC.cpp [new file with mode: 0644]
Source/WebCore/crypto/algorithms/CryptoAlgorithmHMAC.h [new file with mode: 0644]
Source/WebCore/crypto/keys/CryptoKeyHMAC.cpp [new file with mode: 0644]
Source/WebCore/crypto/keys/CryptoKeyHMAC.h [new file with mode: 0644]
Source/WebCore/crypto/mac/CryptoAlgorithmHMACMac.cpp [new file with mode: 0644]
Source/WebCore/crypto/mac/CryptoAlgorithmRegistryMac.cpp

index e74b23e..795a6c2 100644 (file)
@@ -1,3 +1,13 @@
+2013-11-01  Alexey Proskuryakov  <ap@apple.com>
+
+        Add a Mac WebCrypto implementation of HMAC importKey/sign/verify
+        https://bugs.webkit.org/show_bug.cgi?id=123598
+
+        Reviewed by Anders Carlsson.
+
+        * crypto/subtle/hmac-sign-verify-expected.txt: Added.
+        * crypto/subtle/hmac-sign-verify.html: Added.
+
 2013-10-31  Oliver Hunt  <oliver@apple.com>
 
         JavaScript parser bug
diff --git a/LayoutTests/crypto/subtle/hmac-sign-verify-expected.txt b/LayoutTests/crypto/subtle/hmac-sign-verify-expected.txt
new file mode 100644 (file)
index 0000000..7e3f4e9
--- /dev/null
@@ -0,0 +1,20 @@
+Test crypto.subtle.digest.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a raw HMAC key from string literal...
+PASS key.type is 'secret'
+PASS key.extractable is true
+PASS key.algorithm.name is 'hmac'
+PASS key.algorithm.length is 1
+PASS key.algorithm.hash.name is 'sha-1'
+PASS key.usages is ['sign', 'verify']
+Using the key to sign 'foo'...
+    = [be bb c0 2e 46 b0 f8 11 83 f4 0c 25 dc e2 3e 50 45 d6 55 19]
+Verifying the signature...
+PASS verificationResult is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/hmac-sign-verify.html b/LayoutTests/crypto/subtle/hmac-sign-verify.html
new file mode 100644 (file)
index 0000000..f56b855
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+<script src="resources/common.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Test crypto.subtle.digest.");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+var hmacKey = asciiToArrayBuffer('a');
+var extractable = true;
+
+debug("Importing a raw HMAC key from string literal...");
+crypto.subtle.importKey("raw", hmacKey, {name: 'hmac', hash: {name: 'sha-1'}}, extractable, ["sign", "verify"]).then(function(result) {
+    key = result;
+    shouldBe("key.type", "'secret'");
+    shouldBe("key.extractable", "true");
+    shouldBe("key.algorithm.name", "'hmac'");
+    shouldBe("key.algorithm.length", "1"); // See <https://www.w3.org/Bugs/Public/show_bug.cgi?id=23098>.
+    shouldBe("key.algorithm.hash.name", "'sha-1'");
+    shouldBe("key.usages", "['sign', 'verify']");
+
+    debug("Using the key to sign 'foo'...");
+    return crypto.subtle.sign(key.algorithm, key, [asciiToArrayBuffer('foo')]);
+}).then(function(result) {
+    printAcceptedResult(result);
+
+    debug("Verifying the signature...");
+    return crypto.subtle.verify(key.algorithm, key, result, [asciiToArrayBuffer('foo')]);
+}).then(function(result) {
+    verificationResult = result;
+    shouldBe("verificationResult", "true");
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 8d09827..9c924e6 100644 (file)
@@ -1,3 +1,46 @@
+2013-11-01  Alexey Proskuryakov  <ap@apple.com>
+
+        Add a Mac WebCrypto implementation of HMAC importKey/sign/verify
+        https://bugs.webkit.org/show_bug.cgi?id=123598
+
+        Reviewed by Anders Carlsson.
+
+        Test: crypto/subtle/hmac-sign-verify.html
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSSubtleCryptoCustom.cpp: Added property svn:eol-style.
+        (WebCore::createAlgorithmFromJSValue):
+        (WebCore::cryptoOperationDataFromJSValue):
+        (WebCore::cryptoKeyFormatFromJSValue):
+        (WebCore::cryptoKeyUsagesFromJSValue):
+        (WebCore::JSSubtleCrypto::sign):
+        (WebCore::JSSubtleCrypto::verify):
+        (WebCore::JSSubtleCrypto::digest):
+        (WebCore::JSSubtleCrypto::importKey):
+        * crypto/SubtleCrypto.idl:
+        * crypto/algorithms/CryptoAlgorithmHMAC.cpp: Added.
+        (WebCore::CryptoAlgorithmHMAC::CryptoAlgorithmHMAC):
+        (WebCore::CryptoAlgorithmHMAC::~CryptoAlgorithmHMAC):
+        (WebCore::CryptoAlgorithmHMAC::create):
+        (WebCore::CryptoAlgorithmHMAC::identifier):
+        (WebCore::CryptoAlgorithmHMAC::importKey):
+        (WebCore::CryptoAlgorithmHMAC::exportKey):
+        * crypto/algorithms/CryptoAlgorithmHMAC.h: Added.
+        * crypto/keys: Added.
+        * crypto/keys/CryptoKeyHMAC.cpp: Added.
+        (WebCore::CryptoKeyHMAC::CryptoKeyHMAC):
+        (WebCore::CryptoKeyHMAC::~CryptoKeyHMAC):
+        (WebCore::CryptoKeyHMAC::buildAlgorithmDescription):
+        * crypto/keys/CryptoKeyHMAC.h: Added.
+        * crypto/mac/CryptoAlgorithmHMACMac.cpp: Added.
+        (WebCore::getCommonCryptoAlgorithm):
+        (WebCore::calculateSignature):
+        (WebCore::CryptoAlgorithmHMAC::sign):
+        (WebCore::CryptoAlgorithmHMAC::verify):
+        (WebCore::CryptoAlgorithmHMAC::generateKey):
+        * crypto/mac/CryptoAlgorithmRegistryMac.cpp:
+        (WebCore::CryptoAlgorithmRegistry::platformRegisterAlgorithms):
+
 2013-10-31  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Clean up a few Inspector interfaces
index a078152..dee7b21 100644 (file)
                E125F82B1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F8291822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp */; };
                E125F82C1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.h in Headers */ = {isa = PBXBuildFile; fileRef = E125F82A1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.h */; };
                E125F82E1822CFFF00D84CD9 /* CryptoAlgorithmSHA1Mac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F82D1822CFFF00D84CD9 /* CryptoAlgorithmSHA1Mac.cpp */; };
+               E125F8311822F11B00D84CD9 /* CryptoAlgorithmHMAC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F82F1822F11B00D84CD9 /* CryptoAlgorithmHMAC.cpp */; };
+               E125F8321822F11B00D84CD9 /* CryptoAlgorithmHMAC.h in Headers */ = {isa = PBXBuildFile; fileRef = E125F8301822F11B00D84CD9 /* CryptoAlgorithmHMAC.h */; };
+               E125F8351822F18A00D84CD9 /* CryptoKeyHMAC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F8331822F18A00D84CD9 /* CryptoKeyHMAC.cpp */; };
+               E125F8361822F18A00D84CD9 /* CryptoKeyHMAC.h in Headers */ = {isa = PBXBuildFile; fileRef = E125F8341822F18A00D84CD9 /* CryptoKeyHMAC.h */; };
+               E125F8381822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F8371822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp */; };
                E12719C70EEEC16800F61213 /* NavigatorBase.h in Headers */ = {isa = PBXBuildFile; fileRef = E12719C60EEEC16800F61213 /* NavigatorBase.h */; };
                E12719CA0EEEC21300F61213 /* NavigatorBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E12719C90EEEC21300F61213 /* NavigatorBase.cpp */; };
                E1271A0B0EEEC77A00F61213 /* WorkerNavigator.h in Headers */ = {isa = PBXBuildFile; fileRef = E1271A0A0EEEC77A00F61213 /* WorkerNavigator.h */; };
                E125F8291822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmSHA1.cpp; sourceTree = "<group>"; };
                E125F82A1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmSHA1.h; sourceTree = "<group>"; };
                E125F82D1822CFFF00D84CD9 /* CryptoAlgorithmSHA1Mac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoAlgorithmSHA1Mac.cpp; path = mac/CryptoAlgorithmSHA1Mac.cpp; sourceTree = "<group>"; };
+               E125F82F1822F11B00D84CD9 /* CryptoAlgorithmHMAC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmHMAC.cpp; sourceTree = "<group>"; };
+               E125F8301822F11B00D84CD9 /* CryptoAlgorithmHMAC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmHMAC.h; sourceTree = "<group>"; };
+               E125F8331822F18A00D84CD9 /* CryptoKeyHMAC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoKeyHMAC.cpp; path = keys/CryptoKeyHMAC.cpp; sourceTree = "<group>"; };
+               E125F8341822F18A00D84CD9 /* CryptoKeyHMAC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CryptoKeyHMAC.h; path = keys/CryptoKeyHMAC.h; sourceTree = "<group>"; };
+               E125F8371822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoAlgorithmHMACMac.cpp; path = mac/CryptoAlgorithmHMACMac.cpp; sourceTree = "<group>"; };
                E12719C60EEEC16800F61213 /* NavigatorBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NavigatorBase.h; sourceTree = "<group>"; };
                E12719C90EEEC21300F61213 /* NavigatorBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NavigatorBase.cpp; sourceTree = "<group>"; };
                E1271A0A0EEEC77A00F61213 /* WorkerNavigator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WorkerNavigator.h; sourceTree = "<group>"; };
                E172AF71180F343400FBADB9 /* mac */ = {
                        isa = PBXGroup;
                        children = (
+                               E125F8371822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp */,
                                E1BB84AC1822CA7400525043 /* CryptoAlgorithmRegistryMac.cpp */,
                                E125F82D1822CFFF00D84CD9 /* CryptoAlgorithmSHA1Mac.cpp */,
                        );
                E172AF7C180F3B0D00FBADB9 /* algorithms */ = {
                        isa = PBXGroup;
                        children = (
+                               E125F82F1822F11B00D84CD9 /* CryptoAlgorithmHMAC.cpp */,
+                               E125F8301822F11B00D84CD9 /* CryptoAlgorithmHMAC.h */,
                                E125F8291822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp */,
                                E125F82A1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.h */,
                        );
                E19DA29D181995CE00088BC8 /* keys */ = {
                        isa = PBXGroup;
                        children = (
+                               E125F8331822F18A00D84CD9 /* CryptoKeyHMAC.cpp */,
+                               E125F8341822F18A00D84CD9 /* CryptoKeyHMAC.h */,
                        );
                        name = keys;
                        sourceTree = "<group>";
                                85D389B20A991A7F00282145 /* DOMAttr.h in Headers */,
                                85E7118D0AC5D5350053270F /* DOMAttrInternal.h in Headers */,
                                BC946EEF107FDBAC00857193 /* DOMBeforeLoadEvent.h in Headers */,
+                               E125F8361822F18A00D84CD9 /* CryptoKeyHMAC.h in Headers */,
                                2E2D99E710E2BC1C00496337 /* DOMBlob.h in Headers */,
                                2E2D99EA10E2BC3800496337 /* DOMBlobInternal.h in Headers */,
                                85089CD70A98C42800A275AA /* DOMCDATASection.h in Headers */,
                                B2227A2A0D00BF220071B782 /* SVGGradientElement.h in Headers */,
                                B2227AB60D00BF220071B782 /* SVGGraphicsElement.h in Headers */,
                                650FBF2B0D9AF047008FC292 /* SVGHKernElement.h in Headers */,
+                               E125F8321822F11B00D84CD9 /* CryptoAlgorithmHMAC.h in Headers */,
                                51D719BA181106E00016DC51 /* IDBAny.h in Headers */,
                                B25599A40D00D8BA00BB825C /* SVGImage.h in Headers */,
                                E4AE7C1617D1BB950009FB31 /* ElementIterator.h in Headers */,
                                A29532CF15DD5E1700469EBC /* CustomFilterValidatedProgram.cpp in Sources */,
                                97BC6A201505F081001B74AC /* Database.cpp in Sources */,
                                97BC6A231505F081001B74AC /* DatabaseAuthorizer.cpp in Sources */,
+                               E125F8351822F18A00D84CD9 /* CryptoKeyHMAC.cpp in Sources */,
                                511EF2C517F0FD3500E4FA16 /* JSIDBIndex.cpp in Sources */,
                                FE16CFD3169D1DED00D3A0C7 /* DatabaseBackend.cpp in Sources */,
                                97BC69DA1505F076001B74AC /* DatabaseBackendBase.cpp in Sources */,
                                F5C041E40FFCA96D00839D4A /* DOMHTMLDataListElement.mm in Sources */,
                                E157A8E818184C67009F821D /* JSCryptoKeyCustom.cpp in Sources */,
                                0705852317FDC140005F2BCB /* MediaTrackConstraints.cpp in Sources */,
+                               E125F8311822F11B00D84CD9 /* CryptoAlgorithmHMAC.cpp in Sources */,
                                D359D792129CA3C00006E5D2 /* DOMHTMLDetailsElement.mm in Sources */,
                                85BA4D0C0AA688680088052D /* DOMHTMLDirectoryElement.mm in Sources */,
                                85BA4D0E0AA688680088052D /* DOMHTMLDivElement.mm in Sources */,
                                9B7E78BD16F16CC600126914 /* HTMLTreeBuilderSimulator.cpp in Sources */,
                                A8EA79F30A1916DF00A8EF5F /* HTMLUListElement.cpp in Sources */,
                                E44613AA0CD6331000FADA75 /* HTMLVideoElement.cpp in Sources */,
+                               E125F8381822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp in Sources */,
                                BCCD74E50A4C8DDF005FDA6D /* HTMLViewSourceDocument.cpp in Sources */,
                                977B3879122883E900B81FF8 /* HTMLViewSourceParser.cpp in Sources */,
                                0B8C56D40F28627F000502E1 /* HTTPHeaderMap.cpp in Sources */,
index f3bf533..96eed48 100644 (file)
@@ -49,7 +49,7 @@ static std::unique_ptr<CryptoAlgorithm> createAlgorithmFromJSValue(ExecState* ex
         return nullptr;
     }
 
-    std::unique_ptr<CryptoAlgorithm> result(CryptoAlgorithmRegistry::shared().create(algorithmIdentifier));
+    auto result = CryptoAlgorithmRegistry::shared().create(algorithmIdentifier);
     if (!result)
         setDOMException(exec, NOT_SUPPORTED_ERR);
     return result;
@@ -78,18 +78,184 @@ static bool sequenceOfCryptoOperationDataFromJSValue(ExecState* exec, JSValue va
     return true;
 }
 
+static bool cryptoOperationDataFromJSValue(ExecState* exec, JSValue value, CryptoOperationData& result)
+{
+    if (ArrayBuffer* buffer = toArrayBuffer(value))
+        result = std::make_pair(static_cast<char*>(buffer->data()), buffer->byteLength());
+    else if (RefPtr<ArrayBufferView> bufferView = toArrayBufferView(value))
+        result = std::make_pair(static_cast<char*>(bufferView->baseAddress()), bufferView->byteLength());
+    else {
+        throwTypeError(exec, "Only ArrayBuffer and ArrayBufferView objects can be part of CryptoOperationData sequence");
+        return false;
+    }
+    return true;
+}
+
+static bool cryptoKeyFormatFromJSValue(ExecState* exec, JSValue value, CryptoKeyFormat& result)
+{
+    String keyFormatString = value.toString(exec)->value(exec);
+    if (exec->hadException())
+        return false;
+    if (keyFormatString == "raw")
+        result = CryptoKeyFormat::Raw;
+    else if (keyFormatString == "pkcs8")
+        result = CryptoKeyFormat::PKCS8;
+    else if (keyFormatString == "spki")
+        result = CryptoKeyFormat::SPKI;
+    else if (keyFormatString == "jwk")
+        result = CryptoKeyFormat::JWK;
+    else {
+        throwTypeError(exec);
+        return false;
+    }
+    return true;
+}
+
+static bool cryptoKeyUsagesFromJSValue(ExecState* exec, JSValue value, CryptoKeyUsage& result)
+{
+    if (!isJSArray(value)) {
+        throwTypeError(exec);
+        return false;
+    }
+
+    result = 0;
+
+    JSC::JSArray* array = asArray(value);
+    for (size_t i = 0; i < array->length(); ++i) {
+        JSC::JSValue element = array->getIndex(exec, i);
+        String usageString = element.toString(exec)->value(exec);
+        if (exec->hadException())
+            return false;
+        if (usageString == "encrypt")
+            result |= CryptoKeyUsageEncrypt;
+        else if (usageString == "decrypt")
+            result |= CryptoKeyUsageDecrypt;
+        else if (usageString == "sign")
+            result |= CryptoKeyUsageSign;
+        else if (usageString == "verify")
+            result |= CryptoKeyUsageVerify;
+        else if (usageString == "deriveKey")
+            result |= CryptoKeyUsageDeriveKey;
+        else if (usageString == "deriveBits")
+            result |= CryptoKeyUsageDeriveBits;
+        else if (usageString == "wrapKey")
+            result |= CryptoKeyUsageWrapKey;
+        else if (usageString == "unwrapKey")
+            result |= CryptoKeyUsageUnwrapKey;
+    }
+    return true;
+}
+
+JSValue JSSubtleCrypto::sign(ExecState* exec)
+{
+    if (exec->argumentCount() < 3)
+        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
+
+    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
+    if (!algorithm) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    auto parameters = JSCryptoAlgorithmDictionary::createParametersForSign(exec, algorithm->identifier(), exec->uncheckedArgument(0));
+    if (!parameters) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
+    if (!key)
+        return throwTypeError(exec);
+
+    if (!key->allows(CryptoKeyUsageSign)) {
+        m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages does not include 'sign'");
+        setDOMException(exec, NOT_SUPPORTED_ERR);
+        return jsUndefined();
+    }
+
+    Vector<CryptoOperationData> data;
+    if (!sequenceOfCryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), data)) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
+    auto promiseWrapper = PromiseWrapper::create(globalObject(), promise);
+
+    ExceptionCode ec = 0;
+    algorithm->sign(*parameters, *key.get(), data, std::move(promiseWrapper), ec);
+    if (ec) {
+        setDOMException(exec, ec);
+        return jsUndefined();
+    }
+
+    return promise;
+}
+
+JSValue JSSubtleCrypto::verify(ExecState* exec)
+{
+    if (exec->argumentCount() < 4)
+        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
+
+    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
+    if (!algorithm) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    auto parameters = JSCryptoAlgorithmDictionary::createParametersForVerify(exec, algorithm->identifier(), exec->uncheckedArgument(0));
+    if (!parameters) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
+    if (!key)
+        return throwTypeError(exec);
+
+    if (!key->allows(CryptoKeyUsageVerify)) {
+        m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages does not include 'verify'");
+        setDOMException(exec, NOT_SUPPORTED_ERR);
+        return jsUndefined();
+    }
+
+    CryptoOperationData signature;
+    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), signature)) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    Vector<CryptoOperationData> data;
+    if (!sequenceOfCryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(3), data)) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
+    auto promiseWrapper = PromiseWrapper::create(globalObject(), promise);
+
+    ExceptionCode ec = 0;
+    algorithm->verify(*parameters, *key, signature, data, std::move(promiseWrapper), ec);
+    if (ec) {
+        setDOMException(exec, ec);
+        return jsUndefined();
+    }
+
+    return promise;
+}
+
 JSValue JSSubtleCrypto::digest(ExecState* exec)
 {
     if (exec->argumentCount() < 2)
         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
 
-    std::unique_ptr<CryptoAlgorithm> algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
+    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
     if (!algorithm) {
         ASSERT(exec->hadException());
         return jsUndefined();
     }
 
-    std::unique_ptr<CryptoAlgorithmParameters> parameters = JSCryptoAlgorithmDictionary::createParametersForDigest(exec, algorithm->identifier(), exec->uncheckedArgument(0));
+    auto parameters = JSCryptoAlgorithmDictionary::createParametersForDigest(exec, algorithm->identifier(), exec->uncheckedArgument(0));
     if (!parameters) {
         ASSERT(exec->hadException());
         return jsUndefined();
@@ -114,6 +280,72 @@ JSValue JSSubtleCrypto::digest(ExecState* exec)
     return promise;
 }
 
+JSValue JSSubtleCrypto::importKey(JSC::ExecState* exec)
+{
+    if (exec->argumentCount() < 3)
+        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
+
+    CryptoKeyFormat keyFormat;
+    if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    CryptoOperationData data;
+    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    std::unique_ptr<CryptoAlgorithm> algorithm;
+    if (!exec->uncheckedArgument(2).isNull()) {
+        algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(2));
+        if (!algorithm) {
+            ASSERT(exec->hadException());
+            return jsUndefined();
+        }
+    }
+    // The algorithm can presumably be null when we can deduce it from the key (JWE perhaps?)
+    // But we only support raw key format right now.
+    if (!algorithm) {
+        setDOMException(exec, NOT_SUPPORTED_ERR);
+        return jsUndefined();
+    }
+
+    auto parameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, algorithm->identifier(), exec->uncheckedArgument(2));
+    if (!parameters) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    bool extractable = false;
+    if (exec->argumentCount() >= 4) {
+        extractable = exec->uncheckedArgument(3).toBoolean(exec);
+        if (exec->hadException())
+            return jsUndefined();
+    }
+
+    CryptoKeyUsage keyUsages = 0;
+    if (exec->argumentCount() >= 5) {
+        if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(4), keyUsages)) {
+            ASSERT(exec->hadException());
+            return jsUndefined();
+        }
+    }
+
+    JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
+    auto promiseWrapper = PromiseWrapper::create(globalObject(), promise);
+
+    ExceptionCode ec = 0;
+    algorithm->importKey(*parameters, keyFormat, data, extractable, keyUsages, std::move(promiseWrapper), ec);
+    if (ec) {
+        setDOMException(exec, ec);
+        return jsUndefined();
+    }
+
+    return promise;
+}
+
 } // namespace WebCore
 
 #endif
index 67c6a32..d00c4df 100644 (file)
@@ -30,5 +30,8 @@
     NoInterfaceObject,
     OperationsNotDeletable
 ] interface SubtleCrypto {
+    [Custom] Promise sign(AlgorithmIdentifier algorithm, Key key, sequence<CryptoOperationData> data);
+    [Custom] Promise verify(AlgorithmIdentifier algorithm, Key key, CryptoOperationData signature, sequence<CryptoOperationData> data);
     [Custom] Promise digest(AlgorithmIdentifier algorithm, sequence<CryptoOperationData> data);
+    [Custom] Promise importKey(KeyFormat format, CryptoOperationData keyData, AlgorithmIdentifier? algorithm, optional boolean extractable, optional KeyUsage[] keyUsages);
 };
diff --git a/Source/WebCore/crypto/algorithms/CryptoAlgorithmHMAC.cpp b/Source/WebCore/crypto/algorithms/CryptoAlgorithmHMAC.cpp
new file mode 100644 (file)
index 0000000..e8d4bdc
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 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 "CryptoAlgorithmHMAC.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#include "CryptoAlgorithmHmacParams.h"
+#include "CryptoKeyHMAC.h"
+#include "ExceptionCode.h"
+#include "JSDOMPromise.h"
+
+namespace WebCore {
+
+const char* const CryptoAlgorithmHMAC::s_name = "hmac";
+
+CryptoAlgorithmHMAC::CryptoAlgorithmHMAC()
+{
+}
+
+CryptoAlgorithmHMAC::~CryptoAlgorithmHMAC()
+{
+}
+
+std::unique_ptr<CryptoAlgorithm> CryptoAlgorithmHMAC::create()
+{
+    return std::unique_ptr<CryptoAlgorithm>(new CryptoAlgorithmHMAC);
+}
+
+CryptoAlgorithmIdentifier CryptoAlgorithmHMAC::identifier() const
+{
+    return s_identifier;
+}
+
+void CryptoAlgorithmHMAC::importKey(const CryptoAlgorithmParameters& parameters, CryptoKeyFormat format, const CryptoOperationData& data, bool extractable, CryptoKeyUsage usage, std::unique_ptr<PromiseWrapper> promise, ExceptionCode& ec)
+{
+    if (format != CryptoKeyFormat::Raw) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    const CryptoAlgorithmHmacParams& hmacParameters = static_cast<const CryptoAlgorithmHmacParams&>(parameters);
+    Vector<char> keyData;
+    keyData.append(data.first, data.second);
+    RefPtr<CryptoKeyHMAC> result = CryptoKeyHMAC::create(keyData, hmacParameters.hash, extractable, usage);
+    promise->fulfill(result.release());
+}
+
+void CryptoAlgorithmHMAC::exportKey(const CryptoAlgorithmParameters&, CryptoKeyFormat, const CryptoKey&, std::unique_ptr<PromiseWrapper>, ExceptionCode& ec)
+{
+    // Not implemented yet.
+    ec = NOT_SUPPORTED_ERR;
+}
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)
diff --git a/Source/WebCore/crypto/algorithms/CryptoAlgorithmHMAC.h b/Source/WebCore/crypto/algorithms/CryptoAlgorithmHMAC.h
new file mode 100644 (file)
index 0000000..3082e29
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef CryptoAlgorithmHMAC_h
+#define CryptoAlgorithmHMAC_h
+
+#include "CryptoAlgorithm.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+namespace WebCore {
+
+class CryptoAlgorithmHMAC FINAL : public CryptoAlgorithm {
+public:
+    static const char* const s_name;
+    static const CryptoAlgorithmIdentifier s_identifier = CryptoAlgorithmIdentifier::HMAC;
+
+    static std::unique_ptr<CryptoAlgorithm> create();
+
+    virtual CryptoAlgorithmIdentifier identifier() const OVERRIDE;
+
+    virtual void sign(const CryptoAlgorithmParameters&, const CryptoKey&, const Vector<CryptoOperationData>&, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+    virtual void verify(const CryptoAlgorithmParameters&, const CryptoKey&, const CryptoOperationData& signature, const Vector<CryptoOperationData>& data, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+    virtual void generateKey(const CryptoAlgorithmParameters&, bool extractable, CryptoKeyUsage, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+    virtual void importKey(const CryptoAlgorithmParameters&, CryptoKeyFormat, const CryptoOperationData&, bool extractable, CryptoKeyUsage, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+    virtual void exportKey(const CryptoAlgorithmParameters&, CryptoKeyFormat, const CryptoKey&, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+
+private:
+    CryptoAlgorithmHMAC();
+    virtual ~CryptoAlgorithmHMAC();
+};
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)
+
+
+#endif // CryptoAlgorithmHMAC_h
diff --git a/Source/WebCore/crypto/keys/CryptoKeyHMAC.cpp b/Source/WebCore/crypto/keys/CryptoKeyHMAC.cpp
new file mode 100644 (file)
index 0000000..f60dcf9
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2013 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 "CryptoKeyHMAC.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#include "CryptoAlgorithmDescriptionBuilder.h"
+#include "CryptoAlgorithmRegistry.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+CryptoKeyHMAC::CryptoKeyHMAC(const Vector<char>& key, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsage usage)
+    : CryptoKey(CryptoAlgorithmIdentifier::HMAC, CryptoKeyType::Secret, extractable, usage)
+    , m_hash(hash)
+    , m_key(key)
+{
+}
+
+CryptoKeyHMAC::~CryptoKeyHMAC()
+{
+}
+
+void CryptoKeyHMAC::buildAlgorithmDescription(CryptoAlgorithmDescriptionBuilder& builder) const
+{
+    CryptoKey::buildAlgorithmDescription(builder);
+
+    auto hashDescriptionBuilder = builder.createEmptyClone();
+    hashDescriptionBuilder->add("name", CryptoAlgorithmRegistry::shared().nameForIdentifier(m_hash));
+    builder.add("hash", *hashDescriptionBuilder);
+
+    builder.add("length", m_key.size());
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SUBTLE_CRYPTO)
diff --git a/Source/WebCore/crypto/keys/CryptoKeyHMAC.h b/Source/WebCore/crypto/keys/CryptoKeyHMAC.h
new file mode 100644 (file)
index 0000000..57dd31d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef CryptoKeyHMAC_h
+#define CryptoKeyHMAC_h
+
+#include "CryptoKey.h"
+#include <wtf/Ref.h>
+#include <wtf/Vector.h>
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+namespace WebCore {
+
+class CryptoKeyHMAC FINAL : public CryptoKey {
+public:
+    static PassRefPtr<CryptoKeyHMAC> create(const Vector<char>& key, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsage usage)
+    {
+        return adoptRef(new CryptoKeyHMAC(key, hash, extractable, usage));
+    }
+    virtual ~CryptoKeyHMAC();
+
+    const Vector<char>& key() const { return m_key; }
+
+    virtual void buildAlgorithmDescription(CryptoAlgorithmDescriptionBuilder&) const OVERRIDE;
+
+private:
+    CryptoKeyHMAC(const Vector<char>& key, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsage);
+
+    CryptoAlgorithmIdentifier m_hash;
+    Vector<char> m_key;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SUBTLE_CRYPTO)
+#endif // CryptoKeyHMAC_h
diff --git a/Source/WebCore/crypto/mac/CryptoAlgorithmHMACMac.cpp b/Source/WebCore/crypto/mac/CryptoAlgorithmHMACMac.cpp
new file mode 100644 (file)
index 0000000..a8146eb
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2013 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 "CryptoAlgorithmHMAC.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#include "CryptoAlgorithmHmacParams.h"
+#include "CryptoKeyHMAC.h"
+#include "ExceptionCode.h"
+#include "JSDOMPromise.h"
+#include <CommonCrypto/CommonHMAC.h>
+
+namespace WebCore {
+
+static bool getCommonCryptoAlgorithm(CryptoAlgorithmIdentifier hashFunction, CCHmacAlgorithm& algorithm)
+{
+    switch (hashFunction) {
+    case CryptoAlgorithmIdentifier::SHA_1:
+        algorithm = kCCHmacAlgSHA1;
+        return true;
+    case CryptoAlgorithmIdentifier::SHA_224:
+        algorithm = kCCHmacAlgSHA224;
+        return true;
+    case CryptoAlgorithmIdentifier::SHA_256:
+        algorithm = kCCHmacAlgSHA256;
+        return true;
+    case CryptoAlgorithmIdentifier::SHA_384:
+        algorithm = kCCHmacAlgSHA384;
+        return true;
+    case CryptoAlgorithmIdentifier::SHA_512:
+        algorithm = kCCHmacAlgSHA512;
+        return true;
+    default:
+        return false;
+    }
+}
+
+static Vector<unsigned char> calculateSignature(CCHmacAlgorithm algorithm, const Vector<char>& key, const Vector<CryptoOperationData>& data)
+{
+    size_t digestLength;
+    switch (algorithm) {
+    case kCCHmacAlgSHA1:
+        digestLength = CC_SHA1_DIGEST_LENGTH;
+        break;
+    case kCCHmacAlgSHA224:
+        digestLength = CC_SHA224_DIGEST_LENGTH;
+        break;
+    case kCCHmacAlgSHA256:
+        digestLength = CC_SHA256_DIGEST_LENGTH;
+        break;
+    case kCCHmacAlgSHA384:
+        digestLength = CC_SHA384_DIGEST_LENGTH;
+        break;
+    case kCCHmacAlgSHA512:
+        digestLength = CC_SHA512_DIGEST_LENGTH;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    CCHmacContext context;
+    CCHmacInit(&context, algorithm, key.data(), key.size());
+    for (size_t i = 0, size = data.size(); i < size; ++i)
+        CCHmacUpdate(&context, data[i].first, data[i].second);
+
+    Vector<unsigned char> result(digestLength);
+    CCHmacFinal(&context, result.data());
+    return result;
+}
+
+void CryptoAlgorithmHMAC::sign(const CryptoAlgorithmParameters& parameters, const CryptoKey& key, const Vector<CryptoOperationData>& data, std::unique_ptr<PromiseWrapper> promise, ExceptionCode& ec)
+{
+    const CryptoAlgorithmHmacParams& hmacParameters = static_cast<const CryptoAlgorithmHmacParams&>(parameters);
+    const CryptoKeyHMAC& hmacKey = static_cast<const CryptoKeyHMAC&>(key);
+
+    CCHmacAlgorithm algorithm;
+    if (!getCommonCryptoAlgorithm(hmacParameters.hash, algorithm)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+
+    Vector<unsigned char> signature = calculateSignature(algorithm, hmacKey.key(), data);
+
+    promise->fulfill(signature);
+}
+
+void CryptoAlgorithmHMAC::verify(const CryptoAlgorithmParameters& parameters, const CryptoKey& key, const CryptoOperationData& expectedSignature, const Vector<CryptoOperationData>& data, std::unique_ptr<PromiseWrapper> promise, ExceptionCode& ec)
+{
+    const CryptoAlgorithmHmacParams& hmacParameters = static_cast<const CryptoAlgorithmHmacParams&>(parameters);
+    const CryptoKeyHMAC& hmacKey = static_cast<const CryptoKeyHMAC&>(key);
+
+    CCHmacAlgorithm algorithm;
+    if (!getCommonCryptoAlgorithm(hmacParameters.hash, algorithm)) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+
+    Vector<unsigned char> signature = calculateSignature(algorithm, hmacKey.key(), data);
+
+    bool result = signature.size() == expectedSignature.second && !memcmp(signature.data(), expectedSignature.first, signature.size());
+
+    promise->fulfill(result);
+}
+
+void CryptoAlgorithmHMAC::generateKey(const CryptoAlgorithmParameters&, bool /*extractable*/, CryptoKeyUsage, std::unique_ptr<PromiseWrapper>, ExceptionCode& ec)
+{
+    // Not yet implemented.
+    ec = NOT_SUPPORTED_ERR;
+}
+
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)
index a80c65c..c5cbdfc 100644 (file)
 
 #if ENABLE(SUBTLE_CRYPTO)
 
-//#include "CryptoAlgorithmHMAC.h"
+#include "CryptoAlgorithmHMAC.h"
 #include "CryptoAlgorithmSHA1.h"
 
 namespace WebCore {
 
 void CryptoAlgorithmRegistry::platformRegisterAlgorithms()
 {
-//    registerAlgorithm(CryptoAlgorithmHMAC::s_name, CryptoAlgorithmHMAC::s_identifier, CryptoAlgorithmHMAC::create);
+    registerAlgorithm(CryptoAlgorithmHMAC::s_name, CryptoAlgorithmHMAC::s_identifier, CryptoAlgorithmHMAC::create);
     registerAlgorithm(CryptoAlgorithmSHA1::s_name, CryptoAlgorithmSHA1::s_identifier, CryptoAlgorithmSHA1::create);
 }