Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/dom/WebCryptoCommon.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_dom_WebCryptoCommon_h
8
#define mozilla_dom_WebCryptoCommon_h
9
10
#include "js/StructuredClone.h"
11
#include "mozilla/ArrayUtils.h"
12
#include "mozilla/dom/CryptoBuffer.h"
13
#include "nsContentUtils.h"
14
#include "nsString.h"
15
#include "pk11pub.h"
16
17
// WebCrypto algorithm names
18
0
#define WEBCRYPTO_ALG_AES_CBC       "AES-CBC"
19
0
#define WEBCRYPTO_ALG_AES_CTR       "AES-CTR"
20
0
#define WEBCRYPTO_ALG_AES_GCM       "AES-GCM"
21
0
#define WEBCRYPTO_ALG_AES_KW        "AES-KW"
22
0
#define WEBCRYPTO_ALG_SHA1          "SHA-1"
23
0
#define WEBCRYPTO_ALG_SHA256        "SHA-256"
24
0
#define WEBCRYPTO_ALG_SHA384        "SHA-384"
25
0
#define WEBCRYPTO_ALG_SHA512        "SHA-512"
26
0
#define WEBCRYPTO_ALG_HMAC          "HMAC"
27
0
#define WEBCRYPTO_ALG_HKDF          "HKDF"
28
0
#define WEBCRYPTO_ALG_PBKDF2        "PBKDF2"
29
0
#define WEBCRYPTO_ALG_RSASSA_PKCS1  "RSASSA-PKCS1-v1_5"
30
0
#define WEBCRYPTO_ALG_RSA_OAEP      "RSA-OAEP"
31
0
#define WEBCRYPTO_ALG_RSA_PSS       "RSA-PSS"
32
0
#define WEBCRYPTO_ALG_ECDH          "ECDH"
33
0
#define WEBCRYPTO_ALG_ECDSA         "ECDSA"
34
0
#define WEBCRYPTO_ALG_DH            "DH"
35
36
// WebCrypto key formats
37
0
#define WEBCRYPTO_KEY_FORMAT_RAW    "raw"
38
0
#define WEBCRYPTO_KEY_FORMAT_PKCS8  "pkcs8"
39
0
#define WEBCRYPTO_KEY_FORMAT_SPKI   "spki"
40
0
#define WEBCRYPTO_KEY_FORMAT_JWK    "jwk"
41
42
// WebCrypto key types
43
0
#define WEBCRYPTO_KEY_TYPE_PUBLIC  "public"
44
0
#define WEBCRYPTO_KEY_TYPE_PRIVATE "private"
45
0
#define WEBCRYPTO_KEY_TYPE_SECRET  "secret"
46
47
// WebCrypto key usages
48
0
#define WEBCRYPTO_KEY_USAGE_ENCRYPT     "encrypt"
49
0
#define WEBCRYPTO_KEY_USAGE_DECRYPT     "decrypt"
50
0
#define WEBCRYPTO_KEY_USAGE_SIGN        "sign"
51
0
#define WEBCRYPTO_KEY_USAGE_VERIFY      "verify"
52
0
#define WEBCRYPTO_KEY_USAGE_DERIVEKEY   "deriveKey"
53
0
#define WEBCRYPTO_KEY_USAGE_DERIVEBITS  "deriveBits"
54
0
#define WEBCRYPTO_KEY_USAGE_WRAPKEY     "wrapKey"
55
0
#define WEBCRYPTO_KEY_USAGE_UNWRAPKEY   "unwrapKey"
56
57
// WebCrypto named curves
58
0
#define WEBCRYPTO_NAMED_CURVE_P256  "P-256"
59
0
#define WEBCRYPTO_NAMED_CURVE_P384  "P-384"
60
0
#define WEBCRYPTO_NAMED_CURVE_P521  "P-521"
61
62
// JWK key types
63
#define JWK_TYPE_SYMMETRIC          "oct"
64
0
#define JWK_TYPE_RSA                "RSA"
65
0
#define JWK_TYPE_EC                 "EC"
66
67
// JWK algorithms
68
#define JWK_ALG_A128CBC             "A128CBC"  // CBC
69
#define JWK_ALG_A192CBC             "A192CBC"
70
#define JWK_ALG_A256CBC             "A256CBC"
71
#define JWK_ALG_A128CTR             "A128CTR"  // CTR
72
#define JWK_ALG_A192CTR             "A192CTR"
73
#define JWK_ALG_A256CTR             "A256CTR"
74
#define JWK_ALG_A128GCM             "A128GCM"  // GCM
75
#define JWK_ALG_A192GCM             "A192GCM"
76
#define JWK_ALG_A256GCM             "A256GCM"
77
#define JWK_ALG_A128KW              "A128KW"   // KW
78
#define JWK_ALG_A192KW              "A192KW"
79
#define JWK_ALG_A256KW              "A256KW"
80
#define JWK_ALG_HS1                 "HS1"      // HMAC
81
#define JWK_ALG_HS256               "HS256"
82
#define JWK_ALG_HS384               "HS384"
83
#define JWK_ALG_HS512               "HS512"
84
#define JWK_ALG_RS1                 "RS1"      // RSASSA-PKCS1
85
#define JWK_ALG_RS256               "RS256"
86
#define JWK_ALG_RS384               "RS384"
87
#define JWK_ALG_RS512               "RS512"
88
#define JWK_ALG_RSA_OAEP            "RSA-OAEP" // RSA-OAEP
89
#define JWK_ALG_RSA_OAEP_256        "RSA-OAEP-256"
90
#define JWK_ALG_RSA_OAEP_384        "RSA-OAEP-384"
91
#define JWK_ALG_RSA_OAEP_512        "RSA-OAEP-512"
92
#define JWK_ALG_PS1                 "PS1"      // RSA-PSS
93
#define JWK_ALG_PS256               "PS256"
94
#define JWK_ALG_PS384               "PS384"
95
#define JWK_ALG_PS512               "PS512"
96
0
#define JWK_ALG_ECDSA_P_256         "ES256"
97
#define JWK_ALG_ECDSA_P_384         "ES384"
98
#define JWK_ALG_ECDSA_P_521         "ES521"
99
100
// JWK usages
101
0
#define JWK_USE_ENC                 "enc"
102
0
#define JWK_USE_SIG                 "sig"
103
104
// Define an unknown mechanism type
105
0
#define UNKNOWN_CK_MECHANISM        CKM_VENDOR_DEFINED+1
106
107
// python security/pkix/tools/DottedOIDToCode.py id-ecDH 1.3.132.112
108
static const uint8_t id_ecDH[] = { 0x2b, 0x81, 0x04, 0x70 };
109
const SECItem SEC_OID_DATA_EC_DH = { siBuffer, (unsigned char*)id_ecDH,
110
                                     static_cast<unsigned int>(
111
                                       mozilla::ArrayLength(id_ecDH)) };
112
113
// python security/pkix/tools/DottedOIDToCode.py dhKeyAgreement 1.2.840.113549.1.3.1
114
static const uint8_t dhKeyAgreement[] = {
115
  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x03, 0x01
116
};
117
const SECItem SEC_OID_DATA_DH_KEY_AGREEMENT = { siBuffer,
118
                                                (unsigned char*)dhKeyAgreement,
119
                                                static_cast<unsigned int>(
120
                                                  mozilla::ArrayLength(dhKeyAgreement)) };
121
122
namespace mozilla {
123
namespace dom {
124
125
// Helper functions for structured cloning
126
inline bool
127
ReadString(JSStructuredCloneReader* aReader, nsString& aString)
128
0
{
129
0
  bool read;
130
0
  uint32_t nameLength, zero;
131
0
  read = JS_ReadUint32Pair(aReader, &nameLength, &zero);
132
0
  if (!read) {
133
0
    return false;
134
0
  }
135
0
136
0
  if (NS_WARN_IF(!aString.SetLength(nameLength, fallible))) {
137
0
    return false;
138
0
  }
139
0
  size_t charSize = sizeof(nsString::char_type);
140
0
  read = JS_ReadBytes(aReader, (void*) aString.BeginWriting(), nameLength * charSize);
141
0
  if (!read) {
142
0
    return false;
143
0
  }
144
0
145
0
  return true;
146
0
}
147
148
inline bool
149
WriteString(JSStructuredCloneWriter* aWriter, const nsString& aString)
150
0
{
151
0
  size_t charSize = sizeof(nsString::char_type);
152
0
  return JS_WriteUint32Pair(aWriter, aString.Length(), 0) &&
153
0
         JS_WriteBytes(aWriter, aString.get(), aString.Length() * charSize);
154
0
}
155
156
inline bool
157
ReadBuffer(JSStructuredCloneReader* aReader, CryptoBuffer& aBuffer)
158
0
{
159
0
  uint32_t length, zero;
160
0
  bool ret = JS_ReadUint32Pair(aReader, &length, &zero);
161
0
  if (!ret) {
162
0
    return false;
163
0
  }
164
0
165
0
  if (length > 0) {
166
0
    if (!aBuffer.SetLength(length, fallible)) {
167
0
      return false;
168
0
    }
169
0
    ret = JS_ReadBytes(aReader, aBuffer.Elements(), aBuffer.Length());
170
0
  }
171
0
  return ret;
172
0
}
173
174
inline bool
175
WriteBuffer(JSStructuredCloneWriter* aWriter, const uint8_t* aBuffer, size_t aLength)
176
0
{
177
0
  bool ret = JS_WriteUint32Pair(aWriter, aLength, 0);
178
0
  if (ret && aLength > 0) {
179
0
    ret = JS_WriteBytes(aWriter, aBuffer, aLength);
180
0
  }
181
0
  return ret;
182
0
}
183
184
inline bool
185
WriteBuffer(JSStructuredCloneWriter* aWriter, const CryptoBuffer& aBuffer)
186
0
{
187
0
  return WriteBuffer(aWriter, aBuffer.Elements(), aBuffer.Length());
188
0
}
189
190
inline CK_MECHANISM_TYPE
191
MapAlgorithmNameToMechanism(const nsString& aName)
192
0
{
193
0
  CK_MECHANISM_TYPE mechanism(UNKNOWN_CK_MECHANISM);
194
0
195
0
  // Set mechanism based on algorithm name
196
0
  if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) {
197
0
    mechanism = CKM_AES_CBC_PAD;
198
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) {
199
0
    mechanism = CKM_AES_CTR;
200
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
201
0
    mechanism = CKM_AES_GCM;
202
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
203
0
    mechanism = CKM_NSS_AES_KEY_WRAP;
204
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
205
0
    mechanism = CKM_SHA_1;
206
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
207
0
    mechanism = CKM_SHA256;
208
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
209
0
    mechanism = CKM_SHA384;
210
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
211
0
    mechanism = CKM_SHA512;
212
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
213
0
    mechanism = CKM_PKCS5_PBKD2;
214
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
215
0
    mechanism = CKM_RSA_PKCS;
216
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
217
0
    mechanism = CKM_RSA_PKCS_OAEP;
218
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
219
0
    mechanism = CKM_RSA_PKCS_PSS;
220
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
221
0
    mechanism = CKM_ECDH1_DERIVE;
222
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
223
0
    mechanism = CKM_DH_PKCS_DERIVE;
224
0
  }
225
0
226
0
  return mechanism;
227
0
}
228
229
#define NORMALIZED_EQUALS(aTest, aConst) \
230
0
        nsContentUtils::EqualsIgnoreASCIICase(aTest, NS_LITERAL_STRING(aConst))
231
232
inline bool
233
NormalizeToken(const nsString& aName, nsString& aDest)
234
0
{
235
0
  // Algorithm names
236
0
  if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_CBC)) {
237
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_AES_CBC);
238
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_CTR)) {
239
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_AES_CTR);
240
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_GCM)) {
241
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_AES_GCM);
242
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_KW)) {
243
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_AES_KW);
244
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA1)) {
245
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_SHA1);
246
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA256)) {
247
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_SHA256);
248
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA384)) {
249
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_SHA384);
250
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA512)) {
251
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_SHA512);
252
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HMAC)) {
253
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_HMAC);
254
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HKDF)) {
255
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_HKDF);
256
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_PBKDF2)) {
257
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_PBKDF2);
258
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSASSA_PKCS1)) {
259
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1);
260
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_OAEP)) {
261
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP);
262
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_PSS)) {
263
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_PSS);
264
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) {
265
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH);
266
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDSA)) {
267
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_ECDSA);
268
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_DH)) {
269
0
    aDest.AssignLiteral(WEBCRYPTO_ALG_DH);
270
0
  // Named curve values
271
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P256)) {
272
0
    aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256);
273
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P384)) {
274
0
    aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384);
275
0
  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P521)) {
276
0
    aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521);
277
0
  } else {
278
0
    return false;
279
0
  }
280
0
281
0
  return true;
282
0
}
283
284
inline bool
285
CheckEncodedECParameters(const SECItem* aEcParams)
286
0
{
287
0
  // Need at least two bytes for a valid ASN.1 encoding.
288
0
  if (aEcParams->len < 2) {
289
0
    return false;
290
0
  }
291
0
292
0
  // Check the ASN.1 tag.
293
0
  if (aEcParams->data[0] != SEC_ASN1_OBJECT_ID) {
294
0
    return false;
295
0
  }
296
0
297
0
  // OID tags are short, we never need more than one length byte.
298
0
  if (aEcParams->data[1] >= 128) {
299
0
    return false;
300
0
  }
301
0
302
0
  // Check that the SECItem's length is correct.
303
0
  if (aEcParams->len != (unsigned)aEcParams->data[1] + 2) {
304
0
    return false;
305
0
  }
306
0
307
0
  return true;
308
0
}
309
310
inline SECItem*
311
CreateECParamsForCurve(const nsString& aNamedCurve, PLArenaPool* aArena)
312
0
{
313
0
  MOZ_ASSERT(aArena);
314
0
  SECOidTag curveOIDTag;
315
0
316
0
  if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P256)) {
317
0
    curveOIDTag = SEC_OID_SECG_EC_SECP256R1;
318
0
  } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P384)) {
319
0
    curveOIDTag = SEC_OID_SECG_EC_SECP384R1;
320
0
  } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P521)) {
321
0
    curveOIDTag = SEC_OID_SECG_EC_SECP521R1;
322
0
  } else {
323
0
    return nullptr;
324
0
  }
325
0
326
0
  // Retrieve curve data by OID tag.
327
0
  SECOidData* oidData = SECOID_FindOIDByTag(curveOIDTag);
328
0
  if (!oidData) {
329
0
    return nullptr;
330
0
  }
331
0
332
0
  // Create parameters.
333
0
  SECItem* params = ::SECITEM_AllocItem(aArena, nullptr, 2 + oidData->oid.len);
334
0
  if (!params) {
335
0
    return nullptr;
336
0
  }
337
0
338
0
  // Set parameters.
339
0
  params->data[0] = SEC_ASN1_OBJECT_ID;
340
0
  params->data[1] = oidData->oid.len;
341
0
  memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
342
0
343
0
  // Sanity check the params we just created.
344
0
  if (!CheckEncodedECParameters(params)) {
345
0
    return nullptr;
346
0
  }
347
0
348
0
  return params;
349
0
}
350
351
} // namespace dom
352
} // namespace mozilla
353
354
#endif // mozilla_dom_WebCryptoCommon_h