ec.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  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. #include "components/webcrypto/algorithms/ec.h"
  5. #include <stddef.h>
  6. #include <utility>
  7. #include "base/containers/span.h"
  8. #include "components/webcrypto/algorithms/asymmetric_key_util.h"
  9. #include "components/webcrypto/algorithms/util.h"
  10. #include "components/webcrypto/blink_key_handle.h"
  11. #include "components/webcrypto/generate_key_result.h"
  12. #include "components/webcrypto/jwk.h"
  13. #include "components/webcrypto/status.h"
  14. #include "crypto/openssl_util.h"
  15. #include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
  16. #include "third_party/blink/public/platform/web_crypto_key_algorithm.h"
  17. #include "third_party/boringssl/src/include/openssl/bn.h"
  18. #include "third_party/boringssl/src/include/openssl/bytestring.h"
  19. #include "third_party/boringssl/src/include/openssl/ec.h"
  20. #include "third_party/boringssl/src/include/openssl/ec_key.h"
  21. #include "third_party/boringssl/src/include/openssl/evp.h"
  22. #include "third_party/boringssl/src/include/openssl/mem.h"
  23. namespace webcrypto {
  24. namespace {
  25. // Maps a blink::WebCryptoNamedCurve to the corresponding NID used by
  26. // BoringSSL.
  27. Status WebCryptoCurveToNid(blink::WebCryptoNamedCurve named_curve, int* nid) {
  28. switch (named_curve) {
  29. case blink::kWebCryptoNamedCurveP256:
  30. *nid = NID_X9_62_prime256v1;
  31. return Status::Success();
  32. case blink::kWebCryptoNamedCurveP384:
  33. *nid = NID_secp384r1;
  34. return Status::Success();
  35. case blink::kWebCryptoNamedCurveP521:
  36. *nid = NID_secp521r1;
  37. return Status::Success();
  38. }
  39. return Status::ErrorUnsupported();
  40. }
  41. // Maps a BoringSSL NID to the corresponding WebCrypto named curve.
  42. Status NidToWebCryptoCurve(int nid, blink::WebCryptoNamedCurve* named_curve) {
  43. switch (nid) {
  44. case NID_X9_62_prime256v1:
  45. *named_curve = blink::kWebCryptoNamedCurveP256;
  46. return Status::Success();
  47. case NID_secp384r1:
  48. *named_curve = blink::kWebCryptoNamedCurveP384;
  49. return Status::Success();
  50. case NID_secp521r1:
  51. *named_curve = blink::kWebCryptoNamedCurveP521;
  52. return Status::Success();
  53. }
  54. return Status::ErrorImportedEcKeyIncorrectCurve();
  55. }
  56. struct JwkCrvMapping {
  57. const char* jwk_curve;
  58. blink::WebCryptoNamedCurve named_curve;
  59. };
  60. const JwkCrvMapping kJwkCrvMappings[] = {
  61. {"P-256", blink::kWebCryptoNamedCurveP256},
  62. {"P-384", blink::kWebCryptoNamedCurveP384},
  63. {"P-521", blink::kWebCryptoNamedCurveP521},
  64. };
  65. // Gets the "crv" parameter from a JWK and converts it to a WebCryptoNamedCurve.
  66. Status ReadJwkCrv(const JwkReader& jwk,
  67. blink::WebCryptoNamedCurve* named_curve) {
  68. std::string jwk_curve;
  69. Status status = jwk.GetString("crv", &jwk_curve);
  70. if (status.IsError())
  71. return status;
  72. for (const auto& mapping : kJwkCrvMappings) {
  73. if (mapping.jwk_curve == jwk_curve) {
  74. *named_curve = mapping.named_curve;
  75. return Status::Success();
  76. }
  77. }
  78. return Status::ErrorJwkIncorrectCrv();
  79. }
  80. // Converts a WebCryptoNamedCurve to an equivalent JWK "crv".
  81. Status WebCryptoCurveToJwkCrv(blink::WebCryptoNamedCurve named_curve,
  82. std::string* jwk_crv) {
  83. for (const auto& mapping : kJwkCrvMappings) {
  84. if (mapping.named_curve == named_curve) {
  85. *jwk_crv = mapping.jwk_curve;
  86. return Status::Success();
  87. }
  88. }
  89. return Status::ErrorUnexpected();
  90. }
  91. // Verifies that an EC key imported from PKCS8 or SPKI format is correct.
  92. // This involves verifying the key validity, and the NID for the named curve.
  93. // Also removes the EC_PKEY_NO_PUBKEY flag if present.
  94. Status VerifyEcKeyAfterSpkiOrPkcs8Import(
  95. EVP_PKEY* pkey,
  96. blink::WebCryptoNamedCurve expected_named_curve) {
  97. crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
  98. EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey);
  99. if (!ec)
  100. return Status::ErrorUnexpected();
  101. // When importing an ECPrivateKey, the public key is optional. If it was
  102. // omitted then the public key will be calculated by BoringSSL and added into
  103. // the EC_KEY. However an encoding flag is set such that when exporting to
  104. // PKCS8 format the public key is once again omitted. Remove this flag.
  105. unsigned int enc_flags = EC_KEY_get_enc_flags(ec);
  106. enc_flags &= ~EC_PKEY_NO_PUBKEY;
  107. EC_KEY_set_enc_flags(ec, enc_flags);
  108. if (!EC_KEY_check_key(ec))
  109. return Status::ErrorEcKeyInvalid();
  110. // Make sure the curve matches the expected curve name.
  111. int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
  112. blink::WebCryptoNamedCurve named_curve = blink::kWebCryptoNamedCurveP256;
  113. Status status = NidToWebCryptoCurve(curve_nid, &named_curve);
  114. if (status.IsError())
  115. return status;
  116. if (named_curve != expected_named_curve)
  117. return Status::ErrorImportedEcKeyIncorrectCurve();
  118. return Status::Success();
  119. }
  120. // Creates an EC_KEY for the given WebCryptoNamedCurve.
  121. Status CreateEC_KEY(blink::WebCryptoNamedCurve named_curve,
  122. bssl::UniquePtr<EC_KEY>* ec) {
  123. int curve_nid = 0;
  124. Status status = WebCryptoCurveToNid(named_curve, &curve_nid);
  125. if (status.IsError())
  126. return status;
  127. ec->reset(EC_KEY_new_by_curve_name(curve_nid));
  128. if (!ec->get())
  129. return Status::OperationError();
  130. return Status::Success();
  131. }
  132. // Writes an unsigned BIGNUM into |jwk|, zero-padding it to a length of
  133. // |padded_length|.
  134. Status WritePaddedBIGNUM(const std::string& member_name,
  135. const BIGNUM* value,
  136. size_t padded_length,
  137. JwkWriter* jwk) {
  138. std::vector<uint8_t> padded_bytes(padded_length);
  139. if (!BN_bn2bin_padded(padded_bytes.data(), padded_bytes.size(), value))
  140. return Status::OperationError();
  141. jwk->SetBytes(member_name, padded_bytes);
  142. return Status::Success();
  143. }
  144. // Reads a fixed length BIGNUM from a JWK.
  145. Status ReadPaddedBIGNUM(const JwkReader& jwk,
  146. const std::string& member_name,
  147. size_t expected_length,
  148. bssl::UniquePtr<BIGNUM>* out) {
  149. std::vector<uint8_t> bytes;
  150. Status status = jwk.GetBytes(member_name, &bytes);
  151. if (status.IsError())
  152. return status;
  153. if (bytes.size() != expected_length) {
  154. return Status::JwkOctetStringWrongLength(member_name, expected_length,
  155. bytes.size());
  156. }
  157. out->reset(BN_bin2bn(bytes.data(), bytes.size(), nullptr));
  158. return Status::Success();
  159. }
  160. int GetGroupDegreeInBytes(EC_KEY* ec) {
  161. const EC_GROUP* group = EC_KEY_get0_group(ec);
  162. return NumBitsToBytes(EC_GROUP_get_degree(group));
  163. }
  164. // Extracts the public key as affine coordinates (x,y).
  165. Status GetPublicKey(EC_KEY* ec,
  166. bssl::UniquePtr<BIGNUM>* x,
  167. bssl::UniquePtr<BIGNUM>* y) {
  168. const EC_GROUP* group = EC_KEY_get0_group(ec);
  169. const EC_POINT* point = EC_KEY_get0_public_key(ec);
  170. x->reset(BN_new());
  171. y->reset(BN_new());
  172. if (!EC_POINT_get_affine_coordinates_GFp(group, point, x->get(), y->get(),
  173. nullptr)) {
  174. return Status::OperationError();
  175. }
  176. return Status::Success();
  177. }
  178. // Synthesizes an import algorithm given a key algorithm, so that
  179. // deserialization can re-use the ImportKey*() methods.
  180. blink::WebCryptoAlgorithm SynthesizeImportAlgorithmForClone(
  181. const blink::WebCryptoKeyAlgorithm& algorithm) {
  182. return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
  183. algorithm.Id(), new blink::WebCryptoEcKeyImportParams(
  184. algorithm.EcParams()->NamedCurve()));
  185. }
  186. } // namespace
  187. Status EcAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
  188. bool extractable,
  189. blink::WebCryptoKeyUsageMask combined_usages,
  190. GenerateKeyResult* result) const {
  191. blink::WebCryptoKeyUsageMask public_usages = 0;
  192. blink::WebCryptoKeyUsageMask private_usages = 0;
  193. Status status = GetUsagesForGenerateAsymmetricKey(
  194. combined_usages, all_public_key_usages_, all_private_key_usages_,
  195. &public_usages, &private_usages);
  196. if (status.IsError())
  197. return status;
  198. const blink::WebCryptoEcKeyGenParams* params = algorithm.EcKeyGenParams();
  199. crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
  200. // Generate an EC key pair.
  201. bssl::UniquePtr<EC_KEY> ec_private_key;
  202. status = CreateEC_KEY(params->NamedCurve(), &ec_private_key);
  203. if (status.IsError())
  204. return status;
  205. if (!EC_KEY_generate_key(ec_private_key.get()))
  206. return Status::OperationError();
  207. // Construct an EVP_PKEY for the private key.
  208. bssl::UniquePtr<EVP_PKEY> private_pkey(EVP_PKEY_new());
  209. if (!private_pkey ||
  210. !EVP_PKEY_set1_EC_KEY(private_pkey.get(), ec_private_key.get())) {
  211. return Status::OperationError();
  212. }
  213. // Construct an EVP_PKEY for just the public key.
  214. bssl::UniquePtr<EC_KEY> ec_public_key;
  215. bssl::UniquePtr<EVP_PKEY> public_pkey(EVP_PKEY_new());
  216. status = CreateEC_KEY(params->NamedCurve(), &ec_public_key);
  217. if (status.IsError())
  218. return status;
  219. if (!EC_KEY_set_public_key(ec_public_key.get(),
  220. EC_KEY_get0_public_key(ec_private_key.get()))) {
  221. return Status::OperationError();
  222. }
  223. if (!public_pkey ||
  224. !EVP_PKEY_set1_EC_KEY(public_pkey.get(), ec_public_key.get())) {
  225. return Status::OperationError();
  226. }
  227. blink::WebCryptoKey public_key;
  228. blink::WebCryptoKey private_key;
  229. blink::WebCryptoKeyAlgorithm key_algorithm =
  230. blink::WebCryptoKeyAlgorithm::CreateEc(algorithm.Id(),
  231. params->NamedCurve());
  232. // Note that extractable is unconditionally set to true. This is because per
  233. // the WebCrypto spec generated public keys are always extractable.
  234. status = CreateWebCryptoPublicKey(std::move(public_pkey), key_algorithm, true,
  235. public_usages, &public_key);
  236. if (status.IsError())
  237. return status;
  238. status = CreateWebCryptoPrivateKey(std::move(private_pkey), key_algorithm,
  239. extractable, private_usages, &private_key);
  240. if (status.IsError())
  241. return status;
  242. result->AssignKeyPair(public_key, private_key);
  243. return Status::Success();
  244. }
  245. Status EcAlgorithm::ImportKey(blink::WebCryptoKeyFormat format,
  246. base::span<const uint8_t> key_data,
  247. const blink::WebCryptoAlgorithm& algorithm,
  248. bool extractable,
  249. blink::WebCryptoKeyUsageMask usages,
  250. blink::WebCryptoKey* key) const {
  251. switch (format) {
  252. case blink::kWebCryptoKeyFormatRaw:
  253. return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
  254. case blink::kWebCryptoKeyFormatPkcs8:
  255. return ImportKeyPkcs8(key_data, algorithm, extractable, usages, key);
  256. case blink::kWebCryptoKeyFormatSpki:
  257. return ImportKeySpki(key_data, algorithm, extractable, usages, key);
  258. case blink::kWebCryptoKeyFormatJwk:
  259. return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
  260. default:
  261. return Status::ErrorUnsupportedImportKeyFormat();
  262. }
  263. }
  264. Status EcAlgorithm::ExportKey(blink::WebCryptoKeyFormat format,
  265. const blink::WebCryptoKey& key,
  266. std::vector<uint8_t>* buffer) const {
  267. switch (format) {
  268. case blink::kWebCryptoKeyFormatRaw:
  269. return ExportKeyRaw(key, buffer);
  270. case blink::kWebCryptoKeyFormatPkcs8:
  271. return ExportKeyPkcs8(key, buffer);
  272. case blink::kWebCryptoKeyFormatSpki:
  273. return ExportKeySpki(key, buffer);
  274. case blink::kWebCryptoKeyFormatJwk:
  275. return ExportKeyJwk(key, buffer);
  276. default:
  277. return Status::ErrorUnsupportedExportKeyFormat();
  278. }
  279. }
  280. Status EcAlgorithm::ImportKeyRaw(base::span<const uint8_t> key_data,
  281. const blink::WebCryptoAlgorithm& algorithm,
  282. bool extractable,
  283. blink::WebCryptoKeyUsageMask usages,
  284. blink::WebCryptoKey* key) const {
  285. crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
  286. Status status = CheckKeyCreationUsages(all_public_key_usages_, usages);
  287. if (status.IsError())
  288. return status;
  289. const blink::WebCryptoEcKeyImportParams* params =
  290. algorithm.EcKeyImportParams();
  291. // Create an EC_KEY.
  292. bssl::UniquePtr<EC_KEY> ec;
  293. status = CreateEC_KEY(params->NamedCurve(), &ec);
  294. if (status.IsError())
  295. return status;
  296. bssl::UniquePtr<EC_POINT> point(EC_POINT_new(EC_KEY_get0_group(ec.get())));
  297. if (!point.get())
  298. return Status::OperationError();
  299. // Convert the "raw" input from X9.62 format to an EC_POINT.
  300. if (!EC_POINT_oct2point(EC_KEY_get0_group(ec.get()), point.get(),
  301. key_data.data(), key_data.size(), nullptr)) {
  302. return Status::DataError();
  303. }
  304. // Copy the point (public key) into the EC_KEY.
  305. if (!EC_KEY_set_public_key(ec.get(), point.get()))
  306. return Status::OperationError();
  307. // Verify the key.
  308. if (!EC_KEY_check_key(ec.get()))
  309. return Status::ErrorEcKeyInvalid();
  310. // Wrap the EC_KEY into an EVP_PKEY.
  311. bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
  312. if (!pkey || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get()))
  313. return Status::OperationError();
  314. blink::WebCryptoKeyAlgorithm key_algorithm =
  315. blink::WebCryptoKeyAlgorithm::CreateEc(algorithm.Id(),
  316. params->NamedCurve());
  317. // Wrap the EVP_PKEY into a WebCryptoKey
  318. return CreateWebCryptoPublicKey(std::move(pkey), key_algorithm, extractable,
  319. usages, key);
  320. }
  321. Status EcAlgorithm::ImportKeyPkcs8(base::span<const uint8_t> key_data,
  322. const blink::WebCryptoAlgorithm& algorithm,
  323. bool extractable,
  324. blink::WebCryptoKeyUsageMask usages,
  325. blink::WebCryptoKey* key) const {
  326. Status status = CheckKeyCreationUsages(all_private_key_usages_, usages);
  327. if (status.IsError())
  328. return status;
  329. bssl::UniquePtr<EVP_PKEY> private_key;
  330. status = ImportUnverifiedPkeyFromPkcs8(key_data, EVP_PKEY_EC, &private_key);
  331. if (status.IsError())
  332. return status;
  333. const blink::WebCryptoEcKeyImportParams* params =
  334. algorithm.EcKeyImportParams();
  335. status = VerifyEcKeyAfterSpkiOrPkcs8Import(private_key.get(),
  336. params->NamedCurve());
  337. if (status.IsError())
  338. return status;
  339. return CreateWebCryptoPrivateKey(std::move(private_key),
  340. blink::WebCryptoKeyAlgorithm::CreateEc(
  341. algorithm.Id(), params->NamedCurve()),
  342. extractable, usages, key);
  343. }
  344. Status EcAlgorithm::ImportKeySpki(base::span<const uint8_t> key_data,
  345. const blink::WebCryptoAlgorithm& algorithm,
  346. bool extractable,
  347. blink::WebCryptoKeyUsageMask usages,
  348. blink::WebCryptoKey* key) const {
  349. Status status = CheckKeyCreationUsages(all_public_key_usages_, usages);
  350. if (status.IsError())
  351. return status;
  352. bssl::UniquePtr<EVP_PKEY> public_key;
  353. status = ImportUnverifiedPkeyFromSpki(key_data, EVP_PKEY_EC, &public_key);
  354. if (status.IsError())
  355. return status;
  356. const blink::WebCryptoEcKeyImportParams* params =
  357. algorithm.EcKeyImportParams();
  358. status =
  359. VerifyEcKeyAfterSpkiOrPkcs8Import(public_key.get(), params->NamedCurve());
  360. if (status.IsError())
  361. return status;
  362. return CreateWebCryptoPublicKey(std::move(public_key),
  363. blink::WebCryptoKeyAlgorithm::CreateEc(
  364. algorithm.Id(), params->NamedCurve()),
  365. extractable, usages, key);
  366. }
  367. // The format for JWK EC keys is given by:
  368. // https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-36#section-6.2
  369. Status EcAlgorithm::ImportKeyJwk(base::span<const uint8_t> key_data,
  370. const blink::WebCryptoAlgorithm& algorithm,
  371. bool extractable,
  372. blink::WebCryptoKeyUsageMask usages,
  373. blink::WebCryptoKey* key) const {
  374. crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
  375. const blink::WebCryptoEcKeyImportParams* params =
  376. algorithm.EcKeyImportParams();
  377. // When importing EC keys from JWK there may be up to *three* separate curve
  378. // names:
  379. //
  380. // (1) The one given to WebCrypto's importKey (params->namedCurve()).
  381. // (2) JWK's "crv" member
  382. // (3) A curve implied by JWK's "alg" member.
  383. //
  384. // (In the case of ECDSA, the "alg" member implicitly names a curve and hash)
  385. JwkReader jwk;
  386. Status status = jwk.Init(key_data, extractable, usages, "EC",
  387. GetJwkAlgorithm(params->NamedCurve()));
  388. if (status.IsError())
  389. return status;
  390. // Verify that "crv" matches expected curve.
  391. blink::WebCryptoNamedCurve jwk_crv = blink::kWebCryptoNamedCurveP256;
  392. status = ReadJwkCrv(jwk, &jwk_crv);
  393. if (status.IsError())
  394. return status;
  395. if (jwk_crv != params->NamedCurve())
  396. return Status::ErrorJwkIncorrectCrv();
  397. // Only private keys have a "d" parameter. The key may still be invalid, but
  398. // tentatively decide if it is a public or private key.
  399. bool is_private_key = jwk.HasMember("d");
  400. // Now that the key type is known, verify the usages.
  401. if (is_private_key) {
  402. status = CheckKeyCreationUsages(all_private_key_usages_, usages);
  403. } else {
  404. status = CheckKeyCreationUsages(all_public_key_usages_, usages);
  405. }
  406. if (status.IsError())
  407. return status;
  408. // Create an EC_KEY.
  409. bssl::UniquePtr<EC_KEY> ec;
  410. status = CreateEC_KEY(params->NamedCurve(), &ec);
  411. if (status.IsError())
  412. return status;
  413. // JWK requires the length of x, y, d to match the group degree.
  414. int degree_bytes = GetGroupDegreeInBytes(ec.get());
  415. // Read the public key's uncompressed affine coordinates.
  416. bssl::UniquePtr<BIGNUM> x;
  417. status = ReadPaddedBIGNUM(jwk, "x", degree_bytes, &x);
  418. if (status.IsError())
  419. return status;
  420. bssl::UniquePtr<BIGNUM> y;
  421. status = ReadPaddedBIGNUM(jwk, "y", degree_bytes, &y);
  422. if (status.IsError())
  423. return status;
  424. // TODO(eroman): Distinguish more accurately between a DataError and
  425. // OperationError. In general if this fails it was due to the key being an
  426. // invalid EC key.
  427. if (!EC_KEY_set_public_key_affine_coordinates(ec.get(), x.get(), y.get()))
  428. return Status::DataError();
  429. // Extract the "d" parameters.
  430. if (is_private_key) {
  431. bssl::UniquePtr<BIGNUM> d;
  432. status = ReadPaddedBIGNUM(jwk, "d", degree_bytes, &d);
  433. if (status.IsError())
  434. return status;
  435. if (!EC_KEY_set_private_key(ec.get(), d.get()))
  436. return Status::OperationError();
  437. }
  438. // Verify the key.
  439. if (!EC_KEY_check_key(ec.get()))
  440. return Status::ErrorEcKeyInvalid();
  441. // Wrap the EC_KEY into an EVP_PKEY.
  442. bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
  443. if (!pkey || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get()))
  444. return Status::OperationError();
  445. blink::WebCryptoKeyAlgorithm key_algorithm =
  446. blink::WebCryptoKeyAlgorithm::CreateEc(algorithm.Id(),
  447. params->NamedCurve());
  448. // Wrap the EVP_PKEY into a WebCryptoKey
  449. if (is_private_key) {
  450. return CreateWebCryptoPrivateKey(std::move(pkey), key_algorithm,
  451. extractable, usages, key);
  452. }
  453. return CreateWebCryptoPublicKey(std::move(pkey), key_algorithm, extractable,
  454. usages, key);
  455. }
  456. Status EcAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
  457. std::vector<uint8_t>* buffer) const {
  458. crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
  459. if (key.GetType() != blink::kWebCryptoKeyTypePublic)
  460. return Status::ErrorUnexpectedKeyType();
  461. EVP_PKEY* pkey = GetEVP_PKEY(key);
  462. EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey);
  463. if (!ec)
  464. return Status::ErrorUnexpected();
  465. // Serialize the public key as an uncompressed point in X9.62 form.
  466. uint8_t* raw;
  467. size_t raw_len;
  468. bssl::ScopedCBB cbb;
  469. if (!CBB_init(cbb.get(), 0) ||
  470. !EC_POINT_point2cbb(cbb.get(), EC_KEY_get0_group(ec),
  471. EC_KEY_get0_public_key(ec),
  472. POINT_CONVERSION_UNCOMPRESSED, nullptr) ||
  473. !CBB_finish(cbb.get(), &raw, &raw_len)) {
  474. return Status::OperationError();
  475. }
  476. buffer->assign(raw, raw + raw_len);
  477. OPENSSL_free(raw);
  478. return Status::Success();
  479. }
  480. Status EcAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
  481. std::vector<uint8_t>* buffer) const {
  482. if (key.GetType() != blink::kWebCryptoKeyTypePrivate)
  483. return Status::ErrorUnexpectedKeyType();
  484. return ExportPKeyPkcs8(GetEVP_PKEY(key), buffer);
  485. }
  486. Status EcAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
  487. std::vector<uint8_t>* buffer) const {
  488. if (key.GetType() != blink::kWebCryptoKeyTypePublic)
  489. return Status::ErrorUnexpectedKeyType();
  490. return ExportPKeySpki(GetEVP_PKEY(key), buffer);
  491. }
  492. // The format for JWK EC keys is given by:
  493. // https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-36#section-6.2
  494. Status EcAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
  495. std::vector<uint8_t>* buffer) const {
  496. crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
  497. EVP_PKEY* pkey = GetEVP_PKEY(key);
  498. EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey);
  499. if (!ec)
  500. return Status::ErrorUnexpected();
  501. // No "alg" is set for EC keys.
  502. JwkWriter jwk(std::string(), key.Extractable(), key.Usages(), "EC");
  503. // Set the crv
  504. std::string crv;
  505. Status status =
  506. WebCryptoCurveToJwkCrv(key.Algorithm().EcParams()->NamedCurve(), &crv);
  507. if (status.IsError())
  508. return status;
  509. int degree_bytes = GetGroupDegreeInBytes(ec);
  510. jwk.SetString("crv", crv);
  511. bssl::UniquePtr<BIGNUM> x;
  512. bssl::UniquePtr<BIGNUM> y;
  513. status = GetPublicKey(ec, &x, &y);
  514. if (status.IsError())
  515. return status;
  516. status = WritePaddedBIGNUM("x", x.get(), degree_bytes, &jwk);
  517. if (status.IsError())
  518. return status;
  519. status = WritePaddedBIGNUM("y", y.get(), degree_bytes, &jwk);
  520. if (status.IsError())
  521. return status;
  522. if (key.GetType() == blink::kWebCryptoKeyTypePrivate) {
  523. const BIGNUM* d = EC_KEY_get0_private_key(ec);
  524. status = WritePaddedBIGNUM("d", d, degree_bytes, &jwk);
  525. if (status.IsError())
  526. return status;
  527. }
  528. jwk.ToJson(buffer);
  529. return Status::Success();
  530. }
  531. // TODO(eroman): Defer import to the crypto thread. http://crbug.com/430763
  532. Status EcAlgorithm::DeserializeKeyForClone(
  533. const blink::WebCryptoKeyAlgorithm& algorithm,
  534. blink::WebCryptoKeyType type,
  535. bool extractable,
  536. blink::WebCryptoKeyUsageMask usages,
  537. base::span<const uint8_t> key_data,
  538. blink::WebCryptoKey* key) const {
  539. if (algorithm.ParamsType() != blink::kWebCryptoKeyAlgorithmParamsTypeEc)
  540. return Status::ErrorUnexpected();
  541. blink::WebCryptoAlgorithm import_algorithm =
  542. SynthesizeImportAlgorithmForClone(algorithm);
  543. Status status;
  544. // The serialized data will be either SPKI or PKCS8 formatted.
  545. switch (type) {
  546. case blink::kWebCryptoKeyTypePublic:
  547. status =
  548. ImportKeySpki(key_data, import_algorithm, extractable, usages, key);
  549. break;
  550. case blink::kWebCryptoKeyTypePrivate:
  551. status =
  552. ImportKeyPkcs8(key_data, import_algorithm, extractable, usages, key);
  553. break;
  554. default:
  555. return Status::ErrorUnexpected();
  556. }
  557. if (!status.IsSuccess())
  558. return status;
  559. // There is some duplicated information in the serialized format used by
  560. // structured clone (since the KeyAlgorithm is serialized separately from the
  561. // key data). Use this extra information to further validate what was
  562. // deserialized from the key data.
  563. if (algorithm.Id() != key->Algorithm().Id())
  564. return Status::ErrorUnexpected();
  565. if (type != key->GetType())
  566. return Status::ErrorUnexpected();
  567. if (algorithm.EcParams()->NamedCurve() !=
  568. key->Algorithm().EcParams()->NamedCurve()) {
  569. return Status::ErrorUnexpected();
  570. }
  571. return Status::Success();
  572. }
  573. } // namespace webcrypto