blob: 0f5502b52ac560a1154c65d373d5ef83005ef79d [file] [log] [blame]
// Copyright (c) 2010 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.
#include "entd/crypto_pkcs11.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/string_number_conversions.h"
#include <chromeos/utility.h>
#include <openssl/bn.h>
#include "entd/utils.h"
namespace entd {
namespace crypto {
// PKCS#11 Helper Constants.
static const CK_OBJECT_CLASS kPublicKeyClass = CKO_PUBLIC_KEY;
static const CK_OBJECT_CLASS kPrivateKeyClass = CKO_PRIVATE_KEY;
static const CK_BBOOL kCkTrue = TRUE;
static const CK_BBOOL kCkFalse = FALSE;
static const CK_BYTE kPublicExponent[] = { 0x01, 0x00,
0x01 }; // 65537 in bytes.
static const CK_ULONG kDefaultKeySize = 2048; // in bits.
typedef std::vector<CK_ATTRIBUTE> TemplateAttributes;
typedef std::map<CK_ATTRIBUTE_TYPE, CK_BBOOL> TemplateBoolValues;
typedef std::map<CK_ATTRIBUTE_TYPE, CK_ULONG> TemplateUlongValues;
typedef std::map<CK_ATTRIBUTE_TYPE, chromeos::Blob> TemplateBinaryValues;
typedef std::map<CK_ATTRIBUTE_TYPE, std::string> TemplateStringValues;
// PKCS#11 structures uses pointers to buffers. This structure holds the
// buffers result of translation of user's input, required to complete
// the request.
typedef struct {
TemplateBoolValues bool_values;
TemplateUlongValues ulong_values;
TemplateBinaryValues binary_values;
TemplateStringValues string_values;
} TemplateValueStore;
// Dirty little macros to make copying things from PKCS#11 structs a little
// cleaner.
#define SET_CK_STRING(self, record, field) \
self->Set(v8::String::New(#field), \
v8::String::New(reinterpret_cast<char*>(&record.field[0]), \
CkStringLength(record.field, \
sizeof(record.field))))
#define SET_CK_ULONG(self, record, field) \
self->Set(v8::String::New(#field), \
v8::Integer::NewFromUnsigned(record.field))
// Reflect PKCS#11 constants into JavaScript.
#define SET_CK_CONST(self, name) \
self->Set(v8::String::New(#name), \
v8::Integer::NewFromUnsigned(name), v8::ReadOnly)
bool CKRVToString(CK_RV rv, std::string* rv_string) {
v8::Handle<v8::Function> ctor = Pkcs11::constructor_template()->GetFunction();
v8::Handle<v8::Array> ary = ctor->GetPropertyNames();
for (uint32_t i = 0; i < ary->Length(); ++i) {
v8::String::AsciiValue name(ary->Get(i));
if (strncmp("CKR_", *name, 4) == 0) {
uint32_t value = ctor->Get(ary->Get(i))->Uint32Value();
if (value == rv) {
rv_string->assign(*name, name.length());
return true;
}
}
}
unsigned int urv = rv;
rv_string->assign(StringPrintf("0x%08X", urv));
return false;
}
// Check that a CK_RV value is CKR_OK, throw a V8 exception if it is not.
bool OkOrThrow(CK_RV rv) {
if (rv != CKR_OK) {
std::string rv_string;
CKRVToString(rv, &rv_string);
utils::ThrowV8Exception("PKCS#11 Error: " + rv_string);
return false;
}
return true;
}
// Check that a CK_RV value is CKR_OK, log a warning if it is not.
bool OkOrWarn(CK_RV rv) {
if (rv != CKR_OK) {
std::string rv_string;
CKRVToString(rv, &rv_string);
LOG(WARNING) << "PKCS#11 Error: " << rv_string;
return false;
}
return true;
}
// Most strings returned by the PKCS#11 API are padded with spaces to a
// known length. This function returns the length of a string minus the
// trailing space. Some fields seem to ignore the spec and null pad rather
// than space pad, so we deal with those here too.
int CkStringLength(CK_CHAR_PTR value, CK_ULONG length) {
for (CK_ULONG i = length; i > 0; --i) {
if (value[i - 1] != ' ' && value[i - 1] != '\0')
return i;
}
return 0;
}
bool Pkcs11::Slots::Initialize() {
return true;
}
// static.
bool Pkcs11::Slots::InitializeTemplate(
v8::Handle<v8::FunctionTemplate> ctor_t) {
v8::Handle<v8::ObjectTemplate> instance_t = ctor_t->InstanceTemplate();
instance_t->SetAccessor(v8::String::New("length"),
GetLength,
0, // Length is readonly, so setter is NULL.
v8::Handle<v8::Value>(), // Don't need any data.
v8::DEFAULT, // DEFAULT AccessControl.
v8::DontDelete);
instance_t->SetIndexedPropertyHandler(GetIndexedProperty,
SetIndexedProperty,
QueryIndexedProperty,
DeleteIndexedProperty,
EnumerateIndexedProperties);
return true;
}
// static.
v8::Handle<v8::Value> Pkcs11::Slots::GetIndexedProperty(
uint32_t index, const v8::AccessorInfo& info) {
Pkcs11::Slots* slots = Pkcs11::Slots::UnwrapOrThrow(info.This(), "this");
if (!slots)
return v8::Undefined();
CK_ULONG num_slots = 0;
CK_RV rv = C_GetSlotList(FALSE, NULL, &num_slots);
if (!OkOrThrow(rv))
return v8::Undefined();
if (index >= num_slots)
return v8::Undefined();
SlotMap::iterator it = slots->slot_map_.find(index);
if (it == slots->slot_map_.end()) {
// We haven't created a Pkcs11::Slot for this slot id yet, time to make one.
Pkcs11::Slot::Reference slot(Pkcs11::Slot::New());
if (slot.IsEmpty() || !slot->Initialize(index))
return ThrowException("Error initializing slot");
slots->slot_map_[index] = slot;
return slot->js_object();
}
return it->second->js_object();
}
// static.
v8::Handle<v8::Value> Pkcs11::Slots::SetIndexedProperty(
uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
Pkcs11::Slots* slots = Pkcs11::Slots::UnwrapOrThrow(info.This(), "this");
if (!slots)
return v8::Undefined();
return ThrowException("Attempt to write to read only property");
}
// static.
v8::Handle<v8::Boolean> Pkcs11::Slots::QueryIndexedProperty(
uint32_t index, const v8::AccessorInfo& info) {
Pkcs11::Slots* slots = Pkcs11::Slots::UnwrapOrWarn(info.This(), "this");
if (!slots)
return v8::False();
CK_ULONG num_slots = 0;
CK_RV rv = C_GetSlotList(FALSE, NULL, &num_slots);
if (!OkOrWarn(rv))
return v8::False();
if (index >= num_slots)
return v8::False();
return v8::True();
}
// static.
v8::Handle<v8::Boolean> Pkcs11::Slots::DeleteIndexedProperty(
uint32_t index, const v8::AccessorInfo& info) {
Pkcs11::Slots* slots = Pkcs11::Slots::UnwrapOrThrow(info.This(), "this");
if (!slots)
return v8::False();
ThrowException("Attempt to delete read only property");
return v8::False();
}
// static.
v8::Handle<v8::Array> Pkcs11::Slots::EnumerateIndexedProperties(
const v8::AccessorInfo& info) {
Pkcs11::Slots* slots = Pkcs11::Slots::UnwrapOrWarn(info.This(), "this");
if (!slots)
return v8::Array::New();
CK_ULONG num_slots = 0;
CK_RV rv = C_GetSlotList(FALSE, NULL, &num_slots);
if (!OkOrThrow(rv))
return v8::Array::New();
v8::Handle<v8::Array> ary = v8::Array::New(num_slots);
for (uint32_t i = 0; i < num_slots; ++i)
ary->Set(i, v8::Integer::New(i));
return ary;
}
// static.
v8::Handle<v8::Value> Pkcs11::Slots::GetLength(v8::Local<v8::String> property,
const v8::AccessorInfo& info) {
Pkcs11::Slots* slots = Pkcs11::Slots::UnwrapOrThrow(info.This(), "this");
if (!slots)
return v8::Undefined();
CK_ULONG num_slots = 0;
CK_RV rv = C_GetSlotList(FALSE, NULL, &num_slots);
if (!OkOrThrow(rv))
return v8::Undefined();
return v8::Integer::NewFromUnsigned(num_slots);
}
bool Pkcs11::Slot::Initialize(CK_SLOT_ID slot_id) {
slot_id_ = slot_id;
return Refresh();
}
// static.
bool Pkcs11::Slot::InitializeTemplate(v8::Handle<v8::FunctionTemplate> ctor_t) {
v8::Handle<v8::ObjectTemplate> instance_t = ctor_t->InstanceTemplate();
SET_CK_CONST(ctor_t, CKF_TOKEN_PRESENT);
SET_CK_CONST(ctor_t, CKF_REMOVABLE_DEVICE);
SET_CK_CONST(ctor_t, CKF_HW_SLOT);
BindMethod(instance_t, &Pkcs11::Slot::CallRefresh, "refresh");
instance_t->SetAccessor(v8::String::New("token"),
GetToken,
0, // Token is readonly, so setter is NULL.
v8::Handle<v8::Value>(), // Don't need any data.
v8::DEFAULT, // DEFAULT AccessControl.
v8::DontDelete);
return true;
}
v8::Handle<v8::Value> Pkcs11::Slot::CallRefresh(const v8::Arguments& args) {
if (!Refresh())
return ThrowException("Unexpected error");
return v8::Undefined();
}
bool Pkcs11::Slot::Refresh() {
CK_SLOT_INFO slot_info;
CK_RV rv = C_GetSlotInfo(slot_id_, &slot_info);
if (!OkOrWarn(rv))
return false;
v8::Handle<v8::Object> self = js_object();
if (self.IsEmpty())
return false;
SET_CK_STRING(self, slot_info, slotDescription);
SET_CK_STRING(self, slot_info, manufacturerID);
SET_CK_ULONG(self, slot_info, flags);
if (slot_info.flags & CKF_TOKEN_PRESENT) {
if (token_.IsEmpty()) {
if (!token_.Copy(Pkcs11::Token::New()) || !token_->Initialize(slot_id_)) {
LOG(ERROR) << "Error creating Pkcs11::Token instance";
return false;
}
}
} else {
token_.set_native_ptr(NULL);
}
return true;
}
// static.
v8::Handle<v8::Value> Pkcs11::Slot::GetToken(v8::Local<v8::String> property,
const v8::AccessorInfo& info) {
Pkcs11::Slot* slot = Pkcs11::Slot::UnwrapOrThrow(info.This(), "this");
if (!slot)
return v8::Undefined();
if (slot->token_.IsEmpty())
return v8::Null();
return slot->token_.js_object();
}
bool Pkcs11::Token::Initialize(CK_SLOT_ID slot_id) {
slot_id_ = slot_id;
js_object()->Set(v8::String::NewSymbol("slotId"),
v8::Integer::NewFromUnsigned(slot_id_));
return Refresh();
}
// static.
bool Pkcs11::Token::InitializeTemplate(
v8::Handle<v8::FunctionTemplate> ctor_t) {
// Opencryptoki defaults, as per their README: http://tinyurl.com/2cafmsp.
ctor_t->Set(v8::String::New("DEFAULT_SO_PIN"),
v8::String::New("87654321"));
ctor_t->Set(v8::String::New("DEFAULT_USER_PIN"),
v8::String::New("12345678"));
// openSession() flags...
SET_CK_CONST(ctor_t, CKF_RW_SESSION);
// token flags...
SET_CK_CONST(ctor_t, CKF_RNG);
SET_CK_CONST(ctor_t, CKF_WRITE_PROTECTED);
SET_CK_CONST(ctor_t, CKF_LOGIN_REQUIRED);
SET_CK_CONST(ctor_t, CKF_USER_PIN_INITIALIZED);
SET_CK_CONST(ctor_t, CKF_RESTORE_KEY_NOT_NEEDED);
SET_CK_CONST(ctor_t, CKF_CLOCK_ON_TOKEN);
SET_CK_CONST(ctor_t, CKF_PROTECTED_AUTHENTICATION_PATH);
SET_CK_CONST(ctor_t, CKF_DUAL_CRYPTO_OPERATIONS);
SET_CK_CONST(ctor_t, CKF_TOKEN_INITIALIZED);
SET_CK_CONST(ctor_t, CKF_USER_PIN_COUNT_LOW);
SET_CK_CONST(ctor_t, CKF_USER_PIN_FINAL_TRY);
SET_CK_CONST(ctor_t, CKF_USER_PIN_LOCKED);
SET_CK_CONST(ctor_t, CKF_USER_PIN_TO_BE_CHANGED);
SET_CK_CONST(ctor_t, CKF_SO_PIN_COUNT_LOW);
SET_CK_CONST(ctor_t, CKF_SO_PIN_FINAL_TRY);
SET_CK_CONST(ctor_t, CKF_SO_PIN_LOCKED);
SET_CK_CONST(ctor_t, CKF_SO_PIN_TO_BE_CHANGED);
v8::Handle<v8::ObjectTemplate> instance_t = ctor_t->InstanceTemplate();
BindMethod(instance_t, &Pkcs11::Token::CallRefresh, "refresh");
BindMethod(instance_t, &Pkcs11::Token::InitToken, "initToken");
BindMethod(instance_t, &Pkcs11::Token::OpenSession, "openSession");
BindMethod(instance_t, &Pkcs11::Token::CloseAllSessions, "closeAllSessions");
return true;
}
bool Pkcs11::Token::Refresh() {
CK_TOKEN_INFO token_info;
CK_RV rv = C_GetTokenInfo(slot_id_, &token_info);
if (!OkOrWarn(rv))
return false;
v8::Handle<v8::Object> self = js_object();
if (self.IsEmpty())
return false;
SET_CK_STRING(self, token_info, label);
SET_CK_STRING(self, token_info, manufacturerID);
SET_CK_STRING(self, token_info, model);
SET_CK_STRING(self, token_info, serialNumber);
SET_CK_ULONG(self, token_info, flags);
SET_CK_ULONG(self, token_info, ulMaxSessionCount);
SET_CK_ULONG(self, token_info, ulSessionCount);
SET_CK_ULONG(self, token_info, ulMaxRwSessionCount);
SET_CK_ULONG(self, token_info, ulRwSessionCount);
SET_CK_ULONG(self, token_info, ulMaxPinLen);
SET_CK_ULONG(self, token_info, ulMinPinLen);
SET_CK_ULONG(self, token_info, ulTotalPublicMemory);
SET_CK_ULONG(self, token_info, ulFreePublicMemory);
SET_CK_ULONG(self, token_info, ulTotalPrivateMemory);
SET_CK_ULONG(self, token_info, ulFreePrivateMemory);
return true;
}
v8::Handle<v8::Value> Pkcs11::Token::InitToken(const v8::Arguments& args) {
if (args.Length() < 1)
return ThrowException("Missing required parameter: soPin");
v8::String::AsciiValue ascii_pin(args[0]);
if (args.Length() < 2)
return ThrowException("Missing required parameter: label");
v8::String::AsciiValue ascii_label(args[1]);
if (ascii_label.length() > 32)
return ThrowException("Label must be 32 characters or less");
CK_CHAR ck_label[32];
memset(ck_label, ' ', sizeof(ck_label));
memcpy(ck_label, *ascii_label, ascii_label.length());
OkOrThrow(C_InitToken(slot_id_,
reinterpret_cast<CK_CHAR_PTR>(*ascii_pin),
ascii_pin.length(), ck_label));
return v8::Undefined();
}
v8::Handle<v8::Value> Pkcs11::Token::OpenSession(const v8::Arguments& args) {
if (args.Length() < 1)
return ThrowException("Missing required parameter: sessionFlags");
uint32_t session_flags = args[0]->Uint32Value();
CK_SESSION_HANDLE session_handle = 0;
if (!OkOrThrow(C_OpenSession(slot_id_, session_flags | CKF_SERIAL_SESSION,
NULL, NULL, &session_handle))) {
return v8::Undefined();
}
Pkcs11::Session::Reference session = Pkcs11::Session::New();
if (!session->Initialize(slot_id_, session_handle))
return ThrowException("Unexpected error");
return session->js_object();
}
v8::Handle<v8::Value> Pkcs11::Token::CloseAllSessions(
const v8::Arguments& args) {
OkOrThrow(C_CloseAllSessions(slot_id_));
return v8::Undefined();
}
v8::Handle<v8::Value> Pkcs11::Token::CallRefresh(const v8::Arguments& args) {
if (!Refresh())
return ThrowException("Unexpected error");
return v8::Undefined();
}
bool Pkcs11::Session::Initialize(const CK_SLOT_ID slot_id,
const CK_SESSION_HANDLE& session_handle) {
slot_id_ = slot_id;
session_handle_ = session_handle;
return Refresh();
}
// static.
bool Pkcs11::Session::InitializeTemplate(
v8::Handle<v8::FunctionTemplate> ctor_t) {
// Session states...
SET_CK_CONST(ctor_t, CKU_SO);
SET_CK_CONST(ctor_t, CKS_RO_PUBLIC_SESSION);
SET_CK_CONST(ctor_t, CKS_RO_USER_FUNCTIONS);
SET_CK_CONST(ctor_t, CKS_RW_PUBLIC_SESSION);
SET_CK_CONST(ctor_t, CKS_RW_USER_FUNCTIONS);
SET_CK_CONST(ctor_t, CKS_RW_SO_FUNCTIONS);
// Session flags...
SET_CK_CONST(ctor_t, CKF_RW_SESSION);
SET_CK_CONST(ctor_t, CKF_SERIAL_SESSION);
// User types for login()...
SET_CK_CONST(ctor_t, CKU_SO);
SET_CK_CONST(ctor_t, CKU_USER);
// Keypair generation.
SET_CK_CONST(ctor_t, CKM_RSA_PKCS_KEY_PAIR_GEN);
v8::Handle<v8::ObjectTemplate> instance_t = ctor_t->InstanceTemplate();
BindMethod(instance_t, &Pkcs11::Session::CallRefresh, "refresh");
BindMethod(instance_t, &Pkcs11::Session::Close, "close");
BindMethod(instance_t, &Pkcs11::Session::Login, "login");
BindMethod(instance_t, &Pkcs11::Session::Logout, "logout");
BindMethod(instance_t, &Pkcs11::Session::InitPin, "initPin");
BindMethod(instance_t, &Pkcs11::Session::SetPin, "setPin");
BindMethod(instance_t, &Pkcs11::Session::GenerateKeyPair, "generateKeyPair");
BindMethod(instance_t, &Pkcs11::Session::FindObjects, "findObjects");
BindMethod(instance_t, &Pkcs11::Session::CreateObject, "createObject");
BindMethod(instance_t, &Pkcs11::Session::LogoutAndClose, "logoutAndClose");
return true;
}
bool Pkcs11::Session::Refresh() {
CK_SESSION_INFO session_info;
CK_RV rv = C_GetSessionInfo(session_handle_, &session_info);
if (!OkOrWarn(rv))
return false;
v8::Handle<v8::Object> self = js_object();
if (self.IsEmpty())
return false;
SET_CK_ULONG(self, session_info, slotID);
SET_CK_ULONG(self, session_info, state);
SET_CK_ULONG(self, session_info, flags);
return true;
}
v8::Handle<v8::Value> Pkcs11::Session::CallRefresh(const v8::Arguments& args) {
if (!Refresh())
return ThrowException("Unexpected error");
return v8::Undefined();
}
v8::Handle<v8::Value> Pkcs11::Session::InitPin(const v8::Arguments& args) {
if (args.Length() < 1)
return ThrowException("Missing required parameter: pin");
v8::String::AsciiValue ascii_pin(args[0]);
OkOrThrow(C_InitPIN(session_handle_,
reinterpret_cast<CK_CHAR_PTR>(*ascii_pin),
ascii_pin.length()));
return v8::Undefined();
}
v8::Handle<v8::Value> Pkcs11::Session::Close(const v8::Arguments& args) {
if (!session_handle_)
return ThrowException("Not open");
if (logged_in_) {
if (!OkOrThrow(C_Logout(session_handle_)))
return v8::Undefined();
logged_in_ = false;
}
OkOrThrow(C_CloseSession(session_handle_));
session_handle_ = 0;
return v8::Undefined();
}
v8::Handle<v8::Value> Pkcs11::Session::Login(const v8::Arguments& args) {
if (args.Length() < 1)
return ThrowException("Missing required parameter: userType");
uint32_t user_type = args[0]->Uint32Value();
if (user_type != CKU_USER && user_type != CKU_SO)
return ThrowException("Invalid value for parameter: userType");
if (args.Length() < 2)
return ThrowException("Missing required parameter: pin");
v8::String::AsciiValue ascii_pin(args[1]);
logged_in_ = false;
CK_RV rv = C_Login(session_handle_, user_type,
reinterpret_cast<CK_CHAR_PTR>(*ascii_pin),
ascii_pin.length());
if (rv == CKR_PIN_INCORRECT)
return v8::False();
if (!OkOrThrow(rv))
return v8::Undefined();
logged_in_ = true;
return v8::True();
}
v8::Handle<v8::Value> Pkcs11::Session::Logout(const v8::Arguments& args) {
OkOrThrow(C_Logout(session_handle_));
logged_in_ = false;
return v8::Undefined();
}
v8::Handle<v8::Value> Pkcs11::Session::LogoutAndClose(
const v8::Arguments& args) {
Logout(args);
Close(args);
return v8::Undefined();
}
v8::Handle<v8::Value> Pkcs11::Session::SetPin(const v8::Arguments& args) {
if (args.Length() < 1)
return ThrowException("Missing required parameter: oldPin");
v8::String::AsciiValue old_pin(args[0]);
if (args.Length() < 2)
return ThrowException("Missing required parameter: newPin");
v8::String::AsciiValue new_pin(args[1]);
OkOrThrow(C_SetPIN(session_handle_,
reinterpret_cast<CK_CHAR_PTR>(*old_pin), old_pin.length(),
reinterpret_cast<CK_CHAR_PTR>(*new_pin), new_pin.length())
);
return v8::Undefined();
}
// Returns true if specified attribute exists in the template.
bool HasAttribute(const TemplateValueStore& store,
const CK_ATTRIBUTE_TYPE value) {
if (store.bool_values.find(value) != store.bool_values.end())
return true;
if (store.ulong_values.find(value) != store.ulong_values.end())
return true;
if (store.binary_values.find(value) != store.binary_values.end())
return true;
if (store.string_values.find(value) != store.string_values.end())
return true;
return false;
}
// Retrieves a ULONG attribute from the template.
// returns true if value was found. false otherwise.
bool GetUlongAttribute(const TemplateValueStore& store,
const CK_ATTRIBUTE_TYPE name,
CK_ULONG* value) {
TemplateUlongValues::const_iterator finder = store.ulong_values.find(name);
if (finder != store.ulong_values.end()) {
*value = finder->second;
return true;
}
return false;
}
// Copy all attributes from source to destination.
void CopyAttributes(const TemplateValueStore& source,
TemplateValueStore* target) {
target->bool_values.insert(source.bool_values.begin(),
source.bool_values.end());
target->ulong_values.insert(source.ulong_values.begin(),
source.ulong_values.end());
target->binary_values.insert(source.binary_values.begin(),
source.binary_values.end());
target->string_values.insert(source.string_values.begin(),
source.string_values.end());
}
// Add a BOOL attribute to the template.
bool AddBoolAttribute(const uint32_t option_code, const CK_BBOOL value,
TemplateValueStore* store) {
if (HasAttribute(*store, option_code)) {
utils::ThrowV8Exception("Attribute specified more than once: " +
base::IntToString(option_code));
return false;
}
store->bool_values[option_code] = value;
return true;
}
// Add an ULONG attribute to the template.
bool AddUlongAttribute(const uint32_t option_code, const CK_ULONG value,
TemplateValueStore* store) {
if (HasAttribute(*store, option_code)) {
utils::ThrowV8Exception("Attribute specified more than once: " +
base::IntToString(option_code));
return false;
}
store->ulong_values[option_code] = value;
return true;
}
// Adds a BYTE* attribute to the template (from a binary buffer).
bool AddBinaryAttribute(const uint32_t option_code,
const chromeos::Blob& value,
TemplateValueStore* store) {
if (HasAttribute(*store, option_code)) {
utils::ThrowV8Exception("Attribute specified more than once: " +
base::IntToString(option_code));
return false;
}
store->binary_values[option_code] = value;
return true;
}
// Converts the argument based on its type:
// type == number -- converts to hex.
// type != number -- assume is hex.
std::string ValueToHex(const v8::Handle<v8::Value>& option_value) {
std::string value_hex;
if (option_value->IsNumber()) {
// Input is numeric. Convert to hex format.
uint32_t value = option_value->Uint32Value();
std::stringstream value_stream;
value_stream << std::hex << value;
value_hex.assign(value_stream.str());
} else {
// Input is non-numeric. Assume hex format.
v8::String::AsciiValue value_ascii(option_value);
value_hex.assign(*value_ascii);
}
if (value_hex.length() & 1)
value_hex.insert(0, "0");
return value_hex;
}
// Adds a BYTE* attribute to the template (from an HEX string).
bool AddBinaryAttribute(const uint32_t option_code,
const v8::Handle<v8::Value>& option_value,
TemplateValueStore* store) {
std::string value_hex;
value_hex = ValueToHex(option_value);
chromeos::Blob value_binary;
if (!base::HexStringToBytes(value_hex, &value_binary)) {
utils::ThrowV8Exception("Invalid binary object");
return false;
}
return AddBinaryAttribute(option_code, value_binary, store);
}
// Adds a STRING attribute to the template.
bool AddStringAttribute(const uint32_t option_code,
const v8::Handle<v8::Value>& option_value,
TemplateValueStore* store) {
if (HasAttribute(*store, option_code)) {
utils::ThrowV8Exception("Attribute specified more than once: " +
base::IntToString(option_code));
return false;
}
std::string value = utils::ValueAsUtf8String(option_value);
store->string_values[option_code] = value;
return true;
}
// Parses the template from user input parameters, converting them
// into the appropriate buffers and storing into the template store.
//
// Once all parsing is done and all attributes are added to the store,
// BuildTemplate should be called to create the PKCS#11 compatible
// input structure.
bool ParseTemplate(const std::string& template_type,
const v8::Handle<v8::Value>& args,
TemplateValueStore* store) {
if (!args->IsArray()) {
utils::ThrowV8Exception("Expected array for parameter: " + template_type);
return false;
}
v8::Local<v8::Array> options = v8::Array::Cast(*args);
for (unsigned int i = 0; i < options->Length(); i++) {
v8::Local<v8::Value> option = options->Get(i);
if (!option->IsArray()) {
utils::ThrowV8Exception("Expected array for parameter " +
template_type + " [" + base::IntToString(i) +
"]");
return false;
}
v8::Local<v8::Array> option_values = v8::Array::Cast(*option);
if (option_values->Length() != 2) {
utils::ThrowV8Exception("Incorrect input parameter " +
base::IntToString(i) +
": expected format is [name, value]");
return false;
}
// Parse [name, value] pair.
v8::Local<v8::Value> cka_name = option_values->Get(0);
v8::Local<v8::Value> cka_value = option_values->Get(1);
if (!cka_name->IsNumber()) {
utils::ThrowV8Exception("Incorrect input parameter " +
base::IntToString(i) +
": name has to be a Object.CKA* constant");
return false;
}
bool ret;
uint32_t cka_attrib = cka_name->Uint32Value();
switch (cka_attrib) {
// BOOL values.
case CKA_DECRYPT:
case CKA_ENCRYPT:
case CKA_PRIVATE:
case CKA_SENSITIVE:
case CKA_SIGN:
case CKA_TOKEN:
case CKA_UNWRAP:
case CKA_VERIFY:
case CKA_WRAP: {
CK_BBOOL value = cka_value->ToBoolean()->Value();
ret = AddBoolAttribute(cka_attrib, value, store);
break;
}
// ULONG values.
case CKA_CLASS:
case CKA_KEY_TYPE:
case CKA_CERTIFICATE_TYPE:
case CKA_MODULUS_BITS: {
CK_ULONG value = cka_value->Uint32Value();
ret = AddUlongAttribute(cka_attrib, value, store);
break;
}
// BINARY values.
case CKA_ID:
case CKA_COEFFICIENT:
case CKA_EXPONENT_1:
case CKA_EXPONENT_2:
case CKA_PRIME_1:
case CKA_PRIME_2:
case CKA_PUBLIC_EXPONENT:
case CKA_PRIVATE_EXPONENT:
case CKA_VALUE:
case CKA_MODULUS: {
ret = AddBinaryAttribute(cka_attrib, cka_value, store);
break;
}
// STRING values.
case CKA_SUBJECT:
case CKA_LABEL: {
ret = AddStringAttribute(cka_attrib, cka_value, store);
break;
}
default:
utils::ThrowV8Exception("Incorrect input parameter " +
base::IntToString(i) +
": name is invalid");
ret = false;
}
if (!ret)
return false;
}
return true;
}
// Builds a template using the skeleton defined in the TemplateValueStore.
//
// This function should be called once per pair (Store, Attribs). Best if
// all parameters are added to the store prior to calling this function,
// and call it just once.
void BuildTemplate(const TemplateValueStore& store,
TemplateAttributes* attribs) {
TemplateBoolValues::const_iterator bool_item;
for (bool_item = store.bool_values.begin();
bool_item != store.bool_values.end(); bool_item++) {
CK_ATTRIBUTE attrib = { bool_item->first,
const_cast<CK_BBOOL*>(&bool_item->second),
sizeof(bool_item->second) };
attribs->push_back(attrib);
}
TemplateUlongValues::const_iterator ulong_item;
for (ulong_item = store.ulong_values.begin();
ulong_item != store.ulong_values.end(); ulong_item++) {
CK_ATTRIBUTE attrib = { ulong_item->first,
const_cast<CK_ULONG*>(&ulong_item->second),
sizeof(ulong_item->second) };
attribs->push_back(attrib);
}
TemplateBinaryValues::const_iterator binary_item;
for (binary_item = store.binary_values.begin();
binary_item != store.binary_values.end(); binary_item++) {
CK_ATTRIBUTE attrib = { binary_item->first,
const_cast<CK_BYTE*>(&binary_item->second[0]),
binary_item->second.size() };
attribs->push_back(attrib);
}
TemplateStringValues::const_iterator string_item;
for (string_item = store.string_values.begin();
string_item != store.string_values.end(); string_item++) {
CK_ATTRIBUTE attrib = { string_item->first,
const_cast<char*>(string_item->second.c_str()),
string_item->second.length() };
attribs->push_back(attrib);
}
}
v8::Handle<v8::Value> Pkcs11::Session::FindObjects(const v8::Arguments& args) {
if (args.Length() < 1)
return ThrowException("Missing required parameter: search template");
// Template attributes.
TemplateAttributes find_template;
TemplateValueStore find_store;
// Parse template arguments.
if (!ParseTemplate("template", args[0], &find_store))
return v8::Undefined();
BuildTemplate(find_store, &find_template);
CK_RV rv = C_FindObjectsInit(session_handle_, &find_template[0],
find_template.size());
if (!OkOrThrow(rv))
return v8::Undefined();
CK_ULONG object_count;
CK_OBJECT_HANDLE object_handle;
std::vector<Object::Reference> objects_found;
while (true) {
rv = C_FindObjects(session_handle_, &object_handle, 1, &object_count);
if (!OkOrThrow(rv))
return v8::Undefined();
if (object_count == 0)
break;
Object::Reference object = Object::New();
if (object.IsEmpty() ||
!object->Initialize(session_handle_, object_handle)) {
return ThrowException("Error initializing result object");
}
objects_found.push_back(object);
}
rv = C_FindObjectsFinal(session_handle_);
if (!OkOrThrow(rv))
return v8::Undefined();
// Construct result array.
v8::Handle<v8::Array> result = v8::Array::New(objects_found.size());
for (size_t i = 0; i < objects_found.size(); ++i)
result->Set(i, objects_found[i]->js_object());
return result;
}
void AddPublicExponent(TemplateValueStore* store) {
if (!HasAttribute(*store, CKA_PUBLIC_EXPONENT)) {
chromeos::Blob public_exponent;
public_exponent.assign(kPublicExponent,
kPublicExponent + sizeof(kPublicExponent));
AddBinaryAttribute(CKA_PUBLIC_EXPONENT, public_exponent,store);
}
}
v8::Handle<v8::Value> Pkcs11::Session::CreateObject(const v8::Arguments& args) {
if (args.Length() < 1)
return ThrowException("Missing required parameter: create template");
// Template attributes.
TemplateAttributes create_template;
TemplateValueStore create_store;
// Parse template arguments.
if (!ParseTemplate("template", args[0], &create_store))
return v8::Undefined();
// Check for required parameters.
if (!HasAttribute(create_store, CKA_CLASS))
return ThrowException("Missing required parameter: Object.CKA_CLASS");
CK_OBJECT_CLASS object_class;
if (!GetUlongAttribute(create_store, CKA_CLASS, &object_class))
return ThrowException("Cannot retrieve object class");
if (object_class == CKO_PUBLIC_KEY || object_class == CKO_PRIVATE_KEY)
AddPublicExponent(&create_store);
BuildTemplate(create_store, &create_template);
CK_OBJECT_HANDLE object_handle;
CK_RV rv = C_CreateObject(session_handle_, &create_template[0],
create_template.size(), &object_handle);
if (!OkOrThrow(rv))
return v8::Undefined();
// Construct result object.
Object::Reference result = Object::New();
if (result.IsEmpty() || !result->Initialize(session_handle_, object_handle))
return ThrowException("Error initializing result object");
return result->js_object();
}
v8::Handle<v8::Value> Pkcs11::Session::GenerateKeyPair(
const v8::Arguments& args) {
if (args.Length() < 1)
return ThrowException("Missing required parameter: mechanism");
if (!args[0]->IsNumber() && !args[0]->IsNull())
return ThrowException("Invalid value for parameter: mechanism");
// Default parameters.
uint32_t mech_type = CKM_RSA_PKCS_KEY_PAIR_GEN;
// Parse mechanism arguments.
if (args[0]->IsNumber())
mech_type = args[0]->Uint32Value();
if (args.Length() < 2)
return ThrowException("Missing required parameter: public");
// Public key attributes.
TemplateValueStore public_key_store;
TemplateAttributes public_key_template;
// Parse public template arguments.
if (!ParseTemplate("public", args[1], &public_key_store))
return v8::Undefined();
if (args.Length() < 3)
return ThrowException("Missing required parameter: private");
// Private key attributes.
TemplateValueStore private_key_store;
TemplateAttributes private_key_template;
// Parse private template arguments.
if (!ParseTemplate("private", args[2], &private_key_store))
return v8::Undefined();
// Optional common attributes.
if (args.Length() >= 4) {
// Common attributes.
TemplateAttributes common_key_template;
TemplateValueStore common_key_store;
// Parse common template arguments.
if (!ParseTemplate("common", args[3], &common_key_store))
return v8::Undefined();
// Add common values to private and public templates.
CopyAttributes(common_key_store, &public_key_store);
CopyAttributes(common_key_store, &private_key_store);
}
// Add default template values.
if (!HasAttribute(public_key_store, CKA_CLASS))
AddUlongAttribute(CKA_CLASS, kPublicKeyClass, &public_key_store);
AddPublicExponent(&public_key_store);
if (!HasAttribute(public_key_store, CKA_MODULUS_BITS))
AddUlongAttribute(CKA_MODULUS_BITS, kDefaultKeySize, &public_key_store);
if (!HasAttribute(private_key_store, CKA_CLASS))
AddUlongAttribute(CKA_CLASS, kPrivateKeyClass, &private_key_store);
// Build key templates.
BuildTemplate(public_key_store, &public_key_template);
BuildTemplate(private_key_store, &private_key_template);
// Define key generation mechanism attributes.
CK_MECHANISM key_mechanism = { mech_type, NULL_PTR, 0 };
CK_OBJECT_HANDLE public_key;
CK_OBJECT_HANDLE private_key;
CK_RV rv = C_GenerateKeyPair(session_handle_, &key_mechanism,
&public_key_template[0],
public_key_template.size(),
&private_key_template[0],
private_key_template.size(),
&public_key, &private_key);
if (!OkOrThrow(rv))
return v8::Undefined();
return v8::True();
}
bool Pkcs11::Object::Initialize(const CK_SESSION_HANDLE& session_handle,
const CK_OBJECT_HANDLE& object_handle) {
session_handle_ = session_handle;
object_handle_ = object_handle;
return true;
}
// static
bool Pkcs11::Object::InitializeTemplate(
v8::Handle<v8::FunctionTemplate> ctor_t) {
// Attributes.
SET_CK_CONST(ctor_t, CKA_CLASS);
SET_CK_CONST(ctor_t, CKA_CERTIFICATE_TYPE);
SET_CK_CONST(ctor_t, CKA_COEFFICIENT);
SET_CK_CONST(ctor_t, CKA_DECRYPT);
SET_CK_CONST(ctor_t, CKA_ENCRYPT);
SET_CK_CONST(ctor_t, CKA_EXPONENT_1);
SET_CK_CONST(ctor_t, CKA_EXPONENT_2);
SET_CK_CONST(ctor_t, CKA_ID);
SET_CK_CONST(ctor_t, CKA_KEY_TYPE);
SET_CK_CONST(ctor_t, CKA_LABEL);
SET_CK_CONST(ctor_t, CKA_MODULUS);
SET_CK_CONST(ctor_t, CKA_MODULUS_BITS);
SET_CK_CONST(ctor_t, CKA_PRIME_1);
SET_CK_CONST(ctor_t, CKA_PRIME_2);
SET_CK_CONST(ctor_t, CKA_PRIVATE);
SET_CK_CONST(ctor_t, CKA_PRIVATE_EXPONENT);
SET_CK_CONST(ctor_t, CKA_PUBLIC_EXPONENT);
SET_CK_CONST(ctor_t, CKA_SENSITIVE);
SET_CK_CONST(ctor_t, CKA_SIGN);
SET_CK_CONST(ctor_t, CKA_SUBJECT);
SET_CK_CONST(ctor_t, CKA_TOKEN);
SET_CK_CONST(ctor_t, CKA_UNWRAP);
SET_CK_CONST(ctor_t, CKA_VALUE);
SET_CK_CONST(ctor_t, CKA_VERIFY);
SET_CK_CONST(ctor_t, CKA_WRAP);
// Key types.
SET_CK_CONST(ctor_t, CKK_AES);
SET_CK_CONST(ctor_t, CKK_BATON);
SET_CK_CONST(ctor_t, CKK_CAST);
SET_CK_CONST(ctor_t, CKK_CAST128);
SET_CK_CONST(ctor_t, CKK_CAST3);
SET_CK_CONST(ctor_t, CKK_CAST5);
SET_CK_CONST(ctor_t, CKK_CDMF);
SET_CK_CONST(ctor_t, CKK_DES);
SET_CK_CONST(ctor_t, CKK_DES2);
SET_CK_CONST(ctor_t, CKK_DES3);
SET_CK_CONST(ctor_t, CKK_DH);
SET_CK_CONST(ctor_t, CKK_DSA);
SET_CK_CONST(ctor_t, CKK_EC);
SET_CK_CONST(ctor_t, CKK_ECDSA);
SET_CK_CONST(ctor_t, CKK_GENERIC_SECRET);
SET_CK_CONST(ctor_t, CKK_IDEA);
SET_CK_CONST(ctor_t, CKK_JUNIPER);
SET_CK_CONST(ctor_t, CKK_KEA);
SET_CK_CONST(ctor_t, CKK_RC2);
SET_CK_CONST(ctor_t, CKK_RC4);
SET_CK_CONST(ctor_t, CKK_RC5);
SET_CK_CONST(ctor_t, CKK_RSA);
SET_CK_CONST(ctor_t, CKK_SKIPJACK);
SET_CK_CONST(ctor_t, CKK_VENDOR_DEFINED);
SET_CK_CONST(ctor_t, CKK_X9_42_DH);
// Object types.
SET_CK_CONST(ctor_t, CKO_CERTIFICATE);
SET_CK_CONST(ctor_t, CKO_DATA);
SET_CK_CONST(ctor_t, CKO_DOMAIN_PARAMETERS);
SET_CK_CONST(ctor_t, CKO_HW_FEATURE);
SET_CK_CONST(ctor_t, CKO_PRIVATE_KEY);
SET_CK_CONST(ctor_t, CKO_PUBLIC_KEY);
SET_CK_CONST(ctor_t, CKO_SECRET_KEY);
SET_CK_CONST(ctor_t, CKO_VENDOR_DEFINED);
// Certificate types.
SET_CK_CONST(ctor_t, CKC_X_509);
SET_CK_CONST(ctor_t, CKC_VENDOR_DEFINED);
v8::Handle<v8::ObjectTemplate> instance_t = ctor_t->InstanceTemplate();
BindMethod(instance_t, &Pkcs11::Object::DestroyObject, "destroy");
return true;
}
v8::Handle<v8::Value> Pkcs11::Object::DestroyObject(const v8::Arguments& args) {
CK_RV rv = C_DestroyObject(session_handle_, object_handle_);
if (!OkOrThrow(rv))
return v8::Undefined();
return v8::True();
}
v8::Handle<v8::Value> Pkcs11::Construct(const v8::Arguments& args) {
if (!OkOrThrow(InitializeLibrary()))
return v8::Undefined();
if (!Initialize())
return ThrowException("Error initializing Pkcs11 object");
return args.This();
}
// static.
CK_RV Pkcs11::InitializeLibrary() {
static CK_RV rv = CKR_CANCEL;
if (rv != CKR_OK)
rv = C_Initialize(NULL);
if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
rv = CKR_OK;
OkOrWarn(rv);
return rv;
}
bool Pkcs11::Initialize() {
if (!OkOrWarn(InitializeLibrary()))
return false;
v8::Handle<v8::Object> self = js_object();
Pkcs11::Slots::Reference slots = Pkcs11::Slots::New();
slots->Initialize();
self->Set(v8::String::New("slots"), slots->js_object());
return true;
}
// static.
bool Pkcs11::InitializeTemplate(v8::Handle<v8::FunctionTemplate> ctor_t) {
ctor_t->Set(v8::String::NewSymbol("Slots"),
Pkcs11::Slots::constructor_template());
ctor_t->Set(v8::String::NewSymbol("Slot"),
Pkcs11::Slot::constructor_template());
ctor_t->Set(v8::String::NewSymbol("Token"),
Pkcs11::Token::constructor_template());
ctor_t->Set(v8::String::NewSymbol("Session"),
Pkcs11::Session::constructor_template());
ctor_t->Set(v8::String::NewSymbol("Object"),
Pkcs11::Object::constructor_template());
// These are in the order they appear in opencryptoki/pkcs11types.h.
SET_CK_CONST(ctor_t, CKR_OK);
SET_CK_CONST(ctor_t, CKR_CANCEL);
SET_CK_CONST(ctor_t, CKR_HOST_MEMORY);
SET_CK_CONST(ctor_t, CKR_SLOT_ID_INVALID);
SET_CK_CONST(ctor_t, CKR_GENERAL_ERROR);
SET_CK_CONST(ctor_t, CKR_FUNCTION_FAILED);
SET_CK_CONST(ctor_t, CKR_ARGUMENTS_BAD);
SET_CK_CONST(ctor_t, CKR_NO_EVENT);
SET_CK_CONST(ctor_t, CKR_NEED_TO_CREATE_THREADS);
SET_CK_CONST(ctor_t, CKR_CANT_LOCK);
SET_CK_CONST(ctor_t, CKR_ATTRIBUTE_READ_ONLY);
SET_CK_CONST(ctor_t, CKR_ATTRIBUTE_SENSITIVE);
SET_CK_CONST(ctor_t, CKR_ATTRIBUTE_TYPE_INVALID);
SET_CK_CONST(ctor_t, CKR_ATTRIBUTE_VALUE_INVALID);
SET_CK_CONST(ctor_t, CKR_DATA_INVALID);
SET_CK_CONST(ctor_t, CKR_DATA_LEN_RANGE);
SET_CK_CONST(ctor_t, CKR_DEVICE_ERROR);
SET_CK_CONST(ctor_t, CKR_DEVICE_MEMORY);
SET_CK_CONST(ctor_t, CKR_DEVICE_REMOVED);
SET_CK_CONST(ctor_t, CKR_ENCRYPTED_DATA_INVALID);
SET_CK_CONST(ctor_t, CKR_ENCRYPTED_DATA_LEN_RANGE);
SET_CK_CONST(ctor_t, CKR_FUNCTION_CANCELED);
SET_CK_CONST(ctor_t, CKR_FUNCTION_NOT_PARALLEL);
SET_CK_CONST(ctor_t, CKR_FUNCTION_NOT_SUPPORTED);
SET_CK_CONST(ctor_t, CKR_KEY_HANDLE_INVALID);
SET_CK_CONST(ctor_t, CKR_KEY_SIZE_RANGE);
SET_CK_CONST(ctor_t, CKR_KEY_TYPE_INCONSISTENT);
SET_CK_CONST(ctor_t, CKR_KEY_NOT_NEEDED);
SET_CK_CONST(ctor_t, CKR_KEY_CHANGED);
SET_CK_CONST(ctor_t, CKR_KEY_NEEDED);
SET_CK_CONST(ctor_t, CKR_KEY_INDIGESTIBLE);
SET_CK_CONST(ctor_t, CKR_KEY_FUNCTION_NOT_PERMITTED);
SET_CK_CONST(ctor_t, CKR_KEY_NOT_WRAPPABLE);
SET_CK_CONST(ctor_t, CKR_KEY_UNEXTRACTABLE);
SET_CK_CONST(ctor_t, CKR_MECHANISM_INVALID);
SET_CK_CONST(ctor_t, CKR_MECHANISM_PARAM_INVALID);
SET_CK_CONST(ctor_t, CKR_OBJECT_HANDLE_INVALID);
SET_CK_CONST(ctor_t, CKR_OPERATION_ACTIVE);
SET_CK_CONST(ctor_t, CKR_OPERATION_NOT_INITIALIZED);
SET_CK_CONST(ctor_t, CKR_PIN_INCORRECT);
SET_CK_CONST(ctor_t, CKR_PIN_INVALID);
SET_CK_CONST(ctor_t, CKR_PIN_LEN_RANGE);
SET_CK_CONST(ctor_t, CKR_PIN_EXPIRED);
SET_CK_CONST(ctor_t, CKR_PIN_LOCKED);
SET_CK_CONST(ctor_t, CKR_SESSION_CLOSED);
SET_CK_CONST(ctor_t, CKR_SESSION_COUNT);
SET_CK_CONST(ctor_t, CKR_SESSION_HANDLE_INVALID);
SET_CK_CONST(ctor_t, CKR_SESSION_PARALLEL_NOT_SUPPORTED);
SET_CK_CONST(ctor_t, CKR_SESSION_READ_ONLY);
SET_CK_CONST(ctor_t, CKR_SESSION_EXISTS);
SET_CK_CONST(ctor_t, CKR_SESSION_READ_ONLY_EXISTS);
SET_CK_CONST(ctor_t, CKR_SESSION_READ_WRITE_SO_EXISTS);
SET_CK_CONST(ctor_t, CKR_SIGNATURE_INVALID);
SET_CK_CONST(ctor_t, CKR_SIGNATURE_LEN_RANGE);
SET_CK_CONST(ctor_t, CKR_TEMPLATE_INCOMPLETE);
SET_CK_CONST(ctor_t, CKR_TEMPLATE_INCONSISTENT);
SET_CK_CONST(ctor_t, CKR_TOKEN_NOT_PRESENT);
SET_CK_CONST(ctor_t, CKR_TOKEN_NOT_RECOGNIZED);
SET_CK_CONST(ctor_t, CKR_TOKEN_WRITE_PROTECTED);
SET_CK_CONST(ctor_t, CKR_UNWRAPPING_KEY_HANDLE_INVALID);
SET_CK_CONST(ctor_t, CKR_UNWRAPPING_KEY_SIZE_RANGE);
SET_CK_CONST(ctor_t, CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT);
SET_CK_CONST(ctor_t, CKR_USER_ALREADY_LOGGED_IN);
SET_CK_CONST(ctor_t, CKR_USER_NOT_LOGGED_IN);
SET_CK_CONST(ctor_t, CKR_USER_PIN_NOT_INITIALIZED);
SET_CK_CONST(ctor_t, CKR_USER_TYPE_INVALID);
SET_CK_CONST(ctor_t, CKR_USER_ANOTHER_ALREADY_LOGGED_IN);
SET_CK_CONST(ctor_t, CKR_USER_TOO_MANY_TYPES);
SET_CK_CONST(ctor_t, CKR_WRAPPED_KEY_INVALID);
SET_CK_CONST(ctor_t, CKR_WRAPPED_KEY_LEN_RANGE);
SET_CK_CONST(ctor_t, CKR_WRAPPING_KEY_HANDLE_INVALID);
SET_CK_CONST(ctor_t, CKR_WRAPPING_KEY_SIZE_RANGE);
SET_CK_CONST(ctor_t, CKR_WRAPPING_KEY_TYPE_INCONSISTENT);
SET_CK_CONST(ctor_t, CKR_RANDOM_SEED_NOT_SUPPORTED);
SET_CK_CONST(ctor_t, CKR_RANDOM_NO_RNG);
SET_CK_CONST(ctor_t, CKR_DOMAIN_PARAMS_INVALID);
SET_CK_CONST(ctor_t, CKR_BUFFER_TOO_SMALL);
SET_CK_CONST(ctor_t, CKR_SAVED_STATE_INVALID);
SET_CK_CONST(ctor_t, CKR_INFORMATION_SENSITIVE);
SET_CK_CONST(ctor_t, CKR_STATE_UNSAVEABLE);
SET_CK_CONST(ctor_t, CKR_CRYPTOKI_NOT_INITIALIZED);
SET_CK_CONST(ctor_t, CKR_CRYPTOKI_ALREADY_INITIALIZED);
SET_CK_CONST(ctor_t, CKR_MUTEX_BAD);
SET_CK_CONST(ctor_t, CKR_MUTEX_NOT_LOCKED);
SET_CK_CONST(ctor_t, CKR_VENDOR_DEFINED);
return true;
}
} // namespace crypto
} // namespace entd