...

Source file src/github.com/sassoftware/relic/signers/starman/tarmd.go

Documentation: github.com/sassoftware/relic/signers/starman

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    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  			// has a digest but no contents
    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