github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/pkg/securelaunch/measurement/dmi.go (about) 1 // Copyright 2019 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 measurement 6 7 import ( 8 "bytes" 9 "encoding/json" 10 "errors" 11 "fmt" 12 "io" 13 "log" 14 15 "github.com/digitalocean/go-smbios/smbios" 16 slaunch "github.com/u-root/u-root/pkg/securelaunch" 17 "github.com/u-root/u-root/pkg/securelaunch/tpm" 18 ) 19 20 // DMI Events are expected to be a COMBINED_EVENT extend, as such the json 21 // definition is designed to allow clusters of DMI fields/strings. 22 // 23 // Example json: 24 // { 25 // "type": "dmi", 26 // [ 27 // { 28 // "label": "BIOS", 29 // "fields": [ 30 // "bios-vendor", 31 // "bios-version", 32 // "bios-release-date" 33 // ] 34 // } 35 // { 36 // "label": "System", 37 // "fields": [ 38 // "system-manufacturer", 39 // "system-product-name", 40 // "system-version" 41 // ] 42 // } 43 // ] 44 // } 45 type fieldCluster struct { 46 Label string `json:"label"` 47 Fields []string `json:"fields"` 48 } 49 50 /* describes the "dmi" portion of policy file */ 51 type DmiCollector struct { 52 Type string `json:"type"` 53 Clusters []fieldCluster `json:"events"` 54 } 55 56 /* 57 * NewDmiCollector extracts the "dmi" portion from the policy file. 58 * initializes a new DmiCollector structure. 59 * returns error if unmarshalling of DmiCollector fails 60 */ 61 func NewDmiCollector(config []byte) (Collector, error) { 62 slaunch.Debug("New DMI Collector initialized") 63 var dc = new(DmiCollector) 64 err := json.Unmarshal(config, &dc) 65 if err != nil { 66 return nil, err 67 } 68 return dc, nil 69 } 70 71 /* 72 * below look up table is from man dmidecode. 73 * used to lookup the dmi type parsed from policy file. 74 * e.g if policy file contains BIOS, this table would return 0. 75 */ 76 var type_table = map[string]uint8{ 77 "BIOS": 0, 78 "System": 1, 79 "Base Board": 2, 80 "Chassis": 3, 81 "Processor": 4, 82 "Memory Controller": 5, 83 "Memory Module": 6, 84 "Cache": 7, 85 "Port Connector": 8, 86 "System Slots": 9, 87 "On Board Devices": 10, 88 "OEM Strings": 11, 89 "System Configuration Options": 12, 90 "BIOS Language": 13, 91 "Group Associations": 14, 92 "System Event Log": 15, 93 "Physical Memory Array": 16, 94 "Memory Device": 17, 95 "32-bit Memory Error": 18, 96 "Memory Array Mapped Address": 19, 97 "Memory Device Mapped Address": 20, 98 "Built-in Pointing Device": 21, 99 "Portable Battery": 22, 100 "System Reset": 23, 101 "Hardware Security": 24, 102 "System Power Controls": 25, 103 "Voltage Probe": 26, 104 "Cooling Device": 27, 105 "Temperature Probe": 28, 106 "Electrical Current Probe": 29, 107 "Out-of-band Remote Access": 30, 108 "Boot Integrity Services": 31, 109 "System Boot": 32, 110 "64-bit Memory Error": 33, 111 "Management Device": 34, 112 "Management Device Component": 35, 113 "Management Device Threshold Data": 36, 114 "Memory Channel": 37, 115 "IPMI Device": 38, 116 "Power Supply": 39, 117 "Additional Information": 40, 118 "Onboard Device": 41, 119 } 120 121 /* 122 * Collect satisfies collector interface. It calls 123 * 1. smbios package to get all smbios data, 124 * 2. then, filters smbios data based on type provided in policy file, and 125 * 3. the filtered data is then measured into the tpmHandle (tpm device). 126 */ 127 func (s *DmiCollector) Collect(tpmHandle io.ReadWriteCloser) error { 128 slaunch.Debug("DMI Collector: Entering ") 129 if s.Type != "dmi" { 130 return errors.New("Invalid type passed to a DmiCollector method") 131 } 132 133 // Find SMBIOS data in operating system-specific location. 134 rc, _, err := smbios.Stream() 135 if err != nil { 136 return fmt.Errorf("failed to open stream: %v", err) 137 } 138 139 // Be sure to close the stream! 140 defer rc.Close() 141 142 // Decode SMBIOS structures from the stream. 143 d := smbios.NewDecoder(rc) 144 data, err := d.Decode() 145 if err != nil { 146 return fmt.Errorf("failed to decode structures: %v", err) 147 } 148 149 var labels []string // collect all types entered by user in one slice 150 for _, fieldCluster := range s.Clusters { 151 labels = append(labels, fieldCluster.Label) 152 } 153 154 for _, k := range data { // k ==> data for each dmi type 155 // Only look at types mentioned in policy file. 156 for _, label := range labels { 157 if k.Header.Type != type_table[label] { 158 continue 159 } 160 161 slaunch.Debug("DMI Collector: Hashing %s information", label) 162 b := new(bytes.Buffer) 163 for _, str := range k.Strings { 164 b.WriteString(str) 165 } 166 167 // TODO: Extract and Measure specific "Fields" of a FieldCluster on user's request. 168 // For example: for BIOS type(type=0), currently we measure entire output 169 // but in future we could measure individual fields like bios-vendor, bios-version etc. 170 171 slaunch.Debug("DMI Collector: Measured dmi label=%s", label) 172 if e := tpm.ExtendPCRDebug(tpmHandle, pcr, bytes.NewReader(b.Bytes())); e != nil { 173 log.Printf("DMI Collector: err =%v", e) 174 return e 175 } 176 } 177 } 178 179 return nil 180 }