Skip to content

Commit

Permalink
Check repomd.xml signatures properly
Browse files Browse the repository at this point in the history
  • Loading branch information
moio committed Jun 5, 2018
1 parent 8f297f7 commit 708db15
Showing 1 changed file with 54 additions and 16 deletions.
70 changes: 54 additions & 16 deletions get/syncer.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package get

import (
"bytes"
"compress/gzip"
"crypto"
"encoding/xml"
"fmt"
"io"
"io/ioutil"
"log"
"net/url"
"path"

"github.com/moio/minima/util"
"golang.org/x/crypto/openpgp"
)

// common
Expand Down Expand Up @@ -97,6 +100,12 @@ func (r *Syncer) StoreRepo() (err error) {
if checksumError {
log.Printf(err.Error())
log.Printf("Checksum did not match, presumably the repo was published while syncing, retrying...\n")
}

_, signatureError := err.(*SignatureError)
if signatureError {
log.Printf(err.Error())
log.Printf("Signature not valid, presumably the repo was published while syncing, retrying...\n")
} else {
return err
}
Expand Down Expand Up @@ -162,7 +171,17 @@ func (r *Syncer) downloadStoreApply(relativePath string, checksum string, descri
// paths to download
func (r *Syncer) processMetadata(checksumMap map[string]XMLChecksum) (packagesToDownload []XMLPackage, packagesToRecycle []XMLPackage, err error) {
err = r.downloadStoreApply(repomdPath, "", path.Base(repomdPath), 0, func(reader io.ReadCloser) (err error) {
decoder := xml.NewDecoder(reader)
b, err := ioutil.ReadAll(reader)
if err != nil {
return
}

err = r.checkRepomdSignature(bytes.NewReader(b))
if err != nil {
return
}

decoder := xml.NewDecoder(bytes.NewReader(b))
var repomd XMLRepomd
err = decoder.Decode(&repomd)
if err != nil {
Expand Down Expand Up @@ -197,32 +216,53 @@ func (r *Syncer) processMetadata(checksumMap map[string]XMLChecksum) (packagesTo
return
}

return
}

func (r *Syncer) checkRepomdSignature(repomdReader io.Reader) (err error) {
ascPath := repomdPath + ".asc"
err = r.downloadStore(ascPath, path.Base(ascPath))
if err != nil {
uerr, unexpectedStatusCode := err.(*UnexpectedStatusCodeError)
if unexpectedStatusCode && uerr.StatusCode == 404 {
log.Printf("Got 404, ignoring...")
} else {
keyPath := repomdPath + ".key"

err = r.downloadStoreApply(ascPath, "", path.Base(ascPath), 0, func(signatureReader io.ReadCloser) (err error) {
err = r.downloadStoreApply(keyPath, "", path.Base(keyPath), 0, func(keyReader io.ReadCloser) (err error) {
keyring, err := openpgp.ReadArmoredKeyRing(keyReader)
if err != nil {
return &SignatureError{"repomd.key file does not contain a valid signature"}
}
_, err = openpgp.CheckArmoredDetachedSignature(keyring, repomdReader, signatureReader)
if err != nil {
return &SignatureError{"repomd.asc signature check failed, signature is not valid"}
}
return
})
if err != nil {
uerr, unexpectedStatusCode := err.(*UnexpectedStatusCodeError)
if unexpectedStatusCode && uerr.StatusCode == 404 {
log.Printf("Got 404, ignoring...")
err = nil
}
}
}

keyPath := repomdPath + ".key"
err = r.downloadStore(keyPath, path.Base(keyPath))
return
})
if err != nil {
uerr, unexpectedStatusCode := err.(*UnexpectedStatusCodeError)
if unexpectedStatusCode && uerr.StatusCode == 404 {
log.Printf("Got 404, ignoring...")
err = nil
} else {
return
}
}

return
}

// SignatureError is returned if a signature was found but it's invalid
type SignatureError struct {
reason string
}

func (e *SignatureError) Error() string {
return fmt.Sprintf("Signature error: %s", e.reason)
}

func (r *Syncer) readMetaData(reader io.Reader) (primary XMLMetaData, err error) {
gzReader, err := gzip.NewReader(reader)
if err != nil {
Expand All @@ -243,7 +283,6 @@ func (r *Syncer) readChecksumMap() (checksumMap map[string]XMLChecksum) {
if err == ErrFileNotFound {
log.Println("First-time sync started")
} else {
log.Println(err.Error())
log.Println("Error while reading previously-downloaded metadata. Starting sync from scratch")
}
return
Expand All @@ -254,7 +293,6 @@ func (r *Syncer) readChecksumMap() (checksumMap map[string]XMLChecksum) {
var repomd XMLRepomd
err = decoder.Decode(&repomd)
if err != nil {
log.Println(err.Error())
log.Println("Error while parsing previously-downloaded metadata. Starting sync from scratch")
return
}
Expand Down

0 comments on commit 708db15

Please sign in to comment.