#!perl
use strict;
use warnings;
BEGIN {
require Test::More;
eval { require Digest::MD5 } or Test::More->import(skip_all => 'Need Digest::MD5');
eval { require Digest::HMAC_MD5 } or Test::More->import(skip_all => 'Need Digest::HMAC_MD5');
}
use Test::More (tests => 33);
use Authen::SASL qw(Perl);
use_ok 'Authen::SASL::Perl::DIGEST_MD5';
my $authname;
my $sasl = Authen::SASL->new(
mechanism => 'DIGEST-MD5',
callback => {
getsecret => sub { $_[2]->('fred') },
},
);
ok($sasl,'new');
no warnings 'once';
# override for testing as by default it uses $$, time and rand
$Authen::SASL::Perl::DIGEST_MD5::NONCE = "foobaz";
is($sasl->mechanism, 'DIGEST-MD5', 'sasl mechanism');
my $server = $sasl->server_new("ldap","elwood.innosoft.com", { no_integrity => 1 });
is($server->mechanism, 'DIGEST-MD5', 'conn mechanism');
## simple success without authzid
{
my $expected_ss = join ",",
'algorithm=md5-sess',
'charset=utf-8',
'cipher="rc4,3des,des,rc4-56,rc4-40"',
'maxbuf=16777215',
'nonce="80338e79d2ca9b9c090ebaaa2ef293c7"',
'qop="auth"',
'realm="elwood.innosoft.com"';
my $ss;
$server->server_start('', sub { $ss = shift });
is($ss, $expected_ss, 'server_start');
my $c1 = join ",", qw(
charset=utf-8
cnonce="3858f62230ac3c915f300c664312c63f"
digest-uri="ldap/elwood.innosoft.com"
nc=00000001
nonce="80338e79d2ca9b9c090ebaaa2ef293c7"
qop=auth
realm="elwood.innosoft.com"
response=39ab7388b1f52492b1b87cda55177d04
username="gbarr"
);
my $s1;
$server->server_step($c1, sub { $s1 = shift });
ok $server->is_success, "This is the first and only step";
ok !$server->error, "no error" or diag $server->error;
ok !$server->need_step, "over";
is $server->property('ssf'), 0, "auth doesn't provide any protection";
is($s1, "rspauth=dbf4b44d397bafd53be835344988ec9d", "rspauth matches");
}
# try with an authname
{
my $expected_ss = join ",",
'algorithm=md5-sess',
'charset=utf-8',
'cipher="rc4,3des,des,rc4-56,rc4-40"',
'maxbuf=16777215',
'nonce="80338e79d2ca9b9c090ebaaa2ef293c7"',
'qop="auth"',
'realm="elwood.innosoft.com"';
my $ss;
$server->server_start('', sub { $ss = shift });
is($ss, $expected_ss, 'server_start');
ok !$server->is_success, "not success yet";
ok !$server->error, "no error" or diag $server->error;
ok $server->need_step, "we need one more step";
$authname = 'meme';
my $c1 = join ",", qw(
authzid="meme"
charset=utf-8
cnonce="3858f62230ac3c915f300c664312c63f"
digest-uri="ldap/elwood.innosoft.com"
nc=00000002
nonce="80338e79d2ca9b9c090ebaaa2ef293c7"
qop=auth
realm="elwood.innosoft.com"
response=e01f51543754aa665cfa2c621d59ee9e
username="gbarr"
);
my $s1;
$server->server_step($c1, sub { $s1 = shift });
is($s1, "rspauth=d10458627b2b6bb553d796f4d805fdd1", "rspauth")
or diag $server->error;
ok $server->is_success, "success!";
ok !$server->error, "no error" or diag $server->error;
ok !$server->need_step, "over";
is $server->property('ssf'), 0, "auth doesn't provide any protection";
}
## using auth-conf (if available)
{
SKIP: {
skip "Crypt not available", 6
if $Authen::SASL::Perl::DIGEST_MD5::NO_CRYPT_AVAILABLE;
$server = $sasl->server_new("ldap","elwood.innosoft.com");
my $expected_ss = join ",",
'algorithm=md5-sess',
'charset=utf-8',
'cipher="rc4,3des,des,rc4-56,rc4-40"',
'maxbuf=16777215',
'nonce="80338e79d2ca9b9c090ebaaa2ef293c7"',
'qop="auth,auth-conf,auth-int"',
'realm="elwood.innosoft.com"';
my $ss;
$server->server_start('', sub { $ss = shift });
is($ss, $expected_ss, 'server_start');
my $c1 = join ",", qw(
charset=utf-8
cnonce="3858f62230ac3c915f300c664312c63f"
digest-uri="ldap/elwood.innosoft.com"
nc=00000001
nonce="80338e79d2ca9b9c090ebaaa2ef293c7"
qop=auth-conf
realm="elwood.innosoft.com"
response=e3c8b38d9bd9556761253e9879c4a8a2
username="gbarr"
);
my $s1;
$server->server_step($c1, sub { $s1 = shift });
ok $server->is_success, "This is the first and only step";
ok !$server->error, "no error" or diag $server->error;
ok !$server->need_step, "over";
is($s1, "rspauth=1b1156d0e7f046bd0ea1476eb7d63a7b", "rspauth matches");
## we have negociated the conf layer
ok $server->property('ssf') > 1, "yes! secure layer set up";
};
}
## wrong challenge response
{
$server = $sasl->server_new("ldap","elwood.innosoft.com");
$server->server_start('');
my $c1 = join ",", qw(
charset=utf-8
cnonce="3858f62230ac3c915f300c664312c63f"
digest-uri="ldap/elwood.innosoft.com"
nc=00000001
nonce="80338e79d2ca9b9c090ebaaa2ef293c7"
qop=auth-conf
realm="elwood.innosoft.com"
response=nottherightone
username="gbarr"
);
$server->server_step($c1);
ok !$server->is_success, "Bad challenge";
if ($Authen::SASL::Perl::DIGEST_MD5::NO_CRYPT_AVAILABLE) {
like $server->error, qr/Client qop not supported/, $server->error;
}
else {
like $server->error, qr/incorrect.*response/i, $server->error;
}
}
## multiple digest-uri;
{
$server = $sasl->server_new("ldap","elwood.innosoft.com");
$server->server_start('');
my $c1 = join ",", qw(
charset=utf-8
cnonce="3858f62230ac3c915f300c664312c63f"
digest-uri="ldap/elwood.innosoft.com"
digest-uri="ldap/elwood.innosoft.com"
nc=00000001
nonce="80338e79d2ca9b9c090ebaaa2ef293c7"
qop=auth-conf
realm="elwood.innosoft.com"
response=e3c8b38d9bd9556761253e9879c4a8a2
username="gbarr"
);
$server->server_step($c1);
ok !$server->is_success, "Bad challenge";
like $server->error, qr/Bad.*challenge/i, $server->error;
}
## nonce-count;
{
$server = $sasl->server_new("ldap","elwood.innosoft.com");
$server->server_start('');
my $c1 = join ",", qw(
charset=utf-8
cnonce="3858f62230ac3c915f300c664312c63f"
digest-uri="ldap/elwood.innosoft.com"
nc=00000001
nonce="80338e79d2ca9b9c090ebaaa2ef293c7"
qop=auth-conf
realm="elwood.innosoft.com"
response=e3c8b38d9bd9556761253e9879c4a8a2
username="gbarr"
);
SKIP: {
skip "no crypt available", 4
if $Authen::SASL::Perl::DIGEST_MD5::NO_CRYPT_AVAILABLE;
$server->server_step($c1);
ok $server->is_success, "first is success";
ok ! $server->error, "no error";
$server->server_step($c1);
ok !$server->is_success, "replay attack";
like $server->error, qr/nonce-count.*match/i, $server->error;
}
}