1bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// found in the LICENSE file.
4bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
5bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "net/cert/jwk_serializer.h"
6bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
7bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include <cert.h>
8bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include <keyhi.h>
9bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include <nss.h>
10bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
11bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/base64.h"
12bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/values.h"
13bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "crypto/nss_util.h"
14bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "crypto/scoped_nss_types.h"
15bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
16bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace net {
17bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
18bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace JwkSerializer {
19bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
20bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace {
21bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
22bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool ConvertEcPrime256v1PublicKeyInfoToJwk(
23bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    CERTSubjectPublicKeyInfo* spki,
24bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    base::DictionaryValue* public_key_jwk) {
25ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  static const int kUncompressedEncodingType = 4;
26bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  static const int kPrime256v1PublicKeyLength = 64;
27bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // The public key value is encoded as 0x04 + 64 bytes of public key.
28bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // NSS gives the length as the bit length.
29bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (spki->subjectPublicKey.len != (kPrime256v1PublicKeyLength + 1) * 8 ||
30ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      spki->subjectPublicKey.data[0] != kUncompressedEncodingType)
31bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return false;
32bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  public_key_jwk->SetString("kty", "EC");
34bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  public_key_jwk->SetString("crv", "P-256");
35bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
36bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::StringPiece x(
37bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      reinterpret_cast<char*>(spki->subjectPublicKey.data + 1),
38bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      kPrime256v1PublicKeyLength / 2);
39bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  std::string x_b64;
40bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::Base64Encode(x, &x_b64);
41bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  public_key_jwk->SetString("x", x_b64);
42bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
43bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::StringPiece y(
44bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      reinterpret_cast<char*>(spki->subjectPublicKey.data + 1 +
45bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                              kPrime256v1PublicKeyLength / 2),
46bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      kPrime256v1PublicKeyLength / 2);
47bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  std::string y_b64;
48bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::Base64Encode(y, &y_b64);
49bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  public_key_jwk->SetString("y", y_b64);
50bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  return true;
51bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
52bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
53bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool ConvertEcPublicKeyInfoToJwk(
54bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    CERTSubjectPublicKeyInfo* spki,
55bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    base::DictionaryValue* public_key_jwk) {
56bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // 1.2.840.10045.3.1.7
57bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // (iso.member-body.us.ansi-x9-62.ellipticCurve.primeCurve.prime256v1)
58bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // (This includes the DER-encoded type (OID) and length: parameters can be
59bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // anything, so the DER type isn't implied, and NSS includes it.)
60bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  static const unsigned char kPrime256v1[] = {
61bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
62bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  };
63bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (spki->algorithm.parameters.len == sizeof(kPrime256v1) &&
64bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      !memcmp(spki->algorithm.parameters.data, kPrime256v1,
65bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch              sizeof(kPrime256v1))) {
66bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return ConvertEcPrime256v1PublicKeyInfoToJwk(spki, public_key_jwk);
67bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  }
68bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // TODO(juanlang): other curves
69bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  return false;
70bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
71bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)typedef scoped_ptr<
73bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    CERTSubjectPublicKeyInfo,
74bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
75bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                         SECKEY_DestroySubjectPublicKeyInfo> >
76bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    ScopedCERTSubjectPublicKeyInfo;
77bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
78bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}  // namespace
79bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
80bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool ConvertSpkiFromDerToJwk(
81bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    const base::StringPiece& spki_der,
82bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    base::DictionaryValue* public_key_jwk) {
83bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  public_key_jwk->Clear();
84bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
85bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  crypto::EnsureNSSInit();
86bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
87bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (!NSS_IsInitialized())
88bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return false;
89bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
90bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  SECItem sec_item;
91bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  sec_item.data = const_cast<unsigned char*>(
92bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      reinterpret_cast<const unsigned char*>(spki_der.data()));
93bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  sec_item.len = spki_der.size();
94bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ScopedCERTSubjectPublicKeyInfo spki(
95bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      SECKEY_DecodeDERSubjectPublicKeyInfo(&sec_item));
96bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (!spki)
97bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return false;
98bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
99bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // 1.2.840.10045.2
100bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // (iso.member-body.us.ansi-x9-62.id-ecPublicKey)
101bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // (This omits the ASN.1 encoding of the type (OID) and length: the fact that
102bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // this is an OID is already clear, and NSS omits it here.)
103bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  static const unsigned char kIdEcPublicKey[] = {
104bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01
105bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  };
106bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  bool rv = false;
107bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (spki->algorithm.algorithm.len == sizeof(kIdEcPublicKey) &&
108bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      !memcmp(spki->algorithm.algorithm.data, kIdEcPublicKey,
109bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch              sizeof(kIdEcPublicKey))) {
110bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    rv = ConvertEcPublicKeyInfoToJwk(spki.get(), public_key_jwk);
111bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  }
112bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // TODO(juanlang): other algorithms
113bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  return rv;
114bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
115bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
116bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}  // namespace JwkSerializer
117bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
118bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}  // namespace net
119