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