You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ut...@apache.org on 2019/06/26 17:34:18 UTC
[mynewt-newt] 01/06: Add support for signing images with ed25519
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
commit 53f9e0ca5a28efbcfe8aa2202a49ad64111b7d20
Author: Fabio Utzig <ut...@apache.org>
AuthorDate: Thu May 9 12:35:43 2019 -0300
Add support for signing images with ed25519
---
artifact/image/create.go | 23 +++++++++++-
artifact/image/image.go | 5 ++-
artifact/sec/key.go | 96 +++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 111 insertions(+), 13 deletions(-)
diff --git a/artifact/image/create.go b/artifact/image/create.go
index cbbc410..fbe88d9 100644
--- a/artifact/image/create.go
+++ b/artifact/image/create.go
@@ -29,6 +29,7 @@ import (
"encoding/asn1"
"encoding/binary"
"encoding/hex"
+ "golang.org/x/crypto/ed25519"
"io/ioutil"
"math/big"
@@ -80,7 +81,7 @@ func sigTlvType(key sec.SignKey) uint8 {
default:
return 0
}
- } else {
+ } else if key.Ec != nil {
switch key.Ec.Curve.Params().Name {
case "P-224":
return IMAGE_TLV_ECDSA224
@@ -89,6 +90,10 @@ func sigTlvType(key sec.SignKey) uint8 {
default:
return 0
}
+ } else if key.Ed25519 != nil {
+ return IMAGE_TLV_ED25519
+ } else {
+ panic("invalid key; neither RSA nor ECC nor ED25519")
}
}
@@ -153,13 +158,27 @@ func GenerateSigEc(key sec.SignKey, hash []byte) ([]byte, error) {
return signature, nil
}
+func GenerateSigEd25519(key sec.SignKey, hash []byte) ([]byte, error) {
+ sig := ed25519.Sign(*key.Ed25519, hash)
+
+ if len(sig) != ed25519.SignatureSize {
+ return nil, util.FmtNewtError("Something is really wrong\n")
+ }
+
+ return sig, nil
+}
+
func GenerateSig(key sec.SignKey, hash []byte) ([]byte, error) {
key.AssertValid()
if key.Rsa != nil {
return GenerateSigRsa(key, hash)
- } else {
+ } else if key.Ec != nil {
return GenerateSigEc(key, hash)
+ } else if key.Ed25519 != nil {
+ return GenerateSigEd25519(key, hash)
+ } else {
+ panic("invalid key; neither RSA nor ECC nor ED25519")
}
}
diff --git a/artifact/image/image.go b/artifact/image/image.go
index 9855223..ab57b36 100644
--- a/artifact/image/image.go
+++ b/artifact/image/image.go
@@ -64,6 +64,7 @@ const (
IMAGE_TLV_ECDSA224 = 0x21
IMAGE_TLV_ECDSA256 = 0x22
IMAGE_TLV_RSA3072 = 0x23
+ IMAGE_TLV_ED25519 = 0x24
IMAGE_TLV_ENC_RSA = 0x30
IMAGE_TLV_ENC_KEK = 0x31
)
@@ -75,6 +76,7 @@ var imageTlvTypeNameMap = map[uint8]string{
IMAGE_TLV_ECDSA224: "ECDSA224",
IMAGE_TLV_ECDSA256: "ECDSA256",
IMAGE_TLV_RSA3072: "RSA3072",
+ IMAGE_TLV_ED25519: "ED25519",
IMAGE_TLV_ENC_RSA: "ENC_RSA",
IMAGE_TLV_ENC_KEK: "ENC_KEK",
}
@@ -141,7 +143,8 @@ func ImageTlvTypeIsSig(tlvType uint8) bool {
return tlvType == IMAGE_TLV_RSA2048 ||
tlvType == IMAGE_TLV_RSA3072 ||
tlvType == IMAGE_TLV_ECDSA224 ||
- tlvType == IMAGE_TLV_ECDSA256
+ tlvType == IMAGE_TLV_ECDSA256 ||
+ tlvType == IMAGE_TLV_ED25519
}
func ParseVersion(versStr string) (ImageVersion, error) {
diff --git a/artifact/sec/key.go b/artifact/sec/key.go
index 9d073bd..5914b20 100644
--- a/artifact/sec/key.go
+++ b/artifact/sec/key.go
@@ -27,9 +27,11 @@ import (
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
+ "crypto/x509/pkix"
"encoding/asn1"
"encoding/base64"
"encoding/pem"
+ "golang.org/x/crypto/ed25519"
"io/ioutil"
keywrap "github.com/NickBall/go-aes-key-wrap"
@@ -39,8 +41,56 @@ import (
type SignKey struct {
// Only one of these members is non-nil.
- Rsa *rsa.PrivateKey
- Ec *ecdsa.PrivateKey
+ Rsa *rsa.PrivateKey
+ Ec *ecdsa.PrivateKey
+ Ed25519 *ed25519.PrivateKey
+}
+
+type ed25519Pkcs struct {
+ Version int
+ Algo pkix.AlgorithmIdentifier
+ SeedKey []byte
+}
+
+var oidPrivateKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
+
+// Parse an ed25519 PKCS#8 certificate
+func parseEd25519Pkcs8(der []byte) (key *ed25519.PrivateKey, err error) {
+ var privKey ed25519Pkcs
+ if _, err := asn1.Unmarshal(der, &privKey); err != nil {
+ return nil, util.FmtNewtError("Error parsing ASN1 key")
+ }
+ switch {
+ case privKey.Algo.Algorithm.Equal(oidPrivateKeyEd25519):
+ // ASN1 header (type+length) + seed
+ if len(privKey.SeedKey) != ed25519.SeedSize+2 {
+ return nil, util.FmtNewtError("Unexpected size for Ed25519 private key")
+ }
+ key := ed25519.NewKeyFromSeed(privKey.SeedKey[2:])
+ return &key, nil
+ default:
+ return nil, util.FmtNewtError("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
+ }
+}
+
+type pkixPublicKey struct {
+ Algo pkix.AlgorithmIdentifier
+ BitString asn1.BitString
+}
+
+func marshalEd25519(pubbytes []uint8) []uint8 {
+ pkix := pkixPublicKey{
+ Algo: pkix.AlgorithmIdentifier{
+ Algorithm: oidPrivateKeyEd25519,
+ },
+ BitString: asn1.BitString{
+ Bytes: pubbytes,
+ BitLength: 8 * len(pubbytes),
+ },
+ }
+
+ ret, _ := asn1.Marshal(pkix)
+ return ret
}
func ParsePrivateKey(keyBytes []byte) (interface{}, error) {
@@ -83,8 +133,13 @@ func ParsePrivateKey(keyBytes []byte) (interface{}, error) {
// the key itself.
privKey, err = x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
- return nil, util.FmtNewtError(
- "Private key parsing failed: %s", err)
+ var _privKey interface{}
+ _privKey, err = parseEd25519Pkcs8(block.Bytes)
+ if err != nil {
+ return nil, util.FmtNewtError(
+ "Private key parsing failed: %s", err)
+ }
+ privKey = _privKey
}
}
if block != nil && block.Type == "ENCRYPTED PRIVATE KEY" {
@@ -118,6 +173,8 @@ func BuildPrivateKey(keyBytes []byte) (SignKey, error) {
key.Rsa = priv
case *ecdsa.PrivateKey:
key.Ec = priv
+ case *ed25519.PrivateKey:
+ key.Ed25519 = priv
default:
return key, util.NewNewtError("Unknown private key format")
}
@@ -151,12 +208,22 @@ func ReadKeys(filenames []string) ([]SignKey, error) {
}
func (key *SignKey) AssertValid() {
- if key.Rsa == nil && key.Ec == nil {
- panic("invalid key; neither RSA nor ECC")
+ if key.Rsa == nil && key.Ec == nil && key.Ed25519 == nil {
+ panic("invalid key; neither RSA nor ECC nor ED25519")
}
- if key.Rsa != nil && key.Ec != nil {
- panic("invalid key; neither RSA nor ECC")
+ total := 0
+ if key.Rsa != nil {
+ total++
+ }
+ if key.Ec != nil {
+ total++
+ }
+ if key.Ed25519 != nil {
+ total++
+ }
+ if total != 1 {
+ panic("invalid key; neither RSA nor ECC nor ED25519")
}
}
@@ -167,7 +234,7 @@ func (key *SignKey) PubBytes() ([]uint8, error) {
if key.Rsa != nil {
pubkey, _ = asn1.Marshal(key.Rsa.PublicKey)
- } else {
+ } else if key.Ec != nil {
switch key.Ec.Curve.Params().Name {
case "P-224":
fallthrough
@@ -176,6 +243,11 @@ func (key *SignKey) PubBytes() ([]uint8, error) {
default:
return nil, util.NewNewtError("Unsupported ECC curve")
}
+ } else if key.Ed25519 != nil {
+ bytes := key.Ed25519.Public().(ed25519.PublicKey)
+ pubkey = marshalEd25519(bytes)
+ } else {
+ panic("invalid key; neither RSA nor ECC nor ED25519")
}
return pubkey, nil
@@ -192,7 +264,7 @@ func (key *SignKey) SigLen() uint16 {
if key.Rsa != nil {
pubk := key.Rsa.Public().(*rsa.PublicKey)
return uint16(pubk.Size())
- } else {
+ } else if key.Ec != nil {
switch key.Ec.Curve.Params().Name {
case "P-224":
return 68
@@ -201,6 +273,10 @@ func (key *SignKey) SigLen() uint16 {
default:
return 0
}
+ } else if key.Ed25519 != nil {
+ return ed25519.SignatureSize
+ } else {
+ panic("invalid key; neither RSA nor ECC nor ED25519")
}
}