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

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


The following commit(s) were added to refs/heads/master by this push:
     new 9eebb58  Add support for declaring a key file under target
9eebb58 is described below

commit 9eebb584deb57efa4cf9e3eafc8f0f1fcae45cd0
Author: Fabio Utzig <[email protected]>
AuthorDate: Tue Apr 24 20:36:01 2018 -0300

    Add support for declaring a key file under target
    
    This allows the user to input a key file using `target.key_file`.
    The file will be parsed and an output .c file with the bootloader
    required public key will be written.
---
 newt/builder/targetbuild.go | 83 +++++++++++++++++++++++++++++++++++++++++++++
 newt/image/image.go         | 62 +++++++++++++++------------------
 newt/target/target.go       |  3 ++
 3 files changed, 114 insertions(+), 34 deletions(-)

diff --git a/newt/builder/targetbuild.go b/newt/builder/targetbuild.go
index cc2b6be..d7a7a19 100644
--- a/newt/builder/targetbuild.go
+++ b/newt/builder/targetbuild.go
@@ -20,7 +20,12 @@
 package builder
 
 import (
+       "bufio"
+       "crypto/ecdsa"
+       "crypto/rsa"
+       "crypto/x509"
        "encoding/json"
+       "encoding/pem"
        "fmt"
        "io/ioutil"
        "os"
@@ -60,6 +65,7 @@ type TargetBuilder struct {
        LoaderBuilder *Builder
        LoaderList    interfaces.PackageList
 
+       keyFile          string
        injectedSettings map[string]string
 
        res *resolve.Resolution
@@ -89,6 +95,7 @@ func NewTargetTester(target *target.Target,
                compilerPkg:      compilerPkg,
                appPkg:           target.App(),
                loaderPkg:        target.Loader(),
+               keyFile:          target.KeyFile,
                testPkg:          testPkg,
                injectedSettings: map[string]string{},
        }
@@ -347,6 +354,75 @@ func (t *TargetBuilder) buildLoader() error {
 
 }
 
+/// Generates a .c source file with public key information required by the
+/// bootloader.
+///
+/// The input filename should be supplied by the user in the target.yml file,
+/// using the `target.key_file` option. This file can be either a private key
+/// in PEM format, an extracted public key in PEM format or a DER file.
+///
+/// To extract a PEM public key from the private key:
+///   `openssl ec -in ec_pk.pem -pubout -out pubkey.pub`
+///   `openssl rsa -in rsa_pk.pem -RSAPublicKey_out -out pubkey.pub`
+func (t *TargetBuilder) autogenKeys() error {
+       keyBytes, err := ioutil.ReadFile(t.keyFile)
+       if err != nil {
+               return util.NewNewtError(fmt.Sprintf("Error reading key file: 
%s", err))
+       }
+
+       // Initially try parsing a private key in PEM format, if it fails try
+       // parsing as PEM public key, otherwise accepted as raw key data (DER)
+
+       privKey, err := image.ParsePrivateKey(keyBytes)
+       if err == nil {
+               switch pk := privKey.(type) {
+               case *rsa.PrivateKey:
+                       keyBytes = x509.MarshalPKCS1PublicKey(&pk.PublicKey)
+               case *ecdsa.PrivateKey:
+                       keyBytes, err = x509.MarshalPKIXPublicKey(&pk.PublicKey)
+                       if err != nil {
+                               return util.NewNewtError("Failed parsing EC 
public key")
+                       }
+               default:
+                       return util.NewNewtError("Unknown private key format")
+               }
+       } else {
+               b, _ := pem.Decode(keyBytes)
+               if b != nil && (b.Type == "PUBLIC KEY" || b.Type == "RSA PUBLIC 
KEY") {
+                       keyBytes = b.Bytes
+               }
+       }
+
+       srcDir := GeneratedSrcDir(t.target.Name())
+
+       f, _ := os.Create(srcDir + "/pubkey-autogen.c")
+       w := bufio.NewWriter(f)
+
+       fmt.Fprintln(w, "/* Autogenerated, do not edit. */")
+       fmt.Fprintln(w, "#include <bootutil/sign_key.h>")
+       fmt.Fprintf(w, "const unsigned char key[] = {")
+       for count, b := range keyBytes {
+               if count % 8 == 0 {
+                       fmt.Fprintf(w, "\n    ")
+               } else {
+                       fmt.Fprintf(w, " ")
+               }
+               fmt.Fprintf(w, "0x%02x,", b)
+       }
+       fmt.Fprintf(w, "\n};\n")
+       fmt.Fprintf(w, "const unsigned int key_len = %v;\n", len(keyBytes))
+       fmt.Fprintln(w, "const struct bootutil_key bootutil_keys[] = {")
+       fmt.Fprintln(w, "    [0] = {")
+       fmt.Fprintln(w, "        .key = key,")
+       fmt.Fprintln(w, "        .len = &key_len,")
+       fmt.Fprintln(w, "    },")
+       fmt.Fprintln(w, "};")
+       fmt.Fprintln(w, "const int bootutil_key_cnt = 1;");
+       w.Flush()
+
+       return nil
+}
+
 func (t *TargetBuilder) Build() error {
        if err := t.PrepBuild(); err != nil {
                return err
@@ -359,6 +435,13 @@ func (t *TargetBuilder) Build() error {
                return err
        }
 
+       if t.keyFile != "" {
+               err := t.autogenKeys()
+               if err != nil {
+                       return err
+               }
+       }
+
        if err := t.AppBuilder.Build(); err != nil {
                return err
        }
diff --git a/newt/image/image.go b/newt/image/image.go
index 176939b..f43d5b9 100644
--- a/newt/image/image.go
+++ b/newt/image/image.go
@@ -297,13 +297,11 @@ func (image *Image) SetVersion(versStr string) error {
        return nil
 }
 
-func (image *Image) SetSigningKey(fileName string, keyId uint8) error {
-       data, err := ioutil.ReadFile(fileName)
-       if err != nil {
-               return util.NewNewtError(fmt.Sprintf("Error reading key file: 
%s", err))
-       }
+func ParsePrivateKey(keyBytes []byte) (interface{}, error) {
+       var privKey interface{}
+       var err error
 
-       block, data := pem.Decode(data)
+       block, data := pem.Decode(keyBytes)
        if block != nil && block.Type == "EC PARAMETERS" {
                /*
                 * Openssl prepends an EC PARAMETERS block before the
@@ -317,65 +315,61 @@ func (image *Image) SetSigningKey(fileName string, keyId 
uint8) error {
                 * ParsePKCS1PrivateKey returns an RSA private key from its 
ASN.1
                 * PKCS#1 DER encoded form.
                 */
-               privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+               privKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
                if err != nil {
-                       return util.NewNewtError(fmt.Sprintf("Private key 
parsing "+
+                       return nil, util.NewNewtError(fmt.Sprintf("Private key 
parsing "+
                                "failed: %s", err))
                }
-               image.SigningRSA = privateKey
        }
        if block != nil && block.Type == "EC PRIVATE KEY" {
                /*
                 * ParseECPrivateKey returns a EC private key
                 */
-               privateKey, err := x509.ParseECPrivateKey(block.Bytes)
+               privKey, err = x509.ParseECPrivateKey(block.Bytes)
                if err != nil {
-                       return util.NewNewtError(fmt.Sprintf("Private key 
parsing "+
+                       return nil, util.NewNewtError(fmt.Sprintf("Private key 
parsing "+
                                "failed: %s", err))
                }
-               image.SigningEC = privateKey
        }
        if block != nil && block.Type == "PRIVATE KEY" {
                // This indicates a PKCS#8 unencrypted private key.
                // The particular type of key will be indicated within
                // the key itself.
-               privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+               privKey, err = x509.ParsePKCS8PrivateKey(block.Bytes)
                if err != nil {
-                       return util.NewNewtError(fmt.Sprintf("Private key 
parsing "+
+                       return nil, util.NewNewtError(fmt.Sprintf("Private key 
parsing "+
                                "failed: %s", err))
                }
-
-               err = image.storeKey(privateKey)
-               if err != nil {
-                       return err
-               }
        }
        if block != nil && block.Type == "ENCRYPTED PRIVATE KEY" {
                // This indicates a PKCS#8 key wrapped with PKCS#5
                // encryption.
-               privateKey, err := parseEncryptedPrivateKey(block.Bytes)
-               if err != nil {
-                       return util.FmtNewtError("Unable to decode encrypted 
private key: %s", err)
-               }
-
-               err = image.storeKey(privateKey)
+               privKey, err = parseEncryptedPrivateKey(block.Bytes)
                if err != nil {
-                       return err
+                       return nil, util.FmtNewtError("Unable to decode 
encrypted private key: %s", err)
                }
        }
-       if image.SigningEC == nil && image.SigningRSA == nil {
-               return util.NewNewtError("Unknown private key format, EC/RSA 
private " +
+       if privKey == nil {
+               return nil, util.NewNewtError("Unknown private key format, 
EC/RSA private " +
                        "key in PEM format only.")
        }
-       image.KeyId = keyId
 
-       return nil
+       return privKey, nil
 }
 
-// Store the given key in this image, determining the type of key and
-// storing it in the appropriate field.
-func (image *Image) storeKey(key interface{}) (err error) {
-       switch priv := key.(type) {
+func (image *Image) SetSigningKey(fileName string, keyId uint8) error {
+       keyBytes, err := ioutil.ReadFile(fileName)
+       if err != nil {
+               return util.NewNewtError(fmt.Sprintf("Error reading key file: 
%s", err))
+       }
+
+       image.KeyId = keyId
+       privKey, err := ParsePrivateKey(keyBytes)
+       if err != nil {
+               return err
+       }
+
+       switch priv := privKey.(type) {
        case *rsa.PrivateKey:
                image.SigningRSA = priv
        case *ecdsa.PrivateKey:
diff --git a/newt/target/target.go b/newt/target/target.go
index d814efa..7cd0025 100644
--- a/newt/target/target.go
+++ b/newt/target/target.go
@@ -49,6 +49,7 @@ type Target struct {
        LoaderName   string
        BuildProfile string
        HeaderSize   uint32
+       KeyFile      string
 
        // target.yml configuration structure
        Vars map[string]string
@@ -103,6 +104,8 @@ func (target *Target) Load(basePkg *pkg.LocalPackage) error 
{
                }
        }
 
+       target.KeyFile = target.Vars["target.key_file"]
+
        // Note: App not required in the case of unit tests.
 
        // Remember the name of the configuration file so that it can be 
specified

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to