Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / extensions / api / certificate_provider / certificate_provider_api.cc
blob9e212645ce0449b1a26b775217b5ef0b2a397400
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"
7 #include <stddef.h>
8 #include <stdint.h>
10 #include <vector>
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;
29 namespace {
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.";
38 } // namespace
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(
51 browser_context());
52 DCHECK(service);
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
57 // extension.
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);
69 else
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)));
77 } else {
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
80 // request timed out.
81 return RespondNow(Error(kErrorTimeout));
85 bool CertificateProviderInternalReportCertificatesFunction::
86 ParseCertificateInfo(
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);
92 return false;
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);
99 return false;
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,
107 &type);
109 switch (type) {
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;
117 break;
118 case net::X509Certificate::kPublicKeyTypeECDSA:
119 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR,
120 kErrorECDSANotSupported);
121 return false;
122 default:
123 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR,
124 kErrorUnknownKeyType);
125 return false;
128 for (const api_cp::Hash hash : info.supported_hashes) {
129 switch (hash) {
130 case api_cp::HASH_MD5_SHA1:
131 out_info->supported_hashes.push_back(
132 net::SSLPrivateKey::Hash::MD5_SHA1);
133 break;
134 case api_cp::HASH_SHA1:
135 out_info->supported_hashes.push_back(net::SSLPrivateKey::Hash::SHA1);
136 break;
137 case api_cp::HASH_SHA256:
138 out_info->supported_hashes.push_back(net::SSLPrivateKey::Hash::SHA256);
139 break;
140 case api_cp::HASH_SHA384:
141 out_info->supported_hashes.push_back(net::SSLPrivateKey::Hash::SHA384);
142 break;
143 case api_cp::HASH_SHA512:
144 out_info->supported_hashes.push_back(net::SSLPrivateKey::Hash::SHA512);
145 break;
146 case api_cp::HASH_NONE:
147 NOTREACHED();
148 return false;
151 return true;
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(
165 browser_context());
166 DCHECK(service);
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