aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRasmus Dahlberg <rasmus@mullvad.net>2022-04-13 15:07:34 +0200
committerRasmus Dahlberg <rasmus@mullvad.net>2022-04-13 15:07:34 +0200
commitd86d2433e0da077063bb21dc7c29d491c6fe862f (patch)
tree5f760e33f25bfea5fca3fcb7c9f1f43d79dc99d9
parent468b097a63c52fbf851c4cc99d8b716a13c19aa9 (diff)
parentee322c9e18b9675aab08f4c9f38f6be19b1d6890 (diff)
Merge branch 'sshsig' into main
-rw-r--r--cmd/sigsum/cmd.go23
-rw-r--r--cmd/sigsum/test/keys/ssh7
-rw-r--r--cmd/sigsum/test/keys/ssh.pub1
-rwxr-xr-xcmd/sigsum/test/ssh.sh53
-rw-r--r--go.mod5
-rw-r--r--go.sum13
-rw-r--r--pkg/client/submitter.go2
-rw-r--r--pkg/signatures/ssh/ssh.go89
8 files changed, 179 insertions, 14 deletions
diff --git a/cmd/sigsum/cmd.go b/cmd/sigsum/cmd.go
index 01c1223..c57d9e3 100644
--- a/cmd/sigsum/cmd.go
+++ b/cmd/sigsum/cmd.go
@@ -50,7 +50,7 @@ func cmdBundle(args []string, policy policy.Policy, optBundleType, optBundleKey,
var reqs []requests.Leaf
for _, path := range args {
- checksum, err := fileHash(path)
+ preimage, err := fileHash(path)
if err != nil {
return fmt.Errorf("bundle: %v", err)
}
@@ -66,15 +66,18 @@ func cmdBundle(args []string, policy policy.Policy, optBundleType, optBundleKey,
}
req := requests.Leaf{
- Statement: types.Statement{
- ShardHint: policy.ShardHint(),
- Checksum: *checksum,
- },
+ ShardHint: policy.ShardHint(),
+ Preimage: *preimage,
Signature: *sig,
VerificationKey: *pub,
DomainHint: optBundleDomainHint,
}
- if !req.Statement.Verify(&req.VerificationKey, &req.Signature) {
+
+ sd := types.Statement{
+ ShardHint: req.ShardHint,
+ Checksum: *types.HashFn(req.Preimage[:]),
+ }
+ if !sd.Verify(&req.VerificationKey, &req.Signature) {
return fmt.Errorf("bundle: invalid signature for file %q", path)
}
reqs = append(reqs, req)
@@ -99,16 +102,16 @@ func cmdFormat(args []string, policy policy.Policy) error {
return fmt.Errorf("format: need exactly one file")
}
- checksum, err := fileHash(args[0])
+ preimage, err := fileHash(args[0])
if err != nil {
return fmt.Errorf("format: %v", err)
}
- stm := types.Statement{
+ sd := types.Statement{
ShardHint: policy.ShardHint(),
- Checksum: *checksum,
+ Checksum: *types.HashFn(preimage[:]),
}
- fmt.Printf("%s", stm.ToBinary())
+ fmt.Printf("%s", sd.ToBinary())
return nil
}
diff --git a/cmd/sigsum/test/keys/ssh b/cmd/sigsum/test/keys/ssh
new file mode 100644
index 0000000..2bbd974
--- /dev/null
+++ b/cmd/sigsum/test/keys/ssh
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACC/0wdPezO/W1upVq2RduQ/ieEHn0r6LgwkXEINfJ52fQAAAJCRqZKpkamS
+qQAAAAtzc2gtZWQyNTUxOQAAACC/0wdPezO/W1upVq2RduQ/ieEHn0r6LgwkXEINfJ52fQ
+AAAEClIbTUqSPBTrfD9MCpwTF1Fwit4NXU2ci3R57uq4Aic7/TB097M79bW6lWrZF25D+J
+4QefSvouDCRcQg18nnZ9AAAACmxpbnVzQGJlc2sBAgM=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/cmd/sigsum/test/keys/ssh.pub b/cmd/sigsum/test/keys/ssh.pub
new file mode 100644
index 0000000..14588ac
--- /dev/null
+++ b/cmd/sigsum/test/keys/ssh.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/TB097M79bW6lWrZF25D+J4QefSvouDCRcQg18nnZ9 linus@besk
diff --git a/cmd/sigsum/test/ssh.sh b/cmd/sigsum/test/ssh.sh
new file mode 100755
index 0000000..56cae70
--- /dev/null
+++ b/cmd/sigsum/test/ssh.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+set -eu
+trap cleanup EXIT
+
+priv=keys/ssh
+pub=keys/ssh.pub
+domain_hint=_sigsum_v0.ssh.test.sigsum.org
+msg=msg-$(date +%s)
+num_msg=3
+
+function cleanup() {
+ set +e
+
+ rm -f sigsum
+ for i in $(seq 1 $num_msg); do
+ rm -f $msg-$i{,.trunnel,.sig}
+ done
+
+ exit
+}
+
+go build ../
+
+files=""
+for i in $(seq 1 $num_msg); do
+ echo $msg-$i > $msg-$i
+ if ! openssl dgst -binary $msg-$i | ssh-keygen \
+ -Y sign \
+ -O hashalg=sha256 \
+ -f $priv \
+ -n $(./sigsum namespace) > $msg-$i.sig ; then
+ echo "[FAIL] sign for $num_msg ssh message(s)" >&2
+ exit 1
+ fi
+ files=$(echo -n $files $msg-$i)
+done
+
+echo "[PASS] sign for $num_msg ssh message(s)" >&2
+
+if ! ./sigsum bundle -t ssh -k $pub -d $domain_hint $files; then
+ echo "[FAIL] bundle for $num_msg ssh message(s)" >&2
+ exit 1
+fi
+
+echo "[PASS] bundle for $num_msg ssh message(s)" >&2
+
+if ! ./sigsum verify -t ssh -k $pub $files; then
+ echo "[FAIL] verify for $num_msg ssh message(s)" >&2
+ exit 1
+fi
+
+echo "[PASS] verify for $num_msg ssh message(s)" >&2
diff --git a/go.mod b/go.mod
index 942ca74..4328384 100644
--- a/go.mod
+++ b/go.mod
@@ -2,4 +2,7 @@ module git.sigsum.org/sigsum-tools-go
go 1.15
-require git.sigsum.org/sigsum-lib-go v0.0.2
+require (
+ git.sigsum.org/sigsum-lib-go v0.0.3
+ golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
+)
diff --git a/go.sum b/go.sum
index 03ffc2d..d21009f 100644
--- a/go.sum
+++ b/go.sum
@@ -1,2 +1,15 @@
git.sigsum.org/sigsum-lib-go v0.0.2 h1:1FwdnraPaasw1D1Lb+flRMJRGLTuZrp17AZ6tx+iT/0=
git.sigsum.org/sigsum-lib-go v0.0.2/go.mod h1:DVmlcf0MBHy4IZdnZ5DcbsKkGEd0EkOAoLINhLgcndY=
+git.sigsum.org/sigsum-lib-go v0.0.3 h1:VXtUC/LOPVb990P8dFitQkYx8a1M54hKFcsK7MiZ514=
+git.sigsum.org/sigsum-lib-go v0.0.3/go.mod h1:DVmlcf0MBHy4IZdnZ5DcbsKkGEd0EkOAoLINhLgcndY=
+golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s=
+golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/pkg/client/submitter.go b/pkg/client/submitter.go
index 412890f..287bac3 100644
--- a/pkg/client/submitter.go
+++ b/pkg/client/submitter.go
@@ -75,7 +75,7 @@ func (sc *SubmitClient) AddLeaves(_ context.Context, leaves []requests.Leaf) ([]
l := types.Leaf{
Statement: types.Statement{
ShardHint: leaf.ShardHint,
- Checksum: leaf.Checksum,
+ Checksum: *types.HashFn(leaf.Preimage[:]),
},
Signature: leaf.Signature,
KeyHash: *types.HashFn(leaf.VerificationKey[:]),
diff --git a/pkg/signatures/ssh/ssh.go b/pkg/signatures/ssh/ssh.go
index d5fb8f4..99b2a48 100644
--- a/pkg/signatures/ssh/ssh.go
+++ b/pkg/signatures/ssh/ssh.go
@@ -3,20 +3,105 @@ package ssh
import (
"fmt"
"io"
+ "io/ioutil"
+ "encoding/pem"
+ sshLib "golang.org/x/crypto/ssh"
"git.sigsum.org/sigsum-lib-go/pkg/types"
)
type Parser struct{}
+const (
+ BLOB_PREAMBLE = "SSHSIG"
+ SIG_VERSION = 0x01
+ HASH_ALGO = "sha256"
+)
+
+type sshBlob struct {
+ MagicPreamble [6]byte
+ SigVersion uint32
+ PublicKey string
+ Namespace string
+ Reserved string
+ HashAlgorithm string
+ Signature string
+}
+
+type sshKeypart struct {
+ Type string
+ Key string
+}
+
func (p *Parser) SignatureSuffix() string {
return ".sig"
}
func (p *Parser) PublicKey(r io.Reader) (*types.PublicKey, error) {
- return nil, fmt.Errorf("TODO")
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ return nil, fmt.Errorf("ssh: read failed: %v", err)
+ }
+ var pub types.PublicKey
+ if err := parsePub(pub[:], b); err != nil {
+ return nil, fmt.Errorf("ssh: %v", err)
+ }
+ return &pub, nil
}
func (p *Parser) Signature(r io.Reader) (*types.Signature, error) {
- return nil, fmt.Errorf("TODO")
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ return nil, fmt.Errorf("ssh: signature read failed: %v", err)
+ }
+
+ block, rest := pem.Decode(b)
+ if len(rest) > 0 {
+ return nil, fmt.Errorf("ssh: invalid signature rest: %v", rest)
+ }
+ if block == nil {
+ return nil, fmt.Errorf("ssh: invalid signature PEM format")
+ }
+ if block.Type != "SSH SIGNATURE" {
+ return nil, fmt.Errorf("ssh: invalid signature PEM type: %v", block.Type)
+ }
+
+ var blob sshBlob
+ if err := sshLib.Unmarshal(block.Bytes, &blob); err != nil {
+ return nil, fmt.Errorf("ssh: invalid signature format: %v", err)
+ }
+ if string(blob.MagicPreamble[:]) != BLOB_PREAMBLE {
+ return nil, fmt.Errorf("ssh: invalid signature magic: %s", string(blob.MagicPreamble[:]))
+ }
+ if blob.SigVersion != SIG_VERSION {
+ return nil, fmt.Errorf("ssh: invalid signature version: %d", blob.SigVersion)
+ }
+ if blob.HashAlgorithm != HASH_ALGO {
+ return nil, fmt.Errorf("ssh: invalid signature hash algorithm: %s", blob.HashAlgorithm)
+ }
+
+ var sshSig sshLib.Signature
+ if err := sshLib.Unmarshal([]byte(blob.Signature), &sshSig); err != nil {
+ return nil, fmt.Errorf("ssh: invalid signature blob: %v", err)
+ }
+
+ var sig types.Signature
+ copy(sig[:], sshSig.Blob)
+
+ return &sig, nil
+}
+
+func parsePub(dst, data []byte) error {
+ pubkey, _, _, _, err := sshLib.ParseAuthorizedKey(data)
+ if err != nil {
+ return fmt.Errorf("ssh.ParseAuthorizedKey: %s", err)
+ }
+
+ var keyPart sshKeypart
+ if err := sshLib.Unmarshal(pubkey.Marshal(), &keyPart); err != nil {
+ return fmt.Errorf("ssh: invalid pubkey: %v", err)
+ }
+
+ copy(dst[:], keyPart.Key)
+ return nil
}