You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2019/06/28 16:35:28 UTC

[mynewt-imgmod] 01/02: Use external artifact package

This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-imgmod.git

commit ae6c8665b400d6bd3a2afbd5c417b45ff40594a9
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Jun 26 14:52:28 2019 -0700

    Use external artifact package
    
    The artifact package has been moved out of the newt repo and into its
    own repo (github.com/apache/mynewt-artifact).  Use this external package
    rather than the deprecated one in the newt repo.
---
 cli/image_cmds.go | 123 +++++++++++++++++++++++-
 cli/mfg_cmds.go   | 277 ++++++++++++++++++++++++++++++++++++++++++------------
 cli/util.go       |   8 +-
 go.mod            |   3 +
 go.sum            |  22 ++++-
 iimg/iimg.go      |  93 ++++++------------
 imfg/imfg.go      |   4 +-
 7 files changed, 393 insertions(+), 137 deletions(-)

diff --git a/cli/image_cmds.go b/cli/image_cmds.go
index 76f7c54..2b5852e 100644
--- a/cli/image_cmds.go
+++ b/cli/image_cmds.go
@@ -26,12 +26,14 @@ import (
 	"os"
 	"sort"
 
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
+	"github.com/apache/mynewt-artifact/image"
+	"github.com/apache/mynewt-artifact/manifest"
+	"github.com/apache/mynewt-artifact/sec"
 	"mynewt.apache.org/imgmod/iimg"
-	"mynewt.apache.org/newt/artifact/image"
-	"mynewt.apache.org/newt/artifact/sec"
 	"mynewt.apache.org/newt/util"
 )
 
@@ -146,7 +148,7 @@ func runSignCmd(cmd *cobra.Command, args []string) {
 		ImgmodUsage(cmd, err)
 	}
 
-	keys, err := sec.ReadKeys(args[1:])
+	keys, err := sec.ReadPrivSignKeys(args[1:])
 	if err != nil {
 		ImgmodUsage(cmd, err)
 	}
@@ -467,7 +469,6 @@ func runDecryptFullCmd(cmd *cobra.Command, args []string) {
 	if err != nil {
 		ImgmodUsage(nil, err)
 	}
-
 	if err := writeImage(img, outFilename); err != nil {
 		ImgmodUsage(nil, err)
 	}
@@ -541,6 +542,101 @@ func runEncryptFullCmd(cmd *cobra.Command, args []string) {
 	}
 }
 
+func runVerifyCmd(cmd *cobra.Command, args []string) {
+	anyFails := false
+
+	if len(args) < 1 {
+		ImgmodUsage(cmd, nil)
+	}
+
+	imgFilename := args[0]
+
+	img, err := readImage(imgFilename)
+	if err != nil {
+		ImgmodUsage(cmd, err)
+	}
+
+	st := ""
+	if err := img.VerifyStructure(); err != nil {
+		st = fmt.Sprintf("BAD (%s)", err.Error())
+		anyFails = true
+	} else {
+		st = "good"
+	}
+
+	kes, err := sec.ReadPrivEncKeys(OptEncKeys)
+	if err != nil {
+		ImgmodUsage(nil, errors.Wrapf(err,
+			"error reading encryption key file"))
+	}
+
+	ha := ""
+	if img.IsEncrypted() && len(kes) == 0 {
+		ha = "not checked (image encrypted; no keys specified)"
+	} else {
+		keyIdx, err := img.VerifyHash(kes)
+		if err != nil {
+			ha = fmt.Sprintf("BAD (%s)", err.Error())
+			anyFails = true
+		} else {
+			ha = "good"
+			if keyIdx != -1 {
+				ha += fmt.Sprintf(" (%s)", OptEncKeys[keyIdx])
+			}
+		}
+	}
+
+	iss, err := sec.ReadPubSignKeys(OptSignKeys)
+	if err != nil {
+		ImgmodUsage(nil, errors.Wrapf(err,
+			"error reading signing key file"))
+	}
+
+	sigs, err := img.CollectSigs()
+	if err != nil {
+		ImgmodUsage(nil, err)
+	}
+
+	si := ""
+	if len(sigs) == 0 {
+		si = "n/a"
+	} else if len(iss) == 0 {
+		si = "not checked"
+	} else {
+		idx, err := img.VerifySigs(iss)
+		if err != nil {
+			si = fmt.Sprintf("BAD (%s)", err.Error())
+			anyFails = true
+		} else {
+			si = fmt.Sprintf("good (%s)", OptSignKeys[idx])
+		}
+	}
+
+	ma := "n/a"
+	if OptManifest != "" {
+		man, err := manifest.ReadManifest(OptManifest)
+		if err != nil {
+			ImgmodUsage(nil, err)
+		}
+
+		if err := img.VerifyManifest(man); err != nil {
+			ma = fmt.Sprintf("BAD (%s)", err.Error())
+			anyFails = true
+		} else {
+			ma = "good"
+		}
+	}
+
+	fmt.Printf(" structure: %s\n", st)
+	fmt.Printf("      hash: %s\n", ha)
+	fmt.Printf("signatures: %s\n", si)
+	fmt.Printf("  manifest: %s\n", ma)
+
+	if anyFails {
+		os.Exit(94) // EBADMSG
+	}
+}
+
 func AddImageCommands(cmd *cobra.Command) {
 	imageCmd := &cobra.Command{
 		Use:   "image",
@@ -579,7 +675,7 @@ func AddImageCommands(cmd *cobra.Command) {
 	imageCmd.AddCommand(signCmd)
 
 	addTlvsCmd := &cobra.Command{
-		Use: "addTlvs <img-file> <tlv-type> <data-filename> " +
+		Use: "addtlvs <img-file> <tlv-type> <data-filename> " +
 			"[tlv-type] [data-filename] [...]",
 		Short: "Adds the specified TLVs to a Mynewt image file",
 		Run:   runAddTlvsCmd,
@@ -658,6 +754,8 @@ func AddImageCommands(cmd *cobra.Command) {
 	decryptCmd.PersistentFlags().BoolVarP(&OptInPlace, "inplace", "i", false,
 		"Replace input file")
 
+	imageCmd.AddCommand(decryptCmd)
+
 	decryptFullCmd := &cobra.Command{
 		Use:   "decryptfull <image> <priv-key-der>",
 		Short: "Decrypts an encrypted Mynewt image file (full)",
@@ -705,4 +803,19 @@ func AddImageCommands(cmd *cobra.Command) {
 		"Replace input file")
 
 	imageCmd.AddCommand(encryptFullCmd)
+
+	verifyCmd := &cobra.Command{
+		Use:   "verify <image>",
+		Short: "Verifies an Mynewt image's integrity",
+		Run:   runVerifyCmd,
+	}
+
+	verifyCmd.PersistentFlags().StringSliceVar(&OptSignKeys, "signkey",
+		nil, "Public signing key (.pem) (can be repeated)")
+	verifyCmd.PersistentFlags().StringSliceVar(&OptEncKeys, "enckey",
+		nil, "Private encryption key (.der) (can be repeated)")
+	verifyCmd.PersistentFlags().StringVar(&OptManifest, "manifest",
+		"", "Manifest file")
+
+	imageCmd.AddCommand(verifyCmd)
 }
diff --git a/cli/mfg_cmds.go b/cli/mfg_cmds.go
index afc8461..9ce7108 100644
--- a/cli/mfg_cmds.go
+++ b/cli/mfg_cmds.go
@@ -24,16 +24,17 @@ import (
 	"fmt"
 	"io/ioutil"
 	"os"
+	"sort"
 
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
+	"github.com/apache/mynewt-artifact/flash"
+	"github.com/apache/mynewt-artifact/manifest"
+	"github.com/apache/mynewt-artifact/mfg"
+	"github.com/apache/mynewt-artifact/sec"
 	"mynewt.apache.org/imgmod/imfg"
-	"mynewt.apache.org/newt/artifact/flash"
-	"mynewt.apache.org/newt/artifact/manifest"
-	"mynewt.apache.org/newt/artifact/mfg"
-	"mynewt.apache.org/newt/artifact/misc"
-	"mynewt.apache.org/newt/artifact/sec"
 	"mynewt.apache.org/newt/util"
 )
 
@@ -53,6 +54,37 @@ func readManifest(mfgDir string) (manifest.MfgManifest, error) {
 	return manifest.ReadMfgManifest(mfgDir + "/" + mfg.MANIFEST_FILENAME)
 }
 
+func readMfgDir(mfgDir string) (mfg.Mfg, manifest.MfgManifest, error) {
+	man, err := readManifest(mfgDir)
+	if err != nil {
+		return mfg.Mfg{}, manifest.MfgManifest{}, err
+	}
+
+	binPath := fmt.Sprintf("%s/%s", mfgDir, man.BinPath)
+	bin, err := readMfgBin(binPath)
+	if err != nil {
+		return mfg.Mfg{}, manifest.MfgManifest{}, errors.Wrapf(err,
+			"failed to read \"%s\"", binPath)
+	}
+
+	metaOff := -1
+	if man.Meta != nil {
+		metaOff = man.Meta.EndOffset
+	}
+	m, err := mfg.Parse(bin, metaOff, man.EraseVal)
+	if err != nil {
+		return mfg.Mfg{}, manifest.MfgManifest{}, err
+	}
+
+	return m, man, nil
+}
+
+func mfgTlvStr(tlv mfg.MetaTlv) string {
+	return fmt.Sprintf("%s,0x%02x",
+		mfg.MetaTlvTypeName(tlv.Header.Type),
+		tlv.Header.Type)
+}
+
 func extractFlashAreas(mman manifest.MfgManifest) ([]flash.FlashArea, error) {
 	areas := flash.SortFlashAreasByDevOff(mman.FlashAreas)
 
@@ -138,24 +170,22 @@ func runSplitCmd(cmd *cobra.Command, args []string) {
 	mfgDir := args[0]
 	outDir := args[1]
 
-	mm, err := readManifest(mfgDir)
+	m, man, err := readMfgDir(mfgDir)
 	if err != nil {
 		ImgmodUsage(cmd, err)
 	}
 
-	areas, err := extractFlashAreas(mm)
+	bin, err := m.Bytes(man.EraseVal)
 	if err != nil {
 		ImgmodUsage(nil, err)
 	}
 
-	binPath := fmt.Sprintf("%s/%s", mfgDir, mm.BinPath)
-	bin, err := readMfgBin(binPath)
+	areas, err := extractFlashAreas(man)
 	if err != nil {
-		ImgmodUsage(cmd, util.FmtNewtError(
-			"Failed to read \"%s\": %s", binPath, err.Error()))
+		ImgmodUsage(nil, err)
 	}
 
-	nbmap, err := imfg.Split(bin, mm.Device, areas, 0xff)
+	nbmap, err := imfg.Split(bin, man.Device, areas, man.EraseVal)
 	if err != nil {
 		ImgmodUsage(nil, err)
 	}
@@ -204,12 +234,12 @@ func runJoinCmd(cmd *cobra.Command, args []string) {
 		ImgmodUsage(nil, err)
 	}
 
-	bin, err := imfg.Join(nbmap, 0xff, areas)
+	bin, err := imfg.Join(nbmap, mm.EraseVal, areas)
 	if err != nil {
 		ImgmodUsage(nil, err)
 	}
 
-	m, err := mfg.Parse(bin, mm.Meta.EndOffset, 0xff)
+	m, err := mfg.Parse(bin, mm.Meta.EndOffset, mm.EraseVal)
 	if err != nil {
 		ImgmodUsage(nil, err)
 	}
@@ -234,7 +264,7 @@ func runJoinCmd(cmd *cobra.Command, args []string) {
 		}
 	}
 
-	finalBin, err := m.Bytes(0xff)
+	finalBin, err := m.Bytes(mm.EraseVal)
 	if err != nil {
 		ImgmodUsage(nil, err)
 	}
@@ -311,32 +341,18 @@ func runMfgHashableCmd(cmd *cobra.Command, args []string) {
 	mfgDir := args[0]
 	outFilename := OptOutFilename
 
-	// Read manifest and mfgimg.bin.
-	mman, err := readManifest(mfgDir)
+	m, man, err := readMfgDir(mfgDir)
 	if err != nil {
 		ImgmodUsage(cmd, err)
 	}
 
-	binPath := fmt.Sprintf("%s/%s", mfgDir, mman.BinPath)
-	bin, err := readMfgBin(binPath)
-	if err != nil {
-		ImgmodUsage(cmd, util.FmtNewtError(
-			"Failed to read \"%s\": %s", binPath, err.Error()))
-	}
-
-	metaOff := -1
-	if mman.Meta != nil {
-		metaOff = mman.Meta.EndOffset
-	}
-	m, err := mfg.Parse(bin, metaOff, 0xff)
-	if err != nil {
-		ImgmodUsage(nil, err)
-	}
 	// Zero-out hash so that the hash can be recalculated.
-	m.Meta.ClearHash()
+	if m.Meta != nil {
+		m.Meta.ClearHash()
+	}
 
 	// Write hashable content to disk.
-	newBin, err := m.Bytes(0xff)
+	newBin, err := m.Bytes(man.EraseVal)
 	if err != nil {
 		ImgmodUsage(nil, err)
 	}
@@ -357,48 +373,30 @@ func runRehashCmd(cmd *cobra.Command, args []string) {
 		ImgmodUsage(cmd, err)
 	}
 
-	// Read manifest and mfgimg.bin.
-	mman, err := readManifest(mfgDir)
+	m, man, err := readMfgDir(mfgDir)
 	if err != nil {
 		ImgmodUsage(cmd, err)
 	}
 
-	binPath := fmt.Sprintf("%s/%s", mfgDir, mman.BinPath)
-	bin, err := readMfgBin(binPath)
-	if err != nil {
-		ImgmodUsage(cmd, util.FmtNewtError(
-			"Failed to read \"%s\": %s", binPath, err.Error()))
-	}
-
-	// Calculate accurate hash.
-	metaOff := -1
-	if mman.Meta != nil {
-		metaOff = mman.Meta.EndOffset
-	}
-	m, err := mfg.Parse(bin, metaOff, 0xff)
-	if err != nil {
-		ImgmodUsage(nil, err)
-	}
-
-	if err := m.RecalcHash(0xff); err != nil {
+	if err := m.RefillHash(man.EraseVal); err != nil {
 		ImgmodUsage(nil, err)
 	}
 
-	hash, err := m.Hash()
+	hash, err := m.Hash(man.EraseVal)
 	if err != nil {
 		ImgmodUsage(nil, err)
 	}
 
 	// Update manifest.
-	mman.MfgHash = misc.HashString(hash)
+	man.MfgHash = hex.EncodeToString(hash)
 
 	// Write new artifacts.
 	if err := EnsureOutDir(mfgDir, outDir); err != nil {
 		ImgmodUsage(nil, err)
 	}
-	binPath = fmt.Sprintf("%s/%s", outDir, mman.BinPath)
+	binPath := fmt.Sprintf("%s/%s", outDir, man.BinPath)
 
-	newBin, err := m.Bytes(0xff)
+	newBin, err := m.Bytes(man.EraseVal)
 	if err != nil {
 		ImgmodUsage(nil, err)
 	}
@@ -406,7 +404,7 @@ func runRehashCmd(cmd *cobra.Command, args []string) {
 		ImgmodUsage(nil, err)
 	}
 
-	json, err := mman.MarshalJson()
+	json, err := man.MarshalJson()
 	if err != nil {
 		ImgmodUsage(nil, err)
 	}
@@ -515,6 +513,143 @@ func runAddsigMfgCmd(cmd *cobra.Command, args []string) {
 	}
 }
 
+func runRmtlvsMfgCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 2 {
+		ImgmodUsage(cmd, nil)
+	}
+
+	mfgDir := args[0]
+
+	outFilename, err := CalcOutFilename(
+		mfgDir + "/" + mfg.MFG_BIN_IMG_FILENAME)
+	if err != nil {
+		ImgmodUsage(cmd, err)
+	}
+
+	m, man, err := readMfgDir(mfgDir)
+	if err != nil {
+		ImgmodUsage(cmd, err)
+	}
+
+	numTlvs := 0
+	if m.Meta != nil {
+		numTlvs = len(m.Meta.Tlvs)
+	}
+
+	tlvIndices := []int{}
+	idxMap := map[int]struct{}{}
+	for _, arg := range args[1:] {
+		idx, err := util.AtoiNoOct(arg)
+		if err != nil {
+			ImgmodUsage(cmd, util.FmtNewtError("Invalid TLV index: %s", arg))
+		}
+
+		if idx < 0 || idx >= numTlvs {
+			ImgmodUsage(nil, util.FmtNewtError(
+				"TLV index %s out of range; "+
+					"must be in range [0, %d] for this mfgimage",
+				arg, numTlvs-1))
+		}
+
+		if _, ok := idxMap[idx]; ok {
+			ImgmodUsage(nil, util.FmtNewtError(
+				"TLV index %d specified more than once", idx))
+		}
+		idxMap[idx] = struct{}{}
+
+		tlvIndices = append(tlvIndices, idx)
+	}
+
+	// Remove TLVs in reverse order to preserve index mapping.
+	sort.Sort(sort.Reverse(sort.IntSlice(tlvIndices)))
+	for _, idx := range tlvIndices {
+		tlv := m.Meta.Tlvs[idx]
+		util.StatusMessage(util.VERBOSITY_DEFAULT,
+			"Removing TLV%d: %s\n", idx, mfgTlvStr(tlv))
+
+		tlvSz := mfg.META_TLV_HEADER_SZ + len(tlv.Data)
+		m.MetaOff += tlvSz
+		m.Meta.Footer.Size -= uint16(tlvSz)
+
+		m.Meta.Tlvs = append(m.Meta.Tlvs[0:idx], m.Meta.Tlvs[idx+1:]...)
+	}
+
+	// Rehash.
+	if err := m.RefillHash(man.EraseVal); err != nil {
+		ImgmodUsage(nil, err)
+	}
+
+	// Write new artifacts.
+	newBin, err := m.Bytes(man.EraseVal)
+	if err != nil {
+		ImgmodUsage(nil, err)
+	}
+	if err := WriteFile(newBin, outFilename); err != nil {
+		ImgmodUsage(nil, err)
+	}
+}
+
+func runVerifyMfgCmd(cmd *cobra.Command, args []string) {
+	anyFails := false
+
+	if len(args) < 1 {
+		ImgmodUsage(cmd, nil)
+	}
+
+	mfgDir := args[0]
+
+	// Read mfgimg.bin and manifest.
+	m, man, err := readMfgDir(mfgDir)
+	if err != nil {
+		ImgmodUsage(cmd, err)
+	}
+
+	st := ""
+	if err := m.VerifyStructure(man.EraseVal); err != nil {
+		st = fmt.Sprintf("BAD (%s)", err.Error())
+		anyFails = true
+	} else {
+		st = "good"
+	}
+
+	ma := ""
+	if err := m.VerifyManifest(man); err != nil {
+		ma = fmt.Sprintf("BAD (%s)", err.Error())
+		anyFails = true
+	} else {
+		ma = "good"
+	}
+
+	iss, err := sec.ReadPubSignKeys(OptSignKeys)
+	if err != nil {
+		ImgmodUsage(nil, errors.Wrapf(err,
+			"error reading signing key file"))
+	}
+
+	si := ""
+	if len(man.Signatures) == 0 {
+		si = "n/a"
+	} else if len(iss) == 0 {
+		si = "not checked"
+	} else {
+		idx, err := mfg.VerifySigs(man, iss)
+		if err != nil {
+			si = fmt.Sprintf("BAD (%s)", err.Error())
+			anyFails = true
+		} else {
+			si = fmt.Sprintf("good (%s)", OptSignKeys[idx])
+		}
+	}
+
+	fmt.Printf(" structure: %s\n", st)
+	fmt.Printf("signatures: %s\n", si)
+	fmt.Printf("  manifest: %s\n", ma)
+
+	if anyFails {
+		os.Exit(94) // EBADMSG
+	}
+}
+
 func AddMfgCommands(cmd *cobra.Command) {
 	mfgCmd := &cobra.Command{
 		Use:   "mfg",
@@ -620,4 +755,28 @@ func AddMfgCommands(cmd *cobra.Command) {
 		"Replace input files")
 
 	mfgCmd.AddCommand(addsigCmd)
+
+	rmtlvsCmd := &cobra.Command{
+		Use:   "rmtlvs <mfgimage-dir> <tlv-index> [tlv-index] [...]",
+		Short: "Removes the specified TLVs from a Mynewt mfgimage",
+		Run:   runRmtlvsMfgCmd,
+	}
+
+	rmtlvsCmd.PersistentFlags().StringVarP(&OptOutFilename, "outfile", "o", "",
+		"File to write to")
+	rmtlvsCmd.PersistentFlags().BoolVarP(&OptInPlace, "inplace", "i", false,
+		"Replace input file")
+
+	mfgCmd.AddCommand(rmtlvsCmd)
+
+	verifyCmd := &cobra.Command{
+		Use:   "verify <mfgimage-dir>",
+		Short: "Verifies an Mynewt mfgimage's integrity",
+		Run:   runVerifyMfgCmd,
+	}
+
+	verifyCmd.PersistentFlags().StringSliceVar(&OptSignKeys, "signkey",
+		nil, "Public signing key (.pem) (can be repeated)")
+
+	mfgCmd.AddCommand(verifyCmd)
 }
diff --git a/cli/util.go b/cli/util.go
index a2729ad..74d8ebf 100644
--- a/cli/util.go
+++ b/cli/util.go
@@ -32,12 +32,14 @@ import (
 
 var OptOutFilename string
 var OptInPlace bool
+var OptSignKeys []string
+var OptEncKeys []string
+var OptManifest string
 
 func ImgmodUsage(cmd *cobra.Command, err error) {
 	if err != nil {
-		sErr := err.(*util.NewtError)
-		log.Debugf("%s", sErr.StackTrace)
-		fmt.Fprintf(os.Stderr, "Error: %s\n", sErr.Text)
+		log.Debugf("%+v", err)
+		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
 	}
 
 	if cmd != nil {
diff --git a/go.mod b/go.mod
index a1505df..795ba11 100644
--- a/go.mod
+++ b/go.mod
@@ -1,7 +1,10 @@
 module mynewt.apache.org/imgmod
 
 require (
+	github.com/apache/mynewt-artifact v0.0.2
+	github.com/pkg/errors v0.8.1
 	github.com/sirupsen/logrus v1.4.0
 	github.com/spf13/cobra v0.0.3
+	github.com/spf13/pflag v1.0.3 // indirect
 	mynewt.apache.org/newt v0.0.0-20190529170335-75b2c282a77d
 )
diff --git a/go.sum b/go.sum
index ef709dd..6df6f34 100644
--- a/go.sum
+++ b/go.sum
@@ -1,11 +1,16 @@
 github.com/NickBall/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5 h1:5BIUS5hwyLM298mOf8e8TEgD3cCYqc86uaJdQCYZo/o=
 github.com/NickBall/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5/go.mod h1:w5D10RxC0NmPYxmQ438CC1S07zaC1zpvuNW7s5sUk2Q=
+github.com/apache/mynewt-artifact v0.0.2 h1:2tBlf84kyAifrEilcw1kQFQ8kpq4wBSudXpO8BEOXhw=
+github.com/apache/mynewt-artifact v0.0.2/go.mod h1:vFUd47t74KPQMzSBhQ2qp5Hc7D29OU/Tl3xHtFwN3k8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
@@ -16,16 +21,29 @@ github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
 github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 h1:IcSOAf4PyMp3U3XbIEj1/xJ2BjNN2jWv7JoyOsMxXUU=
+golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/sys v0.0.0-20180707002001-3c6ecd8f22c6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-mynewt.apache.org/newt v0.0.0-20190314184600-c5632c20daf3 h1:U9HanOWwCKSPTCZu7ti0MlmMlkWpTiR856BR2bRzHaU=
-mynewt.apache.org/newt v0.0.0-20190314184600-c5632c20daf3/go.mod h1:lFsPYOHxMMWA11pydOeh0GVFiXtx0A9VnzOQ6SiRR88=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 mynewt.apache.org/newt v0.0.0-20190529170335-75b2c282a77d h1:dnv0EBSSD88NahC0Pow+5DOH7gy4D5xj5n1iCIxA2NY=
 mynewt.apache.org/newt v0.0.0-20190529170335-75b2c282a77d/go.mod h1:lFsPYOHxMMWA11pydOeh0GVFiXtx0A9VnzOQ6SiRR88=
diff --git a/iimg/iimg.go b/iimg/iimg.go
index 7c28ed7..29dd8a2 100644
--- a/iimg/iimg.go
+++ b/iimg/iimg.go
@@ -24,8 +24,9 @@ import (
 	"fmt"
 	"strings"
 
-	"mynewt.apache.org/newt/artifact/image"
-	"mynewt.apache.org/newt/artifact/sec"
+	"github.com/apache/mynewt-artifact/errors"
+	"github.com/apache/mynewt-artifact/image"
+	"github.com/apache/mynewt-artifact/sec"
 	"mynewt.apache.org/newt/util"
 )
 
@@ -84,7 +85,7 @@ func DetectInvalidSigTlvs(img image.Image) error {
 
 func VerifyImage(img image.Image) error {
 	if len(img.Tlvs) == 0 || img.Tlvs[0].Header.Type != image.IMAGE_TLV_SHA256 {
-		return util.FmtNewtError("First TLV must be SHA256")
+		return errors.Errorf("First TLV must be SHA256")
 	}
 
 	if err := DetectInvalidSigTlvs(img); err != nil {
@@ -128,33 +129,6 @@ func ExtractSecret(img *image.Image) ([]byte, error) {
 	return tlvs[0].Data, nil
 }
 
-// XXX: Only RSA supported for now.
-func DecryptImage(img image.Image, privKeBytes []byte) (image.Image, error) {
-	cipherSecret, err := ExtractSecret(&img)
-	if err != nil {
-		return img, err
-	}
-
-	privKe, err := sec.ParsePrivKeDer(privKeBytes)
-	if err != nil {
-		return img, err
-	}
-
-	plainSecret, err := sec.DecryptSecretRsa(privKe, cipherSecret)
-	if err != nil {
-		return img, err
-	}
-
-	body, err := sec.EncryptAES(img.Body, plainSecret)
-	if err != nil {
-		return img, err
-	}
-
-	img.Body = body
-
-	return img, nil
-}
-
 func recalcHash(img image.Image) (image.Image, error) {
 	hash, err := img.CalcHash()
 	if err != nil {
@@ -162,18 +136,32 @@ func recalcHash(img image.Image) (image.Image, error) {
 	}
 
 	img.RemoveTlvsWithType(image.IMAGE_TLV_SHA256)
-	img.Tlvs = append(img.Tlvs, image.ImageTlv{
+
+	tlv := image.ImageTlv{
 		Header: image.ImageTlvHdr{
 			Type: image.IMAGE_TLV_SHA256,
 			Pad:  0,
 			Len:  uint16(len(hash)),
 		},
 		Data: hash,
-	})
+	}
+
+	// The SHA256 TLV must come first.
+	img.Tlvs = append([]image.ImageTlv{tlv}, img.Tlvs...)
 
 	return img, nil
 }
 
+// XXX: Only RSA supported for now.
+func DecryptImage(img image.Image, privKeBytes []byte) (image.Image, error) {
+	key, err := sec.ParsePrivEncKey(privKeBytes)
+	if err != nil {
+		return img, err
+	}
+
+	return image.Decrypt(img, key)
+}
+
 func DecryptImageFull(img image.Image,
 	privKeBytes []byte) (image.Image, error) {
 
@@ -195,54 +183,27 @@ func DecryptImageFull(img image.Image,
 }
 
 func EncryptImage(img image.Image, pubKeBytes []byte) (image.Image, error) {
-	tlvp, err := img.FindUniqueTlv(image.IMAGE_TLV_ENC_RSA)
-	if err != nil {
-		return img, err
-	}
-	if tlvp != nil {
-		return img, util.FmtNewtError("Image already contains an ENC_RSA TLV")
-	}
-
-	plainSecret, err := image.GeneratePlainSecret()
-	if err != nil {
-		return img, err
-	}
-
-	cipherSecret, err := image.GenerateCipherSecret(pubKeBytes, plainSecret)
-	if err != nil {
-		return img, err
-	}
-
-	body, err := sec.EncryptAES(img.Body, plainSecret)
+	key, err := sec.ParsePubEncKey(pubKeBytes)
 	if err != nil {
 		return img, err
 	}
-	img.Body = body
 
-	tlv, err := image.GenerateEncTlv(cipherSecret)
-	if err != nil {
-		return img, err
-	}
-	img.Tlvs = append(img.Tlvs, tlv)
-
-	img.Header.Flags |= image.IMAGE_F_ENCRYPTED
-
-	return img, nil
+	return image.Encrypt(img, key)
 }
 
 func EncryptImageFull(img image.Image,
 	pubKeBytes []byte) (image.Image, error) {
 
+	img.Header.Flags |= image.IMAGE_F_ENCRYPTED
+
+	// The hash needs to be recalculated now that the header has changed.
 	var err error
-	img, err = EncryptImage(img, pubKeBytes)
+	img, err = recalcHash(img)
 	if err != nil {
 		return img, err
 	}
 
-	img.Header.Flags |= image.IMAGE_F_ENCRYPTED
-
-	// The hash needs to be recalculated now that the header has changed.
-	img, err = recalcHash(img)
+	img, err = EncryptImage(img, pubKeBytes)
 	if err != nil {
 		return img, err
 	}
diff --git a/imfg/imfg.go b/imfg/imfg.go
index 9472ee1..28dab7a 100644
--- a/imfg/imfg.go
+++ b/imfg/imfg.go
@@ -26,8 +26,8 @@ import (
 	"sort"
 	"strings"
 
-	"mynewt.apache.org/newt/artifact/flash"
-	"mynewt.apache.org/newt/artifact/mfg"
+	"github.com/apache/mynewt-artifact/flash"
+	"github.com/apache/mynewt-artifact/mfg"
 	"mynewt.apache.org/newt/util"
 )