Skip to content

Commit

Permalink
[backend] Add BSRekor module to implement uploading signatures to a r…
Browse files Browse the repository at this point in the history
  • Loading branch information
mlschroe committed Jan 19, 2022
1 parent 911d218 commit 45af724
Showing 1 changed file with 138 additions and 0 deletions.
138 changes: 138 additions & 0 deletions src/backend/BSRekor.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#
# Copyright (c) 2022 SUSE Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program (see the file COPYING); if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
################################################################
#
# Sigstore rekor support
#

package BSRekor;

use strict;

use JSON::XS ();
use MIME::Base64 ();

use BSRPC ':https';
use BSConfiguration;

our $intoto_slsav1 = "https://slsa.dev/provenance/v0.1";
our $intoto_spdx = "https://spdx.dev/Document";
our $intoto_linkv1= "https://in-toto.io/Link/v1";
our $intoto_cosignv1 = "cosign.sigstore.dev/attestation/v1";

sub canonical_json {
my ($d) = @_;
return JSON::XS->new->utf8->canonical->encode($d);
}

sub mime_encode {
my ($d) = @_;
return MIME::Base64::encode_base64($d, '');
}

sub dsse_pae {
my ($type, $payload) = @_;
return sprintf("DSSEv1 %d %s %d ", length($type), $type, length($payload))."$payload";
}

sub upload_entry {
my ($server, $entry) = @_;
my $replyheaders;
my $param = {
'uri' => "$server/api/v1/log/entries",
'request' => 'POST',
'timeout' => 300,
'data' => canonical_json($entry),
'headers' => [ 'Content-Type: application/json' ],
'replyheaders' => \$replyheaders,
'ignorestatus' => 1,
};
my $r = BSRPC::rpc($param);
my $st = $replyheaders->{'status'};
if ($st !~ /^201|409/) {
my $msg = eval { (JSON::XS::decode_json($r) || {})->{'message'} };
die("rekor server: $st ($msg)\n") if $msg;
die("rekor server: $st\n");
}
# entry created or already exists
my $l = $replyheaders->{'location'};
die("rekor server did not return a location\n") unless $l;
$l =~ s/.*\///;
return $l;
# new: {"84f4192f5c38c9eb0973dae7bdd24e0ad6781d9e228b4ee60f411ea0e1050482":{"body":"...","integratedTime":1638195094,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d","logIndex":897532,"verification":{"signedEntryTimestamp":"MEQCIDd8LwH1lbeUfCjwRoX5J7fzZ5qIK4PwMsf+sHJHgCCTAiB1h1nD0OjeleiBph8UtlZMTwlpNLq3cSaZ0Oxc8Gom0A=="}}}
}

sub upload_rekord {
my ($server, $content, $pubkey, $signature, $sigformat) = @_;
my $sig = {
'format' => $sigformat,
'content' => mime_encode($signature),
'publicKey' => { 'content' => mime_encode($pubkey) },
};
my $spec = {
'data' => { 'content' => mime_encode($content) },
'signature' => $sig,
};
my $entry = {
'kind' => 'rekord',
'apiVersion' => '0.0.1',
'spec' => $spec,
};
return upload_entry($server, $entry);
}

sub upload_hashedrekord {
my ($server, $hash, $pubkey, $signature) = @_;
die("bad hash $hash\n") unless $hash =~ /^(.+?):([0-9a-f]+)$/;
my ($hashalgo, $hashvalue) = ($1, $2);
my $sig = {
'content' => mime_encode($signature),
'publicKey' => { 'content' => mime_encode($pubkey) },
};
my $spec = {
'data' => { 'hash' => { 'algorithm' => $hashalgo, 'value' => $hashvalue } },
'signature' => $sig,
};
my $entry = {
'kind' => 'hashedrekord',
'apiVersion' => '0.0.1',
'spec' => $spec,
};
return upload_entry($server, $entry);
}

sub upload_intoto {
my ($server, $pubkey, $payloadtype, $payload, $signature) = @_;
my $envelope = {
'payload' => mime_encode($payload),
'payloadType' => $payloadtype,
'signatures' => [ { 'sig' => mime_encode($signature) } ],
};
my $spec = {
'publicKey' => mime_encode($pubkey),
'content' => { 'envelope' => canonical_json($envelope) },
};
my $entry = {
'kind' => 'intoto',
'apiVersion' => '0.0.1',
'spec' => $spec,
};
return upload_entry($server, $entry);
}

1;

0 comments on commit 45af724

Please sign in to comment.