server/sigserver: delete old and unused sigserver

We can resurrect later. Or more likely: we'll support perkeepd
being configured (#1134) as only a signing server.

Change-Id: I19278e107baf02864c085421327392a6ffbb3364
This commit is contained in:
Brad Fitzpatrick 2018-05-01 13:58:38 -07:00
parent f5de76de22
commit 2f39adc517
18 changed files with 0 additions and 540 deletions

View File

@ -1,4 +0,0 @@
camsigd
sigserver
*.6
*.8

View File

@ -1,83 +0,0 @@
/*
Copyright 2011 The Perkeep Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// The sigserver is a stand-alone JSON signing and verification server.
//
// TODO(bradfitz): as of 2012-01-10 this is very old and superceded by
// the general server and pkg/serverconfig. We should just make it
// possible to configure a signing-only server with
// serverconfig/genconfig.go. I think we basically already can. Then
// we can delete this.
package main // import "perkeep.org/server/sigserver"
import (
"flag"
"fmt"
"log"
"net/http"
"perkeep.org/internal/httputil"
"perkeep.org/pkg/auth"
"perkeep.org/pkg/blob"
"perkeep.org/pkg/webserver"
)
var accessPassword string
var flagPubKeyDir = flag.String("pubkey-dir", "test/pubkey-blobs",
"Temporary development hack; directory to dig-xxxx.camli public keys.")
// TODO: for now, the only implementation of the blobref.Fetcher
// interface for fetching public keys is the "local, from disk"
// implementation used for testing. In reality we'd want to be able
// to fetch these from blobservers.
var pubKeyFetcher = blob.NewSimpleDirectoryFetcher(*flagPubKeyDir)
func handleRoot(conn http.ResponseWriter, req *http.Request) {
fmt.Fprintf(conn, "camsigd")
}
func handleCamliSig(conn http.ResponseWriter, req *http.Request) {
handler := func(conn http.ResponseWriter, req *http.Request) {
httputil.BadRequestError(conn, "Unsupported path or method.")
}
switch req.Method {
case "POST":
switch req.URL.Path {
case "/camli/sig/sign":
handler = auth.RequireAuth(handleSign, auth.OpSign)
case "/camli/sig/verify":
handler = handleVerify
}
}
handler(conn, req)
}
func main() {
flag.Parse()
mode, err := auth.FromEnv()
if err != nil {
log.Fatal(err)
}
auth.SetMode(mode)
ws := webserver.New()
ws.HandleFunc("/", handleRoot)
ws.HandleFunc("/camli/sig/", handleCamliSig)
ws.Serve()
}

View File

@ -1,50 +0,0 @@
#!/usr/bin/perl
use strict;
use LWP::UserAgent;
use HTTP::Request;
use HTTP::Request::Common;
use Getopt::Long;
my $keyid = "26F5ABDA";
my $server = "http://localhost:2856";
GetOptions("keyid=s" => \$keyid,
"server=s" => \$server)
or usage();
$server =~ s!/$!!;
my $file = shift or usage();
-f $file or usage("$file isn't a file");
my $json = do { undef $/; open(my $fh, $file); <$fh> };
sub usage {
my $err = shift;
if ($err) {
print STDERR "Error: $err\n";
}
print STDERR "Usage: client.pl [OPTS] <file.json>\n";
print STDERR "Options:\n";
print STDERR " --keyid=<keyid>\n";
print STDERR " --server=http://host:port\n";
exit(1);
}
my $req = POST("$server/camli/sig/sign",
"Authorization" => "Basic dGVzdDp0ZXN0", # test:test
Content => {
"json" => $json,
"keyid" => $keyid,
});
my $ua = LWP::UserAgent->new;
my $res = $ua->request($req);
unless ($res->is_success) {
die "Failure: " . $res->status_line . ": " . $res->content;
}
print $res->content;

View File

@ -1,4 +0,0 @@
#!/bin/sh
export CAMLI_PASSWORD=test
make && ./sigserver "$@"

View File

@ -1,55 +0,0 @@
/*
Copyright 2011 The Perkeep Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"net/http"
"perkeep.org/internal/httputil"
"perkeep.org/pkg/jsonsign"
)
const maxJSONLength = 1024 * 1024
func handleSign(conn http.ResponseWriter, req *http.Request) {
if !(req.Method == "POST" && req.URL.Path == "/camli/sig/sign") {
httputil.BadRequestError(conn, "Inconfigured handler.")
return
}
req.ParseForm()
jsonStr := req.FormValue("json")
if jsonStr == "" {
httputil.BadRequestError(conn, "Missing json parameter")
return
}
if len(jsonStr) > maxJSONLength {
httputil.BadRequestError(conn, "json parameter too large")
return
}
sreq := &jsonsign.SignRequest{UnsignedJSON: jsonStr, Fetcher: pubKeyFetcher}
signedJson, err := sreq.Sign()
if err != nil {
// TODO: some aren't really a "bad request"
httputil.BadRequestError(conn, fmt.Sprintf("%v", err))
return
}
conn.Write([]byte(signedJson))
}

View File

@ -1,44 +0,0 @@
Sign:
(https) POST /camli/sig/sign
WWW-Authenticate: [user] [b64pass]
json=[json to sign]
keyid=[GnuPG key id / implementation dependent]
On good response:
HTTP 200 OK
(signed blob)
else: (if signing fails)
HTTP 4xx/5xx
TODO(bslatkin): Should the sign response be a more specific value, so
we can tell the difference between a temporary server error and a signing
failure? For verification purposes we need that characteristic anyways.
---
Verify:
(https) POST /camli/sig/verify
sjson=[signed json to verify]
(proposed) keyarmored=[GnuPG armored key]
On good response:
HTTP 200 OK
YES
else: (if verification fails)
HTTP 200 OK
<any other message that describes the problem>
Verify will look in the object to find the "camliSigner" key and use that
blobref's contents (assumed to be a public key) to verify the signature on
the object. Configuring the signing server to have the public key blobref
is out of scope.

View File

@ -1,20 +0,0 @@
#!/usr/bin/perl
use strict;
use Test::More;
use FindBin;
use lib "$FindBin::Bin";
use CamsigdTest;
my $server = CamsigdTest::start();
ok($server, "Started the server") or BAIL_OUT("can't start the server");
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new("GET", $server->root . "/");
my $res = $ua->request($req);
ok($res, "got an HTTP response") or done_testing();
ok($res->is_success, "HTTP response is successful");
done_testing(3);

View File

@ -1,96 +0,0 @@
#!/usr/bin/perl
use strict;
use Test::More;
use FindBin;
use lib "$FindBin::Bin";
use CamsigdTest;
use JSON::Any;
use HTTP::Request::Common;
my $server = CamsigdTest::start();
ok($server, "Started the server") or BAIL_OUT("can't start the server");
my $ua = LWP::UserAgent->new;
use constant CAMLI_SIGNER => "sha1-82e6f3494f698aa498d5906349c0aa0a183d89a6";
my $j = JSON::Any->new;
my $json = $j->objToJson({ "camliVersion" => 1,
"camliSigner" => CAMLI_SIGNER,
"foo" => "bar",
});
# Sign it.
my $sjson;
{
my $req = req("sign", { "json" => $json });
my $res = $ua->request($req);
ok($res, "got an HTTP sig response") or done_testing();
ok($res->is_success, "HTTP sig response is successful") or done_testing();
$sjson = $res->content;
print "Got signed: $sjson";
like($sjson, qr/camliSig/, "contains camliSig substring");
my $sobj = $j->jsonToObj($sjson);
is($sobj->{"foo"}, "bar", "key foo is still bar");
is($sobj->{"camliVersion"}, 1, "key camliVersion is still 1");
ok(defined $sobj->{"camliSig"}, "has camliSig key");
ok(defined $sobj->{"camliSigner"}, "has camliSigner key");
is(scalar keys %$sobj, 4, "total of 3 keys in signed object");
}
# Verify it.
{
my $req = req("verify", { "sjson" => $sjson });
my $res = $ua->request($req);
ok($res, "got an HTTP verify response") or done_testing();
ok($res->is_success, "HTTP verify response is successful") or done_testing();
print "Verify response: " . $res->content;
my $vobj = $j->jsonToObj($res->content);
ok(defined($vobj->{'signatureValid'}), "has 'signatureValid' key");
ok($vobj->{'signatureValid'}, "signature is valid");
my $vdat = $vobj->{'verifiedData'};
ok(defined($vdat), "has verified data");
is($vdat->{'camliSigner'}, CAMLI_SIGNER, "signer matches");
is($vdat->{'foo'}, "bar")
}
# Verification that should fail.
{
my $req = req("verify", { "sjson" => "{}" });
my $res = $ua->request($req);
ok($res, "got an HTTP verify response") or done_testing();
ok($res->is_success, "HTTP verify response is successful") or done_testing();
print "Verify response: " . $res->content;
my $vobj = $j->jsonToObj($res->content);
ok(defined($vobj->{'signatureValid'}), "has 'signatureValid' key");
is(0, $vobj->{'signatureValid'}, "signature is properly invalid");
ok(!defined($vobj->{'verifiedData'}), "no verified data key");
ok(defined($vobj->{'errorMessage'}), "has an error message");
}
# Imposter! Verification should fail.
{
my $eviljson = q{{"camliVersion":1,"camliSigner":"sha1-82e6f3494f698aa498d5906349c0aa0a183d89a6","foo":"evilbar","camliSig":"iQEcBAABAgAGBQJM+tnUAAoJEIUeCLJL7Fq1ruwH/RplOpmrTK51etXUHayRGN0RM0Jxttjwa0pPuiHr7fJifaZo2pvMZOMAttjFEP/HMjvpSVi8P7awBFXXlCTj0CAlexsmCsPEHzITXe3siFzH+XCSmfHNPYYti0apQ2+OcWNnzqWXLiEfP5yRVXxcxoWuxYlnFu+mfw5VdjrJpIa+n3Ys5D4zUPVCSNtF4XV537czqfd9AiSfKCY/aL2NuZykl4WtP3JgYl8btE84EjNLFasQDstcWOvp7rrP6T8hQQotw5/F4SmmFM6ybkWXk/Wkax3XpzW9qL00VqhxHd4JIWaSzSV/WcSQwCoLWc7uXttOWgVtMIhzpjeMlqt1gc0==QYU2"}};
my $req = req("verify", { "sjson" => $eviljson });
my $res = $ua->request($req);
ok($res, "got an HTTP verify response") or done_testing();
ok($res->is_success, "HTTP verify response is successful") or done_testing();
print "Verify response: " . $res->content;
my $vobj = $j->jsonToObj($res->content);
ok(defined($vobj->{'signatureValid'}), "has 'signatureValid' key");
is(0, $vobj->{'signatureValid'}, "signature is properly invalid");
ok(!defined($vobj->{'verifiedData'}), "no verified data key");
ok(defined($vobj->{'errorMessage'}), "has an error message");
like($vobj->{'errorMessage'}, qr/bad signature: RSA verification error/, "verification error");
}
done_testing(29);
sub req {
my ($method, $post_params) = @_;
return POST($server->root . "/camli/sig/" . $method,
"Authorization" => "Basic dGVzdDp0ZXN0", # test:test
Content => $post_params);
}

View File

@ -1,78 +0,0 @@
#!/usr/bin/perl
#
# Common test library for camsigd (sigserver)
package CamsigdTest;
use strict;
use Test::More;
use FindBin;
use LWP::UserAgent;
use HTTP::Request;
use Fcntl;
our $BINARY = "$FindBin::Bin/../sigserver";
sub start {
my ($port_rd, $port_wr, $exit_rd, $exit_wr);
my $flags;
pipe $port_rd, $port_wr;
pipe $exit_rd, $exit_wr;
$flags = fcntl($port_wr, F_GETFD, 0);
fcntl($port_wr, F_SETFD, $flags & ~FD_CLOEXEC);
$flags = fcntl($exit_rd, F_GETFD, 0);
fcntl($exit_rd, F_SETFD, $flags & ~FD_CLOEXEC);
$ENV{TESTING_PORT_WRITE_FD} = fileno($port_wr);
$ENV{TESTING_CONTROL_READ_FD} = fileno($exit_rd);
$ENV{CAMLI_PASSWORD} = "test";
die "Binary $BINARY doesn't exist\n" unless -x $BINARY;
my $pid = fork;
die "Failed to fork" unless defined($pid);
if ($pid == 0) {
# child
exec $BINARY, "-listen=:0";
die "failed to exec: $!\n";
}
close($exit_rd); # child owns this side
close($port_wr); # child owns this side
print "Waiting for server to start...\n";
my $line = <$port_rd>;
close($port_rd);
# Parse the port line out
chomp $line;
# print "Got port line: $line\n";
die "Failed to start, no port info." unless $line =~ /:(\d+)$/;
my $port = $1;
return CamsigdTest::Server->new($pid, $port, $exit_wr);
}
package CamsigdTest::Server;
sub new {
my ($class, $pid, $port, $pipe_writer) = @_;
return bless {
pid => $pid,
port => $port,
pipe_writer => $pipe_writer,
};
}
sub DESTROY {
my $self = shift;
my $pipe = $self->{pipe_writer};
syswrite($pipe, "EXIT\n", 5);
}
sub root {
my $self = shift;
return "http://localhost:$self->{port}";
}
1;

View File

@ -1 +0,0 @@
{"camliVersion":1,"foo":"bar"

View File

@ -1,30 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.10 (GNU/Linux)
mQENBEzgoVsBCAC/56aEJ9BNIGV9FVP+WzenTAkg12k86YqlwJVAB/VwdMlyXxvi
bCT1RVRfnYxscs14LLfcMWF3zMucw16mLlJCBSLvbZ0jn4h+/8vK5WuAdjw2YzLs
WtBcjWn3lV6tb4RJz5gtD/o1w8VWxwAnAVIWZntKAWmkcChCRgdUeWso76+plxE5
aRYBJqdT1mctGqNEISd/WYPMgwnWXQsVi3x4z1dYu2tD9uO1dkAff12z1kyZQIBQ
rexKYRRRh9IKAayD4kgS0wdlULjBU98aeEaMz1ckuB46DX3lAYqmmTEL/Rl9cOI0
Enpn/oOOfYFa5h0AFndZd1blMvruXfdAobjVABEBAAG0JUNhbWxpIFRlc3RlciA8
Y2FtbGktdGVzdEBleGFtcGxlLmNvbT6JATgEEwECACIFAkzgoVsCGwMGCwkIBwMC
BhUIAgkKCwQWAgMBAh4BAheAAAoJECkxpnwm9avaHE0IAJ/pMZgiURl3kefrFMAV
7ei0XDfTekZOwDRcZWTVQ/A97phpzO8t78qLYbFeHuq3myNhrlVO9Gyp+2V904rN
dudoHLhpegf5TNeHGmAGHBxcooMPMp0JyIDnUBxtCNGxgWfbKpEDRsQAjkCc7sR0
H+OegzlEf6JZGzEhV5ohOioTsC1DmJNoQsRz5Kes7sLoAzpQCbCv4yv+1o+mnzgW
9qPJXKxcScc0t2YTvcvpJ7LV8no1OP6vpYqB1A9Pzze6XFBlcXOUKbRKk0fEIV/u
pU3ph1fF7wlyRgA4A3iPwDC4BgVmHYkz9nYPn+7IcT/dDig5SWU+n7WZgGeyv75y
0Ue5AQ0ETOChWwEIALuHxKI+oSH+eeMSXhxcSUXnhp4cUeyvOV7oNPYcmsDclF0Y
7y8NrSPiEZod9vSTEDMq7hd3BG+feCBqjgR4qtmoXguJhWcnJqDBk5iAMuuAph9O
CC8QLACMJPhoxQ0UtDPKlpG4X8kLK1woHd716ulPl2KLjTgd6K4kCGj+CV5Ekn6u
IJj+3IPbYDOwk1l06ksimwQAY4dA1CXOTviH1bVqR6CzuzVPg4hcryWDva1rEO5c
LcOR8Wk/thANFLSNjqX8UgtGXhFZRWxKetFDQiX5f2BKoqTVYvD3pqt+zzyLNFAz
xhMc3cyFfqM8yQdzdEey/DIWtMoDqZCSVMJ63N8AEQEAAYkBHwQYAQIACQUCTOCh
WwIbDAAKCRApMaZ8JvWr2mHACACkco+fAfRK+gmprF2m8E0Bp1frwFH0g4RJVHXQ
BUDbg7OZbWumzD4Br28si6XDVMP6fLOeyD0EHYb6LhAHDkBLqx6e3kKG1mQ8fMIV
O4YMQfskYH2FJqlCtgMnM8N3oslPBTpZedNPSUq7HJh2pKr9GIDi1V+Hgc/qEigE
dj9f2zSSaKZdC4eL73GvlQOh+4XqgaMnMiKfI+/2WlRaJs1KOgKmIp5yHt0qY0ef
y+40BY/z9pMjyUvr/Wwp8KXArw0NAwzp8NUl5fNxRg9XWQWLn6hW8ydR20X3t2ym
iNSWzNQiTT6k7fumOABCoSZsow/AJxQSxqKOJBjgpKjIKCgY
=ru0J
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,6 +0,0 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
iQEcBAABAgAGBQJM9KDoAAoJECkxpnwm9avabeYH/2+Rm1FjSDKIxUlF+RCvaKWYflJuCtazJTWezud3CL+q2DSWEl8o7z6TUDB15w8nzRlLDEXqqGYPec76eyoyh4R98A2oxmms1nJY1HFXWN4LFUcinOBnM175f5qyiFr0c64sSMaBt21Qkt6Ncecg7NpTyl31Uz3JmlG7SZRm5yL08shbNR0AvTSnwUAwyWiy+v9qwvK3VoAxA2CXgJDTudEjf8MoMna0MmF43hWSdqGkqVao5rJtpru+iMHXkaqrgX24go1PRwVOyz6mJdgkqnYMqGinYAw+w05s09wfpQ/xLEuCCYfehtLGcSPEPkfFD701hgo/9OR1w+hdrrFKSNo=
=Nzxs
-----END PGP SIGNATURE-----

View File

@ -1,5 +0,0 @@
{
"foo": "bar",
"blah": "baz" }

View File

@ -1,64 +0,0 @@
/*
Copyright 2011 The Perkeep Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
/*
$ gpg --no-default-keyring --keyring=/tmp/foo --import --armor test/pubkey-blobs/sha1-82e6f3494f69
$ gpg --no-default-keyring --keyring=/tmp/foo --verify sig.tmp doc.tmp ; echo $?
gpg: Signature made Mon 29 Nov 2010 10:59:52 PM PST using RSA key ID 26F5ABDA
gpg: Good signature from "Camli Tester <camli-test@example.com>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: FBB8 9AA3 20A2 806F E497 C049 2931 A67C 26F5 ABDA0
*/
import (
"net/http"
"perkeep.org/internal/httputil"
"perkeep.org/pkg/jsonsign"
)
func handleVerify(conn http.ResponseWriter, req *http.Request) {
if !(req.Method == "POST" && req.URL.Path == "/camli/sig/verify") {
httputil.BadRequestError(conn, "Inconfigured handler.")
return
}
req.ParseForm()
sjson := req.FormValue("sjson")
if sjson == "" {
httputil.BadRequestError(conn, "Missing sjson parameter.")
return
}
m := make(map[string]interface{})
vreq := jsonsign.NewVerificationRequest(sjson, pubKeyFetcher)
if vreq.Verify() {
m["signatureValid"] = 1
m["verifiedData"] = vreq.PayloadMap
} else {
m["signatureValid"] = 0
m["errorMessage"] = vreq.Err.Error()
}
conn.WriteHeader(http.StatusOK) // no HTTP response code fun, error info in JSON
httputil.ReturnJSON(conn, m)
}