Commit e195ec89 authored by cschuet's avatar cschuet Committed by Commit bot

chrome.platformKeys: Add filtering by certificate types

This CL adds the possibility to filter by certificate type
when issuing a certificate request to chrome.platformKeys API.

BUG=488367
TEST=browser_tests:PlatformKeysTest.Basic

Review URL: https://codereview.chromium.org/1141253003

Cr-Commit-Position: refs/heads/master@{#330721}
parent 7344e0bb
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "net/cert/x509_certificate.h" #include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_client_cert_type.h"
namespace content { namespace content {
class BrowserContext; class BrowserContext;
...@@ -47,7 +46,7 @@ struct ClientCertificateRequest { ...@@ -47,7 +46,7 @@ struct ClientCertificateRequest {
// The list of the types of certificates requested, sorted in order of the // The list of the types of certificates requested, sorted in order of the
// server's preference. // server's preference.
std::vector<net::SSLClientCertType> certificate_key_types; std::vector<net::X509Certificate::PublicKeyType> certificate_key_types;
// List of distinguished names of certificate authorities allowed by the // List of distinguished names of certificate authorities allowed by the
// server. Each entry must be a DER-encoded X.509 DistinguishedName. // server. Each entry must be a DER-encoded X.509 DistinguishedName.
...@@ -105,11 +104,14 @@ typedef base::Callback<void(scoped_ptr<net::CertificateList> matches, ...@@ -105,11 +104,14 @@ typedef base::Callback<void(scoped_ptr<net::CertificateList> matches,
const std::string& error_message)> const std::string& error_message)>
SelectCertificatesCallback; SelectCertificatesCallback;
// Returns the list of all certificates that match |request|. |callback| will be // Returns the list of all certificates that were issued by one of the
// invoked with these matches or an error message. // |certificate_authorities|. If |certificate_authorities| is empty, all
void SelectClientCertificates(const ClientCertificateRequest& request, // certificates will be returned. |callback| will be invoked with the matches or
const SelectCertificatesCallback& callback, // an error message.
content::BrowserContext* browser_context); void SelectClientCertificates(
const std::vector<std::string>& certificate_authorities,
const SelectCertificatesCallback& callback,
content::BrowserContext* browser_context);
} // namespace subtle } // namespace subtle
......
...@@ -758,15 +758,20 @@ void SignRSAPKCS1Raw(const std::string& token_id, ...@@ -758,15 +758,20 @@ void SignRSAPKCS1Raw(const std::string& token_id,
browser_context, state_ptr); browser_context, state_ptr);
} }
void SelectClientCertificates(const ClientCertificateRequest& request, void SelectClientCertificates(
const SelectCertificatesCallback& callback, const std::vector<std::string>& certificate_authorities,
content::BrowserContext* browser_context) { const SelectCertificatesCallback& callback,
content::BrowserContext* browser_context) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
scoped_refptr<net::SSLCertRequestInfo> cert_request_info( scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
new net::SSLCertRequestInfo); new net::SSLCertRequestInfo);
cert_request_info->cert_key_types = request.certificate_key_types;
cert_request_info->cert_authorities = request.certificate_authorities; // Currently we do not pass down the requested certificate type to the net
// layer, as it does not support filtering certificates by type. Rather, we
// do not constrain the certificate type here, instead the caller has to apply
// filtering afterwards.
cert_request_info->cert_authorities = certificate_authorities;
const user_manager::User* user = const user_manager::User* user =
chromeos::ProfileHelper::Get()->GetUserByProfile( chromeos::ProfileHelper::Get()->GetUserByProfile(
......
...@@ -481,7 +481,7 @@ class PlatformKeysService::SelectTask : public Task { ...@@ -481,7 +481,7 @@ class PlatformKeysService::SelectTask : public Task {
// |GotMatchingCerts()|. // |GotMatchingCerts()|.
void GetMatchingCerts() { void GetMatchingCerts() {
platform_keys::subtle::SelectClientCertificates( platform_keys::subtle::SelectClientCertificates(
request_, request_.certificate_authorities,
base::Bind(&SelectTask::GotMatchingCerts, weak_factory_.GetWeakPtr()), base::Bind(&SelectTask::GotMatchingCerts, weak_factory_.GetWeakPtr()),
service_->browser_context_); service_->browser_context_);
} }
...@@ -498,7 +498,30 @@ class PlatformKeysService::SelectTask : public Task { ...@@ -498,7 +498,30 @@ class PlatformKeysService::SelectTask : public Task {
DoStep(); DoStep();
return; return;
} }
matches_.swap(*matches);
// If the type field does not contain any entries, certificates of all types
// shall be returned.
if (request_.certificate_key_types.size() == 0) {
matches_.swap(*matches);
DoStep();
return;
}
// Filter the retrieved certificates returning only those whose type is
// equal to one of the entries in the type field of the certificate request.
for (scoped_refptr<net::X509Certificate>& certificate : *matches) {
net::X509Certificate::PublicKeyType actual_key_type =
net::X509Certificate::kPublicKeyTypeUnknown;
size_t unused_key_size = 0;
net::X509Certificate::GetPublicKeyInfo(
certificate->os_cert_handle(), &unused_key_size, &actual_key_type);
const std::vector<net::X509Certificate::PublicKeyType>& accepted_types =
request_.certificate_key_types;
if (std::find(accepted_types.begin(), accepted_types.end(),
actual_key_type) != accepted_types.end()) {
matches_.push_back(certificate.Pass());
}
}
DoStep(); DoStep();
} }
......
...@@ -168,6 +168,21 @@ PlatformKeysInternalSelectClientCertificatesFunction::Run() { ...@@ -168,6 +168,21 @@ PlatformKeysInternalSelectClientCertificatesFunction::Run() {
request.certificate_authorities.push_back( request.certificate_authorities.push_back(
std::string(cert_authority.begin(), cert_authority.end())); std::string(cert_authority.begin(), cert_authority.end()));
} }
for (const api_pk::ClientCertificateType& cert_type :
params->details.request.certificate_types) {
switch (cert_type) {
case api_pk::CLIENT_CERTIFICATE_TYPE_ECDSASIGN:
request.certificate_key_types.push_back(
net::X509Certificate::kPublicKeyTypeECDSA);
break;
case api_pk::CLIENT_CERTIFICATE_TYPE_RSASIGN:
request.certificate_key_types.push_back(
net::X509Certificate::kPublicKeyTypeRSA);
break;
case api_pk::CLIENT_CERTIFICATE_TYPE_NONE:
NOTREACHED();
}
}
content::WebContents* web_contents = nullptr; content::WebContents* web_contents = nullptr;
if (params->details.interactive) { if (params->details.interactive) {
web_contents = GetSenderWebContents(); web_contents = GetSenderWebContents();
......
...@@ -23,7 +23,6 @@ namespace platformKeys { ...@@ -23,7 +23,6 @@ namespace platformKeys {
enum ClientCertificateType { enum ClientCertificateType {
rsaSign, rsaSign,
dssSign,
ecdsaSign ecdsaSign
}; };
...@@ -31,7 +30,9 @@ namespace platformKeys { ...@@ -31,7 +30,9 @@ namespace platformKeys {
// See http://tools.ietf.org/html/rfc4346#section-7.4.4 . // See http://tools.ietf.org/html/rfc4346#section-7.4.4 .
dictionary ClientCertificateRequest { dictionary ClientCertificateRequest {
// This field is a list of the types of certificates requested, sorted in // This field is a list of the types of certificates requested, sorted in
// order of the server's preference. // order of the server's preference. Only certificates of a type contained
// in this list will be retrieved. If <code>certificateTypes</code> is the
// empty list, however, certificates of any type will be returned.
ClientCertificateType[] certificateTypes; ClientCertificateType[] certificateTypes;
// List of distinguished names of certificate authorities allowed by the // List of distinguished names of certificate authorities allowed by the
......
...@@ -237,7 +237,7 @@ function testInteractiveSelectClient1() { ...@@ -237,7 +237,7 @@ function testInteractiveSelectClient1() {
[data.client_1]); [data.client_1]);
} }
function testMatchResult() { function testMatchResultCA1() {
chrome.platformKeys.selectClientCertificates( chrome.platformKeys.selectClientCertificates(
{interactive: false, request: requestCA1()}, {interactive: false, request: requestCA1()},
callbackPass(function(matches) { callbackPass(function(matches) {
...@@ -253,6 +253,38 @@ function testMatchResult() { ...@@ -253,6 +253,38 @@ function testMatchResult() {
})); }));
} }
function testMatchResultECDSA() {
var requestECDSA = {
certificateTypes: ['ecdsaSign'],
certificateAuthorities: []
};
chrome.platformKeys.selectClientCertificates(
{interactive: false, request: requestECDSA},
callbackPass(function(matches) {
assertEq(0, matches.length, 'No matches expected.');
}));
}
function testMatchResultRSA() {
var requestRSA = {
certificateTypes: ['rsaSign'],
certificateAuthorities: []
};
chrome.platformKeys.selectClientCertificates(
{interactive: false, request: requestRSA},
callbackPass(function(matches) {
var expectedAlgorithm = {
modulusLength: 2048,
name: "RSASSA-PKCS1-v1_5",
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
};
var actualAlgorithm = matches[0].keyAlgorithm;
assertEq(
expectedAlgorithm, actualAlgorithm,
'Member algorithm of Match does not equal the expected algorithm');
}));
}
function testGetKeyPairMissingAlgorithName() { function testGetKeyPairMissingAlgorithName() {
var keyParams = { var keyParams = {
// This is missing the algorithm name. // This is missing the algorithm name.
...@@ -433,7 +465,9 @@ var testSuites = { ...@@ -433,7 +465,9 @@ var testSuites = {
testBackgroundInteractiveSelect, testBackgroundInteractiveSelect,
testSelectCA1Certs, testSelectCA1Certs,
testInteractiveSelectNoCerts, testInteractiveSelectNoCerts,
testMatchResult, testMatchResultCA1,
testMatchResultECDSA,
testMatchResultRSA,
testGetKeyPairMissingAlgorithName, testGetKeyPairMissingAlgorithName,
testGetKeyPairRejectsRSAPSS, testGetKeyPairRejectsRSAPSS,
testGetKeyPair, testGetKeyPair,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment