Crypt-HSM

 view release on metacpan or  search on metacpan

lib/Crypt/HSM.xs  view on Meta::CPAN

	av_push(get_av("Crypt::HSM::Encrypt::ISA", GV_ADD), SvREFCNT_inc(stream));
	av_push(get_av("Crypt::HSM::Decrypt::ISA", GV_ADD), SvREFCNT_inc(stream));
	av_push(get_av("Crypt::HSM::Digest::ISA" , GV_ADD), SvREFCNT_inc(stream));
	av_push(get_av("Crypt::HSM::Sign::ISA"   , GV_ADD), SvREFCNT_inc(stream));
	av_push(get_av("Crypt::HSM::Verify::ISA" , GV_ADD), SvREFCNT_inc(stream));
	SvREFCNT_dec(stream);


Crypt::HSM::Provider load(class, const char* path)
CODE:
	void* handle;
	CK_FUNCTION_LIST* funcs;

	handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
	if (!handle)
		croak("Can not open library: %s", dlerror());

	CK_C_GetFunctionList C_GetFunctionList = (CK_C_GetFunctionList) dlsym(handle, "C_GetFunctionList");
	if (C_GetFunctionList == NULL)
		croak("Symbol lookup failed");

	CK_RV rc = C_GetFunctionList(&funcs);
	if (rc != CKR_OK)
		croak_with("Call to C_GetFunctionList failed", rc);
#if defined(USE_THREADS) || defined(__linux__)
	CK_C_INITIALIZE_ARGS init_args = { NULL, NULL, NULL, NULL, CKF_OS_LOCKING_OK, NULL };
#else
	CK_C_INITIALIZE_ARGS init_args = { NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS, NULL };
#endif
	rc = funcs->C_Initialize(&init_args);
	if (rc != CKR_OK)
		croak_with("Call to C_Initialize failed", rc);

	RETVAL = (struct Provider*) PerlMemShared_calloc(1, sizeof(struct Provider));
	refcount_init(&RETVAL->refcount, 1);
	RETVAL->handle = handle;
	RETVAL->funcs = funcs;
OUTPUT: RETVAL


MODULE = Crypt::HSM	 PACKAGE = Crypt::HSM::Provider


HV* info(Crypt::HSM::Provider self)
CODE:
	CK_INFO info;
	CK_RV result = self->funcs->C_GetInfo(&info);
	if (result != CKR_OK)
		croak_with("Couldn't get provider info", result);

	RETVAL = newHV();
	hv_stores(RETVAL, "cryptoki-version", version_to_sv(&info.cryptokiVersion));
	hv_stores(RETVAL, "manufacturer-id", trimmed_value(info.manufacturerID, 32));
	hv_stores(RETVAL, "flags", newRV_noinc((SV*)newHV()));
	hv_stores(RETVAL, "library-description", trimmed_value(info.libraryDescription, 32));
	hv_stores(RETVAL, "library-version", version_to_sv(&info.libraryVersion));
OUTPUT: RETVAL


void slots(Crypt::HSM::Provider self, CK_BBOOL tokenPresent = 1)
PPCODE:
	CK_ULONG count, i;

	CK_RV result = self->funcs->C_GetSlotList(tokenPresent, NULL, &count);
	if ( result != CKR_OK )
		croak_with("Couldn't get slots", result);

	EXTEND(SP, (int)count);

	CK_SLOT_ID_PTR slotList = safecalloc(count, sizeof(CK_SLOT_ID));
	SAVEFREEPV(slotList);

	result = self->funcs->C_GetSlotList(tokenPresent, slotList, &count);
	if (result != CKR_OK)
		croak_with("Couldn't get slots", result);

	for(i = 0; i < count; i++)
		mPUSHs(new_slot(self, slotList[i]));


SV* slot(Crypt::HSM::Provider self, CK_SLOT_ID slot)
CODE:
	RETVAL = new_slot(self, slot);
OUTPUT: RETVAL

SV* wait_for_event(Crypt::HSM::Provider self, ...)
CODE:
	CK_ULONG flags = 0;
	int i;
	for (i = 1; i < items; ++i)
		flags |= get_flags(wait_flags, ST(i));

	CK_SLOT_ID slot;
	CK_RV result = self->funcs->C_WaitForSlotEvent(flags, &slot, NULL);

	if (result == CKR_OK)
		RETVAL = new_slot(self, slot);
	else if (result == CKR_NO_EVENT)
		RETVAL = &PL_sv_undef;
	else
		croak_with("Couldn't wait for slot event", result);
OUTPUT: RETVAL


MODULE = Crypt::HSM	 PACKAGE = Crypt::HSM::Slot


CK_SLOT_ID id(Crypt::HSM::Slot self)
CODE:
	RETVAL = self->slot;
OUTPUT: RETVAL

HV* info(Crypt::HSM::Slot self)
CODE:
	CK_SLOT_INFO info;
	CK_RV result = slot_funcs(self)->C_GetSlotInfo(self->slot, &info);
	if (result != CKR_OK)
		croak_with("Couldn't get slot info", result);

	RETVAL = newHV();
	hv_stores(RETVAL, "description", trimmed_value(info.slotDescription, 64));
	hv_stores(RETVAL, "manufacturer-id", trimmed_value(info.manufacturerID, 32));
	hv_stores(RETVAL, "flags", reverse_flags(slot_flags, info.flags));
	hv_stores(RETVAL, "hardware-version", version_to_sv(&info.hardwareVersion));
	hv_stores(RETVAL, "firmware-version", version_to_sv(&info.firmwareVersion));
OUTPUT: RETVAL

HV* token_info(Crypt::HSM::Slot self)
CODE:
	CK_TOKEN_INFO info;
	CK_RV result = slot_funcs(self)->C_GetTokenInfo(self->slot, &info);
	if (result != CKR_OK)
		croak_with("Couldn't get token info", result);

	RETVAL = newHV();
	hv_stores(RETVAL, "label", trimmed_value(info.label, 32));
	hv_stores(RETVAL, "manufacturer-id", trimmed_value(info.manufacturerID, 32));
	hv_stores(RETVAL, "model", trimmed_value(info.model, 16));
	hv_stores(RETVAL, "serial-number", trimmed_value(info.serialNumber, 16));
	hv_stores(RETVAL, "flags", reverse_flags(token_flags, info.flags));
	hv_stores(RETVAL, "max-session-count", newSVuv(info.ulMaxSessionCount));
	hv_stores(RETVAL, "session-count", newSVuv(info.ulSessionCount));
	hv_stores(RETVAL, "max-rw-session-count", newSVuv(info.ulMaxRwSessionCount));
	hv_stores(RETVAL, "rw-session-count", newSVuv(info.ulRwSessionCount));
	hv_stores(RETVAL, "max-pin-len", newSVuv(info.ulMaxPinLen));
	hv_stores(RETVAL, "min-pin-len", newSVuv(info.ulMinPinLen));
	hv_stores(RETVAL, "total-public-memory", newSVuv(info.ulTotalPublicMemory));
	hv_stores(RETVAL, "free-public-memory", newSVuv(info.ulFreePublicMemory));
	hv_stores(RETVAL, "total-private-memory", newSVuv(info.ulTotalPrivateMemory));
	hv_stores(RETVAL, "free-private-memory", newSVuv(info.ulFreePrivateMemory));
	hv_stores(RETVAL, "hardware-version", version_to_sv(&info.hardwareVersion));
	hv_stores(RETVAL, "firmware-version", version_to_sv(&info.firmwareVersion));
	hv_stores(RETVAL, "utc-time", trimmed_value(info.utcTime, 16));
OUTPUT: RETVAL

Crypt::HSM::Session open_session(Crypt::HSM::Slot self, ...)
CODE:
	CK_NOTIFY Notify = NULL;
	CK_SESSION_HANDLE handle;

	CK_ULONG flags = CKF_SERIAL_SESSION;
	ssize_t current = 1;
	for (current = 1; current + 2 <= items; current += 2) {
		CK_ULONG internal = map_get(session_flags, ST(current), "session flag");
		if (SvTRUE(ST(current + 1)))
			flags |= internal;
		else
			flags &= ~internal;
	}

	CK_RV result = slot_funcs(self)->C_OpenSession(self->slot, flags | CKF_SERIAL_SESSION, NULL, Notify, &handle);
	if (result != CKR_OK)
		croak_with("Could not open session", result);

	RETVAL = PerlMemShared_calloc(1, sizeof(struct Session));
	refcount_init(&RETVAL->refcount, 1);
	RETVAL->slot = slot_refcount_increment(self);
	RETVAL->handle = handle;
OUTPUT: RETVAL

void mechanisms(Crypt::HSM::Slot self)
PPCODE:
	CK_ULONG length, i;
	CK_RV result = slot_funcs(self)->C_GetMechanismList(self->slot, NULL, &length);
	if (result != CKR_OK)
		croak_with("Couldn't get mechanisms length", result);

	CK_MECHANISM_TYPE* types = safecalloc(length, sizeof(CK_MECHANISM_TYPE));
	SAVEFREEPV(types);
	result = slot_funcs(self)->C_GetMechanismList(self->slot, types, &length);
	if (result != CKR_OK)
		croak_with("Couldn't get mechanisms", result);

	for (i = 0; i < length; ++i)
		mXPUSHs(new_mechanism(self, types[i]));

SV* mechanism(Crypt::HSM::Slot self, CK_MECHANISM_TYPE type)
CODE:
	RETVAL = new_mechanism(self, type);
OUTPUT: RETVAL

void close_all_sessions(Crypt::HSM::Slot self)
CODE:
	CK_RV result = slot_funcs(self)->C_CloseAllSessions(self->slot);
	if (result != CKR_OK)
		croak_with("Could not open session", result);


void init_token(Crypt::HSM::Slot self, SV* pin, SV* label)
CODE:
	CK_BYTE label_buffer[32];
	CK_ULONG pin_len, label_len;
	CK_UTF8CHAR* pinPV = get_text(pin, &pin_len);
	CK_UTF8CHAR* labelPV = get_text(label, &label_len);
	memset(label_buffer, ' ', 32);
	memcpy(label_buffer, labelPV, MIN(label_len, 32));

	CK_RV result = slot_funcs(self)->C_InitToken(self->slot, pinPV, pin_len, label_buffer);
	if (result != CKR_OK)
		croak_with("Could not initialize token", result);


MODULE = Crypt::HSM  PACKAGE = Crypt::HSM::Mechanism


SV* name(Crypt::HSM::Mechanism self)
CODE:
	const entry* item = map_reverse_find(mechanisms, self->mechanism);
	RETVAL = item ? newSVpvn(item->key, item->length) : newSV(0);
OUTPUT: RETVAL


Crypt::HSM::Mechanism::Info info(Crypt::HSM::Mechanism self)
CODE:
	RETVAL = safemalloc(sizeof(CK_MECHANISM_INFO));
	CK_RV result = slot_funcs(self->slot)->C_GetMechanismInfo(self->slot->slot, self->mechanism, RETVAL);
	if (result != CKR_OK) {
		Safefree(RETVAL);
		croak_with("Couldn't get mechanism info", result);
	}
OUTPUT: RETVAL


MODULE = Crypt::HSM  PACKAGE = Crypt::HSM::Mechanism::Info


HV* hash(Crypt::HSM::Mechanism::Info self)
CODE:
	RETVAL = newHV();
	hv_stores(RETVAL, "min-key-size", newSVuv(self->ulMinKeySize));
	hv_stores(RETVAL, "max-key-size", newSVuv(self->ulMaxKeySize));
	hv_stores(RETVAL, "flags", reverse_flags(mechanism_flags, self->flags));
OUTPUT: RETVAL


bool has_flags(Crypt::HSM::Mechanism::Info self, ...)
CODE:
	CK_ULONG flags = 0;
	int i;
	for (i = 1; i < items; ++i)
		flags |= get_flags(mechanism_flags, ST(i));
	RETVAL = (self->flags & flags) == flags;
OUTPUT: RETVAL


void flags(Crypt::HSM::Mechanism::Info self)
PPCODE:
	CK_ULONG i;
	for (i = 0; i < CHAR_BIT * sizeof(CK_ULONG); ++i) {
		CK_ULONG right = 1ul << i;
		if (self->flags & right)
			mXPUSHs(entry_to_sv(map_reverse_find(mechanism_flags, right)));
	}


CK_ULONG min_key_size(Crypt::HSM::Mechanism::Info self)
CODE:
	RETVAL = self->ulMinKeySize;
OUTPUT: RETVAL


CK_ULONG max_key_size(Crypt::HSM::Mechanism::Info self)
CODE:
	RETVAL = self->ulMaxKeySize;
OUTPUT: RETVAL


MODULE = Crypt::HSM  PACKAGE = Crypt::HSM::Session PREFIX = session_


HV* info(Crypt::HSM::Session self)
CODE:
	CK_SESSION_INFO info;
	CK_RV result = session_funcs(self)->C_GetSessionInfo(self->handle, &info);
	if (result != CKR_OK)
		croak_with("Couldn't get session info", result);

	RETVAL = newHV();
	hv_stores(RETVAL, "slot-id", newSVuv(info.slotID));
	hv_stores(RETVAL, "state", entry_to_sv(map_reverse_find(state_flags, info.state)));
	hv_stores(RETVAL, "flags", reverse_flags(session_flags, info.flags));
	hv_stores(RETVAL, "device-error", newSVuv(info.ulDeviceError));
OUTPUT: RETVAL


Crypt::HSM::Provider provider(Crypt::HSM::Session self)
CODE:
	RETVAL = provider_refcount_increment(self->slot->provider);
OUTPUT: RETVAL


Crypt::HSM::Slot slot(Crypt::HSM::Session self)
CODE:
	RETVAL = slot_refcount_increment(self->slot);
OUTPUT: RETVAL


void login(Crypt::HSM::Session self, CK_USER_TYPE type, SV* pin)
CODE:
	CK_ULONG pin_len = 0;
	CK_UTF8CHAR* pinPV = NULL;
	if (SvOK(pin))
		pinPV = get_text(pin, &pin_len);
	CK_RV result = session_funcs(self)->C_Login(self->handle, type, pinPV, pin_len);
	if (result != CKR_OK)
		croak_with("Could not log in", result);


void logout(Crypt::HSM::Session self)
CODE:
	CK_RV result = session_funcs(self)->C_Logout(self->handle);
	if (result != CKR_OK)
		croak_with("Could not log out", result);


void init_pin(Crypt::HSM::Session self, SV* pin)
CODE:
	CK_ULONG pin_len = 0;
	CK_UTF8CHAR* pinPV = NULL;
	if (SvOK(pin))
		pinPV = get_text(pin, &pin_len);

	CK_RV result = session_funcs(self)->C_InitPIN(self->handle, pinPV, pin_len);
	if (result != CKR_OK)
		croak_with("Could not initialize pin", result);


void set_pin(Crypt::HSM::Session self, SV* old_pin, SV* new_pin)
CODE:
	CK_ULONG old_pin_len = 0, new_pin_len = 0;
	CK_UTF8CHAR* old_pinPV = NULL, *new_pinPV = NULL;
	if (SvOK(old_pin))
		old_pinPV = get_text(old_pin, &old_pin_len);
	if (SvOK(new_pin))
		new_pinPV = get_text(new_pin, &new_pin_len);

	CK_RV result = session_funcs(self)->C_SetPIN(self->handle, old_pinPV, old_pin_len, new_pinPV, new_pin_len);
	if (result != CKR_OK)
		croak_with("Could not set pin", result);


SV* create_object(Crypt::HSM::Session self, Attributes template)
CODE:
	CK_OBJECT_HANDLE handle;
	CK_RV result = session_funcs(self)->C_CreateObject(self->handle, template.member, template.length, &handle);
	if (result != CKR_OK)
		croak_with("Could not create object", result);

	RETVAL = new_object(self, handle);
OUTPUT: RETVAL


void find_objects(Crypt::HSM::Session self, Attributes attributes = empty)
PPCODE:
	CK_RV result = session_funcs(self)->C_FindObjectsInit(self->handle, attributes.member, attributes.length);
	if (result != CKR_OK)
		croak_with("Could not find objects", result);

	CK_ULONG actual = 0;
	do {
		CK_OBJECT_HANDLE current[16];
		CK_ULONG iter;
		CK_RV result = session_funcs(self)->C_FindObjects(self->handle, current, sizeof(current) / sizeof(*current), &actual);
		if (result != CKR_OK) {
			session_funcs(self)->C_FindObjectsFinal(self->handle);
			croak_with("Could not find objects", result);
		}
		for (iter = 0; iter < actual; ++iter)
			mXPUSHs(new_object(self, current[iter]));
	} while (actual > 0);
	session_funcs(self)->C_FindObjectsFinal(self->handle);


void generate_keypair(Crypt::HSM::Session self, CK_MECHANISM_TYPE mechanism_type, Attributes publicKeyTemplate, Attributes privateKeyTemplate, ...)
PPCODE:
	CK_OBJECT_HANDLE publicKey;
	CK_OBJECT_HANDLE privateKey;

	CK_MECHANISM mechanism = mechanism_from_args(mechanism_type, 4);
	CK_RV result = session_funcs(self)->C_GenerateKeyPair(self->handle, &mechanism, publicKeyTemplate.member, publicKeyTemplate.length, privateKeyTemplate.member, privateKeyTemplate.length, &publicKey, &privateKey);
	if (result != CKR_OK)
		croak_with("Could not create keypair", result);

	mXPUSHs(new_object(self, publicKey));
	mXPUSHs(new_object(self, privateKey));


SV* generate_key(Crypt::HSM::Session self, CK_MECHANISM_TYPE mechanism_type, Attributes keyTemplate = empty, ...)
CODE:
	CK_MECHANISM mechanism = mechanism_from_args(mechanism_type, 3);
	CK_OBJECT_HANDLE handle;
	CK_RV result = session_funcs(self)->C_GenerateKey(self->handle, &mechanism, keyTemplate.member, keyTemplate.length, &handle);
	if (result != CKR_OK)
		croak_with("Could not create key", result);
	RETVAL = new_object(self, handle);
OUTPUT: RETVAL


SV* encrypt(Crypt::HSM::Session self, CK_MECHANISM_TYPE mechanism_type, Crypt::HSM::Object key, SV* data, ...)
CODE:
	CK_MECHANISM mechanism = mechanism_from_args(mechanism_type, 4);
	CK_RV result = session_funcs(self)->C_EncryptInit(self->handle, &mechanism, key->handle);
	if (result != CKR_OK)
		croak_with("Couldn't initialize encryption", result);

	CK_ULONG dataLen, encryptedDataLen;
	CK_BYTE* dataPV = get_buffer(data, &dataLen);
	result = session_funcs(self)->C_Encrypt(self->handle, dataPV, dataLen, NULL, &encryptedDataLen);
	if (result != CKR_OK)
		croak_with("Couldn't compute encrypted length", result);

	RETVAL = newSV(encryptedDataLen);
	SvPOK_only(RETVAL);
	result = session_funcs(self)->C_Encrypt(self->handle, dataPV, dataLen, (CK_BYTE*)SvPVbyte_nolen(RETVAL), &encryptedDataLen);
	if (result != CKR_OK) {
		SvREFCNT_dec(RETVAL);
		croak_with("Couldn't encrypt", result);
	}
	SvCUR(RETVAL) = encryptedDataLen;
OUTPUT: RETVAL


Crypt::HSM::Encrypt open_encrypt(Crypt::HSM::Session self, CK_MECHANISM_TYPE mechanism_type, Crypt::HSM::Object key, ...)
CODE:
	CK_MECHANISM mechanism = mechanism_from_args(mechanism_type, 3);
	CK_RV result = session_funcs(self)->C_EncryptInit(self->handle, &mechanism, key->handle);
	if (result != CKR_OK)
		croak_with("Couldn't initialize encryption", result);

	RETVAL = open_stream(self, key->handle, CK_INVALID_HANDLE);
OUTPUT: RETVAL


SV* decrypt(Crypt::HSM::Session self, CK_MECHANISM_TYPE mechanism_type, Crypt::HSM::Object key, SV* data, ...)
CODE:



( run in 1.176 second using v1.01-cache-2.11-cpan-71847e10f99 )