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 WriteInto(&x_bytes
, degree_bytes
+ 1)), degree_bytes
, x
.get()) ||
66 !BN_bn2bin_padded(reinterpret_cast<uint8_t*>(
67 WriteInto(&y_bytes
, degree_bytes
+ 1)), degree_bytes
, y
.get())) {
71 public_key_jwk
->SetString("kty", "EC");
72 public_key_jwk
->SetString("crv", curve_name
);
75 base::Base64Encode(x_bytes
, &x_b64
);
76 public_key_jwk
->SetString("x", x_b64
);
79 base::Base64Encode(y_bytes
, &y_b64
);
80 public_key_jwk
->SetString("y", y_b64
);
87 bool ConvertSpkiFromDerToJwk(
88 const base::StringPiece
& spki_der
,
89 base::DictionaryValue
* public_key_jwk
) {
90 public_key_jwk
->Clear();
92 crypto::EnsureOpenSSLInit();
93 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
95 const uint8_t *data
= reinterpret_cast<const uint8_t*>(spki_der
.data());
96 const uint8_t *ptr
= data
;
97 crypto::ScopedEVP_PKEY
pubkey(d2i_PUBKEY(NULL
, &ptr
, spki_der
.size()));
98 if (!pubkey
|| ptr
!= data
+ spki_der
.size())
101 if (pubkey
->type
== EVP_PKEY_EC
) {
102 return ConvertEcKeyToJwk(pubkey
.get(), public_key_jwk
, err_tracer
);
104 // TODO(juanlang): other algorithms
109 } // namespace JwkSerializer