From: Wolfgang Bumiller Date: Tue, 2 Apr 2019 10:22:10 +0000 (+0200) Subject: initial release X-Git-Url: https://git.proxmox.com/?p=libpve-u2f-server-perl.git;a=commitdiff_plain;h=b8adb2d581a2f5b4eb8cd17d93121ae1e27eab61 initial release Signed-off-by: Wolfgang Bumiller --- b8adb2d581a2f5b4eb8cd17d93121ae1e27eab61 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9ef3233 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +build +ppport.h +U2F.so +U2F.xsc +*.deb +*.1.pod +*.1.gz diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0d9b3a5 --- /dev/null +++ b/Makefile @@ -0,0 +1,81 @@ +include /usr/share/dpkg/pkg-info.mk +include /usr/share/dpkg/architecture.mk + +PACKAGE=libpve-u2f-server-perl + +BUILDSRC := $(PACKAGE)-$(DEB_VERSION_UPSTREAM_REVISION) + +DESTDIR= +PREFIX=/usr +LIBDIR=$(PREFIX)/lib +DOCDIR=$(PREFIX)/share/doc/$(PACKAGE) +PERLDIR=$(PREFIX)/share/perl5 + +PERL_ARCHLIB != perl -MConfig -e 'print $$Config{archlib};' +PERL_INSTALLVENDORARCH != perl -MConfig -e 'print $$Config{installvendorarch};' +PERL_APIVER != perl -MConfig -e 'print $$Config{debian_abi}//$$Config{version};' +PERL_CC != perl -MConfig -e 'print $$Config{cc};' +PERLSODIR=$(PERL_INSTALLVENDORARCH)/auto +CFLAGS := -shared -fPIC -O2 -Werror -Wtype-limits -Wall -Wl,-z,relro \ + -D_FORTIFY_SOURCE=2 -I$(PERL_ARCHLIB)/CORE -DXS_VERSION=\"1.0\" + +CFLAGS += `pkg-config --cflags u2f-server` +LIBS += `pkg-config --libs u2f-server` + +DEB=$(PACKAGE)_$(DEB_VERSION_UPSTREAM_REVISION)_$(DEB_BUILD_ARCH).deb +DSC=$(PACKAGE)_$(DEB_VERSION_UPSTREAM_REVISION).dsc + +GITVERSION:=$(shell git rev-parse HEAD) + +all: + +ppport.h: + perl -MDevel::PPPort -e 'Devel::PPPort::WriteFile();' + +U2F.c: U2F.xs + xsubpp U2F.xs > U2F.xsc + mv U2F.xsc U2F.c + +U2F.so: U2F.c ppport.h + $(PERL_CC) $(CFLAGS) -o U2F.so U2F.c $(LIBS) + +.PHONY: dinstall +dinstall: deb + dpkg -i $(DEB) + +.PHONY: install +install: PVE/U2F.pm U2F.so + install -D -m 0644 PVE/U2F.pm $(DESTDIR)$(PERLDIR)/PVE/U2F.pm + install -D -m 0644 -s U2F.so $(DESTDIR)$(PERLSODIR)/PVE/U2F/U2F.so + +.PHONY: $(BUILDSRC) +$(BUILDSRC): + rm -rf $(BUILDSRC) + mkdir $(BUILDSRC) + rsync -a debian Makefile PVE U2F.xs $(BUILDSRC)/ + echo "git clone git://git.proxmox.com/git/libpve-u2f-server-perl.git\\ngit checkout $(GITVERSION)" > $(BUILDSRC)/debian/SOURCE + +.PHONY: deb +deb: $(DEB) +$(DEB): $(BUILDSRC) + cd $(BUILDSRC); dpkg-buildpackage -b -us -uc + lintian $(DEB) + +.PHONY: dsc +dsc: $(DSC) +$(DSC): $(BUILDSRC) + cd $(BUILDSRC); dpkg-buildpackage -S -us -uc -d -nc + lintian $(DSC) + +.PHONY: clean +clean: + rm -rf *~ build *.deb *.changes *.buildinfo *.dsc *.tar.gz + find . -name '*~' -exec rm {} ';' + +.PHONY: distclean +distclean: clean + + +.PHONY: upload +upload: $$DEB) + tar cf - $(DEB) | ssh repoman@repo.proxmox.com -- upload --product pve --dist stretch --arch $(ARCH) diff --git a/PVE/U2F.pm b/PVE/U2F.pm new file mode 100644 index 0000000..acc9348 --- /dev/null +++ b/PVE/U2F.pm @@ -0,0 +1,155 @@ +package PVE::U2F; + +use 5.024000; +use strict; +use warnings; + +require Exporter; + +our @ISA = qw(Exporter); + +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. + +# This allows declaration use PVE::U2F::XS ':all'; +# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK +# will save memory. +our %EXPORT_TAGS = ( 'all' => [] ); + +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); +our @EXPORT = (); +our $VERSION = '1.0'; + +require XSLoader; +XSLoader::load('PVE::U2F', $VERSION); + +#### Context creation + +my $global_init = 0; +sub new($) { + my ($class) = @_; + if (!$global_init) { + $global_init = 1; + do_global_init(); + } + if (my $lib = new_impl()) { + return bless { ctx => $lib }, $class; + } + return undef; +} + +sub DESTROY { + my ($self) = @_; + done_impl($self->{ctx}); +} + +#### Error handling + +my @errcodes = ( +qw(memory json base64 crypto origin challenge signature format) +); +sub checkrc($) { + my ($rc) = @_; + return if $rc == 0; + die "u2fs: $errcodes[-$rc-1] error\n" if $rc < 0 && $rc >= -8; + die "u2fs: unknown error\n"; +} + +#### Context initialization + +sub origin($) { return $_[0]->{origin}; } +sub set_origin($$) { + my ($self, $origin) = @_; + checkrc(set_origin_impl($self->{ctx}, $origin)); + return $self->{origin} = $origin; +} + +sub appid($) { return $_[0]->{appid}; } +sub set_appid($$) { + my ($self, $appid) = @_; + checkrc(set_appid_impl($self->{ctx}, $appid)); + return $self->{appid} = $appid; +} + +sub challenge($) { return $_[0]->{challenge}; } +sub set_challenge($$) { + my ($self, $challenge) = @_; + checkrc(set_challenge_impl($self->{ctx}, $challenge)); + return $self->{challenge} = $challenge; +} + +sub keyHandle($) { return $_[0]->{keyHandle}; } +sub set_keyHandle($$) { + my ($self, $keyHandle) = @_; + checkrc(set_keyHandle_impl($self->{ctx}, $keyHandle)); + return $self->{keyHandle} = $keyHandle; +} + +sub publicKey($) { return $_[0]->{publicKey}; } +sub set_publicKey($$) { + my ($self, $publicKey) = @_; + checkrc(set_publicKey_impl($self->{ctx}, $publicKey)); + return $self->{publicKey} = $publicKey; +} + +#### Registration + +sub registration_challenge($) { + my ($self) = @_; + checkrc(registration_challenge_impl($self->{ctx}, my $challenge)); + return $challenge; +} + +sub registration_verify($$) { + my ($self, $response) = @_; + checkrc(registration_verify_impl($self->{ctx}, $response, my $kh, my $pk)); + return ($kh, $pk); +} + +#### Authentication + +sub auth_challenge($) { + my ($self) = @_; + checkrc(auth_challenge_impl($self->{ctx}, my $challenge)); + return $challenge; +} + +sub auth_verify($$) { + my ($self, $response) = @_; + checkrc(auth_verify_impl($self->{ctx}, $response, + my $verified, + my $counter, + my $presence)); + checkrc($verified); + return wantarray ? ($counter, $presence) : 1; +} + +1; +__END__ + +=head1 NAME + +PVE::U2F - Perl bindings for libu2f-server + +=head1 SYNOPSIS + + use PVE::U2F; + +=head1 DESCRIPTION + +Perl bindings for libu2f-server + +=head2 EXPORT + +None by default. + +=head1 SEE ALSO + +TODO + +=head1 AUTHOR + +Proxmox Server Solutions GmbH + +=cut diff --git a/U2F.xs b/U2F.xs new file mode 100644 index 0000000..2e167d2 --- /dev/null +++ b/U2F.xs @@ -0,0 +1,179 @@ +#define PERL_NO_GET_CONTEXT +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#include "ppport.h" + +#include + +MODULE = PVE::U2F PACKAGE = PVE::U2F + +#// Context creation and destruction + +void +do_global_init() + CODE: + u2fs_global_init(0); + +void +do_global_done() + CODE: + u2fs_global_done(); + +SV* +new_impl() + CODE: + u2fs_ctx_t *ctx = NULL; + if (u2fs_init(&ctx) != U2FS_OK) { + RETVAL = &PL_sv_undef; + } else { + RETVAL = newSVpv((char*)&ctx, sizeof(ctx)); + } + OUTPUT: + RETVAL + +void +done_impl(ctx) + SV *ctx + CODE: + if (ctx == &PL_sv_undef) { + croak("u2fs xs: double free"); + } else { + u2fs_ctx_t **pctx = (u2fs_ctx_t**)SvPV_nolen(ctx); + u2fs_done(*pctx); + sv_setsv(ctx, &PL_sv_undef); + } + +#// Context initialization before registration/authentication + +int +set_origin_impl(ctx, origin) + SV *ctx + char *origin + CODE: + u2fs_ctx_t **pctx = (u2fs_ctx_t**)SvPV_nolen(ctx); + RETVAL = u2fs_set_origin(*pctx, origin); + OUTPUT: + RETVAL + +int +set_appid_impl(ctx, appid) + SV *ctx + char *appid + CODE: + u2fs_ctx_t **pctx = (u2fs_ctx_t**)SvPV_nolen(ctx); + RETVAL = u2fs_set_appid(*pctx, appid); + OUTPUT: + RETVAL + +int +set_challenge_impl(ctx, challenge) + SV *ctx + char *challenge + CODE: + u2fs_ctx_t **pctx = (u2fs_ctx_t**)SvPV_nolen(ctx); + RETVAL = u2fs_set_challenge(*pctx, challenge); + OUTPUT: + RETVAL + +int +set_keyHandle_impl(ctx, keyHandle) + SV *ctx + char *keyHandle + CODE: + u2fs_ctx_t **pctx = (u2fs_ctx_t**)SvPV_nolen(ctx); + RETVAL = u2fs_set_keyHandle(*pctx, keyHandle); + OUTPUT: + RETVAL + +int +set_publicKey_impl(ctx, publicKey) + SV *ctx + unsigned char *publicKey + CODE: + u2fs_ctx_t **pctx = (u2fs_ctx_t**)SvPV_nolen(ctx); + RETVAL = u2fs_set_publicKey(*pctx, publicKey); + OUTPUT: + RETVAL + +#// Registration functions + +int +registration_challenge_impl(ctx, outref=&PL_sv_undef) + SV *ctx + SV *outref + CODE: + u2fs_ctx_t **pctx = (u2fs_ctx_t**)SvPV_nolen(ctx); + char *output = NULL; + u2fs_rc rc = u2fs_registration_challenge(*pctx, &output); + if (rc == U2FS_OK) { + sv_setpv(outref, output); + } + RETVAL = rc; + OUTPUT: + RETVAL + +int +registration_verify_impl(ctx, response, kh=&PL_sv_undef, pk=&PL_sv_undef) + SV *ctx + char *response + SV *kh + SV *pk + CODE: + u2fs_ctx_t **pctx = (u2fs_ctx_t**)SvPV_nolen(ctx); + u2fs_reg_res_t *result = NULL; + u2fs_rc rc = u2fs_registration_verify(*pctx, response, &result); + if (rc == U2FS_OK) { + const char *keyHandle = u2fs_get_registration_keyHandle(result); + const char *publicKey = u2fs_get_registration_publicKey(result); + sv_setpv(kh, keyHandle); + sv_setpv(pk, publicKey); + u2fs_free_reg_res(result); + } + RETVAL = rc; + OUTPUT: + RETVAL + +#// Authentication functions +int +auth_challenge_impl(ctx, outref=&PL_sv_undef) + SV *ctx + SV *outref + CODE: + u2fs_ctx_t **pctx = (u2fs_ctx_t**)SvPV_nolen(ctx); + char *output = NULL; + u2fs_rc rc = u2fs_authentication_challenge(*pctx, &output); + if (rc == U2FS_OK) { + sv_setpv(outref, output); + } + RETVAL = rc; + OUTPUT: + RETVAL + +int +auth_verify_impl(ctx, response, verified=&PL_sv_undef, counter=&PL_sv_undef, presence=&PL_sv_undef) + SV *ctx + char *response + SV *verified + SV *counter + SV *presence + CODE: + u2fs_ctx_t **pctx = (u2fs_ctx_t**)SvPV_nolen(ctx); + u2fs_auth_res_t *result = NULL; + u2fs_rc rc = u2fs_authentication_verify(*pctx, response, &result); + if (rc == U2FS_OK) { + u2fs_rc a_verified = 0; + uint32_t a_count = 0; + uint8_t a_presence = 0; + rc = u2fs_get_authentication_result(result, &a_verified, &a_count, &a_presence); + if (rc == U2FS_OK) { + sv_setiv(verified, a_verified); + sv_setuv(counter, a_count); + sv_setuv(presence, a_presence); + } + u2fs_free_auth_res(result); + } + RETVAL = rc; + OUTPUT: + RETVAL diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..1950d15 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +libpve-u2f-server-perl (1.0-1) unstable; urgency=low + + * initial package + + -- Proxmox Support Team Tue, 02 Apr 2019 10:45:19 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..f599e28 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +10 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..ca09ba8 --- /dev/null +++ b/debian/control @@ -0,0 +1,17 @@ +Source: libpve-u2f-server-perl +Section: perl +Priority: optional +Maintainer: Proxmox Support Team +Build-Depends: debhelper (>= 10~), + libu2f-server-dev, +Standards-Version: 3.9.8 +Homepage: https://www.proxmox.com/ + +Package: libpve-u2f-server-perl +Architecture: any +Depends: perl (>= 5.20.1-5), + ${misc:Depends}, + ${perl:Depends}, + ${shlibs:Depends}, +Description: Perl bindings for libu2f-server + This package contains libu2f-server perl binding used by Proxmox VE. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..ae43835 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,16 @@ +Copyright (C) 2019 Proxmox Server Solutions GmbH + +This software is written by Proxmox Server Solutions GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..218df65 --- /dev/null +++ b/debian/rules @@ -0,0 +1,8 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +%: + dh $@