Skip to content

Commit

Permalink
Merge pull request #20 from tomalok/tktauthdigest_directive
Browse files Browse the repository at this point in the history
Added TKTAuthDigest directive, updated docs & exmples.
  • Loading branch information
manuelkasper authored Dec 16, 2016
2 parents e3cc608 + 029d7d3 commit 376feb3
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 26 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
v0.10 (2016-12-16)
------------------
- New option TKTAuthDigest allowing selection of the digest algorithm.
If not configured, the old defaults of SHA1 (for RSA privkey) and DSS1
(for DSA privkey) will be used. SHA224, SHA256, SHA384, and SHA512 are
the additional valid algorithm values. (Contributed by Jake Buchholz)

v0.9 (09/07/2015)
-----------------
- New option TKTAuthHeader allowing custom header(s) to be used instead
Expand Down
12 changes: 10 additions & 2 deletions docs/install.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ <h4>Directives for use in server config, virtual hosts and directory/location/.h
<li>This public key will be used to verify ticket signatures</li>
</ul>
</li>
<li><strong><code>TKTAuthDigest</code></strong>
<ul>
<li>String indicating what digest algorithm to use when verifying ticket signatures</li>
<li>Valid values are SHA1, DSS1, SHA224, SHA256, SHA384, and SHA512</li>
<li>If not specified, the old defaults of SHA1 (for an RSA public key) or DSS1 (for a DSA public key) will be used.</li>
</ul>
</li>
</ul>

<h4>Directives for use in directory/location/.htaccess scope</h4>
Expand Down Expand Up @@ -283,7 +290,8 @@ <h3><a name="ticket_format"></a>Ticket format</h3>
</li>
<li>sig (required)
<ul>
<li>a Base64 encoded RSA or DSA signature over the SHA-1 digest of the content of the ticket up to (but not including) the semicolon before 'sig'</li>
<li>a Base64 encoded RSA or DSA signature over the digest of the content of the ticket up to (but not including) the semicolon before 'sig'</li>
<li>The default digest is SHA-1, unless TKTAuthDigest has specified a different algorithm.</li>
<li>RSA: raw result; DSA: DER encoded sequence of two integers &ndash; see Dss-Sig-Value in RFC 2459</li>
<li><strong>must be the last item in the ticket string</strong></li>
</ul>
Expand Down Expand Up @@ -359,7 +367,7 @@ <h3>Generating a ticket signature on the command line</h3>
| openssl enc -base64 -A
</pre>

<p>Use <code>-dss1</code> for DSA, and <code>-sha1</code> for RSA.</p>
<p>If TKTAuthDigest isn't being used, specify <code>-dss1</code> for DSA, and <code>-sha1</code> for RSA. Otherwise specify the TKTAuthDigest directive's algorithm (i.e. <code>-sha256</code> for SHA256).</p>


<h3>Verifying a ticket signature on the command line</h3>
Expand Down
7 changes: 5 additions & 2 deletions mod_auth_pubtkt.spec
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Summary: Ticket-based authorization module for the Apache HTTP Server
Name: mod_auth_pubtkt
Version: 0.9
Version: 0.10
Release: 0
License: Apache
Group: Applications/System
Source0: https://neon1.net/mod_auth_pubtkt/mod_auth_pubtkt-0.9.tar.gz
Source0: https://neon1.net/mod_auth_pubtkt/mod_auth_pubtkt-0.10.tar.gz
Source1: mod_auth_pubtkt.conf
URL: https://neon1.net/mod_auth_pubtkt/
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
Expand Down Expand Up @@ -42,6 +42,9 @@ rm -rf %{buildroot}
%config %{_sysconfdir}/httpd/conf.d/auth_pubtkt.conf

%changelog
* Fri Dec 16 2016 Jake Buchholz <[email protected]> 0.10-0
- Updated to latest version of mod_auth_pubtkt [0.10]

* Wed Sep 09 2015 Manuel Kasper <[email protected]> 0.9-0
- Updated to latest version of mod_auth_pubtkt [0.9]

Expand Down
2 changes: 2 additions & 0 deletions perl-login/minimal_cgi/login.pl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
## TODO: DO NOT USE THESE keys in a production settings.
## These are just for debugging/testing.
my $key_type = "rsa";
my $digest = undef; # defaults to sha1 or dss1, depending on $key_type
my $public_key = "$FindBin::Bin/../key.pub.pem";
my $private_key = "$FindBin::Bin/../key.priv.pem";

Expand Down Expand Up @@ -151,6 +152,7 @@ sub generate_pubtkt_cookie
my $ticket = pubtkt_generate(
privatekey => $private_key,
keytype => $key_type,
digest => $digest,
clientip => ($use_client_ip) ? remote_addr() : undef,
userid => $user_id,
validuntil => time() + $valid_until_delta,
Expand Down
10 changes: 8 additions & 2 deletions perl-login/mod_auth_pubtkt.pm
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ our $VERSION = '0.1';
my $ticket = pubtkt_generate(
privatekey => "key.priv.pem",
keytype => "rsa",
digest => undef, # or sha1, dss1, sha224, sha256, sha384, or sha512
clientip => undef, # or a valid IP address
userid => "102", # or any ID that makes sense to your application, e.g. email
validuntil => time() + 86400, # valid for one day
Expand All @@ -43,6 +44,7 @@ our $VERSION = '0.1';
my $ok = pubtkt_verify (
publickey => "key.pub.pem",
keytype => "rsa",
digest => undef,
ticket => $ticket
);
die "Ticket verification failed.\n" if not $ok;
Expand Down Expand Up @@ -155,7 +157,9 @@ sub pubtkt_generate
$tkt .= "tokens=$tokens;";
$tkt .= "udata=$user_data";

my $algorithm_param = ( $keytype eq "dsa" ) ? "-dss1" : "-sha1";
my $algorithm_param = '-'.$args{digest} or ( $keytype eq "dsa" ) ? "-dss1" : "-sha1";
croak "Invalid \"digest\" value ($args{digest}), expecting sha1, dss1, sha224, sha256, sha384, or sha512."
if index(" sha1 dss1 sha224 sha256 sha384 sha512 ", " $args{digest} ") == -1;

my @cmd = ( $openssl_bin,
"dgst", $algorithm_param,
Expand Down Expand Up @@ -188,7 +192,9 @@ sub pubtkt_verify
my $keytype = $args{keytype} or croak "Missing \"keytype\" parameter";
croak "Invalid \"keytype\" value ($keytype): expecting 'dsa' or 'rsa'\n"
unless $keytype eq "dsa" || $keytype eq "rsa";
my $algorithm_param = ( $keytype eq "dsa" ) ? "-dss1" : "-sha1";
my $algorithm_param = '-'.$args{digest} or ( $keytype eq "dsa" ) ? "-dss1" : "-sha1";
croak "Invalid \"digest\" value ($args{digest}), expecting sha1, dss1, sha224, sha256, sha384, or sha512."
if index(" sha1 dss1 sha224 sha256 sha384 sha512 ", " $args{digest} ") == -1;

my $ticket_str = $args{ticket} or croak "Missing \"ticket\" parameter";

Expand Down
3 changes: 3 additions & 0 deletions perl-login/test_pubtkt.pl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
my $ticket = pubtkt_generate(
privatekey => "key.priv.pem",
keytype => "rsa",
digest => undef,
clientip => undef,
userid => "102",
validuntil => time() + 86400,
Expand All @@ -34,6 +35,7 @@
my $ok = pubtkt_verify (
publickey => "key.pub.pem",
keytype => "rsa",
digest => undef,
ticket => $ticket
);
die "Ticket verification failed.\n" if not $ok;
Expand All @@ -46,6 +48,7 @@
$ok = pubtkt_verify (
publickey => "key.pub.pem",
keytype => "rsa",
digest => undef,
ticket => $ticket
);

Expand Down
7 changes: 4 additions & 3 deletions php-login/login.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
$privkeyfile = "private/tkt_privkey_dsa.pem";
$pubkeyfile = "private/tkt_pubkey_dsa.pem";
$keytype = "DSA";
$digest = "default";
$localuserdb = "private/users.txt";
$default_timeout = 86400;
$default_graceperiod = 3600;
Expand Down Expand Up @@ -119,7 +120,7 @@ function log_login($ip, $username, $success) {
$tkt_validuntil = time() + $res['timeout'];

/* generate the ticket now and set a domain cookie */
$tkt = pubtkt_generate($privkeyfile, $keytype, $username,
$tkt = pubtkt_generate($privkeyfile, $keytype, $digest, $username,
$_SERVER['REMOTE_ADDR'], $tkt_validuntil, $res['graceperiod'], join(",", $res['tokens']), "");
setcookie("auth_pubtkt", $tkt, 0, "/", $domain, $secure_cookie);

Expand All @@ -145,7 +146,7 @@ function log_login($ip, $username, $success) {

/* Checking validity of the ticket and if we are between begin of grace
period and end of ticket validity. If so we can refresh ticket */
if (pubtkt_verify($pubkeyfile, $keytype, $ticket) && isset($tkt_graceperiod)
if (pubtkt_verify($pubkeyfile, $keytype, $digest, $ticket) && isset($tkt_graceperiod)
&& is_numeric($tkt_graceperiod) && ($tkt_graceperiod <= time())
&& (time() <= $tkt_validuntil)) {

Expand All @@ -157,7 +158,7 @@ function log_login($ip, $username, $success) {
$tkt_validuntil = time() + $user_info['data']['timeout'];

/* generate the ticket now and set a domain cookie */
$tkt = pubtkt_generate($privkeyfile, $keytype, $tkt_uid,
$tkt = pubtkt_generate($privkeyfile, $keytype, $digest, $tkt_uid,
$ticket['cip'], $tkt_validuntil, $user_info['data']['graceperiod'], join(",", $user_info['data']['tokens']), "");
setcookie("auth_pubtkt", $tkt, 0, "/", $domain, $secure_cookie);

Expand Down
14 changes: 12 additions & 2 deletions php-login/pubtkt.inc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ define("OPENSSL_PATH", "/usr/bin/openssl");
Parameters:
privkeyfile path to private key file (PEM format)
privkeytype type of private key ("RSA" or "DSA")
digest digest algorithm ("default" is sha1 or dss1)
also valid: sha224, sha256, sha384, and sha512
uid user ID/username
clientip client IP address (optional; can be empty or null)
validuntil expiration timestamp (e.g. time() + 86400)
Expand All @@ -30,7 +32,7 @@ define("OPENSSL_PATH", "/usr/bin/openssl");
Returns:
ticket string, or FALSE on failure
*/
function pubtkt_generate($privkeyfile, $privkeytype, $uid, $clientip, $validuntil, $graceperiod, $tokens, $udata, $bauth = null) {
function pubtkt_generate($privkeyfile, $privkeytype, $digest, $uid, $clientip, $validuntil, $graceperiod, $tokens, $udata, $bauth = null) {

/* format ticket string */
$tkt = "uid=$uid;";
Expand All @@ -48,6 +50,9 @@ function pubtkt_generate($privkeyfile, $privkeytype, $uid, $clientip, $validunti
$algoparam = "-dss1";
else
$algoparam = "-sha1";

if ($digest != "default")
$algoparam = "-" . $digest;

$fd = @proc_open(OPENSSL_PATH . " dgst $algoparam -binary -sign " . escapeshellarg($privkeyfile),
array(0 => array("pipe", "r"), 1 => array("pipe", "w")), $pipes);
Expand Down Expand Up @@ -118,12 +123,14 @@ function pubtkt_generate_php($privkey, $uid, $clientip, $validuntil, $graceperio
Parameters:
pubkeyfile path to public key file (PEM format)
pubkeytype type of public key ("RSA" or "DSA")
digest digest algorithm ("default" is sha1 or dss1)
also valid: sha224, sha256, sha384, and sha512
ticket ticket string (including signature)
Returns:
ticket valid true/false
*/
function pubtkt_verify($pubkeyfile, $pubkeytype, $ticket) {
function pubtkt_verify($pubkeyfile, $pubkeytype, $digest, $ticket) {
/* strip off signature */
$sigpos = strpos($ticket, ";sig=");
if ($sigpos === false)
Expand All @@ -145,6 +152,9 @@ function pubtkt_verify($pubkeyfile, $pubkeytype, $ticket) {
$algoparam = "-dss1";
else
$algoparam = "-sha1";

if ($digest != "default")
$algoparam = "-" . $digest;

/* check DSA signature */
$fd = proc_open(OPENSSL_PATH . " dgst $algoparam -verify " . escapeshellarg($pubkeyfile) .
Expand Down
49 changes: 35 additions & 14 deletions src/mod_auth_pubtkt.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ static void* create_auth_pubtkt_config(apr_pool_t *p, char* path) {
conf->fake_basic_auth = -1;
conf->passthru_basic_auth = -1;
conf->pubkey = NULL;
conf->digest = NULL;
conf->passthru_basic_key = NULL;
return conf;
}
Expand Down Expand Up @@ -101,6 +102,7 @@ static void* merge_auth_pubtkt_config(apr_pool_t *p, void* parent_dirv, void* su
conf->fake_basic_auth = (subdir->fake_basic_auth >= 0) ? subdir->fake_basic_auth : parent->fake_basic_auth;
conf->passthru_basic_auth = (subdir->passthru_basic_auth >= 0) ? subdir->passthru_basic_auth : parent->passthru_basic_auth;
conf->pubkey = (subdir->pubkey) ? subdir->pubkey : parent->pubkey;
conf->digest = (subdir->digest) ? subdir->digest : parent->digest;
conf->passthru_basic_key = (subdir->passthru_basic_key) ? subdir->passthru_basic_key : parent->passthru_basic_key;

return conf;
Expand Down Expand Up @@ -239,6 +241,35 @@ static const char *setup_pubkey(cmd_parms *cmd, void *cfg, const char *param) {
conf->pubkey->type == EVP_PKEY_DSA3 || conf->pubkey->type == EVP_PKEY_DSA4))
return apr_psprintf(cmd->pool, "unsupported key type %d", conf->pubkey->type);

/* set default digest algorigthm - old defaults for now */
if (conf->pubkey->type == EVP_PKEY_RSA || conf->pubkey->type == EVP_PKEY_RSA2)
conf->digest = EVP_sha1();
else {
conf->digest = EVP_dss1();
}

return NULL;
}

static const char *setup_digest(cmd_parms *cmd, void *cfg, const char *param) {
auth_pubtkt_dir_conf *conf = (auth_pubtkt_dir_conf*)cfg;

if (strcasecmp(param, "SHA1")) {
conf->digest = EVP_sha1();
} else if (strcasecmp(param, "DSS1")) {
conf->digest = EVP_dss1();
} else if (strcasecmp(param, "SHA224")) {
conf->digest = EVP_sha224();
} else if (strcasecmp(param, "SHA256")) {
conf->digest = EVP_sha256();
} else if (strcasecmp(param, "SHA384")) {
conf->digest = EVP_sha384();
} else if (strcasecmp(param, "SHA512")) {
conf->digest = EVP_sha512();
} else {
return apr_pstrcat(cmd->pool, cmd->cmd->name, ": Invalid digest algorithm ", param, NULL);
}

return NULL;
}

Expand Down Expand Up @@ -311,6 +342,9 @@ static const command_rec auth_pubtkt_cmds[] =
AP_INIT_TAKE1("TKTAuthPublicKey", setup_pubkey,
(void *)APR_OFFSETOF(auth_pubtkt_dir_conf, pubkey),
OR_ALL, "public key file to use for verifying signatures"),
AP_INIT_TAKE1("TKTAuthDigest", setup_digest,
(void *)APR_OFFSETOF(auth_pubtkt_dir_conf, digest),
OR_ALL, "digest algorigthm to use for verifying signatures"),
AP_INIT_TAKE1("TKTAuthPassthruBasicKey", setup_passthru_basic_key,
(void *)APR_OFFSETOF(auth_pubtkt_dir_conf, pubkey),
OR_ALL, "key to use for decrypting passthru field, must be exactly 16 characters"),
Expand Down Expand Up @@ -571,7 +605,6 @@ static auth_pubtkt* validate_parse_ticket(request_rec *r, char *ticket) {
int sig_len;
auth_pubtkt *tkt;
EVP_MD_CTX ctx;
const EVP_MD *impl;

if (strlen(ticket) > MAX_TICKET_SIZE) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r,
Expand Down Expand Up @@ -626,21 +659,9 @@ static auth_pubtkt* validate_parse_ticket(request_rec *r, char *ticket) {
tktval_buf, sigptr);
}

if (conf->pubkey->type == EVP_PKEY_RSA || conf->pubkey->type == EVP_PKEY_RSA2)
impl = EVP_sha1();
else if (conf->pubkey->type == EVP_PKEY_DSA || conf->pubkey->type == EVP_PKEY_DSA1 ||
conf->pubkey->type == EVP_PKEY_DSA2 || conf->pubkey->type == EVP_PKEY_DSA3 ||
conf->pubkey->type == EVP_PKEY_DSA4)
impl = EVP_dss1();
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r,
"TKT validate_parse_ticket: invalid algorithm!");
return NULL;
}

ERR_clear_error();

if (!EVP_VerifyInit(&ctx, impl)) {
if (!EVP_VerifyInit(&ctx, conf->digest)) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r,
"TKT validate_parse_ticket: EVP_VerifyInit failed");
return NULL;
Expand Down
3 changes: 2 additions & 1 deletion src/mod_auth_pubtkt.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
#define PASSTHRU_AUTH_KEY_SIZE 16 /* length of symmetric key for passthru basic auth encryption */
#define PASSTHRU_AUTH_IV_SIZE 16

#define PUBTKT_AUTH_VERSION "0.9"
#define PUBTKT_AUTH_VERSION "0.10"

/* ----------------------------------------------------------------------- */
/* Per-directory configuration */
Expand All @@ -75,6 +75,7 @@ typedef struct {
int grace_period;
int passthru_basic_auth;
EVP_PKEY *pubkey; /* public key for signature verification */
const EVP_MD *digest; /* TKTAuthDigest */
const char *passthru_basic_key;
} auth_pubtkt_dir_conf;

Expand Down

0 comments on commit 376feb3

Please sign in to comment.