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 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_client_cert_type.h"
namespace content {
class BrowserContext;
......@@ -47,7 +46,7 @@ struct ClientCertificateRequest {
// The list of the types of certificates requested, sorted in order of the
// 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
// server. Each entry must be a DER-encoded X.509 DistinguishedName.
......@@ -105,11 +104,14 @@ typedef base::Callback<void(scoped_ptr<net::CertificateList> matches,
const std::string& error_message)>
SelectCertificatesCallback;
// Returns the list of all certificates that match |request|. |callback| will be
// invoked with these matches or an error message.
void SelectClientCertificates(const ClientCertificateRequest& request,
const SelectCertificatesCallback& callback,
content::BrowserContext* browser_context);
// Returns the list of all certificates that were issued by one of the
// |certificate_authorities|. If |certificate_authorities| is empty, all
// certificates will be returned. |callback| will be invoked with the matches or
// an error message.
void SelectClientCertificates(
const std::vector<std::string>& certificate_authorities,
const SelectCertificatesCallback& callback,
content::BrowserContext* browser_context);
} // namespace subtle
......
......@@ -758,15 +758,20 @@ void SignRSAPKCS1Raw(const std::string& token_id,
browser_context, state_ptr);
}
void SelectClientCertificates(const ClientCertificateRequest& request,
const SelectCertificatesCallback& callback,
content::BrowserContext* browser_context) {
void SelectClientCertificates(
const std::vector<std::string>& certificate_authorities,
const SelectCertificatesCallback& callback,
content::BrowserContext* browser_context) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
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 =
chromeos::ProfileHelper::Get()->GetUserByProfile(
......
......@@ -481,7 +481,7 @@ class PlatformKeysService::SelectTask : public Task {
// |GotMatchingCerts()|.
void GetMatchingCerts() {
platform_keys::subtle::SelectClientCertificates(
request_,
request_.certificate_authorities,
base::Bind(&SelectTask::GotMatchingCerts, weak_factory_.GetWeakPtr()),
service_->browser_context_);
}
......@@ -498,7 +498,30 @@ class PlatformKeysService::SelectTask : public Task {
DoStep();
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();
}
......
......@@ -168,6 +168,21 @@ PlatformKeysInternalSelectClientCertificatesFunction::Run() {
request.certificate_authorities.push_back(
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;
if (params->details.interactive) {
web_contents = GetSenderWebContents();
......
......@@ -23,7 +23,6 @@ namespace platformKeys {
enum ClientCertificateType {
rsaSign,
dssSign,
ecdsaSign
};
......@@ -31,7 +30,9 @@ namespace platformKeys {
// See http://tools.ietf.org/html/rfc4346#section-7.4.4 .
dictionary ClientCertificateRequest {
// 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;
// List of distinguished names of certificate authorities allowed by the
......
......@@ -237,7 +237,7 @@ function testInteractiveSelectClient1() {
[data.client_1]);
}
function testMatchResult() {
function testMatchResultCA1() {
chrome.platformKeys.selectClientCertificates(
{interactive: false, request: requestCA1()},
callbackPass(function(matches) {
......@@ -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() {
var keyParams = {
// This is missing the algorithm name.
......@@ -433,7 +465,9 @@ var testSuites = {
testBackgroundInteractiveSelect,
testSelectCA1Certs,
testInteractiveSelectNoCerts,
testMatchResult,
testMatchResultCA1,
testMatchResultECDSA,
testMatchResultRSA,
testGetKeyPairMissingAlgorithName,
testGetKeyPairRejectsRSAPSS,
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