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 "chrome/browser/extensions/api/certificate_provider/certificate_provider_api.h"
12 #include "base/logging.h"
13 #include "base/memory/linked_ptr.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/stl_util.h"
16 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
17 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
18 #include "chrome/common/extensions/api/certificate_provider.h"
19 #include "chrome/common/extensions/api/certificate_provider_internal.h"
20 #include "content/public/common/console_message_level.h"
21 #include "net/cert/x509_certificate.h"
22 #include "net/ssl/ssl_private_key.h"
24 namespace extensions
{
26 namespace api_cp
= api::certificate_provider
;
27 namespace api_cpi
= api::certificate_provider_internal
;
31 const char kErrorInvalidX509Cert
[] =
32 "Certificate is not a valid X.509 certificate.";
33 const char kErrorECDSANotSupported
[] = "Key type ECDSA not supported.";
34 const char kErrorUnknownKeyType
[] = "Key type unknown.";
35 const char kErrorAborted
[] = "Request was aborted.";
36 const char kErrorTimeout
[] = "Request timed out, reply rejected.";
40 CertificateProviderInternalReportCertificatesFunction::
41 ~CertificateProviderInternalReportCertificatesFunction() {}
43 ExtensionFunction::ResponseAction
44 CertificateProviderInternalReportCertificatesFunction::Run() {
45 scoped_ptr
<api_cpi::ReportCertificates::Params
> params(
46 api_cpi::ReportCertificates::Params::Create(*args_
));
47 EXTENSION_FUNCTION_VALIDATE(params
);
49 chromeos::CertificateProviderService
* const service
=
50 chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
54 if (!params
->certificates
) {
55 // In the public API, the certificates parameter is mandatory. We only run
56 // into this case, if the custom binding rejected the reply by the
58 return RespondNow(Error(kErrorAborted
));
61 chromeos::certificate_provider::CertificateInfoList cert_infos
;
62 std::vector
<std::vector
<char>> rejected_certificates
;
63 for (linked_ptr
<api_cp::CertificateInfo
> input_cert_info
:
64 *params
->certificates
) {
65 chromeos::certificate_provider::CertificateInfo parsed_cert_info
;
67 if (ParseCertificateInfo(*input_cert_info
, &parsed_cert_info
))
68 cert_infos
.push_back(parsed_cert_info
);
70 rejected_certificates
.push_back(input_cert_info
->certificate
);
73 if (service
->SetCertificatesProvidedByExtension(
74 extension_id(), params
->request_id
, cert_infos
)) {
75 return RespondNow(ArgumentList(
76 api_cpi::ReportCertificates::Results::Create(rejected_certificates
)));
78 // The custom binding already checks for multiple reports to the same
79 // request. The only remaining case, why this reply can fail is that the
81 return RespondNow(Error(kErrorTimeout
));
85 bool CertificateProviderInternalReportCertificatesFunction::
87 const api_cp::CertificateInfo
& info
,
88 chromeos::certificate_provider::CertificateInfo
* out_info
) {
89 const std::vector
<char>& cert_der
= info
.certificate
;
90 if (cert_der
.empty()) {
91 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR
, kErrorInvalidX509Cert
);
95 out_info
->certificate
= net::X509Certificate::CreateFromBytes(
96 vector_as_array(&cert_der
), cert_der
.size());
97 if (!out_info
->certificate
) {
98 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR
, kErrorInvalidX509Cert
);
102 size_t public_key_length_in_bits
= 0;
103 net::X509Certificate::PublicKeyType type
=
104 net::X509Certificate::kPublicKeyTypeUnknown
;
105 net::X509Certificate::GetPublicKeyInfo(
106 out_info
->certificate
->os_cert_handle(), &public_key_length_in_bits
,
110 case net::X509Certificate::kPublicKeyTypeRSA
:
111 DCHECK(public_key_length_in_bits
);
113 // Convert bits to bytes.
114 out_info
->max_signature_length_in_bytes
=
115 (public_key_length_in_bits
+ 7) / 8;
116 out_info
->type
= net::SSLPrivateKey::Type::RSA
;
118 case net::X509Certificate::kPublicKeyTypeECDSA
:
119 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR
,
120 kErrorECDSANotSupported
);
123 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR
,
124 kErrorUnknownKeyType
);
128 for (const api_cp::Hash hash
: info
.supported_hashes
) {
130 case api_cp::HASH_MD5_SHA1
:
131 out_info
->supported_hashes
.push_back(
132 net::SSLPrivateKey::Hash::MD5_SHA1
);
134 case api_cp::HASH_SHA1
:
135 out_info
->supported_hashes
.push_back(net::SSLPrivateKey::Hash::SHA1
);
137 case api_cp::HASH_SHA256
:
138 out_info
->supported_hashes
.push_back(net::SSLPrivateKey::Hash::SHA256
);
140 case api_cp::HASH_SHA384
:
141 out_info
->supported_hashes
.push_back(net::SSLPrivateKey::Hash::SHA384
);
143 case api_cp::HASH_SHA512
:
144 out_info
->supported_hashes
.push_back(net::SSLPrivateKey::Hash::SHA512
);
146 case api_cp::HASH_NONE
:
154 CertificateProviderInternalReportSignatureFunction::
155 ~CertificateProviderInternalReportSignatureFunction() {}
157 ExtensionFunction::ResponseAction
158 CertificateProviderInternalReportSignatureFunction::Run() {
159 scoped_ptr
<api_cpi::ReportSignature::Params
> params(
160 api_cpi::ReportSignature::Params::Create(*args_
));
161 EXTENSION_FUNCTION_VALIDATE(params
);
163 chromeos::CertificateProviderService
* const service
=
164 chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
168 std::vector
<uint8_t> signature
;
169 // If an error occurred, |signature| will not be set.
170 if (params
->signature
)
171 signature
.assign(params
->signature
->begin(), params
->signature
->end());
173 service
->ReplyToSignRequest(extension_id(), params
->request_id
, signature
);
174 return RespondNow(NoArguments());
177 } // namespace extensions