mfg/verify.go (159 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package mfg import ( "bytes" "encoding/hex" "github.com/apache/mynewt-artifact/errors" "github.com/apache/mynewt-artifact/flash" "github.com/apache/mynewt-artifact/manifest" "github.com/apache/mynewt-artifact/sec" ) func (m *Mfg) validateManFlashMap(man manifest.MfgManifest) error { idAreaMap := map[int]flash.FlashArea{} for _, area := range man.FlashAreas { if _, dup := idAreaMap[area.Id]; dup { return errors.Errorf( "mfg manifest contains duplicate flash area: %d", area.Id) } idAreaMap[area.Id] = area } seen := map[int]struct{}{} mmrHasFlash := man.Meta != nil && man.Meta.FlashMap for _, t := range m.Tlvs() { if t.Header.Type == META_TLV_TYPE_FLASH_AREA { if !mmrHasFlash { return errors.Errorf( "mmr contains flash map; manifest indicates otherwise") } body, err := t.StructuredBody() if err != nil { return err } flashBody := body.(*MetaTlvBodyFlashArea) if _, ok := idAreaMap[int(flashBody.Area)]; !ok { return errors.Errorf( "flash area %d missing from mfg manifest", flashBody.Area) } seen[int(flashBody.Area)] = struct{}{} } } if mmrHasFlash { for _, area := range man.FlashAreas { if _, ok := seen[area.Id]; !ok { return errors.Errorf("flash area %d missing from mmr", area.Id) } } } return nil } func (m *Mfg) validateManMmrs(man manifest.MfgManifest) error { areaMap := map[int]struct{}{} if man.Meta != nil { for _, mmr := range man.Meta.Mmrs { fa := man.FindFlashAreaName(mmr.Area) if fa == nil { return errors.Errorf( "flash area %s missing from mfg manifest", mmr.Area) } if _, dup := areaMap[fa.Id]; dup { return errors.Errorf( "mfg manifest contains duplicate mmr ref: %s", mmr.Area) } areaMap[fa.Id] = struct{}{} } } seen := map[int]struct{}{} for _, t := range m.Tlvs() { if t.Header.Type == META_TLV_TYPE_MMR_REF { body, err := t.StructuredBody() if err != nil { return err } mmrBody := body.(*MetaTlvBodyMmrRef) if _, ok := areaMap[int(mmrBody.Area)]; !ok { return errors.Errorf( "mmr ref %d missing from mfg manifest", mmrBody.Area) } seen[int(mmrBody.Area)] = struct{}{} } } for area, _ := range areaMap { if _, ok := seen[area]; !ok { return errors.Errorf("mmr ref %d missing from mmr", area) } } return nil } // VerifyStructure checks an mfgimage's structure and internal consistency. It // returns an error if the mfgimage is incorrect. func (m *Mfg) VerifyStructure(eraseVal byte) error { for _, t := range m.Tlvs() { // Verify that TLV has a valid `type` field. body, err := t.StructuredBody() if err != nil { return err } // Verify contents of hash TLV. switch t.Header.Type { case META_TLV_TYPE_HASH: hashBody := body.(*MetaTlvBodyHash) hash, err := m.RecalcHash(eraseVal) if err != nil { return err } if !bytes.Equal(hash, hashBody.Hash[:]) { return errors.Errorf( "mmr contains incorrect hash: have=%s want=%s", hex.EncodeToString(hashBody.Hash[:]), hex.EncodeToString(hash)) } } } return nil } // VerifyManifest compares an mfgimage's structure to its manifest. It returns // an error if the mfgimage doesn't match the manifest. func (m *Mfg) VerifyManifest(man manifest.MfgManifest) error { if man.Format != 2 { return errors.Errorf( "only mfgimage format 2 supported (have=%d)", man.Format) } mfgHash, err := m.Hash(man.EraseVal) if err != nil { return err } hashStr := hex.EncodeToString(mfgHash) if hashStr != man.MfgHash { return errors.Errorf( "manifest mfg hash different from mmr: man=%s mfg=%s", man.MfgHash, hashStr) } if err := m.validateManFlashMap(man); err != nil { return err } if err := m.validateManMmrs(man); err != nil { return err } // Make sure each target is fully present. for _, t := range man.Targets { if man.FindFlashAreaDevOff(man.Device, t.Offset) == nil { return errors.Errorf( "no flash area in mfgimage corresponding to target \"%s\"", t.Name) } } return nil } // VerifySigs checks an mfgimage's signatures against the provided set of keys. // It succeeds if the mfgimage has no signatures or if any signature can be // verified. An error is returned if there is at least one signature and they // all fail the check. func VerifySigs(man manifest.MfgManifest, keys []sec.PubSignKey) (int, error) { sigs, err := man.SecSigs() if err != nil { return -1, err } hash, err := hex.DecodeString(man.MfgHash) if err != nil { return -1, errors.Wrapf(err, "mfg manifest contains invalid hash: %s", man.MfgHash) } for keyIdx, k := range keys { sigIdx, err := sec.VerifySigs(k, sigs, hash) if err != nil { return -1, errors.Wrapf(err, "failed to verify mfgimg signatures") } if sigIdx != -1 { return keyIdx, nil } } return -1, errors.Errorf("mfg signatures do not match provided keys") }