utzig closed pull request #164: Add support for declaring a key file under
target
URL: https://github.com/apache/mynewt-newt/pull/164
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/newt/builder/targetbuild.go b/newt/builder/targetbuild.go
index cc2b6be7..d7a7a193 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 176939b4..f43d5b91 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 d814efa4..7cd0025b 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
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services