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].