Home | History | Annotate | Download | only in crypto
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "modules/crypto/SubtleCrypto.h"
     33 
     34 #include "bindings/v8/Dictionary.h"
     35 #include "bindings/v8/ExceptionState.h"
     36 #include "core/dom/ExceptionCode.h"
     37 #include "modules/crypto/CryptoResultImpl.h"
     38 #include "modules/crypto/Key.h"
     39 #include "modules/crypto/NormalizeAlgorithm.h"
     40 #include "public/platform/Platform.h"
     41 #include "public/platform/WebCrypto.h"
     42 #include "public/platform/WebCryptoAlgorithm.h"
     43 #include "wtf/ArrayBufferView.h"
     44 
     45 namespace WebCore {
     46 
     47 // FIXME: asynchronous completion of CryptoResult. Need to re-enter the
     48 //        v8::Context before trying to fulfill the promise, and enable test.
     49 
     50 namespace {
     51 
     52 ScriptPromise startCryptoOperation(const Dictionary& rawAlgorithm, Key* key, AlgorithmOperation operationType, ArrayBufferView* signature, ArrayBufferView* dataBuffer, ExceptionState& exceptionState)
     53 {
     54     bool requiresKey = operationType != Digest;
     55 
     56     // Seems like the generated bindings should take care of these however it
     57     // currently doesn't. See also http://crbugh.com/264520
     58     if (requiresKey && !key) {
     59         exceptionState.throwTypeError("Invalid key argument");
     60         return ScriptPromise();
     61     }
     62     if (operationType == Verify && !signature) {
     63         exceptionState.throwTypeError("Invalid signature argument");
     64         return ScriptPromise();
     65     }
     66     if (!dataBuffer) {
     67         exceptionState.throwTypeError("Invalid dataBuffer argument");
     68         return ScriptPromise();
     69     }
     70 
     71     blink::WebCryptoAlgorithm algorithm;
     72     if (!normalizeAlgorithm(rawAlgorithm, operationType, algorithm, exceptionState))
     73         return ScriptPromise();
     74 
     75     if (requiresKey && !key->canBeUsedForAlgorithm(algorithm, operationType, exceptionState))
     76         return ScriptPromise();
     77 
     78     const unsigned char* data = static_cast<const unsigned char*>(dataBuffer->baseAddress());
     79     unsigned dataSize = dataBuffer->byteLength();
     80 
     81     ScriptPromise promise = ScriptPromise::createPending();
     82     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
     83 
     84     switch (operationType) {
     85     case Encrypt:
     86         blink::Platform::current()->crypto()->encrypt(algorithm, key->key(), data, dataSize, result->result());
     87         break;
     88     case Decrypt:
     89         blink::Platform::current()->crypto()->decrypt(algorithm, key->key(), data, dataSize, result->result());
     90         break;
     91     case Sign:
     92         blink::Platform::current()->crypto()->sign(algorithm, key->key(), data, dataSize, result->result());
     93         break;
     94     case Verify:
     95         blink::Platform::current()->crypto()->verifySignature(algorithm, key->key(), reinterpret_cast<const unsigned char*>(signature->baseAddress()), signature->byteLength(), data, dataSize, result->result());
     96         break;
     97     case Digest:
     98         blink::Platform::current()->crypto()->digest(algorithm, data, dataSize, result->result());
     99         break;
    100     default:
    101         ASSERT_NOT_REACHED();
    102         return ScriptPromise();
    103     }
    104 
    105     return promise;
    106 }
    107 
    108 } // namespace
    109 
    110 SubtleCrypto::SubtleCrypto()
    111 {
    112     ScriptWrappable::init(this);
    113 }
    114 
    115 ScriptPromise SubtleCrypto::encrypt(const Dictionary& rawAlgorithm, Key* key, ArrayBufferView* data, ExceptionState& exceptionState)
    116 {
    117     return startCryptoOperation(rawAlgorithm, key, Encrypt, 0, data, exceptionState);
    118 }
    119 
    120 ScriptPromise SubtleCrypto::decrypt(const Dictionary& rawAlgorithm, Key* key, ArrayBufferView* data, ExceptionState& exceptionState)
    121 {
    122     return startCryptoOperation(rawAlgorithm, key, Decrypt, 0, data, exceptionState);
    123 }
    124 
    125 ScriptPromise SubtleCrypto::sign(const Dictionary& rawAlgorithm, Key* key, ArrayBufferView* data, ExceptionState& exceptionState)
    126 {
    127     return startCryptoOperation(rawAlgorithm, key, Sign, 0, data, exceptionState);
    128 }
    129 
    130 ScriptPromise SubtleCrypto::verifySignature(const Dictionary& rawAlgorithm, Key* key, ArrayBufferView* signature, ArrayBufferView* data, ExceptionState& exceptionState)
    131 {
    132     return startCryptoOperation(rawAlgorithm, key, Verify, signature, data, exceptionState);
    133 }
    134 
    135 ScriptPromise SubtleCrypto::digest(const Dictionary& rawAlgorithm, ArrayBufferView* data, ExceptionState& exceptionState)
    136 {
    137     return startCryptoOperation(rawAlgorithm, 0, Digest, 0, data, exceptionState);
    138 }
    139 
    140 ScriptPromise SubtleCrypto::generateKey(const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& exceptionState)
    141 {
    142     blink::WebCryptoKeyUsageMask keyUsages;
    143     if (!Key::parseUsageMask(rawKeyUsages, keyUsages, exceptionState))
    144         return ScriptPromise();
    145 
    146     blink::WebCryptoAlgorithm algorithm;
    147     if (!normalizeAlgorithm(rawAlgorithm, GenerateKey, algorithm, exceptionState))
    148         return ScriptPromise();
    149 
    150     ScriptPromise promise = ScriptPromise::createPending();
    151     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
    152     blink::Platform::current()->crypto()->generateKey(algorithm, extractable, keyUsages, result->result());
    153     return promise;
    154 }
    155 
    156 ScriptPromise SubtleCrypto::importKey(const String& rawFormat, ArrayBufferView* keyData, const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& exceptionState)
    157 {
    158     blink::WebCryptoKeyFormat format;
    159     if (!Key::parseFormat(rawFormat, format, exceptionState))
    160         return ScriptPromise();
    161 
    162     if (!keyData) {
    163         exceptionState.throwTypeError("Invalid keyData argument");
    164         return ScriptPromise();
    165     }
    166 
    167     blink::WebCryptoKeyUsageMask keyUsages;
    168     if (!Key::parseUsageMask(rawKeyUsages, keyUsages, exceptionState))
    169         return ScriptPromise();
    170 
    171     // The algorithm is optional.
    172     blink::WebCryptoAlgorithm algorithm;
    173     if (!rawAlgorithm.isUndefinedOrNull() && !normalizeAlgorithm(rawAlgorithm, ImportKey, algorithm, exceptionState))
    174         return ScriptPromise();
    175 
    176     const unsigned char* keyDataBytes = static_cast<unsigned char*>(keyData->baseAddress());
    177 
    178     ScriptPromise promise = ScriptPromise::createPending();
    179     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
    180     blink::Platform::current()->crypto()->importKey(format, keyDataBytes, keyData->byteLength(), algorithm, extractable, keyUsages, result->result());
    181     return promise;
    182 }
    183 
    184 ScriptPromise SubtleCrypto::exportKey(const String& rawFormat, Key* key, ExceptionState& exceptionState)
    185 {
    186     blink::WebCryptoKeyFormat format;
    187     if (!Key::parseFormat(rawFormat, format, exceptionState))
    188         return ScriptPromise();
    189 
    190     if (!key) {
    191         exceptionState.throwTypeError("Invalid key argument");
    192         return ScriptPromise();
    193     }
    194 
    195     if (!key->extractable()) {
    196         exceptionState.throwDOMException(NotSupportedError, "key is not extractable");
    197         return ScriptPromise();
    198     }
    199 
    200     ScriptPromise promise = ScriptPromise::createPending();
    201     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
    202     blink::Platform::current()->crypto()->exportKey(format, key->key(), result->result());
    203     return promise;
    204 }
    205 
    206 ScriptPromise SubtleCrypto::wrapKey(const String& rawFormat, Key* key, Key* wrappingKey, const Dictionary& rawWrapAlgorithm, ExceptionState& exceptionState)
    207 {
    208     blink::WebCryptoKeyFormat format;
    209     if (!Key::parseFormat(rawFormat, format, exceptionState))
    210         return ScriptPromise();
    211 
    212     if (!key) {
    213         exceptionState.throwTypeError("Invalid key argument");
    214         return ScriptPromise();
    215     }
    216 
    217     if (!wrappingKey) {
    218         exceptionState.throwTypeError("Invalid wrappingKey argument");
    219         return ScriptPromise();
    220     }
    221 
    222     blink::WebCryptoAlgorithm wrapAlgorithm;
    223     if (!normalizeAlgorithm(rawWrapAlgorithm, WrapKey, wrapAlgorithm, exceptionState))
    224         return ScriptPromise();
    225 
    226     if (!key->extractable()) {
    227         exceptionState.throwDOMException(NotSupportedError, "key is not extractable");
    228         return ScriptPromise();
    229     }
    230 
    231     if (!wrappingKey->canBeUsedForAlgorithm(wrapAlgorithm, WrapKey, exceptionState))
    232         return ScriptPromise();
    233 
    234     ScriptPromise promise = ScriptPromise::createPending();
    235     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
    236     blink::Platform::current()->crypto()->wrapKey(format, key->key(), wrappingKey->key(), wrapAlgorithm, result->result());
    237     return promise;
    238 }
    239 
    240 ScriptPromise SubtleCrypto::unwrapKey(const String& rawFormat, ArrayBufferView* wrappedKey, Key* unwrappingKey, const Dictionary& rawUnwrapAlgorithm, const Dictionary& rawUnwrappedKeyAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& exceptionState)
    241 {
    242     blink::WebCryptoKeyFormat format;
    243     if (!Key::parseFormat(rawFormat, format, exceptionState))
    244         return ScriptPromise();
    245 
    246     if (!wrappedKey) {
    247         exceptionState.throwTypeError("Invalid wrappedKey argument");
    248         return ScriptPromise();
    249     }
    250 
    251     if (!unwrappingKey) {
    252         exceptionState.throwTypeError("Invalid unwrappingKey argument");
    253         return ScriptPromise();
    254     }
    255 
    256     blink::WebCryptoAlgorithm unwrapAlgorithm;
    257     if (!normalizeAlgorithm(rawUnwrapAlgorithm, UnwrapKey, unwrapAlgorithm, exceptionState))
    258         return ScriptPromise();
    259 
    260     // The unwrappedKeyAlgorithm is optional.
    261     blink::WebCryptoAlgorithm unwrappedKeyAlgorithm;
    262     if (!rawUnwrappedKeyAlgorithm.isUndefinedOrNull() && !normalizeAlgorithm(rawUnwrappedKeyAlgorithm, ImportKey, unwrappedKeyAlgorithm, exceptionState))
    263         return ScriptPromise();
    264 
    265     blink::WebCryptoKeyUsageMask keyUsages;
    266     if (!Key::parseUsageMask(rawKeyUsages, keyUsages, exceptionState))
    267         return ScriptPromise();
    268 
    269     if (!unwrappingKey->canBeUsedForAlgorithm(unwrapAlgorithm, UnwrapKey, exceptionState))
    270         return ScriptPromise();
    271 
    272     const unsigned char* wrappedKeyData = static_cast<const unsigned char*>(wrappedKey->baseAddress());
    273     unsigned wrappedKeyDataSize = wrappedKey->byteLength();
    274 
    275     ScriptPromise promise = ScriptPromise::createPending();
    276     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
    277     blink::Platform::current()->crypto()->unwrapKey(format, wrappedKeyData, wrappedKeyDataSize, unwrappingKey->key(), unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages, result->result());
    278     return promise;
    279 }
    280 
    281 
    282 } // namespace WebCore
    283