Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
libvmod-crypto
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
uplex-varnish
libvmod-crypto
Commits
bb7a915a
Unverified
Commit
bb7a915a
authored
Mar 24, 2021
by
Nils Goroll
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add a signer
we also reduce the number of tests to 1/10th due to the signing computation required.
parent
e6c7a016
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
359 additions
and
22 deletions
+359
-22
vmod_crypto.c
src/vmod_crypto.c
+216
-10
vmod_crypto.rst
src/vmod_crypto.rst
+69
-0
vmod_crypto.vcc
src/vmod_crypto.vcc
+38
-0
vmod_crypto.tpl
src/vtc/vmod_crypto.tpl
+36
-12
No files found.
src/vmod_crypto.c
View file @
bb7a915a
...
...
@@ -529,6 +529,20 @@ crypto_ctx_task_md_ctx(VRT_CTX, const void *id, EVP_MD_CTX *evpctx, int reset)
return
(
vcvt
->
evpctx
);
}
/*
* ------------------------------------------------------------
* misc
*/
static
int
crypto_err_cb
(
const
char
*
s
,
size_t
l
,
void
*
u
)
{
VRT_CTX
;
CAST_OBJ_NOTNULL
(
ctx
,
u
,
VRT_CTX_MAGIC
);
VSLb
(
ctx
->
vsl
,
SLT_Debug
,
"crypto %.*s"
,
l
,
s
);
return
(
0
);
}
/*
* ------------------------------------------------------------
* $Object verfier()
...
...
@@ -697,16 +711,6 @@ VCL_BOOL vmod_verifier_reset(VRT_CTX,
return
(
!!
crypto_ctx_task_md_ctx
(
ctx
,
vcv
,
vcv
->
evpctx
,
1
));
}
static
int
crypto_err_cb
(
const
char
*
s
,
size_t
l
,
void
*
u
)
{
VRT_CTX
;
CAST_OBJ_NOTNULL
(
ctx
,
u
,
VRT_CTX_MAGIC
);
VSLb
(
ctx
->
vsl
,
SLT_Debug
,
"crypto %.*s"
,
l
,
s
);
return
(
0
);
}
VCL_BOOL
vmod_verifier_valid
(
VRT_CTX
,
struct
vmod_crypto_verifier
*
vcv
,
VCL_BLOB
sig
)
{
...
...
@@ -728,3 +732,205 @@ VCL_BOOL vmod_verifier_valid(VRT_CTX,
}
return
(
r
);
}
/*
* ------------------------------------------------------------
* $Object signer()
*
* XXX structurally this is very similar to the verifier. Using common functions
* has been considered, but the benefits seemed quite marginal
*/
struct
vmod_crypto_signer
{
unsigned
magic
;
#define VMOD_CRYPTO_SIGNER_MAGIC 0x6bba960e
char
*
vcl_name
;
EVP_MD_CTX
*
evpctx
;
};
VCL_VOID
vmod_signer__init
(
VRT_CTX
,
struct
vmod_crypto_signer
**
vcsp
,
const
char
*
vcl_name
,
struct
VARGS
(
signer__init
)
*
args
)
{
struct
vmod_crypto_signer
*
vcs
;
const
EVP_MD
*
md
=
md_evp
(
md_parse
(
args
->
digest
));
EVP_PKEY
*
pkey
;
if
(
md
==
NULL
)
{
VRT_fail
(
ctx
,
"digest %s not supported"
,
args
->
digest
);
return
;
}
if
(
args
->
valid_pem
^
args
->
valid_key
==
0
)
{
VRT_fail
(
ctx
,
"Need either pem or key, but not both"
);
return
;
}
AN
(
vcsp
);
AZ
(
*
vcsp
);
ALLOC_OBJ
(
vcs
,
VMOD_CRYPTO_SIGNER_MAGIC
);
if
(
vcs
==
NULL
)
{
VRT_fail
(
ctx
,
"obj alloc failed"
);
return
;
}
REPLACE
(
vcs
->
vcl_name
,
vcl_name
);
if
(
vcs
->
vcl_name
==
NULL
)
{
VRT_fail
(
ctx
,
"dup vcl_name failed"
);
goto
err_dup
;
}
ERR_clear_error
();
vcs
->
evpctx
=
EVP_MD_CTX_new
();
if
(
vcs
->
evpctx
==
NULL
)
{
VRT_fail
(
ctx
,
"EVP_MD_CTX_new failed, error 0x%lx"
,
ERR_get_error
());
goto
err_evpctx
;
}
if
(
EVP_DigestInit_ex
(
vcs
->
evpctx
,
md
,
NULL
)
!=
1
)
{
VRT_fail
(
ctx
,
"EVP_DigestInit_ex failed, error 0x%lx"
,
ERR_get_error
());
goto
err_digest
;
}
if
(
args
->
valid_pem
)
pkey
=
privkey_pem
(
ctx
,
args
->
pem
,
NULL
);
else
if
(
args
->
valid_key
)
pkey
=
pkey_blob
(
ctx
,
args
->
key
);
else
INCOMPL
();
if
(
pkey
==
NULL
)
goto
err_digest
;
if
(
EVP_DigestSignInit
(
vcs
->
evpctx
,
NULL
,
md
,
NULL
,
pkey
)
!=
1
)
{
VRT_fail
(
ctx
,
"EVP_DigestSignInit failed, error 0x%lx"
,
ERR_get_error
());
EVP_PKEY_free
(
pkey
);
goto
err_digest
;
}
if
(
args
->
valid_pem
)
EVP_PKEY_free
(
pkey
);
*
vcsp
=
vcs
;
return
;
err_digest:
EVP_MD_CTX_free
(
vcs
->
evpctx
);
vcs
->
evpctx
=
NULL
;
err_evpctx:
free
(
vcs
->
vcl_name
);
err_dup:
FREE_OBJ
(
vcs
);
}
VCL_VOID
vmod_signer__fini
(
struct
vmod_crypto_signer
**
vcsp
)
{
struct
vmod_crypto_signer
*
vcs
=
*
vcsp
;
*
vcsp
=
NULL
;
if
(
vcs
==
NULL
)
return
;
CHECK_OBJ
(
vcs
,
VMOD_CRYPTO_SIGNER_MAGIC
);
EVP_MD_CTX_free
(
vcs
->
evpctx
);
vcs
->
evpctx
=
NULL
;
free
(
vcs
->
vcl_name
);
FREE_OBJ
(
vcs
);
}
VCL_BOOL
vmod_signer_update
(
VRT_CTX
,
struct
vmod_crypto_signer
*
vcs
,
VCL_STRANDS
str
)
{
EVP_MD_CTX
*
evpctx
=
crypto_ctx_task_md_ctx
(
ctx
,
vcs
,
vcs
->
evpctx
,
0
);
const
char
*
s
;
int
i
;
if
(
evpctx
==
NULL
)
return
(
0
);
AN
(
str
);
ERR_clear_error
();
for
(
i
=
0
;
i
<
str
->
n
;
i
++
)
{
s
=
str
->
p
[
i
];
if
(
s
==
NULL
||
*
s
==
'\0'
)
continue
;
if
(
EVP_DigestSignUpdate
(
evpctx
,
s
,
strlen
(
s
))
!=
1
)
{
VRT_fail
(
ctx
,
"EVP_DigestSignUpdate"
" failed, error 0x%lx"
,
ERR_get_error
());
return
(
0
);
}
}
return
(
1
);
}
VCL_BOOL
vmod_signer_update_blob
(
VRT_CTX
,
struct
vmod_crypto_signer
*
vcs
,
VCL_BLOB
blob
)
{
EVP_MD_CTX
*
evpctx
=
crypto_ctx_task_md_ctx
(
ctx
,
vcs
,
vcs
->
evpctx
,
0
);
if
(
evpctx
==
NULL
)
return
(
0
);
ERR_clear_error
();
if
(
blob
&&
blob
->
len
>
0
)
{
AN
(
blob
->
blob
);
if
(
EVP_DigestSignUpdate
(
evpctx
,
blob
->
blob
,
blob
->
len
)
!=
1
)
{
VRT_fail
(
ctx
,
"EVP_DigestSignUpdate"
" failed, error 0x%lx"
,
ERR_get_error
());
return
(
0
);
}
}
return
(
1
);
}
VCL_BOOL
vmod_signer_reset
(
VRT_CTX
,
struct
vmod_crypto_signer
*
vcs
)
{
return
(
!!
crypto_ctx_task_md_ctx
(
ctx
,
vcs
,
vcs
->
evpctx
,
1
));
}
VCL_BLOB
vmod_signer_final
(
VRT_CTX
,
struct
vmod_crypto_signer
*
vcs
)
{
EVP_MD_CTX
*
evpctx
=
crypto_ctx_task_md_ctx
(
ctx
,
vcs
,
vcs
->
evpctx
,
0
);
unsigned
char
*
sig
;
size_t
siglen
;
if
(
evpctx
==
NULL
)
return
(
0
);
ERR_clear_error
();
if
(
EVP_DigestSignFinal
(
evpctx
,
NULL
,
&
siglen
)
!=
1
)
goto
err
;
sig
=
WS_Alloc
(
ctx
->
ws
,
siglen
);
if
(
sig
==
NULL
)
{
VRT_fail
(
ctx
,
"%s.final() out of workspace"
,
vcs
->
vcl_name
);
return
(
NULL
);
}
ERR_clear_error
();
if
(
EVP_DigestSignFinal
(
evpctx
,
sig
,
&
siglen
)
!=
1
)
goto
err
;
return
(
VRT_blob
(
ctx
,
"xsigner.final()"
,
sig
,
siglen
,
0x6bba960e
));
err:
VSLb
(
ctx
->
vsl
,
SLT_Debug
,
"%s.final() failed: %s"
,
vcs
->
vcl_name
,
ERR_get_error
());
ERR_print_errors_cb
(
crypto_err_cb
,
(
void
*
)
ctx
);
return
(
NULL
);
}
src/vmod_crypto.rst
View file @
bb7a915a
...
...
@@ -40,6 +40,16 @@ SYNOPSIS
:ref:`xverifier.valid()`
:ref:`crypto.signer()`
:ref:`xsigner.update()`
:ref:`xsigner.update_blob()`
:ref:`xsigner.reset()`
:ref:`xsigner.final()`
DESCRIPTION
===========
...
...
@@ -180,6 +190,65 @@ Note that after calling .valid(), .update can be called again to add
additional data, which can then be validated against a (different)
signature using another call to .valid().
.. _crypto.signer():
new xsigner = crypto.signer(ENUM digest, [STRING pem], [BLOB key])
------------------------------------------------------------------
::
new xsigner = crypto.signer(
ENUM {md_null, md4, md5, sha1, sha224, sha256, sha384, sha512, ripemd160, rmd160, whirlpool} digest,
[STRING pem],
[BLOB key]
)
Create an object to create signatures using _digest_ and _key_.
The _key_ argument should be a call to `xkey.use()`_ on the respective
`crypto.key()`_ private key object.
Alternatively to _key_, the _pem_ argument may be used to pass a
PEM-encoded private key specification. Password protection is not
supported with a _pem_ argument. Use of the _pem_ argument is
deprecated.
Either the _key_ or the _pem_ argument must be given.
.. _xsigner.update():
BOOL xsigner.update(STRING)
---------------------------
Add strings to the data to be signed.
.. _xsigner.update_blob():
BOOL xsigner.update_blob(BLOB)
------------------------------
Add a blob to the data to be signed.
.. _xsigner.reset():
BOOL xsigner.reset()
--------------------
Reset the signer state as if previous calls to the update methods had
not happened.
.. _xsigner.final():
BLOB xsigner.final()
--------------------
Return the signature for data added using `xsigner.update()` and
`xsigner.update_blob()`.
Note that after calling `xsigner.final()`,
`xsigner.update()`/`xsigner.update_blob()` can be called again to add
additional data, and more signatures can be generated with
`xsigner.final()`.
SEE ALSO
========vcl\(7),varnishd\(1)
...
...
src/vmod_crypto.vcc
View file @
bb7a915a
...
...
@@ -113,6 +113,44 @@ Note that after calling .valid(), .update can be called again to add
additional data, which can then be validated against a (different)
signature using another call to .valid().
$Object signer(ENUM {md_null, md4, md5, sha1, sha224,
sha256, sha384, sha512, ripemd160, rmd160, whirlpool} digest,
[STRING pem], [BLOB key])
Create an object to create signatures using _digest_ and _key_.
The _key_ argument should be a call to `xkey.use()`_ on the respective
`crypto.key()`_ private key object.
Alternatively to _key_, the _pem_ argument may be used to pass a
PEM-encoded private key specification. Password protection is not
supported with a _pem_ argument. Use of the _pem_ argument is
deprecated.
Either the _key_ or the _pem_ argument must be given.
$Method BOOL .update(STRANDS)
Add strings to the data to be signed.
$Method BOOL .update_blob(BLOB)
Add a blob to the data to be signed.
$Method BOOL .reset()
Reset the signer state as if previous calls to the update methods had
not happened.
$Method BLOB .final()
Return the signature for data added using `xsigner.update()` and
`xsigner.update_blob()`.
Note that after calling `xsigner.final()`,
`xsigner.update()`/`xsigner.update_blob()` can be called again to add
additional data, and more signatures can be generated with
`xsigner.final()`.
SEE ALSO
========vcl\(7),varnishd\(1)
src/vtc/vmod_crypto.tpl
View file @
bb7a915a
...
...
@@ -13,6 +13,8 @@ varnish v1 -vcl+backend {
sub vcl_init {
new v = crypto.verifier(§
{
MD
}
,
std.fileread("$
{
vtc_dir
}
/keys/§
{
ALG
}
_§
{
BITS
}
.pub.pem"));
new s = crypto.signer(§
{
MD
}
,
std.fileread("$
{
vtc_dir
}
/keys/§
{
ALG
}
_§
{
BITS
}
.pem"));
new sig = blob.blob(
BASE64, encoded=regsuball(
std.fileread(
...
...
@@ -30,13 +32,24 @@ varnish v1 -vcl+backend {
}
sub vcl_deliver {
#
signature of
first half
#
verify
first half
set resp.http.up1a = v.update_blob(
blob.sub(data.get(), §
{
HALF
}
B));
if (v.valid(sig_part.get())) {
set resp.http.ok1a = "true";
} else {
return (synth(400));
return (synth(400, "verify 1st half failed"));
}
# sign first half
set resp.http.sup1a = s.update_blob(
blob.sub(data.get(), §
{
HALF
}
B));
if (blob.equal(s.final(), sig_part.get())) {
set resp.http.sok1a = "true";
} else if (v.valid(s.final())) {
# DSA has entropy in the signature
set resp.http.sok1a = "true";
} else {
return (synth(400, "own sig 1st half does not match/verify"));
}
# update and check full sig
set resp.http.up1b = v.update_blob(
...
...
@@ -44,7 +57,18 @@ varnish v1 -vcl+backend {
if (v.valid(sig.get())) {
set resp.http.ok1b = "true";
} else {
return (synth(400));
return (synth(400, "verify 2nd half failed"));
}
# update and sign full
set resp.http.sup1b = s.update_blob(
blob.sub(data.get(), §
{
LEN
}
B - §
{
HALF
}
B, §
{
HALF
}
B));
if (blob.equal(s.final(), sig.get())) {
set resp.http.sok1b = "true";
} else if (v.valid(s.final())) {
# DSA has entropy in the signature
set resp.http.sok1b = "true";
} else {
return (synth(400, "own sig 2nd half does not match/verify"));
}
# check full sig in one go
v.reset();
...
...
@@ -52,12 +76,12 @@ varnish v1 -vcl+backend {
if (v.valid(sig.get())) {
set resp.http.ok = "true";
} else {
return (synth(400));
return (synth(400
, "verify full failed"
));
}
}
} -start
client c0 -repeat 10
0
-keepalive {
client c0 -repeat 10 -keepalive {
txreq
rxresp
expect resp.status == 200
...
...
@@ -68,7 +92,7 @@ client c0 -repeat 100 -keepalive {
expect resp.http.up == true
expect resp.http.ok == true
} -run
client c1 -repeat 10
0
-keepalive {
client c1 -repeat 10 -keepalive {
txreq
rxresp
expect resp.status == 200
...
...
@@ -79,7 +103,7 @@ client c1 -repeat 100 -keepalive {
expect resp.http.up == true
expect resp.http.ok == true
} -run
client c10 -repeat 10
0
-keepalive {
client c10 -repeat 10 -keepalive {
txreq
rxresp
expect resp.status == 200
...
...
@@ -90,7 +114,7 @@ client c10 -repeat 100 -keepalive {
expect resp.http.up == true
expect resp.http.ok == true
} -run
client c11 -repeat 10
0
-keepalive {
client c11 -repeat 10 -keepalive {
txreq
rxresp
expect resp.status == 200
...
...
@@ -101,7 +125,7 @@ client c11 -repeat 100 -keepalive {
expect resp.http.up == true
expect resp.http.ok == true
} -run
client c110 -repeat 10
0
-keepalive {
client c110 -repeat 10 -keepalive {
txreq
rxresp
expect resp.status == 200
...
...
@@ -112,7 +136,7 @@ client c110 -repeat 100 -keepalive {
expect resp.http.up == true
expect resp.http.ok == true
} -run
client c111 -repeat 10
0
-keepalive {
client c111 -repeat 10 -keepalive {
txreq
rxresp
expect resp.status == 200
...
...
@@ -123,7 +147,7 @@ client c111 -repeat 100 -keepalive {
expect resp.http.up == true
expect resp.http.ok == true
} -run
client c1010 -repeat 10
0
-keepalive {
client c1010 -repeat 10 -keepalive {
txreq
rxresp
expect resp.status == 200
...
...
@@ -134,7 +158,7 @@ client c1010 -repeat 100 -keepalive {
expect resp.http.up == true
expect resp.http.ok == true
} -run
client c1011 -repeat 10
0
-keepalive {
client c1011 -repeat 10 -keepalive {
txreq
rxresp
expect resp.status == 200
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment