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/21 21:25:27 UTC
[mynewt-artifact] 03/23: Artifact library update
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-artifact.git
commit 0bac15238d4dd730c3f395e484811cdb2c0baff0
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Tue Dec 18 18:20:18 2018 -0800
Artifact library update
---
flash/flash.go | 10 +--
image/create.go | 147 ++++++++++++++++++++++---------------------
image/image.go | 52 +++++++++------
image/key.go | 66 +++++++++++++++----
image/v1.go | 16 +++--
mfg/mfg.go | 74 +++++++++++++---------
mfg/paths.go => misc/misc.go | 13 +---
7 files changed, 228 insertions(+), 150 deletions(-)
diff --git a/flash/flash.go b/flash/flash.go
index c37d2dd..6b85814 100644
--- a/flash/flash.go
+++ b/flash/flash.go
@@ -38,11 +38,11 @@ var SYSTEM_AREA_NAME_ID_MAP = map[string]int{
}
type FlashArea struct {
- Name string
- Id int
- Device int
- Offset int
- Size int
+ Name string `json:"name"`
+ Id int `json:"id"`
+ Device int `json:"device"`
+ Offset int `json:"offset"`
+ Size int `json:"size"`
}
type areaOffSorter struct {
diff --git a/image/create.go b/image/create.go
index c3e8820..76e701d 100644
--- a/image/create.go
+++ b/image/create.go
@@ -69,7 +69,7 @@ func NewImageCreator() ImageCreator {
}
}
-func generateEncTlv(cipherSecret []byte) (ImageTlv, error) {
+func GenerateEncTlv(cipherSecret []byte) (ImageTlv, error) {
var encType uint8
if len(cipherSecret) == 256 {
@@ -90,7 +90,7 @@ func generateEncTlv(cipherSecret []byte) (ImageTlv, error) {
}, nil
}
-func generateSigRsa(key ImageSigKey, hash []byte) ([]byte, error) {
+func GenerateSigRsa(key ImageSigKey, hash []byte) ([]byte, error) {
opts := rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthEqualsHash,
}
@@ -103,7 +103,7 @@ func generateSigRsa(key ImageSigKey, hash []byte) ([]byte, error) {
return signature, nil
}
-func generateSigEc(key ImageSigKey, hash []byte) ([]byte, error) {
+func GenerateSigEc(key ImageSigKey, hash []byte) ([]byte, error) {
r, s, err := ecdsa.Sign(rand.Reader, key.Ec, hash)
if err != nil {
return nil, util.FmtNewtError("Failed to compute signature: %s", err)
@@ -130,13 +130,13 @@ func generateSigEc(key ImageSigKey, hash []byte) ([]byte, error) {
return signature, nil
}
-func generateSig(key ImageSigKey, hash []byte) ([]byte, error) {
+func GenerateSig(key ImageSigKey, hash []byte) ([]byte, error) {
key.assertValid()
if key.Rsa != nil {
- return generateSigRsa(key, hash)
+ return GenerateSigRsa(key, hash)
} else {
- return generateSigEc(key, hash)
+ return GenerateSigEc(key, hash)
}
}
@@ -167,7 +167,7 @@ func BuildSigTlvs(keys []ImageSigKey, hash []byte) ([]ImageTlv, error) {
tlvs = append(tlvs, tlv)
// Signature TLV.
- sig, err := generateSig(key, hash)
+ sig, err := GenerateSig(key, hash)
if err != nil {
return nil, err
}
@@ -205,13 +205,18 @@ func GenerateImage(opts ImageCreateOpts) (Image, error) {
}
if opts.SrcEncKeyFilename != "" {
- plainSecret := make([]byte, 16)
- if _, err := rand.Read(plainSecret); err != nil {
+ plainSecret, err := GeneratePlainSecret()
+ if err != nil {
+ return Image{}, err
+ }
+
+ pubKeBytes, err := ioutil.ReadFile(opts.SrcEncKeyFilename)
+ if err != nil {
return Image{}, util.FmtNewtError(
- "Random generation error: %s\n", err)
+ "Error reading pubkey file: %s", err.Error())
}
- cipherSecret, err := ReadEncKey(opts.SrcEncKeyFilename, plainSecret)
+ cipherSecret, err := GenerateCipherSecret(pubKeBytes, plainSecret)
if err != nil {
return Image{}, err
}
@@ -228,7 +233,7 @@ func GenerateImage(opts ImageCreateOpts) (Image, error) {
return ri, nil
}
-func calcHash(initialHash []byte, hdr ImageHdr,
+func calcHash(initialHash []byte, hdr ImageHdr, pad []byte,
plainBody []byte) ([]byte, error) {
hash := sha256.New()
@@ -255,6 +260,10 @@ func calcHash(initialHash []byte, hdr ImageHdr,
return nil, err
}
+ if err := add(pad); err != nil {
+ return nil, err
+ }
+
extra := hdr.HdrSz - IMAGE_HEADER_SIZE
if extra > 0 {
b := make([]byte, extra)
@@ -270,11 +279,43 @@ func calcHash(initialHash []byte, hdr ImageHdr,
return hash.Sum(nil), nil
}
+func EncryptImageBody(imageBody []byte, secret []byte) ([]byte, error) {
+ block, err := aes.NewCipher(secret)
+ if err != nil {
+ return nil, util.NewNewtError("Failed to create block cipher")
+ }
+ nonce := make([]byte, 16)
+ stream := cipher.NewCTR(block, nonce)
+
+ dataBuf := make([]byte, 16)
+ encBuf := make([]byte, 16)
+ r := bytes.NewReader(imageBody)
+ w := bytes.Buffer{}
+ for {
+ cnt, err := r.Read(dataBuf)
+ if err != nil && err != io.EOF {
+ return nil, util.FmtNewtError(
+ "Failed to read from image body: %s", err.Error())
+ }
+ if cnt == 0 {
+ break
+ }
+
+ stream.XORKeyStream(encBuf, dataBuf[0:cnt])
+ if _, err = w.Write(encBuf[0:cnt]); err != nil {
+ return nil, util.FmtNewtError(
+ "Failed to write to image body: %s", err.Error())
+ }
+ }
+
+ return w.Bytes(), nil
+}
+
func (ic *ImageCreator) Create() (Image, error) {
- ri := Image{}
+ img := Image{}
// First the header
- hdr := ImageHdr{
+ img.Header = ImageHdr{
Magic: IMAGE_MAGIC,
Pad1: 0,
HdrSz: IMAGE_HEADER_SIZE,
@@ -286,75 +327,41 @@ func (ic *ImageCreator) Create() (Image, error) {
}
if !ic.Bootable {
- hdr.Flags |= IMAGE_F_NON_BOOTABLE
+ img.Header.Flags |= IMAGE_F_NON_BOOTABLE
}
if ic.CipherSecret != nil {
- hdr.Flags |= IMAGE_F_ENCRYPTED
+ img.Header.Flags |= IMAGE_F_ENCRYPTED
}
if ic.HeaderSize != 0 {
- // Pad the header out to the given size. There will
- // just be zeros between the header and the start of
- // the image when it is padded.
+ // Pad the header out to the given size. There will just be zeros
+ // between the header and the start of the image when it is padded.
extra := ic.HeaderSize - IMAGE_HEADER_SIZE
if extra < 0 {
- return ri, util.FmtNewtError("Image header must be at "+
+ return img, util.FmtNewtError("Image header must be at "+
"least %d bytes", IMAGE_HEADER_SIZE)
}
- hdr.HdrSz = uint16(ic.HeaderSize)
- for i := 0; i < extra; i++ {
- ri.Body = append(ri.Body, 0)
- }
+ img.Header.HdrSz = uint16(ic.HeaderSize)
+ img.Pad = make([]byte, extra)
}
- ri.Header = hdr
-
- hashBytes, err := calcHash(ic.InitialHash, hdr, ic.Body)
+ hashBytes, err := calcHash(ic.InitialHash, img.Header, img.Pad, ic.Body)
if err != nil {
- return ri, err
+ return img, err
}
- var stream cipher.Stream
+ // Followed by data.
if ic.CipherSecret != nil {
- block, err := aes.NewCipher(ic.PlainSecret)
+ encBody, err := EncryptImageBody(ic.Body, ic.PlainSecret)
if err != nil {
- return ri, util.NewNewtError("Failed to create block cipher")
- }
- nonce := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- stream = cipher.NewCTR(block, nonce)
- }
-
- /*
- * Followed by data.
- */
- dataBuf := make([]byte, 16)
- encBuf := make([]byte, 16)
- r := bytes.NewReader(ic.Body)
- w := bytes.Buffer{}
- for {
- cnt, err := r.Read(dataBuf)
- if err != nil && err != io.EOF {
- return ri, util.FmtNewtError(
- "Failed to read from image body: %s", err.Error())
- }
- if cnt == 0 {
- break
- }
-
- if ic.CipherSecret == nil {
- _, err = w.Write(dataBuf[0:cnt])
- } else {
- stream.XORKeyStream(encBuf, dataBuf[0:cnt])
- _, err = w.Write(encBuf[0:cnt])
- }
- if err != nil {
- return ri, util.FmtNewtError(
- "Failed to write to image body: %s", err.Error())
+ return img, err
}
+ img.Body = append(img.Body, encBody...)
+ } else {
+ img.Body = append(img.Body, ic.Body...)
}
- ri.Body = append(ri.Body, w.Bytes()...)
util.StatusMessage(util.VERBOSITY_VERBOSE,
"Computed Hash for image as %s\n", hex.EncodeToString(hashBytes))
@@ -368,21 +375,21 @@ func (ic *ImageCreator) Create() (Image, error) {
},
Data: hashBytes,
}
- ri.Tlvs = append(ri.Tlvs, tlv)
+ img.Tlvs = append(img.Tlvs, tlv)
tlvs, err := BuildSigTlvs(ic.SigKeys, hashBytes)
if err != nil {
- return ri, err
+ return img, err
}
- ri.Tlvs = append(ri.Tlvs, tlvs...)
+ img.Tlvs = append(img.Tlvs, tlvs...)
if ic.CipherSecret != nil {
- tlv, err := generateEncTlv(ic.CipherSecret)
+ tlv, err := GenerateEncTlv(ic.CipherSecret)
if err != nil {
- return ri, err
+ return img, err
}
- ri.Tlvs = append(ri.Tlvs, tlv)
+ img.Tlvs = append(img.Tlvs, tlv)
}
- return ri, nil
+ return img, nil
}
diff --git a/image/image.go b/image/image.go
index 1ed093f..705abe6 100644
--- a/image/image.go
+++ b/image/image.go
@@ -113,6 +113,7 @@ type ImageTrailer struct {
type Image struct {
Header ImageHdr
+ Pad []byte
Body []byte
Tlvs []ImageTlv
}
@@ -186,36 +187,36 @@ func (ver ImageVersion) String() string {
func (h *ImageHdr) Map(offset int) map[string]interface{} {
return map[string]interface{}{
- "Magic": h.Magic,
- "HdrSz": h.HdrSz,
- "ImgSz": h.ImgSz,
- "Flags": h.Flags,
- "Vers": h.Vers.String(),
- "offset": offset,
+ "magic": h.Magic,
+ "hdr_sz": h.HdrSz,
+ "img_sz": h.ImgSz,
+ "flags": h.Flags,
+ "vers": h.Vers.String(),
+ "_offset": offset,
}
}
func rawBodyMap(offset int) map[string]interface{} {
return map[string]interface{}{
- "offset": offset,
+ "_offset": offset,
}
}
func (t *ImageTrailer) Map(offset int) map[string]interface{} {
return map[string]interface{}{
- "Magic": t.Magic,
- "TlvTotLen": t.TlvTotLen,
- "offset": offset,
+ "magic": t.Magic,
+ "tlv_tot_len": t.TlvTotLen,
+ "_offset": offset,
}
}
func (t *ImageTlv) Map(offset int) map[string]interface{} {
return map[string]interface{}{
- "Type": t.Header.Type,
- "typestr": ImageTlvTypeName(t.Header.Type),
- "Len": t.Header.Len,
- "offset": offset,
- "data": hex.EncodeToString(t.Data),
+ "type": t.Header.Type,
+ "len": t.Header.Len,
+ "data": hex.EncodeToString(t.Data),
+ "_typestr": ImageTlvTypeName(t.Header.Type),
+ "_offset": offset,
}
}
@@ -297,19 +298,26 @@ func (i *Image) FindUniqueTlv(tlvType uint8) (*ImageTlv, error) {
return &tlvs[0], nil
}
-func (i *Image) RemoveTlvsIf(pred func(tlv ImageTlv) bool) int {
- numRmed := 0
+func (i *Image) RemoveTlvsIf(pred func(tlv ImageTlv) bool) []ImageTlv {
+ rmed := []ImageTlv{}
+
for idx := 0; idx < len(i.Tlvs); {
tlv := i.Tlvs[idx]
if pred(tlv) {
+ rmed = append(rmed, tlv)
i.Tlvs = append(i.Tlvs[:idx], i.Tlvs[idx+1:]...)
- numRmed++
} else {
idx++
}
}
- return numRmed
+ return rmed
+}
+
+func (i *Image) RemoveTlvsWithType(tlvType uint8) []ImageTlv {
+ return i.RemoveTlvsIf(func(tlv ImageTlv) bool {
+ return tlv.Header.Type == tlvType
+ })
}
func (img *Image) Trailer() ImageTrailer {
@@ -349,6 +357,12 @@ func (i *Image) WritePlusOffsets(w io.Writer) (ImageOffsets, error) {
}
offset += IMAGE_HEADER_SIZE
+ err = binary.Write(w, binary.LittleEndian, i.Pad)
+ if err != nil {
+ return offs, util.ChildNewtError(err)
+ }
+ offset += len(i.Pad)
+
offs.Body = offset
size, err := w.Write(i.Body)
if err != nil {
diff --git a/image/key.go b/image/key.go
index 8345cd9..a343e2d 100644
--- a/image/key.go
+++ b/image/key.go
@@ -21,6 +21,7 @@ package image
import (
"crypto/aes"
+ "crypto/cipher"
"crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
@@ -212,7 +213,7 @@ func (key *ImageSigKey) sigTlvType() uint8 {
}
}
-func parseEncKeyPem(keyBytes []byte, plainSecret []byte) ([]byte, error) {
+func ParsePubKePem(keyBytes []byte) (*rsa.PublicKey, error) {
b, _ := pem.Decode(keyBytes)
if b == nil {
return nil, nil
@@ -237,6 +238,20 @@ func parseEncKeyPem(keyBytes []byte, plainSecret []byte) ([]byte, error) {
"Error parsing pubkey file: %s", err.Error())
}
+ return pubk, nil
+}
+
+func ParsePrivKeDer(keyBytes []byte) (*rsa.PrivateKey, error) {
+ privKey, err := x509.ParsePKCS1PrivateKey(keyBytes)
+ if err != nil {
+ return nil, util.FmtNewtError(
+ "Error parsing private key file: %s", err.Error())
+ }
+
+ return privKey, nil
+}
+
+func EncryptSecretRsa(pubk *rsa.PublicKey, plainSecret []byte) ([]byte, error) {
rng := rand.Reader
cipherSecret, err := rsa.EncryptOAEP(
sha256.New(), rng, pubk, plainSecret, nil)
@@ -248,7 +263,21 @@ func parseEncKeyPem(keyBytes []byte, plainSecret []byte) ([]byte, error) {
return cipherSecret, nil
}
-func parseEncKeyBase64(keyBytes []byte, plainSecret []byte) ([]byte, error) {
+func DecryptSecretRsa(privk *rsa.PrivateKey,
+ cipherSecret []byte) ([]byte, error) {
+
+ rng := rand.Reader
+ plainSecret, err := rsa.DecryptOAEP(
+ sha256.New(), rng, privk, cipherSecret, nil)
+ if err != nil {
+ return nil, util.FmtNewtError(
+ "Error from encryption: %s\n", err.Error())
+ }
+
+ return plainSecret, nil
+}
+
+func ParseKeBase64(keyBytes []byte) (cipher.Block, error) {
kek, err := base64.StdEncoding.DecodeString(string(keyBytes))
if err != nil {
return nil, util.FmtNewtError(
@@ -265,7 +294,11 @@ func parseEncKeyBase64(keyBytes []byte, plainSecret []byte) ([]byte, error) {
"Error creating keywrap cipher: %s", err.Error())
}
- cipherSecret, err := keywrap.Wrap(cipher, plainSecret)
+ return cipher, nil
+}
+
+func encryptSecretAes(c cipher.Block, plainSecret []byte) ([]byte, error) {
+ cipherSecret, err := keywrap.Wrap(c, plainSecret)
if err != nil {
return nil, util.FmtNewtError("Error key-wrapping: %s", err.Error())
}
@@ -273,27 +306,36 @@ func parseEncKeyBase64(keyBytes []byte, plainSecret []byte) ([]byte, error) {
return cipherSecret, nil
}
-func ReadEncKey(filename string, plainSecret []byte) ([]byte, error) {
- keyBytes, err := ioutil.ReadFile(filename)
- if err != nil {
+func GeneratePlainSecret() ([]byte, error) {
+ plainSecret := make([]byte, 16)
+ if _, err := rand.Read(plainSecret); err != nil {
return nil, util.FmtNewtError(
- "Error reading pubkey file: %s", err.Error())
+ "Random generation error: %s\n", err)
}
+ return plainSecret, nil
+}
+
+func GenerateCipherSecret(pubKeBytes []byte,
+ plainSecret []byte) ([]byte, error) {
+
// Try reading as PEM (asymetric key).
- cipherSecret, err := parseEncKeyPem(keyBytes, plainSecret)
+ rsaPubKe, err := ParsePubKePem(pubKeBytes)
if err != nil {
return nil, err
}
- if cipherSecret != nil {
- return cipherSecret, nil
+ if rsaPubKe != nil {
+ return EncryptSecretRsa(rsaPubKe, plainSecret)
}
// Not PEM; assume this is a base64 encoded symetric key
- cipherSecret, err = parseEncKeyBase64(keyBytes, plainSecret)
+ aesPubKe, err := ParseKeBase64(pubKeBytes)
if err != nil {
return nil, err
}
+ if aesPubKe != nil {
+ return encryptSecretAes(aesPubKe, plainSecret)
+ }
- return cipherSecret, nil
+ return nil, util.FmtNewtError("Invalid image-crypt key")
}
diff --git a/image/v1.go b/image/v1.go
index 5540d85..0dc10a5 100644
--- a/image/v1.go
+++ b/image/v1.go
@@ -233,7 +233,7 @@ func generateV1SigTlvRsa(key ImageSigKey, hash []byte) (ImageTlv, error) {
}
func generateV1SigTlvEc(key ImageSigKey, hash []byte) (ImageTlv, error) {
- sig, err := generateSigEc(key, hash)
+ sig, err := GenerateSigEc(key, hash)
if err != nil {
return ImageTlv{}, err
}
@@ -463,13 +463,17 @@ func GenerateV1Image(opts ImageCreateOpts) (ImageV1, error) {
}
if opts.SrcEncKeyFilename != "" {
- plainSecret := make([]byte, 16)
- if _, err := rand.Read(plainSecret); err != nil {
- return ImageV1{}, util.FmtNewtError(
- "Random generation error: %s\n", err)
+ plainSecret, err := GeneratePlainSecret()
+ if err != nil {
+ return ImageV1{}, err
}
- cipherSecret, err := ReadEncKey(opts.SrcEncKeyFilename, plainSecret)
+ pubKeBytes, err := ioutil.ReadFile(opts.SrcEncKeyFilename)
+ if err != nil {
+ return ImageV1{}, util.FmtNewtError(
+ "Error reading pubkey file: %s", err.Error())
+ }
+ cipherSecret, err := GenerateCipherSecret(pubKeBytes, plainSecret)
if err != nil {
return ImageV1{}, err
}
diff --git a/mfg/mfg.go b/mfg/mfg.go
index 8e999ad..3e29523 100644
--- a/mfg/mfg.go
+++ b/mfg/mfg.go
@@ -7,7 +7,7 @@ import (
)
const MFG_IMG_FILENAME = "mfgimg.bin"
-const MFG_MANIFEST_FILENAME = "manifest.json"
+const MANIFEST_FILENAME = "manifest.json"
type Mfg struct {
Bin []byte
@@ -53,27 +53,6 @@ func AddPadding(b []byte, eraseVal byte, padLen int) []byte {
return b
}
-func (m *Mfg) bytesZeroedHash(eraseVal byte) ([]byte, error) {
- binCopy := make([]byte, len(m.Bin))
- copy(binCopy, m.Bin)
-
- m.Meta.ClearHash()
-
- metaBytes, err := m.Meta.Bytes()
- if err != nil {
- return nil, err
- }
-
- padLen := m.MetaOff + len(metaBytes) - len(binCopy)
- if padLen > 0 {
- binCopy = AddPadding(binCopy, eraseVal, padLen)
- }
-
- copy(binCopy[m.MetaOff:m.MetaOff+len(metaBytes)], metaBytes)
-
- return binCopy, nil
-}
-
// Calculates the SHA256 hash, using the full manufacturing image as input.
// Hash-calculation algorithm is as follows:
// 1. Zero out the 32 bytes that will contain the hash.
@@ -86,11 +65,16 @@ func CalcHash(bin []byte) []byte {
return hash[:]
}
-func (m *Mfg) Bytes(eraseVal byte) ([]byte, error) {
+func (m *Mfg) RecalcHash(eraseVal byte) error {
+ if m.Meta == nil || m.Meta.Hash() == nil {
+ return nil
+ }
+
// First, write with zeroed hash.
- bin, err := m.bytesZeroedHash(eraseVal)
+ m.Meta.ClearHash()
+ bin, err := m.Bytes(eraseVal)
if err != nil {
- return nil, err
+ return err
}
// Calculate hash and fill TLV.
@@ -101,13 +85,47 @@ func (m *Mfg) Bytes(eraseVal byte) ([]byte, error) {
hashOff := m.MetaOff + m.Meta.HashOffset()
if hashOff+META_HASH_SZ > len(bin) {
- return nil, util.FmtNewtError(
+ return util.FmtNewtError(
"unexpected error: hash extends beyond end " +
"of manufacturing image")
}
+ }
+
+ return nil
+}
- copy(bin[hashOff:hashOff+META_HASH_SZ], tlv.Data)
+func (m *Mfg) Hash() ([]byte, error) {
+ var hashBytes []byte
+ if m.Meta != nil {
+ hashBytes = m.Meta.Hash()
+ }
+ if hashBytes == nil {
+ // No hash TLV; calculate hash manually.
+ bin, err := m.Bytes(0xff)
+ if err != nil {
+ return nil, err
+ }
+ hashBytes = CalcHash(bin)
}
- return bin, nil
+ return hashBytes, nil
+}
+
+func (m *Mfg) Bytes(eraseVal byte) ([]byte, error) {
+ binCopy := make([]byte, len(m.Bin))
+ copy(binCopy, m.Bin)
+
+ metaBytes, err := m.Meta.Bytes()
+ if err != nil {
+ return nil, err
+ }
+
+ padLen := m.MetaOff + len(metaBytes) - len(binCopy)
+ if padLen > 0 {
+ binCopy = AddPadding(binCopy, eraseVal, padLen)
+ }
+
+ copy(binCopy[m.MetaOff:m.MetaOff+len(metaBytes)], metaBytes)
+
+ return binCopy, nil
}
diff --git a/mfg/paths.go b/misc/misc.go
similarity index 70%
rename from mfg/paths.go
rename to misc/misc.go
index 483aca2..2f685e1 100644
--- a/mfg/paths.go
+++ b/misc/misc.go
@@ -17,19 +17,12 @@
* under the License.
*/
-package mfg
+package misc
import (
"fmt"
- "path/filepath"
)
-const MANIFEST_FILENAME = "manifest.json"
-const BOOT_DIR = "bootloader"
-const BOOT_MANIFEST_PATH = BOOT_DIR + "/manifest.json"
-const SECTION_BIN_DIR = "sections"
-
-func SectionBinPath(mfgPkgName string, sectionNum int) string {
- return fmt.Sprintf("%s/%s-s%d.bin", SECTION_BIN_DIR,
- filepath.Base(mfgPkgName), sectionNum)
+func HashString(hash []byte) string {
+ return fmt.Sprintf("%x", hash)
}