blob: b460f23ebcb09c3ebf9e3911fff2f51299885998 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/gcm_driver/crypto/encryption_header_parsers.h"
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gcm {
namespace {
const uint64_t kDefaultRecordSize = 4096;
TEST(EncryptionHeaderParsersTest, ParseValidEncryptionHeaders) {
struct {
const char* const header;
const char* const parsed_keyid;
const char* const parsed_salt;
uint64_t parsed_rs;
} expected_results[] = {
{ "keyid=foo;salt=c2l4dGVlbmNvb2xieXRlcw;rs=1024",
"foo", "sixteencoolbytes", 1024 },
{ "keyid=foo; salt=c2l4dGVlbmNvb2xieXRlcw; rs=1024",
"foo", "sixteencoolbytes", 1024 },
{ "KEYID=foo;SALT=c2l4dGVlbmNvb2xieXRlcw;RS=1024",
"foo", "sixteencoolbytes", 1024 },
{ " keyid = foo ; salt = c2l4dGVlbmNvb2xieXRlcw ; rs = 1024 ",
"foo", "sixteencoolbytes", 1024 },
{ "keyid=foo", "foo", "", kDefaultRecordSize },
{ "keyid=foo;", "foo", "", kDefaultRecordSize },
{ "keyid=\"foo\"", "foo", "", kDefaultRecordSize },
{ "keyid='foo'", "foo", "", kDefaultRecordSize },
{ "salt=c2l4dGVlbmNvb2xieXRlcw",
"", "sixteencoolbytes", kDefaultRecordSize },
{ "rs=2048", "", "", 2048 },
{ "keyid=foo;someothervalue=1;rs=42", "foo", "", 42 },
{ "keyid=foo;keyid=bar", "bar", "", kDefaultRecordSize },
};
for (size_t i = 0; i < arraysize(expected_results); i++) {
SCOPED_TRACE(i);
std::vector<EncryptionHeaderValues> values;
ASSERT_TRUE(ParseEncryptionHeader(expected_results[i].header, &values));
ASSERT_EQ(1u, values.size());
EXPECT_EQ(expected_results[i].parsed_keyid, values[0].keyid);
EXPECT_EQ(expected_results[i].parsed_salt, values[0].salt);
EXPECT_EQ(expected_results[i].parsed_rs, values[0].rs);
}
}
TEST(EncryptionHeaderParsersTest, ParseValidMultiValueEncryptionHeaders) {
const size_t kNumberOfValues = 2u;
struct {
const char* const header;
struct {
const char* const keyid;
const char* const salt;
uint64_t rs;
} parsed_values[kNumberOfValues];
} expected_results[] = {
{ "keyid=foo;salt=c2l4dGVlbmNvb2xieXRlcw;rs=1024,keyid=foo;salt=c2l4dGVlbm"
"Nvb2xieXRlcw;rs=1024",
{ { "foo", "sixteencoolbytes", 1024 },
{ "foo", "sixteencoolbytes", 1024 } } },
{ "keyid=foo,salt=c2l4dGVlbmNvb2xieXRlcw;rs=1024",
{ { "foo", "", kDefaultRecordSize },
{ "", "sixteencoolbytes", 1024 } } },
{ "keyid=foo,keyid=bar;salt=c2l4dGVlbmNvb2xieXRlcw;rs=1024",
{ { "foo", "", kDefaultRecordSize },
{ "bar", "sixteencoolbytes", 1024 } } },
{ "keyid=\"foo,keyid=bar\",salt=c2l4dGVlbmNvb2xieXRlcw",
{ { "foo,keyid=bar", "", kDefaultRecordSize },
{ "", "sixteencoolbytes", kDefaultRecordSize } } },
};
for (size_t i = 0; i < arraysize(expected_results); i++) {
SCOPED_TRACE(i);
std::vector<EncryptionHeaderValues> values;
ASSERT_TRUE(ParseEncryptionHeader(expected_results[i].header, &values));
ASSERT_EQ(kNumberOfValues, values.size());
for (size_t j = 0; j < kNumberOfValues; ++j) {
EXPECT_EQ(expected_results[i].parsed_values[j].keyid, values[j].keyid);
EXPECT_EQ(expected_results[i].parsed_values[j].salt, values[j].salt);
EXPECT_EQ(expected_results[i].parsed_values[j].rs, values[j].rs);
}
}
}
TEST(EncryptionHeaderParsersTest, ParseInvalidEncryptionHeaders) {
const char* const expected_failures[] = {
"keyid",
"keyid=",
"keyid=foo;novaluekey",
"keyid=foo,keyid",
"salt",
"salt=",
"salt=YmV/2ZXJ-sMDA",
"salt=dHdlbHZlY29vbGJ5dGVz=====",
"salt=123$xyz",
"salt=c2l4dGVlbmNvb2xieXRlcw,salt=123$xyz",
"rs",
"rs=",
"rs=0",
"rs=0x13",
"rs=1",
"rs=-1",
"rs=+5",
"rs=99999999999999999999999999999999",
"rs=2,rs=0",
"rs=foobar",
};
for (size_t i = 0; i < arraysize(expected_failures); i++) {
SCOPED_TRACE(i);
std::vector<EncryptionHeaderValues> values;
EXPECT_FALSE(ParseEncryptionHeader(expected_failures[i], &values));
EXPECT_EQ(0u, values.size());
}
}
TEST(EncryptionHeaderParsersTest, ParseValidCryptoKeyHeaders) {
struct {
const char* const header;
const char* const parsed_keyid;
const char* const parsed_aesgcm128;
const char* const parsed_dh;
} expected_results[] = {
{ "keyid=foo;aesgcm128=c2l4dGVlbmNvb2xieXRlcw;dh=dHdlbHZlY29vbGJ5dGVz",
"foo", "sixteencoolbytes", "twelvecoolbytes" },
{ "keyid=foo; aesgcm128=c2l4dGVlbmNvb2xieXRlcw; dh=dHdlbHZlY29vbGJ5dGVz",
"foo", "sixteencoolbytes", "twelvecoolbytes" },
{ "keyid = foo ; aesgcm128 = c2l4dGVlbmNvb2xieXRlcw ; dh = dHdlbHZlY29vbGJ5"
"dGVz ",
"foo", "sixteencoolbytes", "twelvecoolbytes" },
{ "KEYID=foo;AESGCM128=c2l4dGVlbmNvb2xieXRlcw;DH=dHdlbHZlY29vbGJ5dGVz",
"foo", "sixteencoolbytes", "twelvecoolbytes" },
{ "keyid=foo", "foo", "", "" },
{ "aesgcm128=c2l4dGVlbmNvb2xieXRlcw", "", "sixteencoolbytes", "" },
{ "aesgcm128=\"c2l4dGVlbmNvb2xieXRlcw\"", "", "sixteencoolbytes", "" },
{ "aesgcm128='c2l4dGVlbmNvb2xieXRlcw'", "", "sixteencoolbytes", "" },
{ "dh=dHdlbHZlY29vbGJ5dGVz", "", "", "twelvecoolbytes" },
{ "keyid=foo;someothervalue=bar;aesgcm128=dHdlbHZlY29vbGJ5dGVz",
"foo", "twelvecoolbytes", "" },
{ "keyid=foo;keyid=bar", "bar", "", "" },
};
for (size_t i = 0; i < arraysize(expected_results); i++) {
SCOPED_TRACE(i);
std::vector<CryptoKeyHeaderValues> values;
ASSERT_TRUE(ParseCryptoKeyHeader(expected_results[i].header, &values));
ASSERT_EQ(1u, values.size());
EXPECT_EQ(expected_results[i].parsed_keyid, values[0].keyid);
EXPECT_EQ(expected_results[i].parsed_aesgcm128, values[0].aesgcm128);
EXPECT_EQ(expected_results[i].parsed_dh, values[0].dh);
}
}
TEST(EncryptionHeaderParsersTest, ParseValidMultiValueCryptoKeyHeaders) {
const size_t kNumberOfValues = 2u;
struct {
const char* const header;
struct {
const char* const keyid;
const char* const aesgcm128;
const char* const dh;
} parsed_values[kNumberOfValues];
} expected_results[] = {
{ "keyid=foo;aesgcm128=c2l4dGVlbmNvb2xieXRlcw;dh=dHdlbHZlY29vbGJ5dGVz,"
"keyid=bar;aesgcm128=dHdlbHZlY29vbGJ5dGVz;dh=c2l4dGVlbmNvb2xieXRlcw",
{ { "foo", "sixteencoolbytes", "twelvecoolbytes" },
{ "bar", "twelvecoolbytes", "sixteencoolbytes" } } },
{ "keyid=foo,aesgcm128=c2l4dGVlbmNvb2xieXRlcw",
{ { "foo", "", "" },
{ "", "sixteencoolbytes", "" } } },
{ "keyid=foo,keyid=bar;dh=dHdlbHZlY29vbGJ5dGVz",
{ { "foo", "", "" },
{ "bar", "", "twelvecoolbytes" } } },
{ "keyid=\"foo,keyid=bar\",aesgcm128=c2l4dGVlbmNvb2xieXRlcw",
{ { "foo,keyid=bar", "", "" },
{ "", "sixteencoolbytes", "" } } },
};
for (size_t i = 0; i < arraysize(expected_results); i++) {
SCOPED_TRACE(i);
std::vector<CryptoKeyHeaderValues> values;
ASSERT_TRUE(ParseCryptoKeyHeader(expected_results[i].header, &values));
ASSERT_EQ(kNumberOfValues, values.size());
for (size_t j = 0; j < kNumberOfValues; ++j) {
EXPECT_EQ(expected_results[i].parsed_values[j].keyid, values[j].keyid);
EXPECT_EQ(expected_results[i].parsed_values[j].aesgcm128,
values[j].aesgcm128);
EXPECT_EQ(expected_results[i].parsed_values[j].dh, values[j].dh);
}
}
}
TEST(EncryptionHeaderParsersTest, ParseInvalidCryptoKeyHeaders) {
const char* const expected_failures[] = {
"keyid",
"keyid=",
"keyid=foo,keyid",
"keyid=foo;novaluekey",
"aesgcm128",
"aesgcm128=",
"aesgcm128=123$xyz",
"aesgcm128=foobar,aesgcm128=123$xyz",
"dh",
"dh=",
"dh=YmV/2ZXJ-sMDA",
"dh=dHdlbHZlY29vbGJ5dGVz=====",
"dh=123$xyz",
};
for (size_t i = 0; i < arraysize(expected_failures); i++) {
SCOPED_TRACE(i);
std::vector<CryptoKeyHeaderValues> values;
EXPECT_FALSE(ParseCryptoKeyHeader(expected_failures[i], &values));
EXPECT_EQ(0u, values.size());
}
}
TEST(EncryptionHeaderParsersTest, SixValueHeader) {
const char* const header = "keyid=0,keyid=1,keyid=2,keyid=3,keyid=4,keyid=5";
std::vector<EncryptionHeaderValues> encryption_values;
ASSERT_TRUE(ParseEncryptionHeader(header, &encryption_values));
std::vector<CryptoKeyHeaderValues> crypto_key_values;
ASSERT_TRUE(ParseCryptoKeyHeader(header, &crypto_key_values));
ASSERT_EQ(6u, encryption_values.size());
ASSERT_EQ(6u, crypto_key_values.size());
for (size_t i = 0; i < encryption_values.size(); i++) {
SCOPED_TRACE(i);
const std::string value = base::IntToString(i);
EXPECT_EQ(value, encryption_values[i].keyid);
EXPECT_EQ(value, crypto_key_values[i].keyid);
}
}
TEST(EncryptionHeaderParsersTest, InvalidHeadersDoNotModifyOutput) {
EncryptionHeaderValues encryption_value;
encryption_value.keyid = "mykeyid";
encryption_value.salt = "somesalt";
encryption_value.rs = 42u;
std::vector<EncryptionHeaderValues> encryption_values;
encryption_values.push_back(encryption_value);
ASSERT_FALSE(ParseEncryptionHeader("rs=foobar", &encryption_values));
ASSERT_EQ(1u, encryption_values.size());
EXPECT_EQ("mykeyid", encryption_values[0].keyid);
EXPECT_EQ("somesalt", encryption_values[0].salt);
EXPECT_EQ(42u, encryption_values[0].rs);
CryptoKeyHeaderValues crypto_key_value;
crypto_key_value.keyid = "myotherkeyid";
crypto_key_value.aesgcm128 = "akey";
crypto_key_value.dh = "yourdh";
std::vector<CryptoKeyHeaderValues> crypto_key_values;
crypto_key_values.push_back(crypto_key_value);
ASSERT_FALSE(ParseCryptoKeyHeader("aesgcm128=$$$", &crypto_key_values));
ASSERT_EQ(1u, crypto_key_values.size());
EXPECT_EQ("myotherkeyid", crypto_key_values[0].keyid);
EXPECT_EQ("akey", crypto_key_values[0].aesgcm128);
EXPECT_EQ("yourdh", crypto_key_values[0].dh);
}
} // namespace
} // namespace gcm