1 // Copyright 2013 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.
5 #include "net/cert/jwk_serializer.h"
7 #include <openssl/bn.h>
8 #include <openssl/ec.h>
9 #include <openssl/ec_key.h>
10 #include <openssl/evp.h>
11 #include <openssl/x509.h>
13 #include "base/base64.h"
14 #include "base/logging.h"
15 #include "base/strings/string_util.h"
16 #include "base/values.h"
17 #include "crypto/openssl_util.h"
18 #include "crypto/scoped_openssl_types.h"
22 namespace JwkSerializer
{
26 bool ConvertEcKeyToJwk(EVP_PKEY
* pkey
,
27 base::DictionaryValue
* public_key_jwk
,
28 const crypto::OpenSSLErrStackTracer
& err_tracer
) {
29 crypto::ScopedEC_KEY
ec_key(EVP_PKEY_get1_EC_KEY(pkey
));
32 const EC_GROUP
* ec_group
= EC_KEY_get0_group(ec_key
.get());
36 std::string curve_name
;
37 int nid
= EC_GROUP_get_curve_name(ec_group
);
38 if (nid
== NID_X9_62_prime256v1
) {
40 } else if (nid
== NID_secp384r1
) {
42 } else if (nid
== NID_secp521r1
) {
48 int degree_bytes
= (EC_GROUP_get_degree(ec_group
) + 7) / 8;
50 const EC_POINT
* ec_point
= EC_KEY_get0_public_key(ec_key
.get());
54 crypto::ScopedBIGNUM
x(BN_new());
55 crypto::ScopedBIGNUM
y(BN_new());
56 if (!EC_POINT_get_affine_coordinates_GFp(ec_group
, ec_point
,
57 x
.get(), y
.get(), NULL
)) {
61 // The coordinates are encoded with leading zeros included.
64 if (!BN_bn2bin_padded(reinterpret_cast<uint8_t*>(
65 base::WriteInto(&x_bytes
, degree_bytes
+ 1)),
66 degree_bytes
, x
.get()) ||
67 !BN_bn2bin_padded(reinterpret_cast<uint8_t*>(
68 base::WriteInto(&y_bytes
, degree_bytes
+ 1)),
69 degree_bytes
, y
.get())) {
73 public_key_jwk
->SetString("kty", "EC");
74 public_key_jwk
->SetString("crv", curve_name
);
77 base::Base64Encode(x_bytes
, &x_b64
);
78 public_key_jwk
->SetString("x", x_b64
);
81 base::Base64Encode(y_bytes
, &y_b64
);
82 public_key_jwk
->SetString("y", y_b64
);
89 bool ConvertSpkiFromDerToJwk(
90 const base::StringPiece
& spki_der
,
91 base::DictionaryValue
* public_key_jwk
) {
92 public_key_jwk
->Clear();
94 crypto::EnsureOpenSSLInit();
95 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
97 const uint8_t *data
= reinterpret_cast<const uint8_t*>(spki_der
.data());
98 const uint8_t *ptr
= data
;
99 crypto::ScopedEVP_PKEY
pubkey(d2i_PUBKEY(NULL
, &ptr
, spki_der
.size()));
100 if (!pubkey
|| ptr
!= data
+ spki_der
.size())
103 if (pubkey
->type
== EVP_PKEY_EC
) {
104 return ConvertEcKeyToJwk(pubkey
.get(), public_key_jwk
, err_tracer
);
106 // TODO(juanlang): other algorithms
111 } // namespace JwkSerializer