This commit is contained in:
2019-02-06 00:49:12 +03:00
commit 8dbb1bb605
4796 changed files with 506072 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
#!/usr/bin/perl
use strict;
use Test::More 'no_plan';
use Data::Dumper;
use Net::OpenID::Server;
use Crypt::OpenSSL::DSA;
use Math::BigInt;
for my $num (1..1080) {
my $bi = Math::BigInt->new("$num");
my $bytes = Net::OpenID::Server::_bi2bytes($bi);
my $bi2 = Net::OpenID::Server::_bytes2bi($bytes);
is($bi,$bi2);
printf "$bi = $bi2\n";
}
exit 0;
my ($query_string, %get_vars, $ctype, $content);
my $parse = sub {
%get_vars = map { durl($_) } split(/[&=]/, $query_string);
};
my $pub_key_file = "test.openid_public.key";
my $priv_key_file = "test.openid_private.key";
my $nos = Net::OpenID::Server->new(
args => \%get_vars,
public_key => $pub_key_file,
private_key => $priv_key_file,
);
ok($nos);
# generate a key
my $dsa = Crypt::OpenSSL::DSA->generate_parameters( 512 );
$dsa->generate_key;
print "done.\n";
$dsa->write_pub_key($pub_key_file);
$dsa->write_priv_key($priv_key_file);
my $read_pub_key = sub {
open (F, $pub_key_file);
my $content = do { local $/; <F>; };
close F;
return $content;
};
my $read_priv_key = sub {
open (F, $priv_key_file);
my $content = do { local $/; <F>; };
close F;
return $content;
};
# see if we get our public key back
$query_string = "openid.mode=getpubkey";
$parse->();
$nos->private_key("BOGUS");
for (1..3) {
$nos->public_key($pub_key_file) if $_ == 1;
$nos->public_key($read_pub_key) if $_ == 2;
$nos->public_key($read_pub_key->()) if $_ == 3;
($ctype, $content) = $nos->handle_page;
ok($ctype eq "text/plain");
ok($content =~ /\-\-\-BEGIN/ && $content =~ /\-\-\-END/);
}
# see if we get a user_setup_url vs. signature
$query_string = "openid.is_identity=http://bradfitz.com/&openid.return_to=http://return.example.com/%3Ffoo%3Dbar";
$parse->();
$nos->get_user(sub { return "brad"; });
$nos->is_identity(sub {
my ($u, $url) = @_;
return $u eq "brad" && $url eq "http://bradfitz.com/";
});
# first an untrusted case:
$nos->is_trusted(sub { 0; });
$nos->setup_url("http://setup.example.com/?set1=set2");
($ctype, $content) = $nos->handle_page or die $nos->err;
ok($ctype eq "redirect");
ok($content =~ m!user_setup_url=http://setup\.example\.com!);
ok($content =~ m!return\.example\.com/\?foo=bar\&open!);
# now a trusted case, but with bogus private key:
$nos->is_trusted(sub { 1; });
$nos->private_key("BOGUS");
($ctype, $content) = $nos->handle_page;
ok(! $ctype);
$nos->private_key($priv_key_file);
($ctype, $content) = $nos->handle_page;
ok($ctype eq "redirect");
ok($content =~ m!return\.example\.com/\?foo=bar\&open!);
ok($content =~ m!\&openid\.sig=M!);
$nos->private_key($read_priv_key);
($ctype, $content) = $nos->handle_page;
ok($ctype eq "redirect");
ok($content =~ m!return\.example\.com/\?foo=bar\&open!);
ok($content =~ m!\&openid\.sig=M!);
# checking two types of failure cases
$nos->setup_url("http://setup.example.com/");
$nos->is_trusted(sub { 0; });
# immediate mode:
$query_string = "openid.mode=checkid_immediate&openid.is_identity=http://bradfitz.com/&openid.return_to=http://return.example.com/%3Ffoo%3Dbar";
$parse->();
($ctype, $content) = $nos->handle_page;
ok($ctype eq "redirect");
# setup mode:
$query_string = "openid.mode=checkid_setup&openid.is_identity=http://bradfitz.com/&openid.return_to=http://return.example.com/%3Ffoo%3Dbar";
$parse->();
($ctype, $content) = $nos->handle_page;
ok($ctype eq "setup");
ok($content->{return_to} eq "http://return.example.com/?foo=bar");
sub durl
{
my ($a) = @_;
$a =~ tr/+/ /;
$a =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
return $a;
}

View File

@@ -0,0 +1,318 @@
#!/usr/bin/perl
use strict;
use Test::More 'no_plan';
use Data::Dumper;
use Net::OpenID::Server;
use Crypt::DH;
use Digest::SHA1 qw(sha1 sha1_hex);
for (my $num=1; $num <= 2000; $num += 20) {
my $bi = Math::BigInt->new("$num");
my $bytes = Net::OpenID::Server::_bi2bytes($bi);
my $bi2 = Net::OpenID::Server::_bytes2bi($bytes);
is($bi,$bi2);
}
my ($query_string, %get, %post, $ctype, $content);
my $parse = sub {
%get = map { durl($_) } split(/[&=]/, $query_string);
};
my %res;
my $nos = Net::OpenID::Server->new(
get_args => \%get,
post_args => \%post,
server_secret => "o3kjn3nf9832hf32nfo32nfdo32nro32n29332",
setup_url => "http://server.com/setup.app",
);
ok($nos);
my ($secret, $ahandle);
assoc_clear();
login_success();
assoc_dh();
login_success();
login_im_fail();
login_setup_fail();
login_setup_fail2();
login_bogus_handle();
sub assoc_clear {
%get = ();
# regular associate
%post = (
"openid.mode" => "associate",
"openid.assoc_type" => "HMAC-SHA1",
);
($ctype, $content) = $nos->handle_page;
is($ctype, "text/plain");
%res = parse_reply($content);
ok($res{assoc_handle});
$ahandle = $res{'assoc_handle'};
ok($ahandle !~ /\bSTLS\./);
is($res{assoc_type}, "HMAC-SHA1");
ok(good_date($res{expiry}));
ok(good_date($res{issued}));
ok($res{mac_key});
$secret = $res{'mac_key'};
}
# DH associate
sub assoc_dh {
my $dh = Crypt::DH->new;
$dh->p("155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443");
$dh->g("2");
$dh->generate_keys;
%get = ();
%post = (
"openid.mode" => "associate",
"openid.assoc_type" => "HMAC-SHA1",
"openid.session_type" => "DH-SHA1",
"openid.dh_consumer_public" => _bi2arg($dh->pub_key),
);
($ctype, $content) = $nos->handle_page;
is($ctype, "text/plain");
%res = parse_reply($content);
ok($res{assoc_handle});
ok($res{dh_server_public});
is($res{assoc_type}, "HMAC-SHA1");
is($res{session_type}, "DH-SHA1");
ok(good_date($res{expiry}));
ok(good_date($res{issued}));
ok($res{enc_mac_key});
ok(! $res{mac_key});
my $server_pub = _arg2bi($res{'dh_server_public'});
my $dh_sec = $dh->compute_secret($server_pub);
$ahandle = $res{'assoc_handle'};
ok($ahandle !~ /\bSTLS\./);
is(length(_d64($res{'enc_mac_key'})), 20);
is(length(sha1(_bi2bytes($dh_sec))), 20);
$secret = _d64($res{'enc_mac_key'}) ^ sha1(_bi2bytes($dh_sec));
is(length($secret), 20);
}
# try to login, with success
sub login_success {
$nos->is_identity(sub { 1; });
$nos->is_trusted(sub { 1; });
$nos->get_user(sub { "brad"; });
%post = ();
%get = (
"openid.mode" => "checkid_immediate",
"openid.identity" => "http://bradfitz.com/",
"openid.return_to" => "http://trust.root/return/",
"openid.trust_root" => "http://trust.root/",
"openid.assoc_handle" => $ahandle,
);
($ctype, $content) = $nos->handle_page;
is($ctype, "redirect");
ok($content =~ s!^http://trust.root/return/\?!!);
my %rarg = map { durl($_) } split(/[\&\=]/, $content);
my $token = "";
foreach my $p (split(/,/, $rarg{'openid.signed'})) {
$token .= "$p:" . $rarg{"openid.$p"} . "\n";
}
my $good_sig = _b64(hmac_sha1($token, $secret));
ok($rarg{'openid.sig'}, $good_sig);
# and verify that check_authentication never lets this succeed
%get = ();
%post = (
"openid.mode" => "check_authentication",
);
foreach my $p ("assoc_handle", "sig", "signed", "invalidate_handle",
split(/,/, $rarg{"openid.signed"}))
{
$post{"openid.$p"} ||= $rarg{"openid.$p"};
}
($ctype, $content) = $nos->handle_page;
is($ctype, "text/plain");
%rarg = parse_reply($content);
ok($rarg{"error"} =~ /bad_handle/);
}
# try to login, with success
sub login_bogus_handle {
$nos->is_identity(sub { 1; });
$nos->is_trusted(sub { 1; });
$nos->get_user(sub { "brad"; });
%post = ();
%get = (
"openid.mode" => "checkid_immediate",
"openid.identity" => "http://bradfitz.com/",
"openid.return_to" => "http://trust.root/return/",
"openid.trust_root" => "http://trust.root/",
"openid.assoc_handle" => "GIBBERISH",
);
($ctype, $content) = $nos->handle_page;
is($ctype, "redirect");
ok($content =~ s!^http://trust.root/return/\?!!);
my %rarg = map { durl($_) } split(/[\&\=]/, $content);
is($rarg{'openid.invalidate_handle'}, "GIBBERISH");
ok($rarg{'openid.assoc_handle'} =~ /\bSTLS\./);
# try to verify it with check_authentication
%get = ();
%post = (
"openid.mode" => "check_authentication",
);
foreach my $p ("assoc_handle", "sig", "signed", "invalidate_handle",
split(/,/, $rarg{"openid.signed"}))
{
$post{"openid.$p"} ||= $rarg{"openid.$p"};
}
($ctype, $content) = $nos->handle_page;
is($ctype, "text/plain");
%rarg = parse_reply($content);
ok($rarg{"lifetime"} > 0);
is($rarg{"invalidate_handle"}, "GIBBERISH");
}
# try to login, but fail (immediately)
sub login_im_fail {
$nos->is_identity(sub { 0; });
$nos->is_trusted(sub { 1; });
$nos->get_user(sub { "brad"; });
%post = ();
%get = (
"openid.mode" => "checkid_immediate",
"openid.identity" => "http://bradfitz.com/",
"openid.return_to" => "http://trust.root/return/",
"openid.trust_root" => "http://trust.root/",
"openid.assoc_handle" => $ahandle,
);
($ctype, $content) = $nos->handle_page;
is($ctype, "redirect");
ok($content =~ s!^http://trust.root/return/\?!!);
my %rarg = map { durl($_) } split(/[\&\=]/, $content);
is($rarg{'openid.mode'}, "id_res");
ok($rarg{'openid.user_setup_url'} =~ m!setup\.app.+bradfitz!);
}
# try to login, but fail (w/ setup)
sub login_setup_fail {
$nos->is_identity(sub { 0; });
$nos->is_trusted(sub { 1; });
$nos->get_user(sub { "brad"; });
%post = ();
%get = (
"openid.mode" => "checkid_setup",
"openid.identity" => "http://bradfitz.com/",
"openid.return_to" => "http://trust.root/return/",
"openid.trust_root" => "http://trust.root/",
"openid.assoc_handle" => $ahandle,
);
($ctype, $content) = $nos->handle_page;
is($ctype, "setup");
ok(ref $content eq "HASH");
}
# try to login, but fail (w/ setup redirect)
sub login_setup_fail2 {
$nos->is_identity(sub { 0; });
$nos->is_trusted(sub { 1; });
$nos->get_user(sub { "brad"; });
%post = ();
%get = (
"openid.mode" => "checkid_setup",
"openid.identity" => "http://bradfitz.com/",
"openid.return_to" => "http://trust.root/return/",
"openid.trust_root" => "http://trust.root/",
"openid.assoc_handle" => $ahandle,
);
($ctype, $content) = $nos->handle_page(redirect_for_setup => 1);
is($ctype, "redirect");
ok($content =~ m!^http://.+setup\.app\?!);
}
sub good_date {
return $_[0] =~ /^(\d{4,4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z$/;
}
sub parse_reply {
my $reply = shift;
my %ret;
foreach (split /\n/, $reply) {
next unless /^(\S+?):(.+)/;
$ret{$1} = $2;
}
return %ret;
}
sub durl
{
my ($a) = @_;
$a =~ tr/+/ /;
$a =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
return $a;
}
sub _bi2bytes {
my $bigint = shift;
die "Can't deal with negative numbers" if $bigint->is_negative;
my $bits = $bigint->as_bin;
die unless $bits =~ s/^0b//;
# prepend zeros to round to byte boundary, or to unset high bit
my $prepend = (8 - length($bits) % 8) || ($bits =~ /^1/ ? 8 : 0);
$bits = ("0" x $prepend) . $bits if $prepend;
return pack("B*", $bits);
}
sub _bi2arg {
my $b64 = MIME::Base64::encode_base64(_bi2bytes($_[0]));
$b64 =~ s/\s+//g;
return $b64;
}
sub _b64 {
my $val = MIME::Base64::encode_base64($_[0]);
$val =~ s/\s+//g;
return $val;
}
sub _d64 {
return MIME::Base64::decode_base64($_[0]);
}
sub _bytes2bi {
return Math::BigInt->new("0b" . unpack("B*", $_[0]));
}
sub _arg2bi {
return undef unless defined $_[0] and $_[0] ne "";
# don't acccept base-64 encoded numbers over 700 bytes. which means
# those over 4200 bits.
return Math::BigInt->new("0") if length($_[0]) > 700;
return _bytes2bi(MIME::Base64::decode_base64($_[0]));
}
# From Digest::HMAC
sub hmac_sha1_hex {
unpack("H*", &hmac_sha1);
}
sub hmac_sha1 {
hmac($_[0], $_[1], \&sha1, 64);
}
sub hmac {
my($data, $key, $hash_func, $block_size) = @_;
$block_size ||= 64;
$key = &$hash_func($key) if length($key) > $block_size;
my $k_ipad = $key ^ (chr(0x36) x $block_size);
my $k_opad = $key ^ (chr(0x5c) x $block_size);
&$hash_func($k_opad, &$hash_func($k_ipad, $data));
}