libpve-u2f-server-perl/U2F.xs
Thomas Lamprecht 257314d5ce publicKey data can contain NUL, base64 encode at source
One *mustn't* treat the publicKey as common string, it it's
effectively binary data, and thus can contain 0 at any position.

If we pass it to perl via setpv (PV being string), things may get
cutoff and a wrong pubKey may get saved, thus locking an user out as
it cannot get verified anymore!

Use a simple & fast base64 encoding immediately at the source, using
the correct keylength (U2FS_PUBLIC_KEY_LEN) we can use that.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2019-04-09 12:39:15 +02:00

184 lines
3.7 KiB
Plaintext

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include <u2f-server.h>
#include "base64.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_raw = u2fs_get_registration_publicKey(result);
char *publicKey = base64(publicKey_raw, U2FS_PUBLIC_KEY_LEN);
sv_setpv(kh, keyHandle);
sv_setpv(pk, publicKey);
free(publicKey); publicKey = NULL;
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