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/CryptoOperation.h"
     33 
     34 #include "bindings/v8/ExceptionState.h"
     35 #include "bindings/v8/custom/V8ArrayBufferCustom.h" // MUST precede ScriptPromiseResolver for compilation to work.
     36 #include "bindings/v8/ScriptPromiseResolver.h"
     37 #include "core/dom/ExceptionCode.h"
     38 #include "modules/crypto/Algorithm.h"
     39 #include "public/platform/WebArrayBuffer.h"
     40 #include "public/platform/WebCrypto.h"
     41 #include "wtf/ArrayBuffer.h"
     42 #include "wtf/ArrayBufferView.h"
     43 
     44 namespace WebCore {
     45 
     46 CryptoOperationImpl::CryptoOperationImpl()
     47     : m_state(Initializing)
     48     , m_impl(0)
     49     , m_initializationError(0)
     50 {
     51 }
     52 
     53 bool CryptoOperationImpl::throwInitializationError(ExceptionState& es)
     54 {
     55     ASSERT(m_state != Initializing);
     56 
     57     if (m_initializationError) {
     58         es.throwDOMException(m_initializationError);
     59         return true;
     60     }
     61     return false;
     62 }
     63 
     64 ScriptObject CryptoOperationImpl::finish()
     65 {
     66     switch (m_state) {
     67     case Initializing:
     68         ASSERT_NOT_REACHED();
     69         return ScriptObject();
     70     case Processing:
     71         m_state = Finishing;
     72         // NOTE: The following line can result in re-entrancy to |this|
     73         m_impl->finish();
     74         break;
     75     case Finishing:
     76         // Calling finish() twice is a no-op.
     77         break;
     78     case Done:
     79         // Calling finish() after already complete is a no-op.
     80         ASSERT(!m_impl);
     81         break;
     82     }
     83 
     84     return promiseResolver()->promise();
     85 }
     86 
     87 void CryptoOperationImpl::initializationFailed()
     88 {
     89     ASSERT(m_state == Initializing);
     90 
     91     m_initializationError = NotSupportedError;
     92     m_state = Done;
     93 }
     94 
     95 void CryptoOperationImpl::initializationSucceeded(WebKit::WebCryptoOperation* operationImpl)
     96 {
     97     ASSERT(m_state == Initializing);
     98     ASSERT(operationImpl);
     99     ASSERT(!m_impl);
    100 
    101     m_impl = operationImpl;
    102     m_state = Processing;
    103 }
    104 
    105 void CryptoOperationImpl::completeWithError()
    106 {
    107     ASSERT(m_state == Processing || m_state == Finishing);
    108 
    109     m_impl = 0;
    110     m_state = Done;
    111     promiseResolver()->reject(ScriptValue::createNull());
    112 }
    113 
    114 void CryptoOperationImpl::completeWithArrayBuffer(const WebKit::WebArrayBuffer& buffer)
    115 {
    116     ASSERT(m_state == Processing || m_state == Finishing);
    117 
    118     m_impl = 0;
    119     m_state = Done;
    120     promiseResolver()->fulfill(PassRefPtr<ArrayBuffer>(buffer));
    121 }
    122 
    123 void CryptoOperationImpl::completeWithBoolean(bool b)
    124 {
    125     ASSERT(m_state == Processing || m_state == Finishing);
    126 
    127     m_impl = 0;
    128     m_state = Done;
    129     promiseResolver()->fulfill(ScriptValue::createBoolean(b));
    130 }
    131 
    132 void CryptoOperationImpl::process(const void* bytes, size_t size)
    133 {
    134     switch (m_state) {
    135     case Initializing:
    136         ASSERT_NOT_REACHED();
    137     case Processing:
    138         m_impl->process(reinterpret_cast<const unsigned char*>(bytes), size);
    139         break;
    140     case Finishing:
    141     case Done:
    142         return;
    143     }
    144 }
    145 
    146 ScriptObject CryptoOperationImpl::abort()
    147 {
    148     switch (m_state) {
    149     case Initializing:
    150         ASSERT_NOT_REACHED();
    151         break;
    152     case Processing:
    153     case Finishing:
    154         // This will cause m_impl to be deleted.
    155         m_state = Done;
    156         m_impl->abort();
    157         m_impl = 0;
    158         promiseResolver()->reject(ScriptValue::createNull());
    159     case Done:
    160         ASSERT(!m_impl);
    161         break;
    162     }
    163 
    164     return promiseResolver()->promise();
    165 }
    166 
    167 void CryptoOperationImpl::detach()
    168 {
    169     switch (m_state) {
    170     case Initializing:
    171         ASSERT_NOT_REACHED();
    172         break;
    173     case Processing:
    174         // If the operation has not been finished yet, it has no way of being
    175         // finished now that the CryptoOperation is gone.
    176         m_state = Done;
    177         m_impl->abort();
    178         m_impl = 0;
    179     case Finishing:
    180     case Done:
    181         break;
    182     }
    183 }
    184 
    185 void CryptoOperationImpl::ref()
    186 {
    187     ThreadSafeRefCounted<CryptoOperationImpl>::ref();
    188 }
    189 
    190 void CryptoOperationImpl::deref()
    191 {
    192     ThreadSafeRefCounted<CryptoOperationImpl>::deref();
    193 }
    194 
    195 ScriptPromiseResolver* CryptoOperationImpl::promiseResolver()
    196 {
    197     if (!m_promiseResolver)
    198         m_promiseResolver = ScriptPromiseResolver::create();
    199     return m_promiseResolver.get();
    200 }
    201 
    202 CryptoOperation::~CryptoOperation()
    203 {
    204     m_impl->detach();
    205 }
    206 
    207 PassRefPtr<CryptoOperation> CryptoOperation::create(const WebKit::WebCryptoAlgorithm& algorithm, CryptoOperationImpl* impl)
    208 {
    209     return adoptRef(new CryptoOperation(algorithm, impl));
    210 }
    211 
    212 CryptoOperation::CryptoOperation(const WebKit::WebCryptoAlgorithm& algorithm, CryptoOperationImpl* impl)
    213     : m_algorithm(algorithm)
    214     , m_impl(impl)
    215 {
    216     ASSERT(impl);
    217     ScriptWrappable::init(this);
    218 }
    219 
    220 CryptoOperation* CryptoOperation::process(ArrayBuffer* data)
    221 {
    222     m_impl->process(data->data(), data->byteLength());
    223     return this;
    224 }
    225 
    226 CryptoOperation* CryptoOperation::process(ArrayBufferView* data)
    227 {
    228     m_impl->process(data->baseAddress(), data->byteLength());
    229     return this;
    230 }
    231 
    232 ScriptObject CryptoOperation::finish()
    233 {
    234     return m_impl->finish();
    235 }
    236 
    237 ScriptObject CryptoOperation::abort()
    238 {
    239     return m_impl->abort();
    240 }
    241 
    242 Algorithm* CryptoOperation::algorithm()
    243 {
    244     if (!m_algorithmNode)
    245         m_algorithmNode = Algorithm::create(m_algorithm);
    246     return m_algorithmNode.get();
    247 }
    248 
    249 } // namespace WebCore
    250