blob: aa3ed13287baa8bcf9f5468b415b58e346f7dda0 [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 image
import (
"fmt"
"io/ioutil"
"testing"
"github.com/apache/mynewt-artifact/errors"
"github.com/apache/mynewt-artifact/manifest"
"github.com/apache/mynewt-artifact/sec"
)
const testdataPath = "testdata"
type entry struct {
basename string
form bool
structure bool
hash bool
man bool
sign bool
encrypted bool
}
func readImageData(basename string) []byte {
path := fmt.Sprintf("%s/%s.img", testdataPath, basename)
data, err := ioutil.ReadFile(path)
if err != nil {
panic(fmt.Sprintf("failed to read image file \"%s\": %s", path, err.Error()))
}
return data
}
func readManifest(basename string) manifest.Manifest {
path := fmt.Sprintf("%s/%s.json", testdataPath, basename)
man, err := manifest.ReadManifest(path)
if err != nil {
panic(fmt.Sprintf("failed to read manifest file \"%s\": %s", path, err.Error()))
}
return man
}
func readPubSignKey() sec.PubSignKey {
path := fmt.Sprintf("%s/sign-key.pem", testdataPath)
key, err := sec.ReadPrivSignKey(path)
if err != nil {
panic(fmt.Sprintf("failed to read key file \"%s\": %s", path, err.Error()))
}
return key.PubKey()
}
func readPrivEncKey() sec.PrivEncKey {
path := fmt.Sprintf("%s/enc-key.der", testdataPath)
key, err := sec.ReadPrivEncKey(path)
if err != nil {
panic(fmt.Sprintf("failed to read key file \"%s\": %s", path, err.Error()))
}
return key
}
func testOne(t *testing.T, e entry) {
fatalErr := func(field string, have string, want string, err error) {
s := fmt.Sprintf("image \"%s\" has unexpected `%s` status: "+
"have=%s want=%s", e.basename, field, have, want)
if err != nil {
s += "; " + err.Error()
}
t.Fatal(s)
}
imgData := readImageData(e.basename)
img, err := ParseImage(imgData)
if !e.form {
if err == nil {
fatalErr("form", "good", "bad", nil)
}
return
} else {
if err != nil {
fatalErr("form", "bad", "good", err)
return
}
}
err = img.VerifyStructure()
if !e.structure {
if err == nil {
fatalErr("structure", "good", "bad", nil)
}
return
} else {
if err != nil {
fatalErr("structure", "bad", "good", err)
return
}
}
kek := readPrivEncKey()
kekIdx, err := img.VerifyHash([]sec.PrivEncKey{kek})
if !e.hash {
if err == nil {
fatalErr("hash", "good", "bad", nil)
}
return
} else {
if err != nil {
fatalErr("hash", "bad", "good", err)
return
}
var wantKekIdx int
if e.encrypted {
wantKekIdx = 0
} else {
wantKekIdx = -1
}
if kekIdx != wantKekIdx {
fatalErr("hash", "good", "bad", errors.Errorf(
"wrong kek idx: have=%d want=%d", kekIdx, wantKekIdx))
return
}
}
man := readManifest(e.basename)
err = img.VerifyManifest(man)
if !e.man {
if err == nil {
fatalErr("manifest", "good", "bad", nil)
}
return
} else {
if err != nil {
fatalErr("manifest", "bad", "good", err)
return
}
}
isk := readPubSignKey()
idx, err := img.VerifySigs([]sec.PubSignKey{isk})
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 TestImageVerify(t *testing.T) {
entries := []entry{
entry{
basename: "garbage",
form: false,
structure: false,
man: false,
sign: false,
encrypted: false,
},
entry{
basename: "truncated",
form: false,
structure: false,
man: false,
sign: false,
encrypted: false,
},
entry{
basename: "bad-hash",
form: true,
structure: true,
hash: false,
man: false,
sign: false,
encrypted: false,
},
entry{
basename: "mismatch-hash",
form: true,
structure: true,
hash: true,
man: false,
sign: false,
encrypted: false,
},
entry{
basename: "mismatch-version",
form: true,
structure: true,
hash: true,
man: false,
sign: false,
encrypted: false,
},
entry{
basename: "bad-signature",
form: true,
structure: true,
hash: true,
man: true,
sign: false,
encrypted: false,
},
entry{
basename: "wrong-enc-key",
form: true,
structure: true,
hash: false,
man: true,
sign: true,
encrypted: true,
},
entry{
basename: "good-unsigned-unencrypted",
form: true,
structure: true,
hash: true,
man: true,
sign: false,
encrypted: false,
},
entry{
basename: "good-signed-unencrypted",
form: true,
structure: true,
hash: true,
man: true,
sign: true,
encrypted: false,
},
entry{
basename: "good-signed-encrypted",
form: true,
structure: true,
hash: true,
man: true,
sign: true,
encrypted: true,
},
}
for _, e := range entries {
testOne(t, e)
}
}