Commit 80709e26 authored by pneubeck's avatar pneubeck Committed by Commit bot

chrome.platformKeys.getKeyPair: Check requested algorithm against certificate.

This adds a check that the requested algorithm is actually permitted by the certificate as defined in the algorithm field of the Subject Public Key Info.

BUG=466584

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

Cr-Commit-Position: refs/heads/master@{#322142}
parent 3ca6f10d
......@@ -24,9 +24,13 @@ namespace api_pki = api::platform_keys_internal;
namespace {
const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
const char kErrorAlgorithmNotPermittedByCertificate[] =
"The requested Algorithm is not permitted by the certificate.";
const char kErrorInvalidX509Cert[] =
"Certificate is not a valid X.509 certificate.";
const char kWebCryptoRSASSA_PKCS1_v1_5[] = "RSASSA-PKCS1-v1_5";
struct PublicKeyInfo {
// The X.509 Subject Public Key Info of the key in DER encoding.
std::string public_key_spki_der;
......@@ -46,7 +50,7 @@ struct PublicKeyInfo {
void BuildWebCryptoRSAAlgorithmDictionary(const PublicKeyInfo& key_info,
base::DictionaryValue* algorithm) {
CHECK_EQ(net::X509Certificate::kPublicKeyTypeRSA, key_info.key_type);
algorithm->SetStringWithoutPathExpansion("name", "RSASSA-PKCS1-v1_5");
algorithm->SetStringWithoutPathExpansion("name", kWebCryptoRSASSA_PKCS1_v1_5);
algorithm->SetIntegerWithoutPathExpansion("modulusLength",
key_info.key_size_bits);
......@@ -122,6 +126,13 @@ PlatformKeysInternalGetPublicKeyFunction::Run() {
return RespondNow(Error(kErrorAlgorithmNotSupported));
}
// Currently, the only supported combination is:
// A certificate declaring rsaEncryption in the SubjectPublicKeyInfo used
// with the RSASSA-PKCS1-v1.5 algorithm.
if (params->algorithm_name != kWebCryptoRSASSA_PKCS1_v1_5) {
return RespondNow(Error(kErrorAlgorithmNotPermittedByCertificate));
}
api_pki::GetPublicKey::Results::Algorithm algorithm;
BuildWebCryptoRSAAlgorithmDictionary(key_info,
&algorithm.additional_properties);
......
......@@ -4,7 +4,7 @@
// Internal API for to implement the platformKeys and enterprise.platformKeys
// APIs.
[ implemented_in = "chrome/browser/extensions/api/platform_keys/platform_keys_api.h" ]
[implemented_in = "chrome/browser/extensions/api/platform_keys/platform_keys_api.h"]
namespace platformKeysInternal {
callback SelectCallback = void (platformKeys.Match[] certs);
......@@ -48,9 +48,14 @@ namespace platformKeysInternal {
ArrayBuffer data,
SignCallback callback);
// Calls back <code>callback</code> with details about the key certified by
// <code>certificate</code>.
// Checks whether <code>certificate</code> certifies a key that allows usage
// of the WebCrypto algorithm <code>algorithmName</code>. If so, calls back
// <code>callback</code> with the key info and a WebCrypto
// <code>KeyAlgorithm</code> dictionary describing the key's algorithm. The
// <code>name</code> property will equal <code>algorithmName</code>.
// Otherwise, calls back with an error.
static void getPublicKey(ArrayBuffer certificate,
DOMString algorithmName,
GetPublicKeyCallback callback);
};
};
......@@ -53,14 +53,15 @@ function combineAlgorithms(algorithm, importParams) {
function getPublicKey(cert, importParams, callback) {
importParams = normalizeImportParams(importParams);
// TODO(pneubeck): pass importParams.name to the internal getPublicKey and
// verify on the C++ side that the requested algorithm is compatible with the
// given SubjectPublicKeyInfo of the certificate.
// https://crbug.com/466584
internalAPI.getPublicKey(cert, function(publicKey, algorithm) {
var combinedAlgorithm = combineAlgorithms(algorithm, importParams);
callback(publicKey, combinedAlgorithm);
});
internalAPI.getPublicKey(
cert, importParams.name, function(publicKey, algorithm) {
if (chrome.runtime.lastError) {
callback();
return;
}
var combinedAlgorithm = combineAlgorithms(algorithm, importParams);
callback(publicKey, combinedAlgorithm);
});
}
exports.getPublicKey = getPublicKey;
......@@ -49,6 +49,10 @@ binding.registerCustomHook(function(api) {
apiFunctions.setHandleRequest(
'getKeyPair', function(cert, params, callback) {
getPublicKey(cert, params, function(publicKey, algorithm) {
if (chrome.runtime.lastError) {
callback();
return;
}
callback(createPublicKey(publicKey, algorithm),
createPrivateKey(publicKey, algorithm));
});
......
......@@ -19,11 +19,14 @@ var callbackFail= chrome.test.callbackFail;
// Each value is the path to a file in this extension's folder that will be
// loaded and replaced by a Uint8Array in the setUp() function below.
var data = {
// X.509 client certificates in DER encoding.
// X.509 client certificate in DER encoding.
// Algorithm in SPKI: rsaEncryption.
// openssl x509 -in net/data/ssl/certificates/client_1.pem -outform DER -out
// client_1.der
client_1: 'client_1.der',
// X.509 client certificate in DER encoding.
// Algorithm in SPKI: rsaEncryption.
// openssl x509 -in net/data/ssl/certificates/client_2.pem -outform DER -out
// client_2.der
client_2: 'client_2.der',
......@@ -267,6 +270,17 @@ function testGetKeyPairMissingAlgorithName() {
}
}
function testGetKeyPairRejectsRSAPSS() {
var keyParams = {
name: 'RSA-PSS',
hash: {name: 'SHA-1'}
};
chrome.platformKeys.getKeyPair(
data.client_1.buffer, keyParams,
callbackFail(
'The requested Algorithm is not permitted by the certificate.'));
}
function testGetKeyPair() {
var keyParams = {
// Algorithm names are case-insensitive.
......@@ -390,6 +404,7 @@ var testSuites = {
testInteractiveSelectNoCerts,
testMatchResult,
testGetKeyPairMissingAlgorithName,
testGetKeyPairRejectsRSAPSS,
testGetKeyPair,
testSignNoHash,
testSignSha1Client1,
......
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