github.com/jlowellwofford/u-root@v1.0.0/pkg/boot/package.go (about) 1 // Copyright 2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package boot 6 7 import ( 8 "crypto/rsa" 9 "errors" 10 "fmt" 11 "path" 12 "strings" 13 14 "github.com/u-root/u-root/pkg/cpio" 15 "github.com/u-root/u-root/pkg/uio" 16 "golang.org/x/sys/unix" 17 ) 18 19 // Package is a netboot21 boot package. 20 // 21 // It contains an OSImage to boot as well as arbitrary metadata. 22 type Package struct { 23 OSImage 24 25 // Metadata is a map of relative archive paths -> arbitrary metadata 26 // content. 27 Metadata map[string]string 28 } 29 30 // NewPackage returns a new package based on the given OSImage. 31 func NewPackage(osi OSImage) *Package { 32 return &Package{ 33 OSImage: osi, 34 Metadata: make(map[string]string), 35 } 36 } 37 38 // AddMetadata adds metadata at a relative path. 39 func (p *Package) AddMetadata(relPath string, content string) { 40 p.Metadata[relPath] = content 41 } 42 43 // Pack writes the boot package into archive w. 44 // 45 // TODO(hugelgupf): use a generic private key interface. No idea if we intend 46 // to keep using RSA here. Make usable with TPM. 47 func (p *Package) Pack(w cpio.RecordWriter, signer *rsa.PrivateKey) error { 48 sw := NewSigningWriter(w) 49 50 if len(p.Metadata) > 0 { 51 if err := sw.WriteRecord(cpio.Directory("metadata", 0700)); err != nil { 52 return err 53 } 54 55 for name, r := range p.Metadata { 56 if err := sw.WriteRecord(cpio.StaticFile(path.Join("metadata", name), r, 0700)); err != nil { 57 return err 58 } 59 } 60 } 61 62 if err := p.OSImage.Pack(sw); err != nil { 63 return err 64 } 65 66 if signer != nil { 67 return sw.WriteSignature(signer) 68 } 69 return nil 70 } 71 72 // Unpack unpacks a boot package in rr to p. 73 // 74 // TODO(hugelgupf): RSA? Generalize. 75 func (p *Package) Unpack(rr cpio.RecordReader, pk *rsa.PublicKey) error { 76 *p = Package{ 77 Metadata: make(map[string]string), 78 } 79 80 recs := NewMeasuringReader(rr) 81 a, err := cpio.ReadArchive(recs) 82 if err != nil { 83 return err 84 } 85 if pk != nil { 86 if err := recs.Verify(pk); err != nil { 87 return err 88 } 89 } 90 91 for pth, content := range a.Files { 92 s := strings.Split(pth, "/") 93 if s[0] == "metadata" && content.Info.Mode&unix.S_IFMT == unix.S_IFREG { 94 c, err := uio.ReadAll(content) 95 if err != nil { 96 return err 97 } 98 p.Metadata[path.Join(s[1:]...)] = string(c) 99 } 100 } 101 102 typFile, ok := a.Files["package_type"] 103 if !ok { 104 return errors.New("file 'package_type' missing from boot package") 105 } 106 107 tb, err := uio.ReadAll(typFile) 108 if err != nil { 109 return err 110 } 111 112 pkgType := strings.TrimSpace(string(tb)) 113 imager, ok := osimageMap[pkgType] 114 if !ok { 115 return fmt.Errorf("invalid package type %q not supported", pkgType) 116 } 117 img, err := imager(a) 118 if err != nil { 119 return err 120 } 121 p.OSImage = img 122 return nil 123 }