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