github.com/jlowellwofford/u-root@v1.0.0/pkg/boot/measurement.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 "bytes" 9 "crypto" 10 "crypto/rand" 11 "crypto/rsa" 12 "crypto/sha1" 13 "crypto/sha256" 14 _ "crypto/sha512" 15 //"encoding/binary" 16 "fmt" 17 "io" 18 19 "github.com/google/go-tpm/tpm" 20 "github.com/u-root/u-root/pkg/cpio" 21 "github.com/u-root/u-root/pkg/uio" 22 "golang.org/x/sys/unix" 23 ) 24 25 // MeasuringReader is a cpio.Reader that collects the signed data and compares 26 // it against the signature in the given cpio archive. 27 type MeasuringReader struct { 28 r cpio.RecordReader 29 30 signed *bytes.Buffer 31 signature *bytes.Buffer 32 } 33 34 // NewMeasuringReader returns a new measuring reader. 35 func NewMeasuringReader(r cpio.RecordReader) *MeasuringReader { 36 return &MeasuringReader{ 37 r: r, 38 signed: &bytes.Buffer{}, 39 signature: &bytes.Buffer{}, 40 } 41 } 42 43 // Verify verifies the contents of the archive as read so far. 44 // 45 // NOTE(UGH): Go crypto stuff is totally incompatible. ecdsa.PrivateKey.Sign 46 // does not output shit that is compatible with ecdsa.Verify -- COME ON. Only 47 // ecdsa.Sign does. 48 func (mr *MeasuringReader) Verify(pk *rsa.PublicKey) error { 49 hashed := sha256.Sum256(mr.signed.Bytes()) 50 return rsa.VerifyPKCS1v15(pk, crypto.SHA256, hashed[:], mr.signature.Bytes()) 51 } 52 53 // ExtendTPM extends the given tpm at pcrIndex with the content of the package. 54 func (mr *MeasuringReader) ExtendTPM(tpmRW io.ReadWriter, pcrIndex uint32) error { 55 pcrValue := sha1.Sum(mr.signed.Bytes()) 56 _, err := tpm.PcrExtend(tpmRW, pcrIndex, pcrValue) 57 return err 58 } 59 60 // ReadRecord wraps cpio.Reader.ReadRecord and adds the content to `signed` as 61 // necessary. 62 func (mr *MeasuringReader) ReadRecord() (cpio.Record, error) { 63 for { 64 rec, err := mr.r.ReadRecord() 65 if err != nil { 66 return rec, err 67 } 68 69 switch rec.Name { 70 case "signature": 71 // Error return is intentionally ignored. 72 mr.signature.ReadFrom(uio.Reader(rec)) 73 continue 74 75 case "signature_algo": 76 //err = binary.Read(uio.Reader(rec), binary.LittleEndian, &mr.algo) 77 continue 78 79 default: 80 // Measure all regular files. 81 if rec.Info.Mode&unix.S_IFMT == unix.S_IFREG { 82 if _, err := mr.signed.WriteString(rec.Name); err != nil { 83 return cpio.Record{}, err 84 } 85 if _, err := mr.signed.ReadFrom(uio.Reader(rec)); err != nil { 86 return cpio.Record{}, err 87 } 88 } 89 return rec, nil 90 } 91 } 92 } 93 94 // SigningWriter is a cpio.RecordWriter that collects digests as it writes 95 // files to the cpio archive. 96 type SigningWriter struct { 97 w cpio.RecordWriter 98 99 digest *bytes.Buffer 100 } 101 102 // NewSigningWriter returns a new signing cpio writer. 103 func NewSigningWriter(w cpio.RecordWriter) *SigningWriter { 104 return &SigningWriter{ 105 w: w, 106 digest: &bytes.Buffer{}, 107 } 108 } 109 110 // WriteRecord implements cpio.RecordWriter. 111 func (sw *SigningWriter) WriteRecord(rec cpio.Record) error { 112 rec = cpio.MakeReproducible(rec) 113 if rec.Info.Name == "signature" || rec.Info.Name == "signature_algo" { 114 return fmt.Errorf("cannot write signature or signature_algo files") 115 } 116 if rec.Info.Mode&unix.S_IFMT == unix.S_IFREG { 117 if _, err := sw.digest.WriteString(rec.Info.Name); err != nil { 118 return err 119 } 120 if _, err := sw.digest.ReadFrom(uio.Reader(rec)); err != nil { 121 return err 122 } 123 } 124 return sw.w.WriteRecord(rec) 125 } 126 127 // SHA1Sum returns the SHA1 sum of the collected digest. 128 func (sw *SigningWriter) SHA1Sum() [sha1.Size]byte { 129 return sha1.Sum(sw.digest.Bytes()) 130 } 131 132 // WriteSignature writes the signature and signature_algo files based on the 133 // collected digest. 134 // 135 // TODO(hugelgupf): stop hard-coding the private key and algorithm. Use 136 // crypto.Signer so TPM could be used to sign this if so desired. 137 func (sw *SigningWriter) WriteSignature(signer *rsa.PrivateKey) error { 138 hashed := sha256.Sum256(sw.digest.Bytes()) 139 signature, err := signer.Sign(rand.Reader, hashed[:], crypto.SHA256) 140 if err != nil { 141 return err 142 } 143 if err := sw.w.WriteRecord(cpio.StaticFile("signature", string(signature), 0700)); err != nil { 144 return err 145 } 146 147 return nil 148 /*algo := &bytes.Buffer{} 149 if err := binary.Write(algo, binary.LittleEndian, x509.ECDSAWithSHA512); err != nil { 150 return err 151 } 152 // TODO(hugelgupf): use x509 package for all of this. 153 // TODO(hugelgupf, later): no, please don't. 154 return sw.w.WriteRecord(cpio.StaticFile("signature_algo", string(algo.Bytes()), 0700))*/ 155 }