Changeset 159377 in webkit


Ignore:
Timestamp:
Nov 15, 2013 11:10:31 PM (10 years ago)
Author:
ap@apple.com
Message:

Support exporting symmetric keys as JWK
https://bugs.webkit.org/show_bug.cgi?id=124442

Reviewed by Sam Weinig.

Source/JavaScriptCore:

  • runtime/JSONObject.h: Export JSONStringify.

Source/WebCore:

Error handling is not consistent yet - some errors cause exceptions, and others
result in rejected promises. This part of spec is incomplete, so I basically did
what was most straightforward in each case.

  • bindings/js/JSCryptoKeySerializationJWK.h:
  • bindings/js/JSCryptoKeySerializationJWK.cpp:

(WebCore::JSCryptoKeySerializationJWK::reconcileUsages): Updated a comment with a better link.
(WebCore::JSCryptoKeySerializationJWK::buildJSONForOctetSequence): A helper to building JWK.
(WebCore::JSCryptoKeySerializationJWK::addToJSON): Ditto.
(WebCore::JSCryptoKeySerializationJWK::addBoolToJSON): Ditto.
(WebCore::JSCryptoKeySerializationJWK::addJWKAlgorithmToJSON): Ditto. The code for
mapping is my best guess, this all needs to be specified.
(WebCore::JSCryptoKeySerializationJWK::addJWKUseToJSON): A helper to building JWK.
(WebCore::JSCryptoKeySerializationJWK::serialize): Build a JSON string for the key.

  • bindings/js/JSSubtleCryptoCustom.cpp:

(WebCore::JSSubtleCrypto::importKey): Updated a comment.
(WebCore::JSSubtleCrypto::exportKey): Use CryptoKeySerialization (also for raw keys,
for consistency).

  • crypto/CryptoKey.h:

(WebCore::CryptoKey::algorithmIdentifier):
(WebCore::CryptoKey::usagesBitmap):
Exposed data needed for building JWK (it used to be only exposed in a form suitable
for DOM accessors).

  • crypto/keys/CryptoKeyHMAC.h: Ditto, added an accessor for JWK.
  • crypto/keys/CryptoKeySerializationRaw.cpp: (WebCore::CryptoKeySerializationRaw::serialize):
  • crypto/keys/CryptoKeySerializationRaw.h:

Moved from JSSubtleCryptoCustom.cpp for consistency.

Source/WTF:

Base64URL encoding doesn't use '=' padding, and doesn't need any other options.
Added this mode for encode, and removed policy arguments from exposed functions.

  • wtf/text/Base64.cpp:

(WTF::base64EncodeInternal):
(WTF::base64URLEncode):
(WTF::base64URLDecode):

  • wtf/text/Base64.h:

(WTF::base64URLEncode):

LayoutTests:

  • 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:
Location:
trunk
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r159374 r159377  
     12013-11-15  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Support exporting symmetric keys as JWK
     4        https://bugs.webkit.org/show_bug.cgi?id=124442
     5
     6        Reviewed by Sam Weinig.
     7
     8        * crypto/subtle/aes-export-key-expected.txt:
     9        * crypto/subtle/aes-export-key.html:
     10        * crypto/subtle/hmac-export-key-expected.txt:
     11        * crypto/subtle/hmac-export-key.html:
     12
    1132013-11-15  Simon Fraser  <simon.fraser@apple.com>
    214
  • trunk/LayoutTests/crypto/subtle/aes-export-key-expected.txt

    r159327 r159377  
     1CONSOLE MESSAGE: Key is not extractable
     2CONSOLE MESSAGE: Key is not extractable
    13Test exporting an AES key.
    24
     
    46
    57
     8PASS crypto.subtle.exportKey("raw") threw exception TypeError: Not enough arguments.
     9PASS crypto.subtle.exportKey("raw", null) threw exception TypeError: Type error.
     10PASS crypto.subtle.exportKey("raw", undefined) threw exception TypeError: Type error.
     11PASS crypto.subtle.exportKey("raw", {}) threw exception TypeError: Type error.
     12PASS crypto.subtle.exportKey("raw", 1) threw exception TypeError: Type error.
     13
    614Importing a JWK key...
     15PASS crypto.subtle.exportKey(null, key) threw exception TypeError: Unknown key format.
     16PASS crypto.subtle.exportKey(undefined, key) threw exception TypeError: Unknown key format.
     17PASS crypto.subtle.exportKey({}, key) threw exception TypeError: Unknown key format.
     18PASS crypto.subtle.exportKey("", key) threw exception TypeError: Unknown key format.
     19PASS crypto.subtle.exportKey("foobar", key) threw exception TypeError: Unknown key format.
     20
    721Exporting the key as raw data...
    822PASS bytesToHexString(new Uint8Array(exportedData)) is '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'
     23Exporting the key as JWK...
     24PASS exportedJWK.kty is 'oct'
     25PASS exportedJWK.k is 'jnOw99oOZFLIEPMrgJB55WL46tJSLGt7'
     26PASS exportedJWK.alg is 'A192CBC'
     27PASS exportedJWK.extractable is true
     28PASS exportedJWK.use is 'enc'
     29
     30Importing a key that's not extractable...
     31
     32Trying to export as raw...
     33PASS Rejected, as expected
     34Trying to export as jwk...
     35PASS Rejected, as expected
     36
     37Importing a key with only encrypt+decrypt usage (this doesn't map to anything in JWK, as 'enc' also allows wrap/unwrap)...
     38PASS crypto.subtle.exportKey("jwk", key) threw exception TypeError: Key usages cannot be represented in JWK. Only two variants are supported: sign+verify and encrypt+decrypt+wrapKey+unwrapKey.
    939PASS successfullyParsed is true
    1040
  • trunk/LayoutTests/crypto/subtle/aes-export-key.html

    r159327 r159377  
    1515
    1616var extractable = true;
     17var nonExtractable = false;
    1718
    1819var jwkKey = {
    19     "kty": "oct",
    20     "k": "jnOw99oOZFLIEPMrgJB55WL46tJSLGt7"
     20    kty: "oct",
     21    k: "jnOw99oOZFLIEPMrgJB55WL46tJSLGt7"
    2122};
    2223
    2324var jwkKeyAsArrayBuffer = asciiToUint8Array(JSON.stringify(jwkKey));
    2425
    25 debug("Importing a JWK key...");
    26 crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, "AES-CBC", extractable, []).then(function(result) {
     26shouldThrow('crypto.subtle.exportKey("raw")');
     27shouldThrow('crypto.subtle.exportKey("raw", null)');
     28shouldThrow('crypto.subtle.exportKey("raw", undefined)');
     29shouldThrow('crypto.subtle.exportKey("raw", {})');
     30shouldThrow('crypto.subtle.exportKey("raw", 1)');
     31
     32debug("\nImporting a JWK key...");
     33crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, "AES-CBC", extractable, ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey']).then(function(result) {
    2734    key = result;
    2835
    29     debug("Exporting the key as raw data...");
     36    shouldThrow('crypto.subtle.exportKey(null, key)');
     37    shouldThrow('crypto.subtle.exportKey(undefined, key)');
     38    shouldThrow('crypto.subtle.exportKey({}, key)');
     39    shouldThrow('crypto.subtle.exportKey("", key)');
     40    shouldThrow('crypto.subtle.exportKey("foobar", key)');
     41
     42    debug("\nExporting the key as raw data...");
    3043    return crypto.subtle.exportKey("raw", key);
    3144}).then(function(result) {
    3245    exportedData = result;
    3346    shouldBe("bytesToHexString(new Uint8Array(exportedData))", "'8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'");
     47
     48    debug("Exporting the key as JWK...");
     49    return crypto.subtle.exportKey("jwk", key);
     50}).then(function(result) {
     51    exportedJWK = JSON.parse(result);
     52    shouldBe("exportedJWK.kty", "'oct'");
     53    shouldBe("exportedJWK.k", "'jnOw99oOZFLIEPMrgJB55WL46tJSLGt7'");
     54    shouldBe("exportedJWK.alg", "'A192CBC'");
     55    shouldBe("exportedJWK.extractable", "true");
     56    shouldBe("exportedJWK.use", "'enc'");
     57
     58    debug("\nImporting a key that's not extractable...");
     59    return crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, "AES-CBC", nonExtractable, ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'])
     60}).then(function(result) {
     61    key = result;
     62
     63    debug("\nTrying to export as raw...");
     64    return crypto.subtle.exportKey("raw", key);
     65}).then(function(result) {
     66    testFailed("Promise wasn't rejected");
     67    finishJSTest();
     68}, function() {
     69    testPassed("Rejected, as expected");
     70
     71    debug("Trying to export as jwk...");
     72    return crypto.subtle.exportKey("jwk", key);
     73}).then(function(result) {
     74    testFailed("Promise wasn't rejected");
     75    finishJSTest();
     76}, function() {
     77    testPassed("Rejected, as expected");
     78
     79    // If this test starts to fail because a way to encode encrypt+decrypt is added to JWK, change to something that's not there.
     80    // If all WebCrypto modes are added to JWK, then this test will be obsolete.
     81    debug("\nImporting a key with only encrypt+decrypt usage (this doesn't map to anything in JWK, as 'enc' also allows wrap/unwrap)...");
     82    return crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, "AES-CBC", extractable, ['encrypt', 'decrypt'])
     83}).then(function(result) {
     84    key = result;
     85
     86    // Maybe this should be a rejected promise, not an exception. We'll need to find a way to provide meaningful error messages with such failures.
     87    shouldThrow('crypto.subtle.exportKey("jwk", key)');
    3488
    3589    finishJSTest();
  • trunk/LayoutTests/crypto/subtle/hmac-export-key-expected.txt

    r159327 r159377  
     1CONSOLE MESSAGE: Key is not extractable
     2CONSOLE MESSAGE: Key is not extractable
    13Test exporting an AES key.
    24
     
    57
    68Importing a JWK key...
     9PASS crypto.subtle.exportKey(null, key) threw exception TypeError: Unknown key format.
     10PASS crypto.subtle.exportKey(undefined, key) threw exception TypeError: Unknown key format.
     11PASS crypto.subtle.exportKey({}, key) threw exception TypeError: Unknown key format.
     12PASS crypto.subtle.exportKey("", key) threw exception TypeError: Unknown key format.
     13PASS crypto.subtle.exportKey("foobar", key) threw exception TypeError: Unknown key format.
    714Exporting the key as raw data...
    815PASS bytesToHexString(new Uint8Array(exportedData)) is '6a18e49feff7f3b7e09ec89b7f6deab2f6a18e49feff7f3b7e09ec89b7f6deab'
     16Exporting the key as JWK...
     17PASS exportedJWK.kty is 'oct'
     18PASS exportedJWK.k is 'ahjkn-_387fgnsibf23qsvahjkn-_387fgnsibf23qs'
     19PASS exportedJWK.alg is 'HS256'
     20PASS exportedJWK.extractable is true
     21PASS exportedJWK.use is 'sig'
     22
     23Importing a key that's not extractable...
     24
     25Trying to export as raw...
     26PASS Rejected, as expected
     27Trying to export as jwk...
     28PASS Rejected, as expected
     29
     30Importing a key with only sign usage (this doesn't map to anything in JWK, as 'sig' allows both sign and verify)...
     31PASS crypto.subtle.exportKey("jwk", key) threw exception TypeError: Key usages cannot be represented in JWK. Only two variants are supported: sign+verify and encrypt+decrypt+wrapKey+unwrapKey.
    932PASS successfullyParsed is true
    1033
  • trunk/LayoutTests/crypto/subtle/hmac-export-key.html

    r159327 r159377  
    1515
    1616var extractable = true;
     17var nonExtractable = false;
    1718
    1819var jwkKey = {
     
    2425
    2526debug("Importing a JWK key...");
    26 crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, { name: "HMAC", hash: "SHA-512" }, extractable, ["sign", "verify"]).then(function(result) {
     27crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, { name: "HMAC", hash: "SHA-256" }, extractable, ["sign", "verify"]).then(function(result) {
    2728    key = result;
     29
     30    shouldThrow('crypto.subtle.exportKey(null, key)');
     31    shouldThrow('crypto.subtle.exportKey(undefined, key)');
     32    shouldThrow('crypto.subtle.exportKey({}, key)');
     33    shouldThrow('crypto.subtle.exportKey("", key)');
     34    shouldThrow('crypto.subtle.exportKey("foobar", key)');
    2835
    2936    debug("Exporting the key as raw data...");
     
    3239    exportedData = result;
    3340    shouldBe("bytesToHexString(new Uint8Array(exportedData))", "'6a18e49feff7f3b7e09ec89b7f6deab2f6a18e49feff7f3b7e09ec89b7f6deab'");
     41
     42    debug("Exporting the key as JWK...");
     43    return crypto.subtle.exportKey("jwk", key);
     44}).then(function(result) {
     45    exportedJWK = JSON.parse(result);
     46    shouldBe("exportedJWK.kty", "'oct'");
     47    shouldBe("exportedJWK.k", "'ahjkn-_387fgnsibf23qsvahjkn-_387fgnsibf23qs'");
     48    shouldBe("exportedJWK.alg", "'HS256'");
     49    shouldBe("exportedJWK.extractable", "true");
     50    shouldBe("exportedJWK.use", "'sig'");
     51
     52    debug("\nImporting a key that's not extractable...");
     53    return crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, { name: "HMAC", hash: "SHA-256" }, nonExtractable, ["sign", "verify"]);
     54}).then(function(result) {
     55    key = result;
     56
     57    debug("\nTrying to export as raw...");
     58    return crypto.subtle.exportKey("raw", key);
     59}).then(function(result) {
     60    testFailed("Promise wasn't rejected");
     61    finishJSTest();
     62}, function() {
     63    testPassed("Rejected, as expected");
     64
     65    debug("Trying to export as jwk...");
     66    return crypto.subtle.exportKey("jwk", key);
     67}).then(function(result) {
     68    testFailed("Promise wasn't rejected");
     69    finishJSTest();
     70}, function() {
     71    testPassed("Rejected, as expected");
     72
     73    // If this test starts to fail because a way to encode encrypt+decrypt is added to JWK, change to something that's not there.
     74    // If all WebCrypto modes are added to JWK, then this test will be obsolete.
     75    debug("\nImporting a key with only sign usage (this doesn't map to anything in JWK, as 'sig' allows both sign and verify)...");
     76    return crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, { name: "HMAC", hash: "SHA-256" }, extractable, ['sign'])
     77}).then(function(result) {
     78    key = result;
     79
     80    // Maybe this should be a rejected promise, not an exception. We'll need to find a way to provide meaningful error messages with such failures.
     81    shouldThrow('crypto.subtle.exportKey("jwk", key)');
    3482
    3583    finishJSTest();
  • trunk/Source/JavaScriptCore/ChangeLog

    r159376 r159377  
     12013-11-15  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Support exporting symmetric keys as JWK
     4        https://bugs.webkit.org/show_bug.cgi?id=124442
     5
     6        Reviewed by Sam Weinig.
     7
     8        * runtime/JSONObject.h: Export JSONStringify.
     9
    1102013-11-15  peavo@outlook.com  <peavo@outlook.com>
    211
  • trunk/Source/JavaScriptCore/runtime/JSONObject.h

    r157614 r159377  
    6262
    6363    JS_EXPORT_PRIVATE JSValue JSONParse(ExecState*, const String&);
    64     String JSONStringify(ExecState*, JSValue, unsigned indent);
     64    JS_EXPORT_PRIVATE String JSONStringify(ExecState*, JSValue, unsigned indent);
    6565
    6666    void escapeStringToBuilder(StringBuilder&, const String&);
  • trunk/Source/WTF/ChangeLog

    r159360 r159377  
     12013-11-15  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Support exporting symmetric keys as JWK
     4        https://bugs.webkit.org/show_bug.cgi?id=124442
     5
     6        Reviewed by Sam Weinig.
     7
     8        Base64URL encoding doesn't use '=' padding, and doesn't need any other options.
     9        Added this mode for encode, and removed policy arguments from exposed functions.
     10
     11        * wtf/text/Base64.cpp:
     12        (WTF::base64EncodeInternal):
     13        (WTF::base64URLEncode):
     14        (WTF::base64URLDecode):
     15        * wtf/text/Base64.h:
     16        (WTF::base64URLEncode):
     17
    1182013-11-15  Mark Hahnenberg  <mhahnenberg@apple.com>
    219
  • trunk/Source/WTF/wtf/text/Base64.cpp

    r158933 r159377  
    148148
    149149    // Add padding
    150     while (didx < out.size()) {
    151         out[didx] = '=';
    152         ++didx;
     150    if (policy == Base64URLPolicy)
     151        out.resize(didx);
     152    else {
     153        while (didx < out.size()) {
     154            out[didx] = '=';
     155            ++didx;
     156        }
    153157    }
    154158}
     
    166170}
    167171
    168 String base64URLEncode(const char* data, unsigned length, Base64EncodePolicy policy)
     172String base64URLEncode(const char* data, unsigned length)
    169173{
    170174    Vector<char> result;
    171     base64EncodeInternal(data, length, result, policy, base64URLEncMap);
     175    base64EncodeInternal(data, length, result, Base64URLPolicy, base64URLEncMap);
    172176    return String(result.data(), result.size());
    173177}
    174178
    175 void base64URLEncode(const char* data, unsigned len, Vector<char>& out, Base64EncodePolicy policy)
    176 {
    177     base64EncodeInternal(data, len, out, policy, base64URLEncMap);
     179void base64URLEncode(const char* data, unsigned len, Vector<char>& out)
     180{
     181    base64EncodeInternal(data, len, out, Base64URLPolicy, base64URLEncMap);
    178182}
    179183
     
    266270}
    267271
    268 bool base64URLDecode(const String& in, Vector<char>& out, Base64DecodePolicy policy)
    269 {
    270     return base64DecodeInternal<UChar>(in.characters(), in.length(), out, policy, base64URLDecMap);
    271 }
    272 
    273 bool base64URLDecode(const Vector<char>& in, Vector<char>& out, Base64DecodePolicy policy)
     272bool base64URLDecode(const String& in, Vector<char>& out)
     273{
     274    return base64DecodeInternal<UChar>(in.characters(), in.length(), out, Base64FailOnInvalidCharacter, base64URLDecMap);
     275}
     276
     277bool base64URLDecode(const Vector<char>& in, Vector<char>& out)
    274278{
    275279    out.clear();
     
    279283        return false;
    280284
    281     return base64DecodeInternal<char>(in.data(), in.size(), out, policy, base64URLDecMap);
    282 }
    283 
    284 bool base64URLDecode(const char* data, unsigned len, Vector<char>& out, Base64DecodePolicy policy)
    285 {
    286     return base64DecodeInternal<char>(data, len, out, policy, base64URLDecMap);
     285    return base64DecodeInternal<char>(in.data(), in.size(), out, Base64FailOnInvalidCharacter, base64URLDecMap);
     286}
     287
     288bool base64URLDecode(const char* data, unsigned len, Vector<char>& out)
     289{
     290    return base64DecodeInternal<char>(data, len, out, Base64FailOnInvalidCharacter, base64URLDecMap);
    287291}
    288292
  • trunk/Source/WTF/wtf/text/Base64.h

    r158628 r159377  
    3636enum Base64EncodePolicy {
    3737    Base64DoNotInsertLFs,
    38     Base64InsertLFs
     38    Base64InsertLFs,
     39    Base64URLPolicy // No padding, no LFs.
    3940};
    4041
     
    8283// ======================================================================================
    8384
    84 WTF_EXPORT_PRIVATE void base64URLEncode(const char*, unsigned, Vector<char>&, Base64EncodePolicy = Base64DoNotInsertLFs);
    85 WTF_EXPORT_PRIVATE void base64URLEncode(const Vector<char>&, Vector<char>&, Base64EncodePolicy = Base64DoNotInsertLFs);
    86 WTF_EXPORT_PRIVATE void base64URLEncode(const CString&, Vector<char>&, Base64EncodePolicy = Base64DoNotInsertLFs);
    87 WTF_EXPORT_PRIVATE String base64URLEncode(const char*, unsigned, Base64EncodePolicy = Base64DoNotInsertLFs);
    88 WTF_EXPORT_PRIVATE String base64URLEncode(const Vector<char>&, Base64EncodePolicy = Base64DoNotInsertLFs);
    89 WTF_EXPORT_PRIVATE String base64URLEncode(const CString&, Base64EncodePolicy = Base64DoNotInsertLFs);
     85WTF_EXPORT_PRIVATE void base64URLEncode(const char*, unsigned, Vector<char>&);
     86WTF_EXPORT_PRIVATE void base64URLEncode(const Vector<char>&, Vector<char>&);
     87WTF_EXPORT_PRIVATE void base64URLEncode(const CString&, Vector<char>&);
     88WTF_EXPORT_PRIVATE String base64URLEncode(const char*, unsigned);
     89WTF_EXPORT_PRIVATE String base64URLEncode(const Vector<char>&);
     90WTF_EXPORT_PRIVATE String base64URLEncode(const CString&);
    9091
    91 WTF_EXPORT_PRIVATE bool base64URLDecode(const String&, Vector<char>&, Base64DecodePolicy = Base64FailOnInvalidCharacter);
    92 WTF_EXPORT_PRIVATE bool base64URLDecode(const Vector<char>&, Vector<char>&, Base64DecodePolicy = Base64FailOnInvalidCharacter);
    93 WTF_EXPORT_PRIVATE bool base64URLDecode(const char*, unsigned, Vector<char>&, Base64DecodePolicy = Base64FailOnInvalidCharacter);
     92WTF_EXPORT_PRIVATE bool base64URLDecode(const String&, Vector<char>&);
     93WTF_EXPORT_PRIVATE bool base64URLDecode(const Vector<char>&, Vector<char>&);
     94WTF_EXPORT_PRIVATE bool base64URLDecode(const char*, unsigned, Vector<char>&);
    9495
    95 inline void base64URLEncode(const Vector<char>& in, Vector<char>& out, Base64EncodePolicy policy)
     96inline void base64URLEncode(const Vector<char>& in, Vector<char>& out)
    9697{
    97     base64URLEncode(in.data(), in.size(), out, policy);
     98    base64URLEncode(in.data(), in.size(), out);
    9899}
    99100
    100 inline void base64URLEncode(const CString& in, Vector<char>& out, Base64EncodePolicy policy)
     101inline void base64URLEncode(const CString& in, Vector<char>& out)
    101102{
    102     base64URLEncode(in.data(), in.length(), out, policy);
     103    base64URLEncode(in.data(), in.length(), out);
    103104}
    104105
    105 inline String base64URLEncode(const Vector<char>& in, Base64EncodePolicy policy)
     106inline String base64URLEncode(const Vector<char>& in)
    106107{
    107     return base64URLEncode(in.data(), in.size(), policy);
     108    return base64URLEncode(in.data(), in.size());
    108109}
    109110
    110 inline String base64URLEncode(const CString& in, Base64EncodePolicy policy)
     111inline String base64URLEncode(const CString& in)
    111112{
    112     return base64URLEncode(in.data(), in.length(), policy);
     113    return base64URLEncode(in.data(), in.length());
    113114}
    114115
  • trunk/Source/WebCore/ChangeLog

    r159373 r159377  
     12013-11-15  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Support exporting symmetric keys as JWK
     4        https://bugs.webkit.org/show_bug.cgi?id=124442
     5
     6        Reviewed by Sam Weinig.
     7
     8        Error handling is not consistent yet - some errors cause exceptions, and others
     9        result in rejected promises. This part of spec is incomplete, so I basically did
     10        what was most straightforward in each case.
     11
     12        * bindings/js/JSCryptoKeySerializationJWK.h:
     13        * bindings/js/JSCryptoKeySerializationJWK.cpp:
     14        (WebCore::JSCryptoKeySerializationJWK::reconcileUsages): Updated a comment with a better link.
     15        (WebCore::JSCryptoKeySerializationJWK::buildJSONForOctetSequence): A helper to building JWK.
     16        (WebCore::JSCryptoKeySerializationJWK::addToJSON): Ditto.
     17        (WebCore::JSCryptoKeySerializationJWK::addBoolToJSON): Ditto.
     18        (WebCore::JSCryptoKeySerializationJWK::addJWKAlgorithmToJSON): Ditto. The code for
     19        mapping is my best guess, this all needs to be specified.
     20        (WebCore::JSCryptoKeySerializationJWK::addJWKUseToJSON): A helper to building JWK.
     21        (WebCore::JSCryptoKeySerializationJWK::serialize): Build a JSON string for the key.
     22
     23        * bindings/js/JSSubtleCryptoCustom.cpp:
     24        (WebCore::JSSubtleCrypto::importKey): Updated a comment.
     25        (WebCore::JSSubtleCrypto::exportKey): Use CryptoKeySerialization (also for raw keys,
     26        for consistency).
     27
     28        * crypto/CryptoKey.h:
     29        (WebCore::CryptoKey::algorithmIdentifier):
     30        (WebCore::CryptoKey::usagesBitmap):
     31        Exposed data needed for building JWK (it used to be only exposed in a form suitable
     32        for DOM accessors).
     33
     34        * crypto/keys/CryptoKeyHMAC.h: Ditto, added an accessor for JWK.
     35
     36        * crypto/keys/CryptoKeySerializationRaw.cpp: (WebCore::CryptoKeySerializationRaw::serialize):
     37        * crypto/keys/CryptoKeySerializationRaw.h:
     38        Moved from JSSubtleCryptoCustom.cpp for consistency.
     39
    1402013-11-15  Brady Eidson  <beidson@apple.com>
    241
  • trunk/Source/WebCore/bindings/js/JSCryptoKeySerializationJWK.cpp

    r159213 r159377  
    3333#include "CryptoAlgorithmRegistry.h"
    3434#include "CryptoAlgorithmRsaSsaKeyParams.h"
     35#include "CryptoKey.h"
     36#include "CryptoKeyAES.h"
    3537#include "CryptoKeyDataOctetSequence.h"
    3638#include "CryptoKeyDataRSAComponents.h"
     39#include "CryptoKeyHMAC.h"
    3740#include "ExceptionCode.h"
    3841#include "JSDOMBinding.h"
    3942#include <heap/StrongInlines.h>
    4043#include <runtime/JSONObject.h>
     44#include <runtime/ObjectConstructor.h>
     45#include <runtime/Operations.h>
    4146#include <wtf/text/Base64.h>
    4247
     
    237242
    238243    // FIXME: CryptoKeyUsageDeriveKey, CryptoKeyUsageDeriveBits - should these be implicitly allowed by any JWK use value?
    239     // FIXME: There is a mismatch between specs for wrap/unwrap usages, <http://lists.w3.org/Archives/Public/public-webcrypto/2013Nov/0016.html>.
     244    // FIXME: "use" mapping is in flux, see <https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796>.
    240245    if (jwkUseString == "sig")
    241246        suggestedUsage = suggestedUsage & (CryptoKeyUsageSign | CryptoKeyUsageVerify);
     
    412417}
    413418
     419void JSCryptoKeySerializationJWK::buildJSONForOctetSequence(ExecState* exec, const Vector<char>& keyData, JSObject* result)
     420{
     421    addToJSON(exec, result, "kty", "oct");
     422    addToJSON(exec, result, "k", base64URLEncode(keyData));
     423}
     424
     425void JSCryptoKeySerializationJWK::addToJSON(ExecState* exec, JSObject* json, const char* key, const String& value)
     426{
     427    VM& vm = exec->vm();
     428    Identifier identifier(&vm, key);
     429    json->putDirect(vm, identifier, jsString(exec, value));
     430}
     431
     432void JSCryptoKeySerializationJWK::addBoolToJSON(ExecState* exec, JSObject* json, const char* key, bool value)
     433{
     434    VM& vm = exec->vm();
     435    Identifier identifier(&vm, key);
     436    json->putDirect(vm, identifier, jsBoolean(value));
     437}
     438
     439void JSCryptoKeySerializationJWK::addJWKAlgorithmToJSON(ExecState* exec, JSObject* json, const CryptoKey& key)
     440{
     441    String jwkAlgorithm;
     442    switch (key.algorithmIdentifier()) {
     443    case CryptoAlgorithmIdentifier::HMAC:
     444        switch (toCryptoKeyHMAC(key).hashAlgorithmIdentifier()) {
     445        case CryptoAlgorithmIdentifier::SHA_256:
     446            if (toCryptoKeyHMAC(key).key().size() * 8 >= 256)
     447                jwkAlgorithm = "HS256";
     448            break;
     449        case CryptoAlgorithmIdentifier::SHA_384:
     450            if (toCryptoKeyHMAC(key).key().size() * 8 >= 384)
     451                jwkAlgorithm = "HS384";
     452            break;
     453        case CryptoAlgorithmIdentifier::SHA_512:
     454            if (toCryptoKeyHMAC(key).key().size() * 8 >= 512)
     455                jwkAlgorithm = "HS512";
     456            break;
     457        default:
     458            break;
     459        }
     460        break;
     461    case CryptoAlgorithmIdentifier::AES_CBC:
     462        switch (toCryptoKeyAES(key).key().size() * 8) {
     463        case 128:
     464            jwkAlgorithm = "A128CBC";
     465            break;
     466        case 192:
     467            jwkAlgorithm = "A192CBC";
     468            break;
     469        case 256:
     470            jwkAlgorithm = "A256CBC";
     471            break;
     472        }
     473        break;
     474    default:
     475        break;
     476    }
     477
     478    if (jwkAlgorithm.isNull()) {
     479        // The spec doesn't currently tell whether export should fail, or just skip "alg" (which is an optional key in JWK).
     480        // Perhaps this should depend on whether the key is extractable?
     481        throwTypeError(exec, "Key algorithm and size do not map to any JWK algorithm identifier");
     482        return;
     483    }
     484
     485    addToJSON(exec, json, "alg", jwkAlgorithm);
     486}
     487
     488void JSCryptoKeySerializationJWK::addJWKUseToJSON(ExecState* exec, JSObject* json, CryptoKeyUsage usages)
     489{
     490    // FIXME: "use" mapping is in flux, see <https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796>.
     491    switch (usages) {
     492    case CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey:
     493        addToJSON(exec, json, "use", "enc");
     494        break;
     495    case CryptoKeyUsageSign | CryptoKeyUsageVerify:
     496        addToJSON(exec, json, "use", "sig");
     497        break;
     498    default:
     499        throwTypeError(exec, "Key usages cannot be represented in JWK. Only two variants are supported: sign+verify and encrypt+decrypt+wrapKey+unwrapKey");
     500    }
     501}
     502
     503String JSCryptoKeySerializationJWK::serialize(ExecState* exec, const CryptoKey& key)
     504{
     505    std::unique_ptr<CryptoKeyData> keyData = key.exportData();
     506    if (!keyData) {
     507        // FIXME: Shouldn't happen once all key types implement exportData().
     508        throwTypeError(exec, "Key doesn't support exportKey");
     509        return String();
     510    }
     511
     512    JSObject* result = constructEmptyObject(exec);
     513
     514    addJWKAlgorithmToJSON(exec, result, key);
     515    if (exec->hadException())
     516        return String();
     517
     518    addBoolToJSON(exec, result, "extractable", key.extractable());
     519
     520    addJWKUseToJSON(exec, result, key.usagesBitmap());
     521    if (exec->hadException())
     522        return String();
     523
     524    if (isCryptoKeyDataOctetSequence(*keyData))
     525        buildJSONForOctetSequence(exec, toCryptoKeyDataOctetSequence(*keyData).octetSequence(), result);
     526    else {
     527        throwTypeError(exec, "Key doesn't support exportKey");
     528        return String();
     529    }
     530    ASSERT(!exec->hadException());
     531
     532    return JSONStringify(exec, result, 4);
     533}
     534
    414535} // namespace WebCore
    415536
  • trunk/Source/WebCore/bindings/js/JSCryptoKeySerializationJWK.h

    r159180 r159377  
    4242
    4343class CryptoAlgorithmParameters;
     44class CryptoKey;
    4445
    4546class JSCryptoKeySerializationJWK FINAL : public CryptoKeySerialization {
     
    5354    virtual ~JSCryptoKeySerializationJWK();
    5455
     56    static String serialize(JSC::ExecState* exec, const CryptoKey&);
     57
     58private:
     59    JSCryptoKeySerializationJWK(JSC::ExecState*, const String&);
     60
    5561    virtual bool reconcileAlgorithm(std::unique_ptr<CryptoAlgorithm>&, std::unique_ptr<CryptoAlgorithmParameters>&) const OVERRIDE;
    5662
     
    6066    virtual std::unique_ptr<CryptoKeyData> keyData() const OVERRIDE;
    6167
    62 private:
    63     JSCryptoKeySerializationJWK(JSC::ExecState*, const String&);
     68    static void buildJSONForOctetSequence(JSC::ExecState*, const Vector<char>&, JSC::JSObject* result);
     69    static void addJWKAlgorithmToJSON(JSC::ExecState*, JSC::JSObject*, const CryptoKey& key);
     70    static void addJWKUseToJSON(JSC::ExecState*, JSC::JSObject*, CryptoKeyUsage);
     71    static void addToJSON(JSC::ExecState*, JSC::JSObject*, const char* key, const String& value);
     72    static void addBoolToJSON(JSC::ExecState*, JSC::JSObject*, const char* key, bool value);
    6473
    6574    bool keySizeIsValid(size_t sizeInBits) const;
  • trunk/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp

    r159310 r159377  
    3333#include "CryptoAlgorithmRegistry.h"
    3434#include "CryptoKeyData.h"
    35 #include "CryptoKeyDataOctetSequence.h"
    36 #include "CryptoKeyDataRSAComponents.h"
    3735#include "CryptoKeySerializationRaw.h"
    3836#include "Document.h"
     
    451449    }
    452450    default:
    453         throwTypeError(exec, "Unsupported key format");
     451        throwTypeError(exec, "Unsupported key format for import");
    454452        return jsUndefined();
    455453    }
     
    533531    }
    534532
    535     std::unique_ptr<CryptoKeyData> keyData = key->exportData();
    536     if (!keyData) {
    537         // FIXME: Shouldn't happen once all key types implement exportData().
    538         promiseWrapper->reject(nullptr);
    539         return promise;
    540     }
    541 
    542533    switch (keyFormat) {
    543     case CryptoKeyFormat::Raw:
    544         if (isCryptoKeyDataOctetSequence(*keyData)) {
    545             Vector<unsigned char> result;
    546             result.appendVector(toCryptoKeyDataOctetSequence(*keyData).octetSequence());
     534    case CryptoKeyFormat::Raw: {
     535        Vector<unsigned char> result;
     536        if (CryptoKeySerializationRaw::serialize(*key, result))
    547537            promiseWrapper->fulfill(result);
    548         } else {
     538        else {
    549539            m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key cannot be exported to raw format");
    550540            promiseWrapper->reject(nullptr);
    551541        }
    552542        break;
     543    }
     544    case CryptoKeyFormat::JWK: {
     545        String result = JSCryptoKeySerializationJWK::serialize(exec, *key);
     546        if (exec->hadException())
     547            return jsUndefined();
     548        CString utf8String = result.utf8(StrictConversion);
     549        Vector<unsigned char> resultBuffer;
     550        resultBuffer.append(utf8String.data(), utf8String.length());
     551        promiseWrapper->fulfill(result);
     552        break;
     553    }
    553554    default:
    554         throwTypeError(exec, "Unsupported key format");
     555        throwTypeError(exec, "Unsupported key format for export");
    555556        return jsUndefined();
    556557    }
  • trunk/Source/WebCore/crypto/CryptoKey.h

    r159310 r159377  
    5959    Vector<String> usages() const;
    6060
     61    CryptoAlgorithmIdentifier algorithmIdentifier() const { return m_algorithm; }
     62    CryptoKeyUsage usagesBitmap() const { return m_usages; }
    6163    bool allows(CryptoKeyUsage usage) const { return usage == (m_usages & usage); }
    6264
  • trunk/Source/WebCore/crypto/keys/CryptoKeyHMAC.h

    r159310 r159377  
    4949    const Vector<char>& key() const { return m_key; }
    5050
     51    CryptoAlgorithmIdentifier hashAlgorithmIdentifier() const { return m_hash; }
     52
    5153private:
    5254    CryptoKeyHMAC(const Vector<char>& key, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsage);
  • trunk/Source/WebCore/crypto/keys/CryptoKeySerializationRaw.cpp

    r158943 r159377  
    3030
    3131#include "CryptoAlgorithm.h"
     32#include "CryptoKey.h"
    3233#include "CryptoKeyDataOctetSequence.h"
    3334
     
    6162}
    6263
     64bool CryptoKeySerializationRaw::serialize(const CryptoKey& key, Vector<unsigned char>& result)
     65{
     66    std::unique_ptr<CryptoKeyData> keyData = key.exportData();
     67    if (!keyData) {
     68        // FIXME: Shouldn't happen once all key types implement exportData().
     69        return false;
     70    }
     71
     72    if (!isCryptoKeyDataOctetSequence(*keyData))
     73        return false;
     74
     75    result.appendVector(toCryptoKeyDataOctetSequence(*keyData).octetSequence());
     76    return true;
     77}
     78
     79
    6380} // namespace WebCore
    6481
  • trunk/Source/WebCore/crypto/keys/CryptoKeySerializationRaw.h

    r159213 r159377  
    3535namespace WebCore {
    3636
     37class CryptoKey;
     38
    3739class CryptoKeySerializationRaw FINAL : public CryptoKeySerialization {
    3840    WTF_MAKE_NONCOPYABLE(CryptoKeySerializationRaw);
     
    4446
    4547    virtual ~CryptoKeySerializationRaw();
     48
     49    static bool serialize(const CryptoKey&, Vector<unsigned char>&);
    4650
    4751private:
Note: See TracChangeset for help on using the changeset viewer.