Arch Linux helpers and parsers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
3.7 KiB

  1. package archlinux
  2. import (
  3. "bytes"
  4. "crypto/md5"
  5. "crypto/sha1"
  6. "crypto/sha256"
  7. "crypto/sha512"
  8. "errors"
  9. "fmt"
  10. "hash"
  11. "io"
  12. "io/ioutil"
  13. "log"
  14. "os"
  15. "golang.org/x/crypto/openpgp"
  16. "golang.org/x/crypto/openpgp/packet"
  17. )
  18. // Defaults
  19. const (
  20. DefaultKeyringFile = "/etc/pacman.d/gnupg/pubring.gpg"
  21. )
  22. type hasher struct {
  23. hash.Hash
  24. Name string
  25. Sum []byte
  26. //*sync.WaitGroup
  27. //In chan []byte
  28. }
  29. func newHasher(name string, sum []byte, h hash.Hash) hasher {
  30. n := hasher{
  31. Hash: h,
  32. Name: name,
  33. Sum: sum,
  34. //WaitGroup: new(sync.WaitGroup),
  35. //In: make(chan []byte, 16),
  36. }
  37. /*
  38. n.Add(1)
  39. go n.Run()
  40. */
  41. return n
  42. }
  43. /*
  44. func (h *hasher) Run() {
  45. defer h.Done()
  46. for {
  47. select {
  48. case b := <-h.In:
  49. if b == nil {
  50. return
  51. }
  52. if _, err := h.Hash.Write(b); err != nil {
  53. panic(err)
  54. }
  55. }
  56. }
  57. }
  58. */
  59. // Verify verifies the package file checksums. If filename is empty, the Filename
  60. // field of the struct will be used in stead.
  61. func (pkg *Package) Verify(filename string) error {
  62. if filename == "" {
  63. filename = pkg.Filename
  64. }
  65. f, err := os.Open(filename)
  66. if err != nil {
  67. return err
  68. }
  69. defer f.Close()
  70. var hashers []hasher
  71. addHasher := func(name string, sum []byte, fn func() hash.Hash) {
  72. if len(sum) == 0 {
  73. return
  74. }
  75. hashers = append(hashers, newHasher(name, sum, fn()))
  76. }
  77. addHasher("MD5", pkg.MD5, md5.New)
  78. addHasher("SHA1", pkg.SHA1, sha1.New)
  79. addHasher("SHA256", pkg.SHA256, sha256.New)
  80. addHasher("SHA384", pkg.SHA384, sha512.New384)
  81. addHasher("SHA512", pkg.SHA512, sha512.New)
  82. if len(hashers) == 0 {
  83. return ErrPackageNoChecksums
  84. }
  85. var block [4096]byte
  86. for {
  87. n, err := f.Read(block[:])
  88. if err != nil {
  89. if err == io.EOF {
  90. break
  91. }
  92. }
  93. for _, h := range hashers {
  94. //h.In <- block[:n]
  95. if _, err = h.Write(block[:n]); err != nil {
  96. return err
  97. }
  98. }
  99. }
  100. for _, h := range hashers {
  101. // h.Wait()
  102. if s := h.Hash.Sum(nil); !bytes.Equal(s, h.Sum) {
  103. return fmt.Errorf("archlinux: %s checksum mismatch, got %x, expected %x", h.Name, s, h.Sum)
  104. }
  105. }
  106. return nil
  107. }
  108. // IsSigned returns true if the package has a PGP signature
  109. func (pkg *Package) IsSigned() bool {
  110. return len(pkg.PGPSignature) > 0
  111. }
  112. // PGPKeyID returns the PGP key ID that signed the PGP signature. If there is
  113. // no signature, or if there is an error parsing the signature, 0 is returned.
  114. func (pkg *Package) PGPKeyID() uint64 {
  115. if !pkg.IsSigned() {
  116. return 0
  117. }
  118. var (
  119. r = packet.NewReader(bytes.NewBuffer(pkg.PGPSignature))
  120. p packet.Packet
  121. s *packet.Signature
  122. ok bool
  123. err error
  124. )
  125. for {
  126. if p, err = r.Next(); err != nil {
  127. return 0
  128. }
  129. if s, ok = p.(*packet.Signature); ok {
  130. if s.IssuerKeyId != nil {
  131. return *s.IssuerKeyId
  132. }
  133. }
  134. }
  135. }
  136. // VerifySignature verifies the package file in filename with the known PGP
  137. // signature against the passed keyring.
  138. func (pkg *Package) VerifySignature(filename string, keyring openpgp.EntityList) error {
  139. if !pkg.IsSigned() {
  140. return errors.New("archlinux: package is not PGP signed")
  141. }
  142. f, err := os.Open(filename)
  143. if err != nil {
  144. return err
  145. }
  146. defer f.Close()
  147. _, err = openpgp.CheckDetachedSignature(keyring, f, bytes.NewBuffer(pkg.PGPSignature))
  148. return err
  149. }
  150. // VerifySignatureKeyring verifies the package file in filename with the known
  151. // PGP signature against the passed keyring file.
  152. func (pkg *Package) VerifySignatureKeyring(filename, keyringName string) error {
  153. b, err := ioutil.ReadFile(keyringName)
  154. if err != nil {
  155. return err
  156. }
  157. l, err := openpgp.ReadKeyRing(bytes.NewBuffer(b))
  158. if err != nil {
  159. return err
  160. }
  161. if os.Getenv("DEBUG_KEYRING") != "" {
  162. for _, e := range l {
  163. log.Printf("keyring: %s\n", e.PrimaryKey.KeyIdString())
  164. }
  165. }
  166. return pkg.VerifySignature(filename, l)
  167. }