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-newt.git

commit a6095d7db80304e75b5cc03e0438460954bc7c22
Author: Christopher Collins <ccoll...@apache.org>
AuthorDate: Tue Dec 18 18:18:18 2018 -0800

    larva: Add `image {de,en}crypt` commands
---
 larva/cli/image_cmds.go |  94 ++++++++++++++++++++++++++++++
 larva/cli/mfg_cmds.go   | 151 +++++++++++++++++++++++++++++++++++++-----------
 larva/cli/util.go       |  36 +++++++++++-
 larva/lvimg/lvimg.go    |  72 +++++++++++++++++++++++
 larva/lvmfg/lvmfg.go    |   6 +-
 5 files changed, 321 insertions(+), 38 deletions(-)

diff --git a/larva/cli/image_cmds.go b/larva/cli/image_cmds.go
index cdcac33..846c137 100644
--- a/larva/cli/image_cmds.go
+++ b/larva/cli/image_cmds.go
@@ -399,6 +399,74 @@ func runAddsigCmd(cmd *cobra.Command, args []string) {
        }
 }
 
+func runDecryptCmd(cmd *cobra.Command, args []string) {
+       if len(args) < 2 {
+               LarvaUsage(cmd, nil)
+       }
+
+       imgFilename := args[0]
+       keyFilename := args[1]
+
+       outFilename, err := CalcOutFilename(imgFilename)
+       if err != nil {
+               LarvaUsage(cmd, err)
+       }
+
+       img, err := readImage(imgFilename)
+       if err != nil {
+               LarvaUsage(cmd, err)
+       }
+
+       keyBytes, err := ioutil.ReadFile(keyFilename)
+       if err != nil {
+               LarvaUsage(cmd, util.FmtNewtError(
+                       "Error reading key file: %s", err.Error()))
+       }
+
+       img, err = lvimg.DecryptImage(img, keyBytes)
+       if err != nil {
+               LarvaUsage(nil, err)
+       }
+
+       if err := writeImage(img, outFilename); err != nil {
+               LarvaUsage(nil, err)
+       }
+}
+
+func runEncryptCmd(cmd *cobra.Command, args []string) {
+       if len(args) < 2 {
+               LarvaUsage(cmd, nil)
+       }
+
+       imgFilename := args[0]
+       keyFilename := args[1]
+
+       outFilename, err := CalcOutFilename(imgFilename)
+       if err != nil {
+               LarvaUsage(cmd, err)
+       }
+
+       img, err := readImage(imgFilename)
+       if err != nil {
+               LarvaUsage(cmd, err)
+       }
+
+       keyBytes, err := ioutil.ReadFile(keyFilename)
+       if err != nil {
+               LarvaUsage(cmd, util.FmtNewtError(
+                       "Error reading key file: %s", err.Error()))
+       }
+
+       img, err = lvimg.EncryptImage(img, keyBytes)
+       if err != nil {
+               LarvaUsage(nil, err)
+       }
+
+       if err := writeImage(img, outFilename); err != nil {
+               LarvaUsage(nil, err)
+       }
+}
+
 func AddImageCommands(cmd *cobra.Command) {
        imageCmd := &cobra.Command{
                Use:   "image",
@@ -499,4 +567,30 @@ func AddImageCommands(cmd *cobra.Command) {
                "Replace input file")
 
        imageCmd.AddCommand(addsigCmd)
+
+       decryptCmd := &cobra.Command{
+               Use:   "decrypt <image> <priv-key-der>",
+               Short: "Decrypts an encrypted Mynewt image file",
+               Run:   runDecryptCmd,
+       }
+
+       decryptCmd.PersistentFlags().StringVarP(&OptOutFilename, "outfile", "o",
+               "", "File to write to")
+       decryptCmd.PersistentFlags().BoolVarP(&OptInPlace, "inplace", "i", 
false,
+               "Replace input file")
+
+       imageCmd.AddCommand(decryptCmd)
+
+       encryptCmd := &cobra.Command{
+               Use:   "encrypt <image> <priv-key-der>",
+               Short: "Encrypts a Mynewt image file",
+               Run:   runEncryptCmd,
+       }
+
+       encryptCmd.PersistentFlags().StringVarP(&OptOutFilename, "outfile", "o",
+               "", "File to write to")
+       encryptCmd.PersistentFlags().BoolVarP(&OptInPlace, "inplace", "i", 
false,
+               "Replace input file")
+
+       imageCmd.AddCommand(encryptCmd)
 }
diff --git a/larva/cli/mfg_cmds.go b/larva/cli/mfg_cmds.go
index 1a90b12..45c6372 100644
--- a/larva/cli/mfg_cmds.go
+++ b/larva/cli/mfg_cmds.go
@@ -30,6 +30,7 @@ import (
        "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/larva/lvmfg"
        "mynewt.apache.org/newt/util"
 )
@@ -37,7 +38,7 @@ import (
 func readMfgBin(filename string) ([]byte, error) {
        bin, err := ioutil.ReadFile(filename)
        if err != nil {
-               return nil, util.FmtNewtError(
+               return nil, util.FmtChildNewtError(err,
                        "Failed to read manufacturing image: %s", err.Error())
        }
 
@@ -76,9 +77,9 @@ func createNameBlobMap(binDir string,
 
        for _, area := range areas {
                filename := fmt.Sprintf("%s/%s.bin", binDir, area.Name)
-               bin, err := ioutil.ReadFile(filename)
+               bin, err := readMfgBin(filename)
                if err != nil {
-                       if !os.IsNotExist(err) {
+                       if !util.IsNotExist(err) {
                                return nil, util.ChildNewtError(err)
                        }
                } else {
@@ -144,7 +145,7 @@ func runSplitCmd(cmd *cobra.Command, args []string) {
        }
 
        binPath := fmt.Sprintf("%s/%s", mfgDir, mm.BinPath)
-       bin, err := ioutil.ReadFile(binPath)
+       bin, err := readMfgBin(binPath)
        if err != nil {
                LarvaUsage(cmd, util.FmtNewtError(
                        "Failed to read \"%s\": %s", binPath, err.Error()))
@@ -161,17 +162,13 @@ func runSplitCmd(cmd *cobra.Command, args []string) {
 
        for name, data := range nbmap {
                filename := fmt.Sprintf("%s/%s.bin", outDir, name)
-               if err := ioutil.WriteFile(filename, data,
-                       os.ModePerm); err != nil {
-
-                       LarvaUsage(nil, util.ChildNewtError(err))
+               if err := WriteFile(data, filename); err != nil {
+                       LarvaUsage(nil, err)
                }
        }
 
        mfgDstDir := fmt.Sprintf("%s/mfg", outDir)
-       util.StatusMessage(util.VERBOSITY_DEFAULT,
-               "Copying source mfg directory to %s\n", mfgDstDir)
-       if err := util.CopyDir(mfgDir, mfgDstDir); err != nil {
+       if err := CopyDir(mfgDir, mfgDstDir); err != nil {
                LarvaUsage(nil, err)
        }
 }
@@ -223,9 +220,9 @@ func runJoinCmd(cmd *cobra.Command, args []string) {
                        src := splitDir + "/mfg/" + info.Name()
                        dst := outDir + "/" + info.Name()
                        if info.IsDir() {
-                               err = util.CopyDir(src, dst)
+                               err = CopyDir(src, dst)
                        } else {
-                               err = util.CopyFile(src, dst)
+                               err = CopyFile(src, dst)
                        }
                        if err != nil {
                                LarvaUsage(nil, err)
@@ -238,31 +235,30 @@ func runJoinCmd(cmd *cobra.Command, args []string) {
                LarvaUsage(nil, err)
        }
 
-       if err := ioutil.WriteFile(outDir+"/"+mfg.MFG_IMG_FILENAME, finalBin,
-               os.ModePerm); err != nil {
-
-               LarvaUsage(nil, util.ChildNewtError(err))
+       binPath := fmt.Sprintf("%s/%s", outDir, mfg.MFG_IMG_FILENAME)
+       if err := WriteFile(finalBin, binPath); err != nil {
+               LarvaUsage(nil, err)
        }
 }
 
-func runBootKeyCmd(cmd *cobra.Command, args []string) {
+func runSwapKeyCmd(cmd *cobra.Command, args []string) {
        if len(args) < 3 {
                LarvaUsage(cmd, nil)
        }
 
-       sec0Filename := args[0]
+       mfgimgFilename := args[0]
        okeyFilename := args[1]
        nkeyFilename := args[2]
 
-       outFilename, err := CalcOutFilename(sec0Filename)
+       outFilename, err := CalcOutFilename(mfgimgFilename)
        if err != nil {
                LarvaUsage(cmd, err)
        }
 
-       sec0, err := ioutil.ReadFile(sec0Filename)
+       bin, err := readMfgBin(mfgimgFilename)
        if err != nil {
                LarvaUsage(cmd, util.FmtNewtError(
-                       "Failed to read sec0 file: %s", err.Error()))
+                       "Failed to read mfgimg file: %s", err.Error()))
        }
 
        okey, err := ioutil.ReadFile(okeyFilename)
@@ -277,12 +273,87 @@ func runBootKeyCmd(cmd *cobra.Command, args []string) {
                        "Failed to read new key der: %s", err.Error()))
        }
 
-       if err := lvmfg.ReplaceBootKey(sec0, okey, nkey); err != nil {
+       if err := lvmfg.ReplaceKey(bin, okey, nkey); err != nil {
                LarvaUsage(nil, err)
        }
 
-       if err := ioutil.WriteFile(outFilename, sec0, os.ModePerm); err != nil {
-               LarvaUsage(nil, util.ChildNewtError(err))
+       if err := WriteFile(bin, outFilename); err != nil {
+               LarvaUsage(nil, err)
+       }
+}
+
+func runRehashCmd(cmd *cobra.Command, args []string) {
+       if len(args) < 1 {
+               LarvaUsage(cmd, nil)
+       }
+
+       mfgDir := args[0]
+
+       outDir, err := CalcOutFilename(mfgDir)
+       if err != nil {
+               LarvaUsage(cmd, err)
+       }
+
+       // Read manifest and mfgimg.bin.
+       mman, err := readManifest(mfgDir)
+       if err != nil {
+               LarvaUsage(cmd, err)
+       }
+
+       binPath := fmt.Sprintf("%s/%s", mfgDir, mman.BinPath)
+       bin, err := readMfgBin(binPath)
+       if err != nil {
+               LarvaUsage(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 {
+               LarvaUsage(nil, err)
+       }
+
+       if err := m.RecalcHash(0xff); err != nil {
+               LarvaUsage(nil, err)
+       }
+
+       hash, err := m.Hash()
+       if err != nil {
+               LarvaUsage(nil, err)
+       }
+
+       // Update manifest.
+       mman.MfgHash = misc.HashString(hash)
+
+       // Write new artifacts.
+       if outDir != mfgDir {
+               // Not an in-place operation; copy input directory.
+               if err := CopyDir(mfgDir, outDir); err != nil {
+                       LarvaUsage(nil, err)
+               }
+               binPath = fmt.Sprintf("%s/%s", outDir, mman.BinPath)
+       }
+
+       newBin, err := m.Bytes(0xff)
+       if err != nil {
+               LarvaUsage(nil, err)
+       }
+       if err := WriteFile(newBin, binPath); err != nil {
+               LarvaUsage(nil, err)
+       }
+
+       json, err := mman.MarshalJson()
+       if err != nil {
+               LarvaUsage(nil, err)
+       }
+
+       manPath := fmt.Sprintf("%s/%s", outDir, mfg.MANIFEST_FILENAME)
+       if err := WriteFile(json, manPath); err != nil {
+               LarvaUsage(nil, err)
        }
 }
 
@@ -305,7 +376,7 @@ func AddMfgCommands(cmd *cobra.Command) {
        mfgCmd.AddCommand(showCmd)
 
        splitCmd := &cobra.Command{
-               Use:   "split <mfg-image-dir> <out-dir>",
+               Use:   "split <mfgimage-dir> <out-dir>",
                Short: "Splits a Mynewt mfg section into several files",
                Run:   runSplitCmd,
        }
@@ -320,16 +391,28 @@ func AddMfgCommands(cmd *cobra.Command) {
 
        mfgCmd.AddCommand(joinCmd)
 
-       bootKeyCmd := &cobra.Command{
-               Use:   "bootkey <sec0-bin> <cur-key-der> <new-key-der>",
-               Short: "Replaces the boot key in a manufacturing image",
-               Run:   runBootKeyCmd,
+       swapKeyCmd := &cobra.Command{
+               Use:   "swapkey <mfgimg-bin> <cur-key-der> <new-key-der>",
+               Short: "Replaces a key in a manufacturing image",
+               Run:   runSwapKeyCmd,
        }
 
-       bootKeyCmd.PersistentFlags().StringVarP(&OptOutFilename, "outfile", 
"o", "",
-               "File to write to")
-       bootKeyCmd.PersistentFlags().BoolVarP(&OptInPlace, "inplace", "i", 
false,
+       swapKeyCmd.PersistentFlags().StringVarP(&OptOutFilename, "outfile", "o",
+               "", "File to write to")
+       swapKeyCmd.PersistentFlags().BoolVarP(&OptInPlace, "inplace", "i", 
false,
                "Replace input file")
 
-       mfgCmd.AddCommand(bootKeyCmd)
+       mfgCmd.AddCommand(swapKeyCmd)
+
+       rehashCmd := &cobra.Command{
+               Use:   "rehash <mfgimage-dir>",
+               Short: "Replaces an outdated mfgimage hash with an accurate 
one",
+               Run:   runRehashCmd,
+       }
+       rehashCmd.PersistentFlags().StringVarP(&OptOutFilename, "outdir", "o",
+               "", "Directory to write to")
+       rehashCmd.PersistentFlags().BoolVarP(&OptInPlace, "inplace", "i", false,
+               "Replace input files")
+
+       mfgCmd.AddCommand(rehashCmd)
 }
diff --git a/larva/cli/util.go b/larva/cli/util.go
index 20c3d5e..ce574e3 100644
--- a/larva/cli/util.go
+++ b/larva/cli/util.go
@@ -21,6 +21,7 @@ package cli
 
 import (
        "fmt"
+       "io/ioutil"
        "os"
 
        log "github.com/Sirupsen/logrus"
@@ -40,7 +41,6 @@ func LarvaUsage(cmd *cobra.Command, err error) {
        }
 
        if cmd != nil {
-               fmt.Printf("\n")
                fmt.Printf("%s - ", cmd.Name())
                cmd.Help()
        }
@@ -64,3 +64,37 @@ func CalcOutFilename(inFilename string) (string, error) {
 
        return inFilename, nil
 }
+
+func CopyDir(src string, dst string) error {
+       if err := util.CopyDir(src, dst); err != nil {
+               return util.FmtNewtError(
+                       "Failed to copy directory \"%s\" to \"%s\": %s",
+                       src, dst, err.Error())
+       }
+
+       util.StatusMessage(util.VERBOSITY_DEFAULT,
+               "Copied directory \"%s\" to \"%s\"\n", src, dst)
+       return nil
+}
+
+func CopyFile(src string, dst string) error {
+       if err := util.CopyFile(src, dst); err != nil {
+               return util.FmtNewtError(
+                       "Failed to copy file \"%s\" to \"%s\": %s",
+                       src, dst, err.Error())
+       }
+
+       util.StatusMessage(util.VERBOSITY_DEFAULT,
+               "Copied file \"%s\" to \"%s\"\n", src, dst)
+       return nil
+}
+
+func WriteFile(data []byte, filename string) error {
+       if err := ioutil.WriteFile(filename, data, os.ModePerm); err != nil {
+               return util.FmtNewtError(
+                       "Failed to write file \"%s\": %s", filename, 
err.Error())
+       }
+
+       util.StatusMessage(util.VERBOSITY_DEFAULT, "Wrote file \"%s\"\n", 
filename)
+       return nil
+}
diff --git a/larva/lvimg/lvimg.go b/larva/lvimg/lvimg.go
index 60d5ef4..8522199 100644
--- a/larva/lvimg/lvimg.go
+++ b/larva/lvimg/lvimg.go
@@ -114,3 +114,75 @@ func PadEcdsa256Sig(sig []byte) ([]byte, error) {
 
        return sig, nil
 }
+
+// XXX: Only RSA supported for now.
+func ExtractSecret(img *image.Image) ([]byte, error) {
+       tlvs := img.RemoveTlvsWithType(image.IMAGE_TLV_ENC_RSA)
+       if len(tlvs) != 1 {
+               return nil, util.FmtNewtError(
+                       "Image contains invalid count of ENC_RSA TLVs: %d; must 
contain 1",
+                       len(tlvs))
+       }
+
+       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 := image.ParsePrivKeDer(privKeBytes)
+       if err != nil {
+               return img, err
+       }
+
+       plainSecret, err := image.DecryptSecretRsa(privKe, cipherSecret)
+       if err != nil {
+               return img, err
+       }
+
+       body, err := image.EncryptImageBody(img.Body, plainSecret)
+       if err != nil {
+               return img, err
+       }
+
+       img.Body = body
+       return img, nil
+}
+
+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 := image.EncryptImageBody(img.Body, plainSecret)
+       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)
+
+       return img, nil
+}
diff --git a/larva/lvmfg/lvmfg.go b/larva/lvmfg/lvmfg.go
index dbc0168..8bb6a22 100644
--- a/larva/lvmfg/lvmfg.go
+++ b/larva/lvmfg/lvmfg.go
@@ -136,7 +136,7 @@ func Join(mm NameBlobMap, eraseVal byte,
                                binstr = fmt.Sprintf("%x", bin[:4])
                        }
                        util.StatusMessage(util.VERBOSITY_DEFAULT,
-                               "inserting %s (%x) at offset %d (0x%x)\n",
+                               "inserting %s (%s) at offset %d (0x%x)\n",
                                area.Name, binstr, len(joined), len(joined))
                        joined = append(joined, bin...)
                }
@@ -154,13 +154,13 @@ func Join(mm NameBlobMap, eraseVal byte,
                        "unprocessed flash areas: %s", strings.Join(names, ", 
"))
        }
 
-       // Strip padding from the end of the joined bianry.
+       // Strip padding from the end of the joined binary.
        joined = StripPadding(joined, eraseVal)
 
        return joined, nil
 }
 
-func ReplaceBootKey(sec0 []byte, okey []byte, nkey []byte) error {
+func ReplaceKey(sec0 []byte, okey []byte, nkey []byte) error {
        if len(okey) != len(nkey) {
                return util.FmtNewtError(
                        "key lengths differ (%d != %d)", len(okey), len(nkey))

Reply via email to