...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package starman
18
19 import (
20 "archive/tar"
21 "crypto"
22 "crypto/hmac"
23 "encoding/hex"
24 "encoding/json"
25 "fmt"
26 "io"
27 "os"
28 "strings"
29 )
30
31 type TarMD struct {
32 Name string `json:"name"`
33 Arch string `json:"arch"`
34 Version Version `json:"version"`
35 Files []File `json:"files"`
36 FileCheckSumType string `json:"file_checksum_type"`
37 }
38
39 type Version struct {
40 Epoch string `json:"epoch"`
41 Version string `json:"version"`
42 Release string `json:"release"`
43 }
44
45 type File struct {
46 Name string `json:"name"`
47 Size int64 `json:"size"`
48 Mode int `json:"mode"`
49 Mtime int `json:"mtime"`
50 Digest string `json:"digest"`
51 Flags int `json:"flags"`
52 UserName string `json:"username"`
53 GroupName string `json:"groupname"`
54 }
55
56 var hashMap = map[string]crypto.Hash{
57 "md5": crypto.MD5,
58 "sha1": crypto.SHA1,
59 "sha224": crypto.SHA224,
60 "sha256": crypto.SHA256,
61 "sha384": crypto.SHA384,
62 "sha512": crypto.SHA512,
63 }
64
65 func (i *starmanInfo) verifyFiles(tr *tar.Reader) error {
66 if err := json.Unmarshal(i.mdblob, &i.md); err != nil {
67 return err
68 }
69 md := &i.md
70 hash := hashMap[md.FileCheckSumType]
71 if !hash.Available() {
72 return fmt.Errorf("unknown digest type %s", md.FileCheckSumType)
73 } else if hash < crypto.SHA224 {
74 return fmt.Errorf("digest type %s is too weak", md.FileCheckSumType)
75 }
76 filemap := make(map[string]*File, len(md.Files))
77 for i := range md.Files {
78 filemd := &md.Files[i]
79 filemap[filemd.Name] = filemd
80 }
81 for {
82 hdr, err := tr.Next()
83 if err == io.EOF {
84 break
85 } else if err != nil {
86 return err
87 }
88 name := strings.TrimLeft(hdr.Name, ".")
89 filemd := filemap[name]
90 if filemd == nil {
91 return fmt.Errorf("file %s is missing from metadata", name)
92 }
93 delete(filemap, name)
94
95 if hdr.Typeflag == tar.TypeLink {
96
97 continue
98 } else if filemd.Digest != "" {
99 d := hash.New()
100 if hdr.FileInfo().Mode()&os.ModeSymlink != 0 {
101 d.Write([]byte(hdr.Linkname))
102 } else {
103 if _, err := io.Copy(d, tr); err != nil {
104 return err
105 }
106 }
107 sum := d.Sum(nil)
108 expect, err := hex.DecodeString(filemd.Digest)
109 if err != nil {
110 return err
111 }
112 if !hmac.Equal(expect, sum) {
113 return fmt.Errorf("digest mismatch for %s: given %x, calculated %x", name, expect, sum)
114 }
115 } else {
116 switch hdr.FileInfo().Mode() & os.ModeType {
117 case 0, os.ModeSymlink:
118 return fmt.Errorf("file %s has no digest", name)
119 }
120 }
121 }
122 for k := range filemap {
123 return fmt.Errorf("file %s missing from tar", k)
124 }
125 return nil
126 }
127
View as plain text