blob: 6d90f681b06031e4f254b9443ad9d12ea61bb6b9 [file] [log] [blame]
/**
* 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 (
"fmt"
"io/ioutil"
"testing"
"github.com/apache/mynewt-artifact/manifest"
"github.com/apache/mynewt-artifact/sec"
)
const testdataPath = "testdata"
type entry struct {
basename string
form bool
structure bool
man bool
sign bool
}
func readMfgData(basename string) []byte {
path := fmt.Sprintf("%s/%s.bin", testdataPath, basename)
data, err := ioutil.ReadFile(path)
if err != nil {
panic("failed to read mfgimage file " + path)
}
return data
}
func readManifest(basename string) manifest.MfgManifest {
path := fmt.Sprintf("%s/%s.json", testdataPath, basename)
man, err := manifest.ReadMfgManifest(path)
if err != nil {
panic("failed to read manifest file " + path)
}
return man
}
func readPubKey() sec.PubSignKey {
path := fmt.Sprintf("%s/sign-key.pem", testdataPath)
key, err := sec.ReadPrivSignKey(path)
if err != nil {
panic("failed to read key file " + path)
}
return key.PubKey()
}
func testOne(t *testing.T, e entry) {
fatalErr := func(field string, have string, want string, err error) {
s := fmt.Sprintf("mfgimage \"%s\" has unexpected `%s` status: "+
"have=%s want=%s", e.basename, field, have, want)
if err != nil {
s += "; " + err.Error()
}
t.Fatal(s)
}
mfgData := readMfgData(e.basename)
man := readManifest(e.basename)
var metaOff int
if man.Meta != nil {
metaOff = man.Meta.EndOffset
} else {
metaOff = -1
}
m, err := Parse(mfgData, metaOff, man.EraseVal)
if !e.form {
if err == nil {
fatalErr("form", "good", "bad", nil)
}
return
} else {
if err != nil {
fatalErr("form", "bad", "good", err)
return
}
}
err = m.VerifyStructure(man.EraseVal)
if !e.structure {
if err == nil {
fatalErr("structure", "good", "bad", nil)
}
return
} else {
if err != nil {
fatalErr("structure", "bad", "good", err)
return
}
}
err = m.VerifyManifest(man)
if !e.man {
if err == nil {
fatalErr("manifest", "good", "bad", nil)
}
return
} else {
if err != nil {
fatalErr("manifest", "bad", "good", err)
return
}
}
key := readPubKey()
idx, err := VerifySigs(man, []sec.PubSignKey{key})
if !e.sign {
if err == nil && idx != -1 {
fatalErr("signature", "good", "bad", nil)
}
return
} else {
if err != nil || idx == -1 {
fatalErr("signature", "bad", "good", err)
}
}
}
func TestMfgVerify(t *testing.T) {
entries := []entry{
// Not an mfgimage.
entry{
basename: "garbage",
form: false,
structure: false,
man: false,
sign: false,
},
// Contains a TLV with type=0xaa.
entry{
basename: "unknown-tlv",
form: true,
structure: false,
man: false,
sign: false,
},
// MMR and manifest contain the same incorrect hash.
entry{
basename: "hashx-fm1-ext0-tgts1-sign0",
form: true,
structure: false,
man: false,
sign: false,
},
// MMR hash doesn't match manifest.
entry{
basename: "hashm-fm1-ext0-tgts1-sign0",
form: true,
structure: true,
man: false,
sign: false,
},
// MMR flash map doesn't match manifest.
entry{
basename: "hash1-fmm-ext1-tgts1-sign0",
form: true,
structure: true,
man: false,
sign: false,
},
// MMR ext ref doesn't match manifest.
entry{
basename: "hash1-fm1-extm-tgts1-sign0",
form: true,
structure: true,
man: false,
sign: false,
},
// Manifest indicates build where there is none.
entry{
basename: "hash1-fm1-ext1-tgtsm-sign0",
form: true,
structure: true,
man: false,
sign: false,
},
// Good unsigned mfgimage without ref ext TLV.
entry{
basename: "hash1-fm1-ext0-tgts1-sign0",
form: true,
structure: true,
man: true,
sign: false,
},
// Good unsigned mfgimage.
entry{
basename: "hash1-fm1-ext1-tgts1-sign0",
form: true,
structure: true,
man: true,
sign: false,
},
// Good signed mfgimage.
entry{
basename: "hash1-fm1-ext1-tgts1-sign1",
form: true,
structure: true,
man: true,
sign: true,
},
}
for _, e := range entries {
testOne(t, e)
}
}