mirror of
https://git.proxmox.com/git/libpve-u2f-server-perl
synced 2025-10-04 21:56:12 +00:00
initial release
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
commit
b8adb2d581
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
build
|
||||||
|
ppport.h
|
||||||
|
U2F.so
|
||||||
|
U2F.xsc
|
||||||
|
*.deb
|
||||||
|
*.1.pod
|
||||||
|
*.1.gz
|
81
Makefile
Normal file
81
Makefile
Normal file
@ -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)
|
155
PVE/U2F.pm
Normal file
155
PVE/U2F.pm
Normal file
@ -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 <support@proxmox.com>
|
||||||
|
|
||||||
|
=cut
|
179
U2F.xs
Normal file
179
U2F.xs
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
#define PERL_NO_GET_CONTEXT
|
||||||
|
#include "EXTERN.h"
|
||||||
|
#include "perl.h"
|
||||||
|
#include "XSUB.h"
|
||||||
|
|
||||||
|
#include "ppport.h"
|
||||||
|
|
||||||
|
#include <u2f-server.h>
|
||||||
|
|
||||||
|
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
|
5
debian/changelog
vendored
Normal file
5
debian/changelog
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
libpve-u2f-server-perl (1.0-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* initial package
|
||||||
|
|
||||||
|
-- Proxmox Support Team <support@proxmox.com> Tue, 02 Apr 2019 10:45:19 +0200
|
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
10
|
17
debian/control
vendored
Normal file
17
debian/control
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Source: libpve-u2f-server-perl
|
||||||
|
Section: perl
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: Proxmox Support Team <support@proxmox.com>
|
||||||
|
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.
|
16
debian/copyright
vendored
Normal file
16
debian/copyright
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Copyright (C) 2019 Proxmox Server Solutions GmbH
|
||||||
|
|
||||||
|
This software is written by Proxmox Server Solutions GmbH <support@proxmox.com>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
8
debian/rules
vendored
Executable file
8
debian/rules
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# -*- makefile -*-
|
||||||
|
|
||||||
|
# Uncomment this to turn on verbose mode.
|
||||||
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@
|
Loading…
Reference in New Issue
Block a user