Changeset 163244 in webkit


Ignore:
Timestamp:
Feb 1, 2014 10:14:17 AM (10 years ago)
Author:
ap@apple.com
Message:

Update WebCrypto JWK mapping to use key_ops
https://bugs.webkit.org/show_bug.cgi?id=127609

Reviewed by Sam Weinig.

Source/WebCore:

Updated JWK support ot match current editor draft.

  • bindings/js/JSCryptoKeySerializationJWK.cpp:

(WebCore::getJSArrayFromJSON): Fixed this previously untested function to actually work.
(WebCore::tryJWKKeyOpsValue):
(WebCore::JSCryptoKeySerializationJWK::reconcileUsages):
(WebCore::JSCryptoKeySerializationJWK::reconcileExtractable): Removed an old comment,
these things are now specced.
(WebCore::addToJSON): Made static functions file static, there is no reason for
them to be class members.
(WebCore::buildJSONForOctetSequence):
(WebCore::buildJSONForRSAComponents):
(WebCore::addBoolToJSON):
(WebCore::addJWKAlgorithmToJSON):
(WebCore::addUsagesToJSON):
(WebCore::JSCryptoKeySerializationJWK::serialize):

  • bindings/js/JSCryptoKeySerializationJWK.h:
  • crypto/mac/CryptoAlgorithmAES_KWMac.cpp:

(WebCore::CryptoAlgorithmAES_KW::platformEncrypt):
(WebCore::CryptoAlgorithmAES_KW::platformDecrypt):
Check for length, so that we don't fail silently.

LayoutTests:

  • crypto/subtle/aes-kw-wrap-unwrap-aes-expected.txt:
  • crypto/subtle/aes-kw-wrap-unwrap-aes.html:

Removed a subtest for wrapping JWK. That doesn't really work per the spec, because
JWK is arbitatry length, and AES-KW requires 8*n bytes.

  • crypto/subtle/aes-export-key-expected.txt:
  • crypto/subtle/aes-export-key.html:
  • crypto/subtle/hmac-export-key-expected.txt:
  • crypto/subtle/hmac-export-key.html:
  • crypto/subtle/jwk-export-use-values-expected.txt:
  • crypto/subtle/jwk-export-use-values.html:
  • crypto/subtle/jwk-import-use-values-expected.txt:
  • crypto/subtle/jwk-import-use-values.html:
  • crypto/subtle/rsa-export-key-expected.txt:
  • crypto/subtle/rsa-export-key.html:
  • crypto/subtle/rsa-export-private-key-expected.txt:
  • crypto/subtle/rsa-export-private-key.html:
  • crypto/subtle/rsa-oaep-key-manipulation-expected.txt:
  • crypto/subtle/rsa-oaep-key-manipulation.html:
  • crypto/subtle/rsa-postMessage-expected.txt:
  • crypto/subtle/rsa-postMessage.html:

Updated for the fix.

Location:
trunk
Files:
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r163239 r163244  
     12014-02-01  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Update WebCrypto JWK mapping to use key_ops
     4        https://bugs.webkit.org/show_bug.cgi?id=127609
     5
     6        Reviewed by Sam Weinig.
     7
     8        * crypto/subtle/aes-kw-wrap-unwrap-aes-expected.txt:
     9        * crypto/subtle/aes-kw-wrap-unwrap-aes.html:
     10        Removed a subtest for wrapping JWK. That doesn't really work per the spec, because
     11        JWK is arbitatry length, and AES-KW requires 8*n bytes.
     12
     13        * crypto/subtle/aes-export-key-expected.txt:
     14        * crypto/subtle/aes-export-key.html:
     15        * crypto/subtle/hmac-export-key-expected.txt:
     16        * crypto/subtle/hmac-export-key.html:
     17        * crypto/subtle/jwk-export-use-values-expected.txt:
     18        * crypto/subtle/jwk-export-use-values.html:
     19        * crypto/subtle/jwk-import-use-values-expected.txt:
     20        * crypto/subtle/jwk-import-use-values.html:
     21        * crypto/subtle/rsa-export-key-expected.txt:
     22        * crypto/subtle/rsa-export-key.html:
     23        * crypto/subtle/rsa-export-private-key-expected.txt:
     24        * crypto/subtle/rsa-export-private-key.html:
     25        * crypto/subtle/rsa-oaep-key-manipulation-expected.txt:
     26        * crypto/subtle/rsa-oaep-key-manipulation.html:
     27        * crypto/subtle/rsa-postMessage-expected.txt:
     28        * crypto/subtle/rsa-postMessage.html:
     29        Updated for the fix.
     30
    1312014-02-01  Benjamin Poulain  <bpoulain@apple.com>
    232
  • trunk/LayoutTests/crypto/subtle/aes-export-key-expected.txt

    r160061 r163244  
    2424PASS exportedJWK.alg is 'A192CBC'
    2525PASS exportedJWK.ext is true
    26 PASS exportedJWK.use is 'enc'
     26PASS exportedJWK.use is undefined
     27PASS exportedJWK.key_ops is ['encrypt', 'decrypt', 'wrap', 'unwrap']
    2728
    2829Importing a key that's not extractable...
  • trunk/LayoutTests/crypto/subtle/aes-export-key.html

    r160061 r163244  
    5454    shouldBe("exportedJWK.alg", "'A192CBC'");
    5555    shouldBe("exportedJWK.ext", "true");
    56     shouldBe("exportedJWK.use", "'enc'");
     56    shouldBe("exportedJWK.use", "undefined");
     57    shouldBe("exportedJWK.key_ops", "['encrypt', 'decrypt', 'wrap', 'unwrap']");
    5758
    5859    debug("\nImporting a key that's not extractable...");
  • trunk/LayoutTests/crypto/subtle/aes-kw-wrap-unwrap-aes-expected.txt

    r160547 r163244  
    1717Exporting it...
    1818PASS bytesToHexString(unwrappedKeyData) is bytesToHexString(keyData)
    19 
    20 Wrapping it as JWK...
    21 Unwrapping it...
    22 PASS unwrappedKey.toString() is '[object Key]'
    23 PASS unwrappedKey.type is 'secret'
    24 PASS unwrappedKey.extractable is true
    25 PASS unwrappedKey.algorithm.name is 'AES-CBC'
    26 PASS unwrappedKey.algorithm.length is 128
    27 PASS unwrappedKey.usages is ['decrypt', 'encrypt', 'unwrapKey', 'wrapKey']
    28 Exporting it...
    29 PASS bytesToHexString(unwrappedKeyData) is bytesToHexString(keyData)
    3019PASS successfullyParsed is true
    3120
  • trunk/LayoutTests/crypto/subtle/aes-kw-wrap-unwrap-aes.html

    r160547 r163244  
    5050    shouldBe("bytesToHexString(unwrappedKeyData)", "bytesToHexString(keyData)");
    5151
    52     debug("\nWrapping it as JWK...");
    53     return crypto.subtle.wrapKey("jwk", key, kek, "aes-kw");
    54 }).then(function(result) {
    55     wrappedKey = result;
    56 
    57     debug("Unwrapping it...");
    58     return crypto.subtle.unwrapKey("jwk", wrappedKey, kek, "aes-kw", "aes-cbc", extractable, ["encrypt", "decrypt", "wrapKey", "unwrapKey"]);
    59 }).then(function(result) {
    60     unwrappedKey = result;
    61     shouldBe("unwrappedKey.toString()", "'[object Key]'");
    62     shouldBe("unwrappedKey.type", "'secret'");
    63     shouldBe("unwrappedKey.extractable", "true");
    64     shouldBe("unwrappedKey.algorithm.name", "'AES-CBC'");
    65     shouldBe("unwrappedKey.algorithm.length", "128");
    66     shouldBe("unwrappedKey.usages", "['decrypt', 'encrypt', 'unwrapKey', 'wrapKey']");
    67 
    68     debug("Exporting it...");
    69     return crypto.subtle.exportKey("raw", unwrappedKey);
    70 }).then(function(result) {
    71     unwrappedKeyData = result;
    72     shouldBe("bytesToHexString(unwrappedKeyData)", "bytesToHexString(keyData)");
    73 
    7452    finishJSTest();
    7553});
  • trunk/LayoutTests/crypto/subtle/hmac-export-key-expected.txt

    r160061 r163244  
    1717PASS exportedJWK.alg is 'HS256'
    1818PASS exportedJWK.ext is true
    19 PASS exportedJWK.use is 'sig'
     19PASS exportedJWK.use is undefined
     20PASS exportedJWK.key_ops is ['sign', 'verify']
    2021
    2122Importing a key that's not extractable...
  • trunk/LayoutTests/crypto/subtle/hmac-export-key.html

    r160061 r163244  
    4848    shouldBe("exportedJWK.alg", "'HS256'");
    4949    shouldBe("exportedJWK.ext", "true");
    50     shouldBe("exportedJWK.use", "'sig'");
     50    shouldBe("exportedJWK.use", "undefined");
     51    shouldBe("exportedJWK.key_ops", "['sign', 'verify']");
    5152
    5253    debug("\nImporting a key that's not extractable...");
  • trunk/LayoutTests/crypto/subtle/jwk-export-use-values-expected.txt

    r160061 r163244  
    55
    66encrypt:
    7 PASS jwk.use is 'enconly'
     7PASS jwk.use is undefined
     8PASS jwk.key_ops is ["encrypt"]
    89
    910decrypt:
    10 PASS jwk.use is 'deconly'
     11PASS jwk.use is undefined
     12PASS jwk.key_ops is ["decrypt"]
    1113
    1214encrypt,decrypt:
    13 PASS jwk.use is 'enconly,deconly'
     15PASS jwk.use is undefined
     16PASS jwk.key_ops is ["encrypt","decrypt"]
    1417
    1518wrapKey:
    16 PASS jwk.use is 'wrap'
     19PASS jwk.use is undefined
     20PASS jwk.key_ops is ["wrap"]
    1721
    1822unwrapKey:
    19 PASS jwk.use is 'unwrap'
     23PASS jwk.use is undefined
     24PASS jwk.key_ops is ["unwrap"]
    2025
    2126wrapKey,unwrapKey:
    22 PASS jwk.use is 'wrap,unwrap'
     27PASS jwk.use is undefined
     28PASS jwk.key_ops is ["wrap","unwrap"]
    2329
    2430encrypt,decrypt,wrapKey:
    25 PASS jwk.use is 'enconly,deconly,wrap'
     31PASS jwk.use is undefined
     32PASS jwk.key_ops is ["encrypt","decrypt","wrap"]
    2633
    2734encrypt,decrypt,wrapKey,unwrapKey:
    28 PASS jwk.use is 'enc'
     35PASS jwk.use is undefined
     36PASS jwk.key_ops is ["encrypt","decrypt","wrap","unwrap"]
    2937
    3038sign:
    31 PASS jwk.use is 'sigonly'
     39PASS jwk.use is undefined
     40PASS jwk.key_ops is ["sign"]
    3241
    3342verify:
    34 PASS jwk.use is 'vfyonly'
     43PASS jwk.use is undefined
     44PASS jwk.key_ops is ["verify"]
    3545
    3646sign,verify:
    37 PASS jwk.use is 'sig'
     47PASS jwk.use is undefined
     48PASS jwk.key_ops is ["sign","verify"]
    3849
    3950PASS successfullyParsed is true
  • trunk/LayoutTests/crypto/subtle/jwk-export-use-values.html

    r160061 r163244  
    1919var hmacKeyAsArrayBuffer = Base64URL.parse("ahjkn-_387fgnsibf23qsvahjkn-_387fgnsibf23qs");
    2020
    21 function testWithAESCBC(usages, expectedUse)
     21function testWithAESCBC(usages, expectedKeyOps)
    2222{
    2323    return crypto.subtle.importKey("raw", aesKeyAsArrayBuffer, "AES-CBC", extractable, usages).then(function(result) {
     
    2626        jwk = JSON.parse(bytesToASCIIString(result));
    2727        debug(usages + ":");
    28         shouldBe("jwk.use", "'" + expectedUse + "'");
     28        shouldBe("jwk.use", "undefined");
     29        shouldBe("jwk.key_ops", JSON.stringify(expectedKeyOps));
    2930        debug("");
    3031    });
    3132}
    3233
    33 function testWithHMAC(usages, expectedUse)
     34function testWithHMAC(usages, expectedKeyOps)
    3435{
    3536    return crypto.subtle.importKey("raw", hmacKeyAsArrayBuffer, {name: 'hmac', hash: {name: 'sha-256'}}, extractable, usages).then(function(result) {
     
    3839        jwk = JSON.parse(bytesToASCIIString(result));
    3940        debug(usages + ":");
    40         shouldBe("jwk.use", "'" + expectedUse + "'");
     41        shouldBe("jwk.use", "undefined");
     42        shouldBe("jwk.key_ops", JSON.stringify(expectedKeyOps));
    4143        debug("");
    4244    });
     
    4446
    4547Promise.all([
    46     testWithAESCBC(["encrypt"], "enconly"),
    47     testWithAESCBC(["decrypt"], "deconly"),
    48     testWithAESCBC(["encrypt", "decrypt"], "enconly,deconly"),
    49     testWithAESCBC(["wrapKey"], "wrap"),
    50     testWithAESCBC(["unwrapKey"], "unwrap"),
    51     testWithAESCBC(["wrapKey", "unwrapKey"], "wrap,unwrap"),
    52     testWithAESCBC(["encrypt", "decrypt", "wrapKey"], "enconly,deconly,wrap"),
    53     testWithAESCBC(["encrypt", "decrypt", "wrapKey", "unwrapKey"], "enc"),
    54     testWithHMAC(["sign"], "sigonly"),
    55     testWithHMAC(["verify"], "vfyonly"),
    56     testWithHMAC(["sign", "verify"], "sig"),
     48    testWithAESCBC(["encrypt"], ["encrypt"]),
     49    testWithAESCBC(["decrypt"], ["decrypt"]),
     50    testWithAESCBC(["encrypt", "decrypt"], ["encrypt", "decrypt"]),
     51    testWithAESCBC(["wrapKey"], ["wrap"]),
     52    testWithAESCBC(["unwrapKey"], ["unwrap"]),
     53    testWithAESCBC(["wrapKey", "unwrapKey"], ["wrap", "unwrap"]),
     54    testWithAESCBC(["encrypt", "decrypt", "wrapKey"], ["encrypt", "decrypt", "wrap"]),
     55    testWithAESCBC(["encrypt", "decrypt", "wrapKey", "unwrapKey"], ["encrypt", "decrypt", "wrap", "unwrap"]),
     56    testWithHMAC(["sign"], ["sign"]),
     57    testWithHMAC(["verify"], ["verify"]),
     58    testWithHMAC(["sign", "verify"], ["sign", "verify"]),
    5759]).then(function() { finishJSTest(); } );
    5860</script>
  • trunk/LayoutTests/crypto/subtle/jwk-import-use-values-expected.txt

    r160547 r163244  
    44
    55
    6 enconly:
     6PASS testWithAESCBC(["encrypt"], {key_ops: ["encrypt", "encrypt"]}) threw exception TypeError: JWK key_ops contains a duplicate operation.
     7
     8{"key_ops":["encrypt"]}:
    79PASS key.usages is ["encrypt"]
    810
    9 deconly:
     11{"key_ops":["decrypt"]}:
    1012PASS key.usages is ["decrypt"]
    1113
    12 enconly,deconly:
     14{"key_ops":["encrypt","decrypt"]}:
    1315PASS key.usages is ["decrypt","encrypt"]
    1416
    15 wrap:
     17{"key_ops":["wrap"]}:
    1618PASS key.usages is ["wrapKey"]
    1719
    18 unwrap:
     20{"key_ops":["unwrap"]}:
    1921PASS key.usages is ["unwrapKey"]
    2022
    21 wrap,unwrap:
     23{"key_ops":["wrap","unwrap"]}:
    2224PASS key.usages is ["unwrapKey","wrapKey"]
    2325
    24 enconly,deconly,wrap:
     26{"key_ops":["encrypt","decrypt","wrap"]}:
    2527PASS key.usages is ["decrypt","encrypt","wrapKey"]
    2628
    27 enc:
     29{"use":"enc"}:
    2830PASS key.usages is ["decrypt","encrypt","unwrapKey","wrapKey"]
    2931
    30 sigonly:
     32{"key_ops":["sign"]}:
    3133PASS key.usages is ["sign"]
    3234
    33 vfyonly:
     35{"key_ops":["verify"]}:
    3436PASS key.usages is ["verify"]
    3537
    36 sig:
     38{"use":"sig"}:
    3739PASS key.usages is ["sign","verify"]
    3840
    39 'enconly':
     41{"key_ops":["'encrypt'"]}:
    4042PASS key.usages is []
    4143
    42 enconly :
     44{"key_ops":["encrypt "]}:
    4345PASS key.usages is []
    4446
    45 EncOnly:
     47{"key_ops":["Encrypt"]}:
    4648PASS key.usages is []
    47 
    48 enconly, deconly:
    49 PASS key.usages is ["encrypt"]
    50 
    51 enconly,,deconly:
    52 PASS key.usages is ["decrypt","encrypt"]
    5349
    5450PASS successfullyParsed is true
  • trunk/LayoutTests/crypto/subtle/jwk-import-use-values.html

    r160547 r163244  
    3030};
    3131
    32 function testWithAESCBC(expectedUsages, use)
     32function testWithAESCBC(expectedUsages, jwkUsages)
    3333{
    34     aesKeyAsJSON.use = use;
     34    if (jwkUsages.key_ops) {
     35        aesKeyAsJSON.key_ops = jwkUsages.key_ops;
     36        delete aesKeyAsJSON.use;
     37    } else {
     38        delete aesKeyAsJSON.key_ops;
     39        aesKeyAsJSON.use = jwkUsages.use;
     40    }
     41
    3542    return crypto.subtle.importKey("jwk", asciiToUint8Array(JSON.stringify(aesKeyAsJSON)), "AES-CBC", extractable, ["encrypt", "decrypt", "wrapKey", "unwrapKey"]).then(function(result) {
    3643        key = result;
    37         debug(use + ":");
     44        debug(JSON.stringify(jwkUsages) + ":");
    3845        shouldBe("key.usages", JSON.stringify(expectedUsages));
    3946        debug("");
     
    4148}
    4249
    43 function testWithHMAC(expectedUsages, use)
     50function testWithHMAC(expectedUsages, jwkUsages)
    4451{
    45     hmacKeyAsJSON.use = use;
     52    if (jwkUsages.key_ops) {
     53        hmacKeyAsJSON.key_ops = jwkUsages.key_ops;
     54        delete hmacKeyAsJSON.use;
     55    } else {
     56        delete hmacKeyAsJSON.key_ops;
     57        hmacKeyAsJSON.use = jwkUsages.use;
     58    }
     59
    4660    return crypto.subtle.importKey("jwk", asciiToUint8Array(JSON.stringify(hmacKeyAsJSON)), {name: 'hmac', hash: {name: 'sha-256'}}, extractable, ["sign", "verify"]).then(function(result) {
    4761        key = result;
    48         debug(use + ":");
     62        debug(JSON.stringify(jwkUsages) + ":");
    4963        shouldBe("key.usages", JSON.stringify(expectedUsages));
    5064        debug("");
     
    5266}
    5367
     68// Duplicates are not allowed. We currently raise an exception, although we should reject the promise instead.
     69shouldThrow('testWithAESCBC(["encrypt"], {key_ops: ["encrypt", "encrypt"]})');
     70debug("");
     71
    5472Promise.all([
    55     testWithAESCBC(["encrypt"], "enconly"),
    56     testWithAESCBC(["decrypt"], "deconly"),
    57     testWithAESCBC(["decrypt", "encrypt"], "enconly,deconly"),
    58     testWithAESCBC(["wrapKey"], "wrap"),
    59     testWithAESCBC(["unwrapKey"], "unwrap"),
    60     testWithAESCBC(["unwrapKey", "wrapKey"], "wrap,unwrap"),
    61     testWithAESCBC(["decrypt", "encrypt", "wrapKey"], "enconly,deconly,wrap"),
    62     testWithAESCBC(["decrypt", "encrypt", "unwrapKey", "wrapKey"], "enc"),
    63     testWithHMAC(["sign"], "sigonly"),
    64     testWithHMAC(["verify"], "vfyonly"),
    65     testWithHMAC(["sign", "verify"], "sig"),
     73    testWithAESCBC(["encrypt"], {key_ops: ["encrypt"]}),
     74    testWithAESCBC(["decrypt"], {key_ops: ["decrypt"]}),
     75    testWithAESCBC(["decrypt", "encrypt"], {key_ops: ["encrypt", "decrypt"]}),
     76    testWithAESCBC(["wrapKey"], {key_ops: ["wrap"]}),
     77    testWithAESCBC(["unwrapKey"], {key_ops: ["unwrap"]}),
     78    testWithAESCBC(["unwrapKey", "wrapKey"], {key_ops: ["wrap", "unwrap"]}),
     79    testWithAESCBC(["decrypt", "encrypt", "wrapKey"], {key_ops: ["encrypt", "decrypt", "wrap"]}),
     80    testWithAESCBC(["decrypt", "encrypt", "unwrapKey", "wrapKey"], {use: "enc"}),
     81    testWithHMAC(["sign"], {key_ops: ["sign"]}),
     82    testWithHMAC(["verify"], {key_ops: ["verify"]}),
     83    testWithHMAC(["sign", "verify"], {use: "sig"}),
    6684
    67 // Incorrect use strings. There is currently no spec for what to do, but ignoring unknown uses seems right.
    68     testWithAESCBC([], "'enconly'"),
    69     testWithAESCBC([], "enconly "),
    70     testWithAESCBC([], "EncOnly"),
    71     testWithAESCBC(["encrypt"], "enconly, deconly"),
    72     testWithAESCBC(["decrypt","encrypt"], "enconly,,deconly"),
     85// Unknown key_ops strings are ignored.
     86    testWithAESCBC([], {key_ops: ["'encrypt'"]}),
     87    testWithAESCBC([], {key_ops: ["encrypt "]}),
     88    testWithAESCBC([], {key_ops: ["Encrypt"]}),
    7389
    7490]).then(function() { finishJSTest(); } );
  • trunk/LayoutTests/crypto/subtle/rsa-export-key-expected.txt

    r160061 r163244  
    1818PASS exportedJWK.alg is 'RS256'
    1919PASS exportedJWK.ext is true
    20 PASS exportedJWK.use is 'sig'
     20PASS exportedJWK.use is undefined
     21PASS exportedJWK.key_ops is ['sign', 'verify']
    2122PASS successfullyParsed is true
    2223
  • trunk/LayoutTests/crypto/subtle/rsa-export-key.html

    r160061 r163244  
    4646    shouldBe("exportedJWK.alg", "'RS256'");
    4747    shouldBe("exportedJWK.ext", "true");
    48     shouldBe("exportedJWK.use", "'sig'");
     48    shouldBe("exportedJWK.use", "undefined");
     49    shouldBe("exportedJWK.key_ops", "['sign', 'verify']");
    4950
    5051    finishJSTest();
  • trunk/LayoutTests/crypto/subtle/rsa-export-private-key-expected.txt

    r160061 r163244  
    2020PASS exportedJWK.alg is privateKeyJSON.alg
    2121PASS exportedJWK.ext is true
    22 PASS exportedJWK.use is 'sig'
     22PASS exportedJWK.key_ops is ['sign', 'verify']
     23PASS exportedJWK.use is undefined
    2324PASS successfullyParsed is true
    2425
  • trunk/LayoutTests/crypto/subtle/rsa-export-private-key.html

    r160061 r163244  
    5454    shouldBe("exportedJWK.alg", "privateKeyJSON.alg");
    5555    shouldBe("exportedJWK.ext", "true");
    56     shouldBe("exportedJWK.use", "'sig'");
     56    shouldBe("exportedJWK.key_ops", "['sign', 'verify']");
     57    shouldBe("exportedJWK.use", "undefined");
    5758
    5859    finishJSTest();
  • trunk/LayoutTests/crypto/subtle/rsa-oaep-key-manipulation-expected.txt

    r160547 r163244  
    2828PASS jwkPublicKey.alg is 'RSA-OAEP'
    2929PASS jwkPublicKey.ext is true
    30 PASS jwkPublicKey.use is 'enc'
     30PASS jwkPublicKey.key_ops is ['encrypt', 'decrypt', 'wrap', 'unwrap']
     31PASS jwkPublicKey.use is undefined
    3132PASS jwkPublicKey.kty is 'RSA'
    3233PASS bytesToHexString(Base64URL.parse(jwkPublicKey.e)) is '010001'
  • trunk/LayoutTests/crypto/subtle/rsa-oaep-key-manipulation.html

    r160547 r163244  
    5757    shouldBe("jwkPublicKey.alg", "'RSA-OAEP'");
    5858    shouldBe("jwkPublicKey.ext", "true");
    59     shouldBe("jwkPublicKey.use", "'enc'");
     59    shouldBe("jwkPublicKey.key_ops", "['encrypt', 'decrypt', 'wrap', 'unwrap']");
     60    shouldBe("jwkPublicKey.use", "undefined");
    6061    shouldBe("jwkPublicKey.kty", "'RSA'");
    6162    shouldBe("bytesToHexString(Base64URL.parse(jwkPublicKey.e))", "'010001'");
  • trunk/LayoutTests/crypto/subtle/rsa-postMessage-expected.txt

    r160491 r163244  
    1616PASS exportedJWK.alg is 'RS256'
    1717PASS exportedJWK.ext is true
    18 PASS exportedJWK.use is 'sig'
     18PASS exportedJWK.key_ops is ['sign','verify']
     19PASS exportedJWK.use is undefined
    1920PASS exportedJWK.n is privateKeyJSON.n
    2021PASS exportedJWK.e is privateKeyJSON.e
  • trunk/LayoutTests/crypto/subtle/rsa-postMessage.html

    r160491 r163244  
    4242        shouldBe("exportedJWK.alg", "'RS256'");
    4343        shouldBe("exportedJWK.ext", "true");
    44         shouldBe("exportedJWK.use", "'sig'");
     44        shouldBe("exportedJWK.key_ops", "['sign','verify']");
     45        shouldBe("exportedJWK.use", "undefined");
    4546        shouldBe("exportedJWK.n", "privateKeyJSON.n");
    4647        shouldBe("exportedJWK.e", "privateKeyJSON.e");
  • trunk/Source/WebCore/ChangeLog

    r163242 r163244  
     12014-02-01  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Update WebCrypto JWK mapping to use key_ops
     4        https://bugs.webkit.org/show_bug.cgi?id=127609
     5
     6        Reviewed by Sam Weinig.
     7
     8        Updated JWK support ot match current editor draft.
     9
     10        * bindings/js/JSCryptoKeySerializationJWK.cpp:
     11        (WebCore::getJSArrayFromJSON): Fixed this previously untested function to actually work.
     12        (WebCore::tryJWKKeyOpsValue):
     13        (WebCore::JSCryptoKeySerializationJWK::reconcileUsages):
     14        (WebCore::JSCryptoKeySerializationJWK::reconcileExtractable): Removed an old comment,
     15        these things are now specced.
     16        (WebCore::addToJSON): Made static functions file static, there is no reason for
     17        them to be class members.
     18        (WebCore::buildJSONForOctetSequence):
     19        (WebCore::buildJSONForRSAComponents):
     20        (WebCore::addBoolToJSON):
     21        (WebCore::addJWKAlgorithmToJSON):
     22        (WebCore::addUsagesToJSON):
     23        (WebCore::JSCryptoKeySerializationJWK::serialize):
     24        * bindings/js/JSCryptoKeySerializationJWK.h:
     25
     26        * crypto/mac/CryptoAlgorithmAES_KWMac.cpp:
     27        (WebCore::CryptoAlgorithmAES_KW::platformEncrypt):
     28        (WebCore::CryptoAlgorithmAES_KW::platformDecrypt):
     29        Check for length, so that we don't fail silently.
     30
    1312014-02-01  David Kilzer  <ddkilzer@apple.com>
    232
  • trunk/Source/WebCore/bindings/js/JSCryptoKeySerializationJWK.cpp

    r160502 r163244  
    6161    JSValue value = slot.getValue(exec, identifier);
    6262    ASSERT(!exec->hadException());
    63     if (isJSArray(value)) {
     63    if (!isJSArray(value)) {
    6464        throwTypeError(exec, String::format("Expected an array for \"%s\" JSON key",  key));
    6565        return false;
     
    249249}
    250250
     251static bool tryJWKKeyOpsValue(ExecState* exec, CryptoKeyUsage& usages, const String& operation, const String& tryOperation, CryptoKeyUsage tryUsage)
     252{
     253    if (operation == tryOperation) {
     254        if (usages & tryUsage) {
     255            throwTypeError(exec, "JWK key_ops contains a duplicate operation");
     256            return false;
     257        }
     258        usages |= tryUsage;
     259    }
     260    return true;
     261}
     262
    251263void JSCryptoKeySerializationJWK::reconcileUsages(CryptoKeyUsage& suggestedUsages) const
    252264{
    253     String jwkUseString;
    254     if (!getStringFromJSON(m_exec, m_json.get(), "use", jwkUseString)) {
    255         // "use" is optional in JWK.
     265    CryptoKeyUsage jwkUsages = 0;
     266
     267    JSArray* keyOps;
     268    if (getJSArrayFromJSON(m_exec, m_json.get(), "key_ops", keyOps)) {
     269        for (size_t i = 0; i < keyOps->length(); ++i) {
     270            JSValue jsValue = keyOps->getIndex(m_exec, i);
     271            String operation;
     272            if (!jsValue.getString(m_exec, operation)) {
     273                if (!m_exec->hadException())
     274                    throwTypeError(m_exec, "JWK key_ops attribute could not be processed");
     275                return;
     276            }
     277            if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("sign"), CryptoKeyUsageSign))
     278                return;
     279            if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("verify"), CryptoKeyUsageVerify))
     280                return;
     281            if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("encrypt"), CryptoKeyUsageEncrypt))
     282                return;
     283            if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("decrypt"), CryptoKeyUsageDecrypt))
     284                return;
     285            if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("wrap"), CryptoKeyUsageWrapKey))
     286                return;
     287            if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("unwrap"), CryptoKeyUsageUnwrapKey))
     288                return;
     289            if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("deriveKey"), CryptoKeyUsageDeriveKey))
     290                return;
     291            if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("deriveBits"), CryptoKeyUsageDeriveBits))
     292                return;
     293        }
     294    } else {
     295        if (m_exec->hadException())
     296            return;
     297
     298        String jwkUseString;
     299        if (!getStringFromJSON(m_exec, m_json.get(), "use", jwkUseString)) {
     300            // We have neither key_ops nor use.
     301            return;
     302        }
     303
     304        if (jwkUseString == "enc")
     305            jwkUsages |= (CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey);
     306        else if (jwkUseString == "sig")
     307            jwkUsages |= (CryptoKeyUsageSign | CryptoKeyUsageVerify);
     308        else {
     309            throwTypeError(m_exec, "Unsupported JWK key use value \"" + jwkUseString + "\"");
     310            return;
     311        }
     312    }
     313
     314    suggestedUsages = suggestedUsages & jwkUsages;
     315}
     316
     317void JSCryptoKeySerializationJWK::reconcileExtractable(bool& suggestedExtractable) const
     318{
     319    bool jwkExtractable;
     320    if (!getBooleanFromJSON(m_exec, m_json.get(), "ext", jwkExtractable))
    256321        return;
    257     }
    258 
    259     // Implemented according to a proposal in <https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796>.
    260     Vector<String> jwkUsageValues;
    261     jwkUseString.split(',', jwkUsageValues);
    262     CryptoKeyUsage jwkUsages = 0;
    263     for (size_t i = 0, size = jwkUsageValues.size(); i < size; ++i) {
    264         String jwkUse = jwkUsageValues[i];
    265         if (jwkUse == "sig")
    266             jwkUsages |= (CryptoKeyUsageSign | CryptoKeyUsageVerify);
    267         else if (jwkUse == "enc")
    268             jwkUsages |= (CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey);
    269         else if (jwkUse == "enconly")
    270             jwkUsages |= CryptoKeyUsageEncrypt;
    271         else if (jwkUse == "deconly")
    272             jwkUsages |= CryptoKeyUsageDecrypt;
    273         else if (jwkUse == "sigonly")
    274             jwkUsages |= CryptoKeyUsageSign;
    275         else if (jwkUse == "vfyonly")
    276             jwkUsages |= CryptoKeyUsageVerify;
    277         else if (jwkUse == "drvkey")
    278             jwkUsages |= CryptoKeyUsageDeriveKey;
    279         else if (jwkUse == "drvbits")
    280             jwkUsages |= CryptoKeyUsageDeriveBits;
    281         else if (jwkUse == "wrap")
    282             jwkUsages |= CryptoKeyUsageWrapKey;
    283         else if (jwkUse == "unwrap")
    284             jwkUsages |= CryptoKeyUsageUnwrapKey;
    285     }
    286 
    287     suggestedUsages = suggestedUsages & jwkUsages;
    288 }
    289 
    290 void JSCryptoKeySerializationJWK::reconcileExtractable(bool& suggestedExtractable) const
    291 {
    292     bool jwkExtractable;
    293     if (!getBooleanFromJSON(m_exec, m_json.get(), "ext", jwkExtractable)) {
    294         // "ext" not in JWK or WebCrypto specs yet, implemented according to a proposal in <https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796>.
    295         return;
    296     }
    297322
    298323    suggestedExtractable = suggestedExtractable && jwkExtractable;
     
    473498}
    474499
    475 void JSCryptoKeySerializationJWK::buildJSONForOctetSequence(ExecState* exec, const Vector<uint8_t>& keyData, JSObject* result)
     500static void addToJSON(ExecState* exec, JSObject* json, const char* key, const String& value)
     501{
     502    VM& vm = exec->vm();
     503    Identifier identifier(&vm, key);
     504    json->putDirect(vm, identifier, jsString(exec, value));
     505}
     506
     507static void buildJSONForOctetSequence(ExecState* exec, const Vector<uint8_t>& keyData, JSObject* result)
    476508{
    477509    addToJSON(exec, result, "kty", "oct");
     
    479511}
    480512
    481 void JSCryptoKeySerializationJWK::buildJSONForRSAComponents(JSC::ExecState* exec, const CryptoKeyDataRSAComponents& data, JSC::JSObject* result)
     513static void buildJSONForRSAComponents(JSC::ExecState* exec, const CryptoKeyDataRSAComponents& data, JSC::JSObject* result)
    482514{
    483515    addToJSON(exec, result, "kty", "RSA");
     
    513545}
    514546
    515 void JSCryptoKeySerializationJWK::addToJSON(ExecState* exec, JSObject* json, const char* key, const String& value)
    516 {
    517     VM& vm = exec->vm();
    518     Identifier identifier(&vm, key);
    519     json->putDirect(vm, identifier, jsString(exec, value));
    520 }
    521 
    522 void JSCryptoKeySerializationJWK::addBoolToJSON(ExecState* exec, JSObject* json, const char* key, bool value)
     547static void addBoolToJSON(ExecState* exec, JSObject* json, const char* key, bool value)
    523548{
    524549    VM& vm = exec->vm();
     
    527552}
    528553
    529 void JSCryptoKeySerializationJWK::addJWKAlgorithmToJSON(ExecState* exec, JSObject* json, const CryptoKey& key)
     554static void addJWKAlgorithmToJSON(ExecState* exec, JSObject* json, const CryptoKey& key)
    530555{
    531556    String jwkAlgorithm;
     
    628653}
    629654
    630 static bool processUseValue(StringBuilder& builder, CryptoKeyUsage& usages, const String& useString, CryptoKeyUsage usagesForUseString)
    631 {
    632     if ((usages & usagesForUseString) != usagesForUseString)
    633         return false;
    634 
    635     if (!builder.isEmpty())
    636         builder.append(',');
    637     builder.append(useString);
    638 
    639     usages &= ~usagesForUseString;
    640 
    641     return true;
    642 }
    643 
    644 void JSCryptoKeySerializationJWK::addJWKUseToJSON(ExecState* exec, JSObject* json, CryptoKeyUsage usages)
    645 {
    646     // Use mapping implemented according to a proposal in <https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796>.
    647     StringBuilder useBuilder;
    648     CryptoKeyUsage remainingUsages = usages;
    649     while (remainingUsages) {
    650         if (processUseValue(useBuilder, remainingUsages, "enc", CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey))
    651             continue;
    652         if (processUseValue(useBuilder, remainingUsages, "sig", CryptoKeyUsageSign | CryptoKeyUsageVerify))
    653             continue;
    654         if (processUseValue(useBuilder, remainingUsages, "enconly", CryptoKeyUsageEncrypt))
    655             continue;
    656         if (processUseValue(useBuilder, remainingUsages, "deconly", CryptoKeyUsageDecrypt))
    657             continue;
    658         if (processUseValue(useBuilder, remainingUsages, "sigonly", CryptoKeyUsageSign))
    659             continue;
    660         if (processUseValue(useBuilder, remainingUsages, "vfyonly", CryptoKeyUsageVerify))
    661             continue;
    662         if (processUseValue(useBuilder, remainingUsages, "drvkey", CryptoKeyUsageDeriveKey))
    663             continue;
    664         if (processUseValue(useBuilder, remainingUsages, "drvbits", CryptoKeyUsageDeriveBits))
    665             continue;
    666         if (processUseValue(useBuilder, remainingUsages, "wrap", CryptoKeyUsageWrapKey))
    667             continue;
    668         if (processUseValue(useBuilder, remainingUsages, "unwrap", CryptoKeyUsageUnwrapKey))
    669             continue;
    670         throwTypeError(exec, "Key usages cannot be represented in JWK.");
    671         return;
    672     }
    673 
    674     addToJSON(exec, json, "use", useBuilder.toString());
     655static void addUsagesToJSON(ExecState* exec, JSObject* json, CryptoKeyUsage usages)
     656{
     657    JSArray* keyOps = constructEmptyArray(exec, 0, exec->lexicalGlobalObject(), 0);
     658
     659    unsigned index = 0;
     660    if (usages & CryptoKeyUsageSign)
     661        keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("sign")));
     662    if (usages & CryptoKeyUsageVerify)
     663        keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("verify")));
     664    if (usages & CryptoKeyUsageEncrypt)
     665        keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("encrypt")));
     666    if (usages & CryptoKeyUsageDecrypt)
     667        keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("decrypt")));
     668    if (usages & CryptoKeyUsageWrapKey)
     669        keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("wrap")));
     670    if (usages & CryptoKeyUsageUnwrapKey)
     671        keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("unwrap")));
     672    if (usages & CryptoKeyUsageDeriveKey)
     673        keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("deriveKey")));
     674    if (usages & CryptoKeyUsageDeriveBits)
     675        keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("deriveBits")));
     676
     677    json->putDirect(exec->vm(), Identifier(exec, "key_ops"), keyOps);
    675678}
    676679
     
    692695    addBoolToJSON(exec, result, "ext", key.extractable());
    693696
    694     addJWKUseToJSON(exec, result, key.usagesBitmap());
     697    addUsagesToJSON(exec, result, key.usagesBitmap());
    695698    if (exec->hadException())
    696699        return String();
  • trunk/Source/WebCore/bindings/js/JSCryptoKeySerializationJWK.h

    r162158 r163244  
    6767    virtual std::unique_ptr<CryptoKeyData> keyData() const override;
    6868
    69     static void buildJSONForOctetSequence(JSC::ExecState*, const Vector<uint8_t>&, JSC::JSObject* result);
    70     static void buildJSONForRSAComponents(JSC::ExecState*, const CryptoKeyDataRSAComponents&, JSC::JSObject* result);
    71     static void addJWKAlgorithmToJSON(JSC::ExecState*, JSC::JSObject*, const CryptoKey& key);
    72     static void addJWKUseToJSON(JSC::ExecState*, JSC::JSObject*, CryptoKeyUsage);
    73     static void addToJSON(JSC::ExecState*, JSC::JSObject*, const char* key, const String& value);
    74     static void addBoolToJSON(JSC::ExecState*, JSC::JSObject*, const char* key, bool value);
    75 
    7669    bool keySizeIsValid(size_t sizeInBits) const;
    7770    std::unique_ptr<CryptoKeyData> keyDataOctetSequence() const;
  • trunk/Source/WebCore/crypto/mac/CryptoAlgorithmAES_KWMac.cpp

    r159966 r163244  
    3737void CryptoAlgorithmAES_KW::platformEncrypt(const CryptoKeyAES& key, const CryptoOperationData& data, VectorCallback callback, VoidCallback failureCallback, ExceptionCode&)
    3838{
     39    if (data.second % 8) {
     40        // RFC 3394 uses 64-bit blocks as input.
     41        // <rdar://problem/15949992> CommonCrypto doesn't detect incorrect data length, silently producing a bad cyphertext.
     42        failureCallback();
     43        return;
     44    }
     45
    3946    Vector<uint8_t> result(CCSymmetricWrappedSize(kCCWRAPAES, data.second));
    4047    size_t resultSize = result.size();
     
    5259    Vector<uint8_t> result(CCSymmetricUnwrappedSize(kCCWRAPAES, data.second));
    5360    size_t resultSize = result.size();
     61
     62    if (resultSize % 8) {
     63        failureCallback();
     64        return;
     65    }
     66
    5467    int status = CCSymmetricKeyUnwrap(kCCWRAPAES, CCrfc3394_iv, CCrfc3394_ivLen, key.key().data(), key.key().size(), data.first, data.second, result.data(), &resultSize);
    5568    if (status) {
Note: See TracChangeset for help on using the changeset viewer.