blob: 3e2952323a6827fc6c652d36c88e99d11474d5ea [file] [log] [blame]
package mfg
import (
"crypto/sha256"
"mynewt.apache.org/newt/util"
)
const MFG_IMG_FILENAME = "mfgimg.bin"
const MANIFEST_FILENAME = "manifest.json"
type Mfg struct {
Bin []byte
Meta *Meta
// Unused if Meta==nil.
MetaOff int
}
func Parse(data []byte, metaEndOff int, eraseVal byte) (Mfg, error) {
m := Mfg{
Bin: data,
}
if metaEndOff >= 0 {
meta, _, err := ParseMeta(data[:metaEndOff])
if err != nil {
return m, err
}
m.Meta = &meta
m.MetaOff = metaEndOff - int(meta.Footer.Size)
}
return m, nil
}
func StripPadding(b []byte, eraseVal byte) []byte {
var pad int
for pad = 0; pad < len(b); pad++ {
off := len(b) - pad - 1
if b[off] != eraseVal {
break
}
}
return b[:len(b)-pad]
}
func AddPadding(b []byte, eraseVal byte, padLen int) []byte {
for i := 0; i < padLen; i++ {
b = append(b, eraseVal)
}
return b
}
// Calculates the SHA256 hash, using the full manufacturing image as input.
// Hash-calculation algorithm is as follows:
// 1. Zero out the 32 bytes that will contain the hash.
// 2. Apply SHA256 to the result.
//
// This function assumes that the 32 bytes of hash data have already been
// zeroed.
func CalcHash(bin []byte) []byte {
hash := sha256.Sum256(bin)
return hash[:]
}
func (m *Mfg) RecalcHash(eraseVal byte) error {
if m.Meta == nil || m.Meta.Hash() == nil {
return nil
}
// First, write with zeroed hash.
m.Meta.ClearHash()
bin, err := m.Bytes(eraseVal)
if err != nil {
return err
}
// Calculate hash and fill TLV.
tlv := m.Meta.FindFirstTlv(META_TLV_TYPE_HASH)
if tlv != nil {
hashData := CalcHash(bin)
copy(tlv.Data, hashData)
hashOff := m.MetaOff + m.Meta.HashOffset()
if hashOff+META_HASH_SZ > len(bin) {
return util.FmtNewtError(
"unexpected error: hash extends beyond end " +
"of manufacturing image")
}
}
return nil
}
func (m *Mfg) Hash() ([]byte, error) {
var hashBytes []byte
if m.Meta != nil {
hashBytes = m.Meta.Hash()
}
if hashBytes == nil {
// No hash TLV; calculate hash manually.
bin, err := m.Bytes(0xff)
if err != nil {
return nil, err
}
hashBytes = CalcHash(bin)
}
return hashBytes, nil
}
func (m *Mfg) Bytes(eraseVal byte) ([]byte, error) {
binCopy := make([]byte, len(m.Bin))
copy(binCopy, m.Bin)
metaBytes, err := m.Meta.Bytes()
if err != nil {
return nil, err
}
padLen := m.MetaOff + len(metaBytes) - len(binCopy)
if padLen > 0 {
binCopy = AddPadding(binCopy, eraseVal, padLen)
}
copy(binCopy[m.MetaOff:m.MetaOff+len(metaBytes)], metaBytes)
return binCopy, nil
}