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