File: p256_key_util.cc

package info (click to toggle)
chromium-browser 57.0.2987.98-1~deb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 2,637,852 kB
  • ctags: 2,544,394
  • sloc: cpp: 12,815,961; ansic: 3,676,222; python: 1,147,112; asm: 526,608; java: 523,212; xml: 286,794; perl: 92,654; sh: 86,408; objc: 73,271; makefile: 27,698; cs: 18,487; yacc: 13,031; tcl: 12,957; pascal: 4,875; ml: 4,716; lex: 3,904; sql: 3,862; ruby: 1,982; lisp: 1,508; php: 1,368; exp: 404; awk: 325; csh: 117; jsp: 39; sed: 37
file content (142 lines) | stat: -rw-r--r-- 4,917 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/gcm_driver/crypto/p256_key_util.h"

#include <stddef.h>
#include <stdint.h>

#include <memory>
#include <vector>

#include "base/logging.h"
#include "base/strings/string_util.h"
#include "crypto/ec_private_key.h"
#include "third_party/boringssl/src/include/openssl/ec.h"
#include "third_party/boringssl/src/include/openssl/ecdh.h"
#include "third_party/boringssl/src/include/openssl/evp.h"

namespace gcm {

namespace {

// The first byte in an uncompressed P-256 point per SEC1 2.3.3.
const char kUncompressedPointForm = 0x04;

// A P-256 field element consists of 32 bytes.
const size_t kFieldBytes = 32;

// A P-256 point in uncompressed form consists of 0x04 (to denote that the point
// is uncompressed per SEC1 2.3.3) followed by two, 32-byte field elements.
const size_t kUncompressedPointBytes = 1 + 2 * kFieldBytes;

}  // namespace

bool CreateP256KeyPair(std::string* out_private_key,
                       std::string* out_public_key_x509,
                       std::string* out_public_key) {
  DCHECK(out_private_key);
  DCHECK(out_public_key);

  std::unique_ptr<crypto::ECPrivateKey> key_pair(
      crypto::ECPrivateKey::Create());
  if (!key_pair.get()) {
    DLOG(ERROR) << "Unable to generate a new P-256 key pair.";
    return false;
  }

  std::vector<uint8_t> private_key;

  // Export the encrypted private key with an empty password. This is not done
  // to provide any security, but rather to achieve a consistent private key
  // storage between the BoringSSL and NSS implementations.
  if (!key_pair->ExportEncryptedPrivateKey(&private_key)) {
    DLOG(ERROR) << "Unable to export the private key.";
    return false;
  }

  std::string candidate_public_key;

  // ECPrivateKey::ExportRawPublicKey() returns the EC point in the uncompressed
  // point format, but does not include the leading byte of value 0x04 that
  // indicates usage of uncompressed points, per SEC1 2.3.3.
  if (!key_pair->ExportRawPublicKey(&candidate_public_key) ||
      candidate_public_key.size() != 2 * kFieldBytes) {
    DLOG(ERROR) << "Unable to export the public key.";
    return false;
  }

  std::vector<uint8_t> public_key_x509;

  // Export the public key to an X.509 SubjectPublicKeyInfo for enabling NSS to
  // import the key material when computing a shared secret.
  if (!key_pair->ExportPublicKey(&public_key_x509)) {
    DLOG(ERROR) << "Unable to export the public key as an X.509 "
                << "SubjectPublicKeyInfo block.";
    return false;
  }

  out_private_key->assign(reinterpret_cast<const char*>(private_key.data()),
                          private_key.size());
  out_public_key_x509->assign(
      reinterpret_cast<const char*>(public_key_x509.data()),
      public_key_x509.size());

  // Concatenate the leading 0x04 byte and the two uncompressed points.
  out_public_key->reserve(kUncompressedPointBytes);
  out_public_key->push_back(kUncompressedPointForm);
  out_public_key->append(candidate_public_key);

  return true;
}

bool ComputeSharedP256Secret(const base::StringPiece& private_key,
                             const base::StringPiece& public_key_x509,
                             const base::StringPiece& peer_public_key,
                             std::string* out_shared_secret) {
  DCHECK(out_shared_secret);

  std::unique_ptr<crypto::ECPrivateKey> local_key_pair(
      crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
          std::vector<uint8_t>(private_key.data(),
                               private_key.data() + private_key.size()),
          std::vector<uint8_t>(
              public_key_x509.data(),
              public_key_x509.data() + public_key_x509.size())));

  if (!local_key_pair) {
    DLOG(ERROR) << "Unable to create the local key pair.";
    return false;
  }

  EC_KEY* ec_private_key = EVP_PKEY_get0_EC_KEY(local_key_pair->key());
  if (!ec_private_key || !EC_KEY_check_key(ec_private_key)) {
    DLOG(ERROR) << "The private key is invalid.";
    return false;
  }

  bssl::UniquePtr<EC_POINT> point(
      EC_POINT_new(EC_KEY_get0_group(ec_private_key)));

  if (!point ||
      !EC_POINT_oct2point(
          EC_KEY_get0_group(ec_private_key), point.get(),
          reinterpret_cast<const uint8_t*>(peer_public_key.data()),
          peer_public_key.size(), nullptr)) {
    DLOG(ERROR) << "Can't convert peer public value to curve point.";
    return false;
  }

  uint8_t result[kFieldBytes];
  if (ECDH_compute_key(result, sizeof(result), point.get(), ec_private_key,
                       nullptr) != sizeof(result)) {
    DLOG(ERROR) << "Unable to compute the ECDH shared secret.";
    return false;
  }

  out_shared_secret->assign(reinterpret_cast<char*>(result), sizeof(result));
  return true;
}

}  // namespace gcm