Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / net / ssl / ssl_platform_key_nss.cc
blob22a6eec487dd0ca293fb54039581cdf758ff0b25
1 // Copyright 2015 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/ssl/ssl_platform_key.h"
7 #include <keyhi.h>
8 #include <pk11pub.h>
9 #include <prerror.h>
11 #include <openssl/bn.h>
12 #include <openssl/ecdsa.h>
13 #include <openssl/rsa.h>
15 #include "base/logging.h"
16 #include "base/macros.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/stl_util.h"
19 #include "crypto/scoped_nss_types.h"
20 #include "crypto/scoped_openssl_types.h"
21 #include "net/cert/x509_certificate.h"
22 #include "net/ssl/client_key_store.h"
23 #include "net/ssl/ssl_private_key.h"
24 #include "net/ssl/threaded_ssl_private_key.h"
26 namespace net {
28 namespace {
30 void LogPRError() {
31 PRErrorCode err = PR_GetError();
32 const char* err_name = PR_ErrorToName(err);
33 if (err_name == nullptr)
34 err_name = "";
35 LOG(ERROR) << "Could not sign digest: " << err << " (" << err_name << ")";
38 class SSLPlatformKeyNSS : public ThreadedSSLPrivateKey::Delegate {
39 public:
40 SSLPlatformKeyNSS(SSLPrivateKey::Type type,
41 crypto::ScopedSECKEYPrivateKey key)
42 : type_(type), key_(key.Pass()) {}
43 ~SSLPlatformKeyNSS() override {}
45 SSLPrivateKey::Type GetType() override { return type_; }
47 bool SupportsHash(SSLPrivateKey::Hash hash) override { return true; }
49 size_t GetMaxSignatureLengthInBytes() override {
50 int len = PK11_SignatureLen(key_.get());
51 if (len <= 0)
52 return 0;
53 // NSS signs raw ECDSA signatures rather than a DER-encoded ECDSA-Sig-Value.
54 if (type_ == SSLPrivateKey::Type::ECDSA)
55 return ECDSA_SIG_max_len(static_cast<size_t>(len) / 2);
56 return static_cast<size_t>(len);
59 Error SignDigest(SSLPrivateKey::Hash hash,
60 const base::StringPiece& input,
61 std::vector<uint8_t>* signature) override {
62 SECItem digest_item;
63 digest_item.data =
64 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(input.data()));
65 digest_item.len = input.size();
67 crypto::ScopedOpenSSLBytes free_digest_info;
68 if (type_ == SSLPrivateKey::Type::RSA) {
69 // PK11_Sign expects the caller to prepend the DigestInfo.
70 int hash_nid = NID_undef;
71 switch (hash) {
72 case SSLPrivateKey::Hash::MD5_SHA1:
73 hash_nid = NID_md5_sha1;
74 break;
75 case SSLPrivateKey::Hash::SHA1:
76 hash_nid = NID_sha1;
77 break;
78 case SSLPrivateKey::Hash::SHA256:
79 hash_nid = NID_sha256;
80 break;
81 case SSLPrivateKey::Hash::SHA384:
82 hash_nid = NID_sha384;
83 break;
84 case SSLPrivateKey::Hash::SHA512:
85 hash_nid = NID_sha512;
86 break;
88 DCHECK_NE(NID_undef, hash_nid);
89 int is_alloced;
90 size_t prefix_len;
91 if (!RSA_add_pkcs1_prefix(&digest_item.data, &prefix_len, &is_alloced,
92 hash_nid, digest_item.data, digest_item.len)) {
93 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
95 digest_item.len = prefix_len;
96 if (is_alloced)
97 free_digest_info.reset(digest_item.data);
100 int len = PK11_SignatureLen(key_.get());
101 if (len <= 0) {
102 LogPRError();
103 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
105 signature->resize(len);
106 SECItem signature_item;
107 signature_item.data = vector_as_array(signature);
108 signature_item.len = signature->size();
110 SECStatus rv = PK11_Sign(key_.get(), &signature_item, &digest_item);
111 if (rv != SECSuccess) {
112 LogPRError();
113 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
115 signature->resize(signature_item.len);
117 // NSS emits raw ECDSA signatures, but BoringSSL expects a DER-encoded
118 // ECDSA-Sig-Value.
119 if (type_ == SSLPrivateKey::Type::ECDSA) {
120 if (signature->size() % 2 != 0) {
121 LOG(ERROR) << "Bad signature length";
122 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
124 size_t order_len = signature->size() / 2;
126 // Convert the RAW ECDSA signature to a DER-encoded ECDSA-Sig-Value.
127 crypto::ScopedECDSA_SIG sig(ECDSA_SIG_new());
128 if (!sig || !BN_bin2bn(vector_as_array(signature), order_len, sig->r) ||
129 !BN_bin2bn(vector_as_array(signature) + order_len, order_len,
130 sig->s)) {
131 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
134 int len = i2d_ECDSA_SIG(sig.get(), nullptr);
135 if (len <= 0)
136 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
137 signature->resize(len);
138 uint8_t* ptr = vector_as_array(signature);
139 len = i2d_ECDSA_SIG(sig.get(), &ptr);
140 if (len <= 0)
141 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
142 signature->resize(len);
145 return OK;
148 private:
149 SSLPrivateKey::Type type_;
150 crypto::ScopedSECKEYPrivateKey key_;
152 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyNSS);
155 } // namespace
157 scoped_ptr<SSLPrivateKey> FetchClientCertPrivateKey(
158 X509Certificate* certificate,
159 scoped_refptr<base::SequencedTaskRunner> task_runner) {
160 crypto::ScopedSECKEYPrivateKey key(
161 PK11_FindKeyByAnyCert(certificate->os_cert_handle(), nullptr));
162 if (!key) {
163 return ClientKeyStore::GetInstance()->FetchClientCertPrivateKey(
164 *certificate);
167 KeyType nss_type = SECKEY_GetPrivateKeyType(key.get());
168 SSLPrivateKey::Type type;
169 switch (nss_type) {
170 case rsaKey:
171 type = SSLPrivateKey::Type::RSA;
172 break;
173 case ecKey:
174 type = SSLPrivateKey::Type::ECDSA;
175 break;
176 default:
177 LOG(ERROR) << "Unknown key type: " << nss_type;
178 return nullptr;
180 return make_scoped_ptr(new ThreadedSSLPrivateKey(
181 make_scoped_ptr(new SSLPlatformKeyNSS(type, key.Pass())),
182 task_runner.Pass()));
185 } // namespace net