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/ExceptionState.h"
     35 #include "core/dom/ExceptionCode.h"
     36 #include "core/platform/NotImplemented.h"
     37 #include "modules/crypto/CryptoOperation.h"
     38 #include "modules/crypto/Key.h"
     39 #include "modules/crypto/KeyOperation.h"
     40 #include "modules/crypto/NormalizeAlgorithm.h"
     41 #include "public/platform/Platform.h"
     42 #include "public/platform/WebCrypto.h"
     43 #include "public/platform/WebCryptoAlgorithmParams.h"
     44 #include "wtf/ArrayBufferView.h"
     45 
     46 namespace WebCore {
     47 
     48 // FIXME: Outstanding KeyOperations and CryptoOperations should be aborted when
     49 // tearing down SubtleCrypto (to avoid problems completing a
     50 // ScriptPromiseResolver which is no longer valid).
     51 
     52 namespace {
     53 
     54 WebKit::WebCryptoKeyUsageMask toKeyUsage(AlgorithmOperation operation)
     55 {
     56     switch (operation) {
     57     case Encrypt:
     58         return WebKit::WebCryptoKeyUsageEncrypt;
     59     case Decrypt:
     60         return WebKit::WebCryptoKeyUsageDecrypt;
     61     case Sign:
     62         return WebKit::WebCryptoKeyUsageSign;
     63     case Verify:
     64         return WebKit::WebCryptoKeyUsageVerify;
     65     case DeriveKey:
     66         return WebKit::WebCryptoKeyUsageDeriveKey;
     67     case WrapKey:
     68         return WebKit::WebCryptoKeyUsageWrapKey;
     69     case UnwrapKey:
     70         return WebKit::WebCryptoKeyUsageUnwrapKey;
     71     case Digest:
     72     case GenerateKey:
     73     case ImportKey:
     74     case NumberOfAlgorithmOperations:
     75         break;
     76     }
     77 
     78     ASSERT_NOT_REACHED();
     79     return 0;
     80 }
     81 
     82 bool keyCanBeUsedForAlgorithm(const WebKit::WebCryptoKey& key, const WebKit::WebCryptoAlgorithm& algorithm, AlgorithmOperation op)
     83 {
     84     if (!(key.usages() & toKeyUsage(op)))
     85         return false;
     86 
     87     if (key.algorithm().id() != algorithm.id())
     88         return false;
     89 
     90     if (key.algorithm().paramsType() == WebKit::WebCryptoAlgorithmParamsTypeNone)
     91         return true;
     92 
     93     // Verify that the algorithm-specific parameters for the key conform to the
     94     // algorithm.
     95 
     96     if (key.algorithm().paramsType() == WebKit::WebCryptoAlgorithmParamsTypeHmacParams) {
     97         return key.algorithm().hmacParams()->hash().id() == algorithm.hmacParams()->hash().id();
     98     }
     99 
    100     ASSERT_NOT_REACHED();
    101     return false;
    102 }
    103 
    104 PassRefPtr<CryptoOperation> createCryptoOperation(const Dictionary& rawAlgorithm, Key* key, AlgorithmOperation operationType, ArrayBufferView* signature, ExceptionState& es)
    105 {
    106     WebKit::WebCrypto* platformCrypto = WebKit::Platform::current()->crypto();
    107     if (!platformCrypto) {
    108         es.throwDOMException(NotSupportedError);
    109         return 0;
    110     }
    111 
    112     WebKit::WebCryptoAlgorithm algorithm;
    113     if (!normalizeAlgorithm(rawAlgorithm, operationType, algorithm, es))
    114         return 0;
    115 
    116     // All operations other than Digest require a valid Key.
    117     if (operationType != Digest) {
    118         if (!key) {
    119             es.throwTypeError();
    120             return 0;
    121         }
    122 
    123         if (!keyCanBeUsedForAlgorithm(key->key(), algorithm, operationType)) {
    124             es.throwDOMException(NotSupportedError);
    125             return 0;
    126         }
    127     }
    128 
    129     // Only Verify takes a signature.
    130     if (operationType == Verify && !signature) {
    131         es.throwTypeError();
    132         return 0;
    133     }
    134 
    135     RefPtr<CryptoOperationImpl> opImpl = CryptoOperationImpl::create();
    136     WebKit::WebCryptoOperationResult result(opImpl.get());
    137 
    138     switch (operationType) {
    139     case Encrypt:
    140         platformCrypto->encrypt(algorithm, key->key(), result);
    141         break;
    142     case Decrypt:
    143         platformCrypto->decrypt(algorithm, key->key(), result);
    144         break;
    145     case Sign:
    146         platformCrypto->sign(algorithm, key->key(), result);
    147         break;
    148     case Verify:
    149         platformCrypto->verifySignature(algorithm, key->key(), reinterpret_cast<const unsigned char*>(signature->baseAddress()), signature->byteLength(), result);
    150         break;
    151     case Digest:
    152         platformCrypto->digest(algorithm, result);
    153         break;
    154     default:
    155         ASSERT_NOT_REACHED();
    156         return 0;
    157     }
    158 
    159     if (opImpl->throwInitializationError(es))
    160         return 0;
    161     return CryptoOperation::create(algorithm, opImpl.get());
    162 }
    163 
    164 } // namespace
    165 
    166 SubtleCrypto::SubtleCrypto()
    167 {
    168     ScriptWrappable::init(this);
    169 }
    170 
    171 PassRefPtr<CryptoOperation> SubtleCrypto::encrypt(const Dictionary& rawAlgorithm, Key* key, ExceptionState& es)
    172 {
    173     return createCryptoOperation(rawAlgorithm, key, Encrypt, 0, es);
    174 }
    175 
    176 PassRefPtr<CryptoOperation> SubtleCrypto::decrypt(const Dictionary& rawAlgorithm, Key* key, ExceptionState& es)
    177 {
    178     return createCryptoOperation(rawAlgorithm, key, Decrypt, 0, es);
    179 }
    180 
    181 PassRefPtr<CryptoOperation> SubtleCrypto::sign(const Dictionary& rawAlgorithm, Key* key, ExceptionState& es)
    182 {
    183     return createCryptoOperation(rawAlgorithm, key, Sign, 0, es);
    184 }
    185 
    186 PassRefPtr<CryptoOperation> SubtleCrypto::verifySignature(const Dictionary& rawAlgorithm, Key* key, ArrayBufferView* signature, ExceptionState& es)
    187 {
    188     return createCryptoOperation(rawAlgorithm, key, Verify, signature, es);
    189 }
    190 
    191 PassRefPtr<CryptoOperation> SubtleCrypto::digest(const Dictionary& rawAlgorithm, ExceptionState& es)
    192 {
    193     return createCryptoOperation(rawAlgorithm, 0, Digest, 0, es);
    194 }
    195 
    196 ScriptObject SubtleCrypto::generateKey(const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& es)
    197 {
    198     WebKit::WebCrypto* platformCrypto = WebKit::Platform::current()->crypto();
    199     if (!platformCrypto) {
    200         es.throwDOMException(NotSupportedError);
    201         return ScriptObject();
    202     }
    203 
    204     WebKit::WebCryptoKeyUsageMask keyUsages;
    205     if (!Key::parseUsageMask(rawKeyUsages, keyUsages)) {
    206         es.throwTypeError();
    207         return ScriptObject();
    208     }
    209 
    210     WebKit::WebCryptoAlgorithm algorithm;
    211     if (!normalizeAlgorithm(rawAlgorithm, GenerateKey, algorithm, es))
    212         return ScriptObject();
    213 
    214     RefPtr<KeyOperation> keyOp = KeyOperation::create();
    215     WebKit::WebCryptoKeyOperationResult result(keyOp.get());
    216     platformCrypto->generateKey(algorithm, extractable, keyUsages, result);
    217     return keyOp->returnValue(es);
    218 }
    219 
    220 ScriptObject SubtleCrypto::importKey(const String& rawFormat, ArrayBufferView* keyData, const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& es)
    221 {
    222     WebKit::WebCrypto* platformCrypto = WebKit::Platform::current()->crypto();
    223     if (!platformCrypto) {
    224         es.throwDOMException(NotSupportedError);
    225         return ScriptObject();
    226     }
    227 
    228     if (!keyData) {
    229         es.throwTypeError();
    230         return ScriptObject();
    231     }
    232 
    233     WebKit::WebCryptoKeyUsageMask keyUsages;
    234     if (!Key::parseUsageMask(rawKeyUsages, keyUsages)) {
    235         es.throwTypeError();
    236         return ScriptObject();
    237     }
    238 
    239     WebKit::WebCryptoKeyFormat format;
    240     if (!Key::parseFormat(rawFormat, format)) {
    241         es.throwTypeError();
    242         return ScriptObject();
    243     }
    244 
    245     WebKit::WebCryptoAlgorithm algorithm;
    246     if (!normalizeAlgorithm(rawAlgorithm, ImportKey, algorithm, es))
    247         return ScriptObject();
    248 
    249     const unsigned char* keyDataBytes = static_cast<unsigned char*>(keyData->baseAddress());
    250 
    251     RefPtr<KeyOperation> keyOp = KeyOperation::create();
    252     WebKit::WebCryptoKeyOperationResult result(keyOp.get());
    253     platformCrypto->importKey(format, keyDataBytes, keyData->byteLength(), algorithm, extractable, keyUsages, result);
    254     return keyOp->returnValue(es);
    255 }
    256 
    257 } // namespace WebCore
    258