55 lines
1.1 KiB
Go
55 lines
1.1 KiB
Go
package changeset
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
// Metadata is the metadata for the changeset.
|
|
type Metadata struct {
|
|
// The name of the service
|
|
Name string
|
|
// The git hash of the repo checkout that made the service
|
|
Version string
|
|
// Slug SHA256 hash, this is what is signed
|
|
Hash []byte
|
|
// The SSH signatures for this ChangeSet
|
|
Signatures []*ssh.Signature
|
|
}
|
|
|
|
type ChangeSet struct {
|
|
Metadata Metadata
|
|
SlugFile string
|
|
}
|
|
|
|
func (cs ChangeSet) Validate(trustedKeys []ssh.PublicKey, minNeeded int) error {
|
|
var gotKeys = map[string]struct{}{}
|
|
for _, sig := range cs.Metadata.Signatures {
|
|
for _, pubkey := range trustedKeys {
|
|
fp := ssh.FingerprintSHA256(pubkey)
|
|
|
|
if _, got := gotKeys[fp]; got {
|
|
return fmt.Errorf("changeset: %v signed this changeset more than once", fp)
|
|
}
|
|
|
|
if fp != string(sig.Rest) {
|
|
continue
|
|
}
|
|
|
|
err := pubkey.Verify(cs.Metadata.Hash, sig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
gotKeys[fp] = struct{}{}
|
|
}
|
|
}
|
|
|
|
if gk := len(gotKeys); gk != minNeeded {
|
|
return fmt.Errorf("wanted %d keys, only signed with %d keys", minNeeded, gk)
|
|
}
|
|
|
|
return nil
|
|
}
|