From cdc373563cb620068a6c436678bba3f276be015b Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 23 Mar 2022 12:08:18 +0100 Subject: add support for signing with ssh-keygen TODO: add tests --- pkg/signatures/ssh/ssh.go | 89 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 2 deletions(-) (limited to 'pkg/signatures/ssh') 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 } -- cgit v1.2.3