package signify import ( "bytes" "encoding/base64" "fmt" "io" "io/ioutil" "git.sigsum.org/sigsum-go/pkg/types" ) type Parser struct{} func (p *Parser) SignatureSuffix() string { return ".sig" } func (p *Parser) PublicKey(r io.Reader) (*types.PublicKey, error) { b, err := ioutil.ReadAll(r) if err != nil { return nil, fmt.Errorf("signify: read failed: %v", err) } var pub types.PublicKey if err := parse(pub[:], b); err != nil { return nil, fmt.Errorf("signify: %v", err) } return &pub, nil } func (p *Parser) Signature(r io.Reader) (*types.Signature, error) { b, err := ioutil.ReadAll(r) if err != nil { return nil, fmt.Errorf("signify: read failed: %v", err) } var sig types.Signature if err := parse(sig[:], b); err != nil { return nil, fmt.Errorf("signify: %v", err) } return &sig, nil } func parse(dst, lines []byte) error { commentLine, dataLine, err := parseLines(lines) if err != nil { return fmt.Errorf("invalid: %v", err) } if err := parseCommentLine(commentLine); err != nil { return fmt.Errorf("invalid: %v", err) } if err := parseDataLine(dst, dataLine); err != nil { return fmt.Errorf("invalid: %v", err) } return nil } func parseLines(lines []byte) ([]byte, []byte, error) { split := bytes.Split(lines, []byte("\n")) if len(split) != 3 { return nil, nil, fmt.Errorf("number of lines") } return split[0], split[1], nil } func parseCommentLine(line []byte) error { if !bytes.HasPrefix(line, []byte("untrusted comment: ")) { return fmt.Errorf("no untrusted comment") } return nil } func parseDataLine(dst, line []byte) error { data, err := base64.StdEncoding.DecodeString(string(line)) if err != nil { return fmt.Errorf("base64 encoding") } if len(data) < 2 || !bytes.Equal(data[:2], []byte("Ed")) { return fmt.Errorf("algorithm") } data = data[2:] if len(data) < 8 { return fmt.Errorf("random fingerprint") } data = data[8:] if len(data) != len(dst) { return fmt.Errorf("data length") } copy(dst[:], data) return nil }