Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check notary server gives back expired keys as a fallback #620

Merged
merged 1 commit into from
Jun 4, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 139 additions & 35 deletions tests/50federation/01keys.pl
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,103 @@ sub key_query_via_post {
};
}

test "Key notary server should return an expired key if it can't find any others",
requires => [ $main::HOMESERVER_INFO[0], $main::OUTBOUND_CLIENT, $main::TEST_SERVER_INFO ],

do => sub {
my ( $notary_server, $http_client, $http_server ) = @_;
my $test_server_name = $http_server->server_name;

my ( $pkey, $skey ) = Crypt::NaCl::Sodium->sign->keypair;
my $key_id = "ed25519:key_0";
my $key_expiry = ( time - 86400 ) * 1000; # -24h in msec
my $key_response = build_key_response(
server_name => $test_server_name,
key => $skey,
key_id => $key_id,
valid_until_ts => $key_expiry,
);

# start with a regular request, to populate the notary db
Future->needs_all(
key_query_via_post(
$http_client, $notary_server, $test_server_name, $key_id,
)->then( sub {
my ( $body ) = @_;
log_if_fail "Notary response for request 1", $body;
Future->done(1);
}),

await_http_request(
qr#^/_matrix/key/v2/server#, sub { 1 }
)->then( sub {
my ( $request ) = @_;

log_if_fail "Request 1 from notary server: " . $request->method . " " . $request->path;

$request->respond_json( $key_response );
Future->done(1);
}),
)->then( sub {
# now make a second request, with a later min_valid_until_ts, to force a re-fetch,
# but give the same response back.
Future->needs_all(
key_query_via_post(
$http_client, $notary_server, $test_server_name, $key_id,
min_valid_until_ts => $key_expiry + 1000,
)->then( sub {
my ( $body ) = @_;
log_if_fail "Notary response for request 2", $body;

my $res = $body->{server_keys}[0];
assert_eq( $res->{server_name}, $test_server_name, "server_name" );
assert_json_keys( $res->{verify_keys}, ( $key_id ));
assert_eq( $res->{valid_until_ts}, $key_expiry, "validity ts" );
Future->done(1);
}),

await_http_request(
qr#^/_matrix/key/v2/server#, sub { 1 }
)->then( sub {
my ( $request ) = @_;

log_if_fail "Request 2 from notary server: " . $request->method . " " . $request->path;

$request->respond_json( $key_response );
Future->done(1);
}),
);
})->then( sub {
# finally, make another request, and 400 the request from the notary server.
Future->needs_all(
key_query_via_post(
$http_client, $notary_server, $test_server_name, $key_id,
min_valid_until_ts => $key_expiry + 1000,
)->then( sub {
my ( $body ) = @_;
log_if_fail "Notary response for request 3", $body;

my $res = $body->{server_keys}[0];
assert_eq( $res->{server_name}, $test_server_name, "server_name" );
assert_json_keys( $res->{verify_keys}, ( $key_id ));
assert_eq( $res->{valid_until_ts}, $key_expiry, "validity ts" );
Future->done(1);
}),

await_http_request(
qr#^/_matrix/key/v2/server#, sub { 1 }
)->then( sub {
my ( $request ) = @_;

log_if_fail "Request 3 from notary server: " . $request->method . " " . $request->path;

$request->respond_json( {}, code=>400 );
Future->done(1);
}),
);
});
};

# regression test for https://github.com/matrix-org/synapse/issues/5305
test "Key notary server must not overwrite a valid key with a spurious result from the origin server",
requires => [ $main::HOMESERVER_INFO[0], $main::OUTBOUND_CLIENT, $main::TEST_SERVER_INFO ],
Expand All @@ -187,9 +284,6 @@ sub key_query_via_post {
my $key_id_1 = "ed25519:key_1";
my $key1_expiry = ( time - 86400 ) * 1000; # -24h in msec

my ( $pkey2, $skey2 ) = Crypt::NaCl::Sodium->sign->keypair;
my $key_id_2 = "ed25519:key_2";

# start with a request for key 1
Future->needs_all(
await_http_request(
Expand All @@ -199,24 +293,12 @@ sub key_query_via_post {

log_if_fail "Request 1 from notary server: " . $request->method . " " . $request->path;

my $key_response1 = {
$request->respond_json( build_key_response(
server_name => $test_server_name,
valid_until_ts => $key1_expiry,
verify_keys => {
$key_id_1 => {
key => encode_base64_unpadded( $pkey1 ),
},
},
old_verify_keys => {},
};
sign_json(
$key_response1,
secret_key => $skey1,
origin => $test_server_name,
key => $skey1,
key_id => $key_id_1,
);

$request->respond_json( $key_response1 );
valid_until_ts => $key1_expiry,
));
Future->done(1);
}),

Expand All @@ -242,24 +324,14 @@ sub key_query_via_post {

log_if_fail "Request 2 from notary server: " . $request->method . " " . $request->path;

my $key_response2 = {
my ( $pkey2, $skey2 ) = Crypt::NaCl::Sodium->sign->keypair;
$request->respond_json( build_key_response(
server_name => $test_server_name,
key => $skey2,
key_id => "ed25519:key_2",
valid_until_ts => $key1_expiry + 1000,
verify_keys => {
$key_id_2 => {
key => encode_base64_unpadded( $pkey2 ),
},
},
old_verify_keys => {},
};
sign_json(
$key_response2,
secret_key => $skey2,
origin => $test_server_name,
key_id => $key_id_2,
);

$request->respond_json( $key_response2 );
));

Future->done(1);
}),

Expand Down Expand Up @@ -289,3 +361,35 @@ sub key_query_via_post {
});
});
};


sub build_key_response {
my ( %params ) = @_;

my $server_name = $params{server_name};
my $key_id = $params{key_id};
my $skey = $params{key};
my $expiry = $params{valid_until_ts};

my $pkey = Crypt::NaCl::Sodium->sign->public_key( $skey );

my $response = {
server_name => $server_name,
valid_until_ts => $expiry,
verify_keys => {
$key_id => {
key => encode_base64_unpadded( $pkey ),
},
},
old_verify_keys => {},
};

sign_json(
$response,
secret_key => $skey,
origin => $server_name,
key_id => $key_id,
);

return $response;
}