Artifact library update
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 @@
}
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 generateEncTlv(cipherSecret []byte) (ImageTlv, error) {
+func GenerateEncTlv(cipherSecret []byte) (ImageTlv, error) {
var encType uint8
if len(cipherSecret) == 256 {
@@ -90,7 +90,7 @@
}, 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 @@
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 @@
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 @@
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 @@
}
if opts.SrcEncKeyFilename != "" {
- plainSecret := make([]byte, 16)
- if _, err := rand.Read(plainSecret); err != nil {
- return Image{}, util.FmtNewtError(
- "Random generation error: %s\n", err)
+ plainSecret, err := GeneratePlainSecret()
+ if err != nil {
+ return Image{}, err
}
- cipherSecret, err := ReadEncKey(opts.SrcEncKeyFilename, plainSecret)
+ pubKeBytes, err := ioutil.ReadFile(opts.SrcEncKeyFilename)
+ if err != nil {
+ return Image{}, util.FmtNewtError(
+ "Error reading pubkey file: %s", err.Error())
+ }
+
+ cipherSecret, err := GenerateCipherSecret(pubKeBytes, plainSecret)
if err != nil {
return Image{}, err
}
@@ -228,7 +233,7 @@
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 @@
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 @@
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,76 +327,42 @@
}
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")
+ return img, err
}
- nonce := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- stream = cipher.NewCTR(block, nonce)
+ img.Body = append(img.Body, encBody...)
+ } else {
+ img.Body = append(img.Body, ic.Body...)
}
- /*
- * 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())
- }
- }
- 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 @@
},
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 Image struct {
Header ImageHdr
+ Pad []byte
Body []byte
Tlvs []ImageTlv
}
@@ -186,36 +187,36 @@
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 @@
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 @@
}
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 @@
import (
"crypto/aes"
+ "crypto/cipher"
"crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
@@ -212,7 +213,7 @@
}
}
-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 @@
"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 @@
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 @@
"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 @@
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 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 @@
}
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 @@
)
const MFG_IMG_FILENAME = "mfgimg.bin"
-const MFG_MANIFEST_FILENAME = "manifest.json"
+const MANIFEST_FILENAME = "manifest.json"
type Mfg struct {
Bin []byte
@@ -53,12 +53,68 @@
return b
}
-func (m *Mfg) bytesZeroedHash(eraseVal byte) ([]byte, error) {
+// 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.
+// 2. Apply SHA256 to the result.
+//
+// This function assumes that the 32 bytes of hash data have already been
+// zeroed.
+func CalcHash(bin []byte) []byte {
+ hash := sha256.Sum256(bin)
+ return hash[:]
+}
+
+func (m *Mfg) RecalcHash(eraseVal byte) error {
+ if m.Meta == nil || m.Meta.Hash() == nil {
+ return nil
+ }
+
+ // First, write with zeroed hash.
+ m.Meta.ClearHash()
+ bin, err := m.Bytes(eraseVal)
+ if err != nil {
+ return err
+ }
+
+ // Calculate hash and fill TLV.
+ tlv := m.Meta.FindFirstTlv(META_TLV_TYPE_HASH)
+ if tlv != nil {
+ hashData := CalcHash(bin)
+ copy(tlv.Data, hashData)
+
+ hashOff := m.MetaOff + m.Meta.HashOffset()
+ if hashOff+META_HASH_SZ > len(bin) {
+ return util.FmtNewtError(
+ "unexpected error: hash extends beyond end " +
+ "of manufacturing image")
+ }
+ }
+
+ return nil
+}
+
+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 hashBytes, nil
+}
+
+func (m *Mfg) Bytes(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
@@ -73,41 +129,3 @@
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.
-// 2. Apply SHA256 to the result.
-//
-// This function assumes that the 32 bytes of hash data have already been
-// zeroed.
-func CalcHash(bin []byte) []byte {
- hash := sha256.Sum256(bin)
- return hash[:]
-}
-
-func (m *Mfg) Bytes(eraseVal byte) ([]byte, error) {
- // First, write with zeroed hash.
- bin, err := m.bytesZeroedHash(eraseVal)
- if err != nil {
- return nil, err
- }
-
- // Calculate hash and fill TLV.
- tlv := m.Meta.FindFirstTlv(META_TLV_TYPE_HASH)
- if tlv != nil {
- hashData := CalcHash(bin)
- copy(tlv.Data, hashData)
-
- hashOff := m.MetaOff + m.Meta.HashOffset()
- if hashOff+META_HASH_SZ > len(bin) {
- return nil, util.FmtNewtError(
- "unexpected error: hash extends beyond end " +
- "of manufacturing image")
- }
-
- copy(bin[hashOff:hashOff+META_HASH_SZ], tlv.Data)
- }
-
- return bin, nil
-}
diff --git a/mfg/paths.go b/misc/misc.go
similarity index 69%
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)
}