webcrypto_util.h revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef CONTENT_CHILD_WEBCRYPTO_WEBCRYPTO_UTIL_H_ 6#define CONTENT_CHILD_WEBCRYPTO_WEBCRYPTO_UTIL_H_ 7 8#include <string> 9#include <vector> 10#include "base/basictypes.h" 11#include "base/strings/string_piece.h" 12#include "base/values.h" 13#include "content/common/content_export.h" 14#include "third_party/WebKit/public/platform/WebArrayBuffer.h" 15#include "third_party/WebKit/public/platform/WebCrypto.h" // TODO(eroman): delete 16#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" 17#include "third_party/WebKit/public/platform/WebCryptoKey.h" 18 19namespace content { 20 21namespace webcrypto { 22 23// TODO(eroman): Move Status class to a separate file 24 25// Status indicates whether an operation completed successfully, or with an 26// error. The error is used for verification in unit-tests, as well as for 27// display to the user. 28// 29// As such, it is important that errors DO NOT reveal any sensitive material 30// (like key bytes). 31// 32// Care must be taken with what errors are reported back to blink when doing 33// compound operations like unwrapping a JWK key. In this case, errors 34// generated by the JWK import are not appropriate to report since the wrapped 35// JWK is not visible to the caller. 36class CONTENT_EXPORT Status { 37 public: 38 // Returns true if the Status represents an error (any one of them). 39 bool IsError() const; 40 41 // Returns true if the Status represent success. 42 bool IsSuccess() const; 43 44 // Returns true if the Status contains a non-empty error message. 45 bool HasErrorDetails() const; 46 47 // Returns a UTF-8 error message (non-localized) describing the error. This 48 // message is intended to be displayed in the dev tools console. 49 std::string ToString() const; 50 51 // Constructs a status representing success. 52 static Status Success(); 53 54 // Constructs a status representing a generic error. It contains no extra 55 // details. 56 static Status Error(); 57 58 // ------------------------------------ 59 // Errors when importing a JWK formatted key 60 // ------------------------------------ 61 62 // The key bytes could not parsed as JSON dictionary. This either 63 // means there was a parsing error, or the JSON object was not 64 // convertable to a dictionary. 65 static Status ErrorJwkNotDictionary(); 66 67 // The required property |property| was missing. 68 static Status ErrorJwkPropertyMissing(const std::string& property); 69 70 // The property |property| was not of type |expected_type|. 71 static Status ErrorJwkPropertyWrongType(const std::string& property, 72 const std::string& expected_type); 73 74 // The property |property| was a string, however could not be successfully 75 // base64 decoded. 76 static Status ErrorJwkBase64Decode(const std::string& property); 77 78 // The "ext" parameter was specified but was 79 // incompatible with the value requested by the Web Crypto call. 80 static Status ErrorJwkExtInconsistent(); 81 82 // The "alg" parameter could not be converted to an equivalent 83 // WebCryptoAlgorithm. Either it was malformed or unrecognized. 84 static Status ErrorJwkUnrecognizedAlgorithm(); 85 86 // The "alg" parameter is incompatible with the (optional) Algorithm 87 // specified by the Web Crypto import operation. 88 static Status ErrorJwkAlgorithmInconsistent(); 89 90 // The "alg" parameter was not provided, however neither was an algorithm 91 // provided by the Web Crypto import operation. 92 static Status ErrorJwkAlgorithmMissing(); 93 94 // The "use" parameter was specified, however it couldn't be converted to an 95 // equivalent Web Crypto usage. 96 static Status ErrorJwkUnrecognizedUse(); 97 98 // The "key_ops" parameter was specified, however one of the values in the 99 // array couldn't be converted to an equivalent Web Crypto usage. 100 static Status ErrorJwkUnrecognizedKeyop(); 101 102 // The "use" parameter was specified, however it is incompatible with that 103 // specified by the Web Crypto import operation. 104 static Status ErrorJwkUseInconsistent(); 105 106 // The "key_ops" parameter was specified, however it is incompatible with that 107 // specified by the Web Crypto import operation. 108 static Status ErrorJwkKeyopsInconsistent(); 109 110 // Both the "key_ops" and the "use" parameters were specified, however they 111 // are incompatible with each other. 112 static Status ErrorJwkUseAndKeyopsInconsistent(); 113 114 // TODO(eroman): Private key import through JWK is not yet supported. 115 static Status ErrorJwkRsaPrivateKeyUnsupported(); 116 117 // The "kty" parameter was given and was a string, however it was 118 // unrecognized. 119 static Status ErrorJwkUnrecognizedKty(); 120 121 // The amount of key data provided was incompatible with the selected 122 // algorithm. For instance if the algorith name was A128CBC then EXACTLY 123 // 128-bits of key data must have been provided. If 192-bits of key data were 124 // given that is an error. 125 static Status ErrorJwkIncorrectKeyLength(); 126 127 // ------------------------------------ 128 // Other errors 129 // ------------------------------------ 130 131 // No key data was provided when importing an spki, pkcs8, or jwk formatted 132 // key. This does not apply to raw format, since it is possible to have empty 133 // key data there. 134 static Status ErrorImportEmptyKeyData(); 135 136 // The wrong key was used for the operation. For instance, a public key was 137 // used to verify a RsaSsaPkcs1v1_5 signature, or tried exporting a private 138 // key using spki format. 139 static Status ErrorUnexpectedKeyType(); 140 141 // When doing an AES-CBC encryption/decryption, the "iv" parameter was not 16 142 // bytes. 143 static Status ErrorIncorrectSizeAesCbcIv(); 144 145 // The data provided to an encrypt/decrypt/sign/verify operation was too 146 // large. This can either represent an internal limitation (for instance 147 // representing buffer lengths as uints), or an algorithm restriction (for 148 // instance RSAES can operation on messages relative to the length of the 149 // key's modulus). 150 static Status ErrorDataTooLarge(); 151 152 // The data provided to an encrypt/decrypt/sign/verify operation was too 153 // small. This usually represents an algorithm restriction (for instance 154 // AES-KW requires a minimum of 24 bytes input data). 155 static Status ErrorDataTooSmall(); 156 157 // Something was unsupported or unimplemented. This can mean the algorithm in 158 // question was unsupported, some parameter combination was unsupported, or 159 // something has not yet been implemented. 160 static Status ErrorUnsupported(); 161 162 // Something unexpected happened in the code, which implies there is a 163 // source-level bug. These should not happen, but safer to fail than simply 164 // DCHECK. 165 static Status ErrorUnexpected(); 166 167 // The authentication tag length specified for AES-GCM encrypt/decrypt was 168 // not 32, 64, 96, 104, 112, 120, or 128. 169 static Status ErrorInvalidAesGcmTagLength(); 170 171 // The input data given to an AES-KW encrypt/decrypt operation was not a 172 // multiple of 8 bytes, as required by RFC 3394. 173 static Status ErrorInvalidAesKwDataLength(); 174 175 // The "publicExponent" used to generate a key was invalid: either no bytes 176 // were specified, or the number was too large to fit into an "unsigned long" 177 // (implemention limitation), or the exponent was zero. 178 static Status ErrorGenerateKeyPublicExponent(); 179 180 // The algorithm was null when importing a raw-formatted key. In this case it 181 // is required. 182 static Status ErrorMissingAlgorithmImportRawKey(); 183 184 // The algorithm was null when unwrapping a raw-formatted key. In this case it 185 // is required. 186 static Status ErrorMissingAlgorithmUnwrapRawKey(); 187 188 // The modulus bytes were empty when importing an RSA public key. 189 static Status ErrorImportRsaEmptyModulus(); 190 191 // The the modulus length was zero bits when generating an RSA public key. 192 static Status ErrorGenerateRsaZeroModulus(); 193 194 // The exponent bytes were empty when importing an RSA public key. 195 static Status ErrorImportRsaEmptyExponent(); 196 197 // An unextractable key was used by an operation which exports the key data. 198 static Status ErrorKeyNotExtractable(); 199 200 // The key length specified when generating a key was invalid. Either it was 201 // zero, or it was not a multiple of 8 bits. 202 static Status ErrorGenerateKeyLength(); 203 204 private: 205 enum Type { TYPE_ERROR, TYPE_SUCCESS }; 206 207 // Constructs an error with the specified message. 208 explicit Status(const std::string& error_details_utf8); 209 210 // Constructs a success or error without any details. 211 explicit Status(Type type); 212 213 Type type_; 214 std::string error_details_; 215}; 216 217// Returns a pointer to the start of |data|, or NULL if it is empty. This is a 218// convenience function for getting the pointer, and should not be used beyond 219// the expected lifetime of |data|. 220CONTENT_EXPORT const uint8* Uint8VectorStart(const std::vector<uint8>& data); 221 222// Shrinks a WebArrayBuffer to a new size. 223// TODO(eroman): This works by re-allocating a new buffer. It would be better if 224// the WebArrayBuffer could just be truncated instead. 225void ShrinkBuffer(blink::WebArrayBuffer* buffer, unsigned int new_size); 226 227// Creates a WebArrayBuffer from a uint8 byte array 228blink::WebArrayBuffer CreateArrayBuffer(const uint8* data, 229 unsigned int data_size); 230 231// TODO(eroman): Move this to JWK file. 232// This function decodes unpadded 'base64url' encoded data, as described in 233// RFC4648 (http://www.ietf.org/rfc/rfc4648.txt) Section 5. 234// In Web Crypto, this type of encoding is only used inside JWK. 235CONTENT_EXPORT bool Base64DecodeUrlSafe(const std::string& input, 236 std::string* output); 237 238// Returns an unpadded 'base64url' encoding of the input data, the opposite of 239// Base64DecodeUrlSafe() above. 240std::string Base64EncodeUrlSafe(const base::StringPiece& input); 241 242// Composes a Web Crypto usage mask from an array of JWK key_ops values. 243CONTENT_EXPORT Status GetWebCryptoUsagesFromJwkKeyOps( 244 const base::ListValue* jwk_key_ops_value, 245 blink::WebCryptoKeyUsageMask* jwk_key_ops_mask); 246 247// Composes a JWK key_ops array from a Web Crypto usage mask. 248base::ListValue* CreateJwkKeyOpsFromWebCryptoUsages( 249 blink::WebCryptoKeyUsageMask usage_mask); 250 251CONTENT_EXPORT bool IsHashAlgorithm(blink::WebCryptoAlgorithmId alg_id); 252 253// Returns the "hash" param for an algorithm if it exists, otherwise returns 254// a null algorithm. 255blink::WebCryptoAlgorithm GetInnerHashAlgorithm( 256 const blink::WebCryptoAlgorithm& algorithm); 257 258// Creates a WebCryptoAlgorithm without any parameters. 259CONTENT_EXPORT blink::WebCryptoAlgorithm CreateAlgorithm( 260 blink::WebCryptoAlgorithmId id); 261 262// Creates an HMAC import algorithm whose inner hash algorithm is determined by 263// the specified algorithm ID. It is an error to call this method with a hash 264// algorithm that is not SHA*. 265CONTENT_EXPORT blink::WebCryptoAlgorithm CreateHmacImportAlgorithm( 266 blink::WebCryptoAlgorithmId hash_id); 267 268// Creates an RSASSA-PKCS1-v1_5 algorithm. It is an error to call this with a 269// hash_id that is not a SHA*. 270blink::WebCryptoAlgorithm CreateRsaSsaImportAlgorithm( 271 blink::WebCryptoAlgorithmId hash_id); 272 273// Creates an RSA-OAEP algorithm. It is an error to call this with a hash_id 274// that is not a SHA*. 275blink::WebCryptoAlgorithm CreateRsaOaepImportAlgorithm( 276 blink::WebCryptoAlgorithmId hash_id); 277 278// TODO(eroman): Move to shared_crypto.cc 279// Returns the internal block size for SHA-* 280unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id); 281 282bool CreateSecretKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, 283 unsigned keylen_bytes, 284 blink::WebCryptoKeyAlgorithm* key_algorithm); 285 286} // namespace webcrypto 287 288} // namespace content 289 290#endif // CONTENT_CHILD_WEBCRYPTO_WEBCRYPTO_UTIL_H_ 291