Enable a system PKCS #11 token.
Also added support for importing PKCS #8 formatted private keys as well
as a --slot option in p11_replay, which helps to test this feature.
BUG=chromium:210525
TEST=unit, manual, platform_Pkcs11* autotests
Change-Id: I301029286432a568436bb1ce9d592a5a74ae9c9f
Reviewed-on: https://chromium-review.googlesource.com/183525
Reviewed-by: Darren Krahn <dkrahn@chromium.org>
Commit-Queue: Darren Krahn <dkrahn@chromium.org>
Tested-by: Darren Krahn <dkrahn@chromium.org>
diff --git a/chapsd.conf b/chapsd.conf
index 5b7934f..d2e8143 100644
--- a/chapsd.conf
+++ b/chapsd.conf
@@ -20,5 +20,7 @@
VERBOSE="--v=1"
rm /home/chronos/.chaps_debug_1
fi
+ mkdir -p /var/lib/chaps
+ chown chaps:chronos-access /var/lib/chaps
exec chapsd ${VERBOSE}
end script
diff --git a/p11_replay.cc b/p11_replay.cc
index 97afaeb..339ff85 100644
--- a/p11_replay.cc
+++ b/p11_replay.cc
@@ -60,7 +60,6 @@
LOG(INFO) << "No slots.";
exit(-1);
}
- LOG(INFO) << "Choosing slot " << slot_list[0];
return slot_list[0];
}
@@ -386,10 +385,28 @@
CreateCertificate(session, object_data, object_id, certificate);
X509_free(certificate);
} else if (type == kPrivateKey) {
+ // Try decoding a PKCS#1 RSAPrivateKey structure.
RSA* rsa = d2i_RSAPrivateKey(NULL, &data_start, object_data.length());
if (!rsa) {
- LOG(ERROR) << "OpenSSL error in RSA private key parsing.";
- exit(-1);
+ // Rewind the ptr just in case it was modified.
+ data_start = reinterpret_cast<const unsigned char*>(object_data.c_str());
+ // Try decoding a PKCS#8 structure.
+ PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL,
+ &data_start,
+ object_data.length());
+ if (!p8 || ASN1_TYPE_get(p8->pkey) != V_ASN1_OCTET_STRING) {
+ LOG(ERROR) << "OpenSSL error in PKCS #8 private key parsing.";
+ exit(-1);
+ }
+ // See if we have a RSAPrivateKey in the PKCS#8 structure.
+ data_start = p8->pkey->value.octet_string->data;
+ rsa = d2i_RSAPrivateKey(NULL, &data_start,
+ p8->pkey->value.octet_string->length);
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ if (!rsa) {
+ LOG(ERROR) << "OpenSSL error in RSA private key parsing.";
+ exit(-1);
+ }
}
CreatePrivateKey(session, object_id, "testing_key", rsa);
RSA_free(rsa);
@@ -465,7 +482,7 @@
}
void PrintHelp() {
- printf("Usage: p11_replay [COMMAND]\n");
+ printf("Usage: p11_replay [--slot=<slot>] [COMMAND]\n");
printf("Commands:\n");
printf(" --cleanup : Deletes all test keys.\n");
printf(" --generate [--label=<key_label> --key_size=<size_in_bits>]"
@@ -474,8 +491,8 @@
"useful for comparing key generation on different TPM models.\n");
printf(" --import --path=<path to file> --type=<cert, privkey, pubkey>"
" --id=<token id str>"
- " : Reads an object into the token. Accepts DER formatted"
- " certificates and DER formatted private keys.\n");
+ " : Reads an object into the token. Accepts DER formatted X.509"
+ " certificates and DER formatted PKCS#1 or PKCS#8 private keys.\n");
printf(" --inject [--label=<key_label> --key_size=<size_in_bits>]"
" : Locally generates a key pair suitable for replay tests and injects"
" it into the token.\n");
@@ -592,6 +609,11 @@
chromeos::InitLog(chromeos::kLogToSyslog | chromeos::kLogToStderr);
base::TimeTicks start_ticks = base::TimeTicks::Now();
CK_SLOT_ID slot = Initialize();
+ int tmp_slot = 0;
+ if (cl->HasSwitch("slot") &&
+ base::StringToInt(cl->GetSwitchValueASCII("slot"), &tmp_slot))
+ slot = tmp_slot;
+ LOG(INFO) << "Using slot " << slot;
CK_SESSION_HANDLE session = OpenSession(slot);
PrintTicks(&start_ticks);
string label = "_default";
diff --git a/slot_manager_impl.cc b/slot_manager_impl.cc
index faa7d07..d6df63b 100644
--- a/slot_manager_impl.cc
+++ b/slot_manager_impl.cc
@@ -14,6 +14,7 @@
#include <base/basictypes.h>
#include <base/file_path.h>
+#include <base/file_util.h>
#include <base/logging.h>
#include <base/memory/scoped_ptr.h>
#include <chromeos/secure_blob.h>
@@ -46,6 +47,10 @@
const CK_ULONG kMaxPinLen = 127;
const CK_ULONG kMinPinLen = 6;
const char kSlotDescription[] = "TPM Slot";
+const FilePath::CharType kSystemTokenPath[] =
+ FILE_PATH_LITERAL("/var/lib/chaps");
+const char kSystemTokenAuthData[] = "000000";
+const char kSystemTokenLabel[] = "System TPM Token";
const char kTokenLabel[] = "User-Specific TPM Token";
const char kTokenModel[] = "";
const char kTokenSerialNumber[] = "Not Available";
@@ -289,15 +294,29 @@
LOG(WARNING) << "TPM failed to generate random data.";
}
- // Add default isolate
+ // Add default isolate.
AddIsolate(IsolateCredentialManager::GetDefaultIsolateCredential());
- // Default semantics are to always start with two slots. One 'system' slot
+ // By default we'll start with two slots. This allows for one 'system' slot
// which always has a token available, and one 'user' slot which will have no
// token until a login event is received.
- // TODO(dkrahn): Make this 2 once we're ready to enable the system token.
- // crosbug.com/27759.
- AddSlots(1);
+ AddSlots(2);
+
+ if (file_util::DirectoryExists(FilePath(kSystemTokenPath))) {
+ // Setup the system token.
+ int system_slot_id = 0;
+ if (!LoadToken(IsolateCredentialManager::GetDefaultIsolateCredential(),
+ FilePath(kSystemTokenPath),
+ SecureBlob(kSystemTokenAuthData),
+ kSystemTokenLabel,
+ &system_slot_id)) {
+ LOG(ERROR) << "Failed to load the system token.";
+ return false;
+ }
+ } else {
+ LOG(WARNING) << "System token not loaded because " << kSystemTokenPath
+ << " does not exist.";
+ }
return true;
}
diff --git a/slot_manager_test.cc b/slot_manager_test.cc
index 2da601b..0d066da 100644
--- a/slot_manager_test.cc
+++ b/slot_manager_test.cc
@@ -209,7 +209,7 @@
}
TEST_F(TestSlotManager, DefaultSlotSetup) {
- EXPECT_EQ(1, slot_manager_->GetSlotCount());
+ EXPECT_EQ(2, slot_manager_->GetSlotCount());
EXPECT_FALSE(slot_manager_->IsTokenAccessible(ic_, 0));
}
@@ -304,7 +304,6 @@
kTokenLabel,
&slot_id2));
EXPECT_EQ(slot_id, slot_id2);
- EXPECT_EQ(2, slot_manager_->GetSlotCount());
EXPECT_TRUE(slot_manager_->LoadToken(ic_,
FilePath("another_path"),
MakeBlob(kAuthData),
@@ -317,7 +316,6 @@
slot_manager_->ChangeTokenAuthData(FilePath("yet_another_path"),
MakeBlob(kAuthData),
MakeBlob(kNewAuthData));
- EXPECT_LT(slot_manager_->GetSlotCount(), 5);
// Logout with an unknown path.
slot_manager_->UnloadToken(ic_, FilePath("still_yet_another_path"));
slot_manager_->UnloadToken(ic_, FilePath("some_path"));
@@ -446,7 +444,6 @@
MakeBlob(kAuthData),
kTokenLabel,
&slot_id));
- EXPECT_EQ(1, slot_manager_->GetSlotCount());
EXPECT_TRUE(slot_manager_->OpenIsolate(&new_isolate_1, &new_isolate_created));
EXPECT_TRUE(new_isolate_created);
@@ -455,7 +452,6 @@
MakeBlob(kAuthData),
kTokenLabel,
&slot_id));
- EXPECT_EQ(2, slot_manager_->GetSlotCount());
// Ensure tokens are only accessible with the valid isolate cred.
EXPECT_TRUE(slot_manager_->IsTokenAccessible(new_isolate_0, 0));