blob: 1db9323d1b4c90e9d8275c970c63650b4960a288 [file] [log] [blame]
// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The expensive PKCS #11 operations that occur during a VPN connect are C_Login
// and C_Sign. This program replays these along with minimal overhead calls.
// The --generate switch can be used to prepare a private key to test against.
#include <stdlib.h>
#include <base/basictypes.h>
#include <base/command_line.h>
#include <base/logging.h>
#include <chromeos/syslog_logging.h>
#include "chaps/chaps_utility.h"
#include "pkcs11/cryptoki.h"
static const char* kKeyID = "test";
// Initializes the library and finds an appropriate slot.
static CK_SLOT_ID Initialize() {
CK_RV result = C_Initialize(NULL);
LOG(INFO) << "C_Initialize: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
CK_SLOT_ID slot_list[10];
CK_ULONG slot_count = arraysize(slot_list);
result = C_GetSlotList(CK_TRUE, slot_list, &slot_count);
LOG(INFO) << "C_GetSlotList: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
if (slot_count == 0) {
LOG(INFO) << "No slots.";
exit(-1);
}
return slot_list[0];
}
// Opens a new session and performs a login.
static CK_SESSION_HANDLE Login(CK_SLOT_ID slot) {
CK_RV result = CKR_OK;
CK_SESSION_HANDLE session = 0;
bool session_ready = false;
while (!session_ready) {
result = C_OpenSession(slot,
CKF_SERIAL_SESSION | CKF_RW_SESSION,
NULL, /* Ignore callbacks. */
NULL, /* Ignore callbacks. */
&session);
LOG(INFO) << "C_OpenSession: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
result = C_Login(session, CKU_USER, (CK_UTF8CHAR_PTR)"111111", 6);
LOG(INFO) << "C_Login: " << chaps::CK_RVToString(result);
if (result == CKR_OK) {
session_ready = true;
} else if (result == CKR_USER_ALREADY_LOGGED_IN) {
result = C_Logout(session);
LOG(INFO) << "C_Logout: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
result = C_CloseAllSessions(slot);
LOG(INFO) << "C_CloseAllSessions: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
} else {
exit(-1);
}
}
return session;
}
// Sign some data with a private key.
static void Sign(CK_SESSION_HANDLE session) {
CK_OBJECT_CLASS class_value = CKO_PRIVATE_KEY;
CK_ATTRIBUTE attributes[] = {
{CKA_CLASS, &class_value, sizeof(class_value)},
{CKA_ID, const_cast<char*>(kKeyID), strlen(kKeyID)}
};
CK_RV result = C_FindObjectsInit(session, attributes, arraysize(attributes));
LOG(INFO) << "C_FindObjectsInit: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
CK_OBJECT_HANDLE object = 0;
CK_ULONG object_count = 1;
result = C_FindObjects(session, &object, 1, &object_count);
LOG(INFO) << "C_FindObjects: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
if (object_count == 0) {
LOG(INFO) << "No key.";
exit(-1);
}
CK_MECHANISM mechanism;
mechanism.mechanism = CKM_SHA1_RSA_PKCS;
mechanism.pParameter = NULL;
mechanism.ulParameterLen = 0;
result = C_SignInit(session, &mechanism, object);
LOG(INFO) << "C_SignInit: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
CK_BYTE data[200] = {0};
CK_BYTE signature[256] = {0};
CK_ULONG signature_length = arraysize(signature);
result = C_Sign(session,
data, arraysize(data),
signature, &signature_length);
LOG(INFO) << "C_Sign: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
}
// Generates a test key pair.
static void GenerateKeyPair(CK_SESSION_HANDLE session) {
CK_MECHANISM mechanism;
mechanism.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
mechanism.pParameter = NULL;
mechanism.ulParameterLen = 0;
CK_ULONG bits = 2048;
CK_BYTE e[] = {1, 0, 1};
CK_BBOOL false_value = CK_FALSE;
CK_BBOOL true_value = CK_TRUE;
CK_ATTRIBUTE public_attributes[] = {
{CKA_ENCRYPT, &true_value, sizeof(true_value)},
{CKA_VERIFY, &true_value, sizeof(true_value)},
{CKA_WRAP, &false_value, sizeof(false_value)},
{CKA_TOKEN, &true_value, sizeof(true_value)},
{CKA_PRIVATE, &false_value, sizeof(false_value)},
{CKA_MODULUS_BITS, &bits, sizeof(bits)},
{CKA_PUBLIC_EXPONENT, e, sizeof(e)}
};
CK_ATTRIBUTE private_attributes[] = {
{CKA_DECRYPT, &true_value, sizeof(true_value)},
{CKA_SIGN, &true_value, sizeof(true_value)},
{CKA_UNWRAP, &false_value, sizeof(false_value)},
{CKA_SENSITIVE, &true_value, sizeof(true_value)},
{CKA_TOKEN, &true_value, sizeof(true_value)},
{CKA_PRIVATE, &true_value, sizeof(true_value)},
{CKA_ID, const_cast<char*>(kKeyID), strlen(kKeyID)},
};
CK_OBJECT_HANDLE public_key_handle = 0;
CK_OBJECT_HANDLE private_key_handle = 0;
CK_RV result = C_GenerateKeyPair(session,
&mechanism,
public_attributes,
arraysize(public_attributes),
private_attributes,
arraysize(private_attributes),
&public_key_handle,
&private_key_handle);
LOG(INFO) << "C_GenerateKeyPair: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
}
// Cleans up the session and library.
static void TearDown(CK_SESSION_HANDLE session) {
CK_RV result = C_Logout(session);
LOG(INFO) << "C_Logout: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
result = C_CloseSession(session);
LOG(INFO) << "C_CloseSession: " << chaps::CK_RVToString(result);
if (result != CKR_OK)
exit(-1);
C_Finalize(NULL);
}
int main(int argc, char** argv) {
CommandLine::Init(argc, argv);
bool generate = CommandLine::ForCurrentProcess()->HasSwitch("generate");
chromeos::InitLog(chromeos::kLogToStderr);
CK_SLOT_ID slot = Initialize();
CK_SESSION_HANDLE session = Login(slot);
if (generate) {
GenerateKeyPair(session);
} else {
Sign(session);
}
TearDown(session);
}