You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2019/06/27 20:06:41 UTC
[mynewt-artifact] branch master updated: Add support for ed25519
encrypted signing keys
This is an automated email from the ASF dual-hosted git repository.
ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-artifact.git
The following commit(s) were added to refs/heads/master by this push:
new 49a78be Add support for ed25519 encrypted signing keys
49a78be is described below
commit 49a78be1e9eb942a502d31d9af3a445d0d18e3eb
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Jun 27 11:34:30 2019 -0700
Add support for ed25519 encrypted signing keys
This is almost a straight copy of code from the newt repo, written by
utzig@apache.org.
---
image/create.go | 21 +++++++++-
image/image.go | 5 ++-
sec/pkcs.go | 13 +++++-
sec/sign.go | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++------
sec/util.go | 17 +++++++-
5 files changed, 160 insertions(+), 17 deletions(-)
diff --git a/image/create.go b/image/create.go
index 6167453..1bdf2d1 100644
--- a/image/create.go
+++ b/image/create.go
@@ -33,6 +33,7 @@ import (
"github.com/apache/mynewt-artifact/errors"
"github.com/apache/mynewt-artifact/sec"
+ "golang.org/x/crypto/ed25519"
)
type ImageCreator struct {
@@ -79,7 +80,7 @@ func sigTlvType(key sec.PrivSignKey) uint8 {
default:
return 0
}
- } else {
+ } else if key.Ec != nil {
switch key.Ec.Curve.Params().Name {
case "P-224":
return IMAGE_TLV_ECDSA224
@@ -88,6 +89,8 @@ func sigTlvType(key sec.PrivSignKey) uint8 {
default:
return 0
}
+ } else {
+ return IMAGE_TLV_ED25519
}
}
@@ -152,13 +155,27 @@ func GenerateSigEc(key sec.PrivSignKey, hash []byte) ([]byte, error) {
return signature, nil
}
+func GenerateSigEd25519(key sec.PrivSignKey, hash []byte) ([]byte, error) {
+ sig := ed25519.Sign(*key.Ed25519, hash)
+
+ if len(sig) != ed25519.SignatureSize {
+ return nil, errors.Errorf(
+ "ed25519 signature has wrong length: have=%d want=%d",
+ len(sig), ed25519.SignatureSize)
+ }
+
+ return sig, nil
+}
+
func GenerateSig(key sec.PrivSignKey, 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 {
+ return GenerateSigEd25519(key, hash)
}
}
diff --git a/image/image.go b/image/image.go
index dff4a00..f5dd1bb 100644
--- a/image/image.go
+++ b/image/image.go
@@ -60,6 +60,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
)
@@ -71,6 +72,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",
}
@@ -142,7 +144,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 ImageTlvTypeIsSecret(tlvType uint8) bool {
diff --git a/sec/pkcs.go b/sec/pkcs.go
index 3cf709f..bbd5ac8 100644
--- a/sec/pkcs.go
+++ b/sec/pkcs.go
@@ -78,7 +78,6 @@ type hashFunc func() hash.Hash
func parseEncryptedPrivateKey(der []byte) (key interface{}, err error) {
var wrapper pkcs5
- fmt.Printf("unmarshalling %v\n", der)
if _, err = asn1.Unmarshal(der, &wrapper); err != nil {
return nil, err
}
@@ -153,7 +152,17 @@ func unwrapPbes2Pbkdf2(param *pbkdf2Param, size int, iv []byte, hashNew hashFunc
return nil, err
}
- return x509.ParsePKCS8PrivateKey(plain)
+ privKey, err := x509.ParsePKCS8PrivateKey(plain)
+ if err != nil {
+ var _privKey interface{}
+ _privKey, _err := ParseEd25519Pkcs8(plain)
+ // If this is not an ed25519 key, return
+ // error from x509 parser
+ if _err == nil {
+ return _privKey, _err
+ }
+ }
+ return privKey, err
}
// Verify that PKCS#7 padding is correct on this plaintext message.
diff --git a/sec/sign.go b/sec/sign.go
index 75ebd74..c27060e 100644
--- a/sec/sign.go
+++ b/sec/sign.go
@@ -25,21 +25,25 @@ import (
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
+ "crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"github.com/apache/mynewt-artifact/errors"
+ "golang.org/x/crypto/ed25519"
)
type PrivSignKey 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 PubSignKey struct {
- Rsa *rsa.PublicKey
- Ec *ecdsa.PublicKey
+ Rsa *rsa.PublicKey
+ Ec *ecdsa.PublicKey
+ Ed25519 ed25519.PublicKey
}
type Sig struct {
@@ -47,6 +51,32 @@ type Sig struct {
Data []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 struct {
+ Version int
+ Algo pkix.AlgorithmIdentifier
+ SeedKey []byte
+ }
+
+ if _, err := asn1.Unmarshal(der, &privKey); err != nil {
+ return nil, errors.Errorf("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, errors.Errorf("unexpected size for Ed25519 private key")
+ }
+ key := ed25519.NewKeyFromSeed(privKey.SeedKey[2:])
+ return &key, nil
+ default:
+ return nil, errors.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
+ }
+}
+
func parsePrivSignKeyItf(keyBytes []byte) (interface{}, error) {
var privKey interface{}
var err error
@@ -88,6 +118,20 @@ func parsePrivSignKeyItf(keyBytes []byte) (interface{}, error) {
return nil, errors.Wrapf(err, "Priv key parsing failed")
}
}
+ 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.
+ privKey, err = x509.ParsePKCS8PrivateKey(block.Bytes)
+ if err != nil {
+ var _privKey interface{}
+ _privKey, err = ParseEd25519Pkcs8(block.Bytes)
+ if err != nil {
+ return nil, errors.Wrapf(err, "private key parsing failed")
+ }
+ privKey = _privKey
+ }
+ }
if block != nil && block.Type == "ENCRYPTED PRIVATE KEY" {
// This indicates a PKCS#8 key wrapped with PKCS#5
// encryption.
@@ -119,6 +163,8 @@ func ParsePubSignKey(keyBytes []byte) (PubSignKey, error) {
key.Rsa = pub
case *ecdsa.PublicKey:
key.Ec = pub
+ case ed25519.PublicKey:
+ key.Ed25519 = pub
default:
return key, errors.Errorf("unknown public signing key type: %T", pub)
}
@@ -139,6 +185,8 @@ func ParsePrivSignKey(keyBytes []byte) (PrivSignKey, error) {
key.Rsa = priv
case *ecdsa.PrivateKey:
key.Ec = priv
+ case *ed25519.PrivateKey:
+ key.Ed25519 = priv
default:
return key, errors.Errorf("unknown private key type: %T", itf)
}
@@ -147,8 +195,8 @@ func ParsePrivSignKey(keyBytes []byte) (PrivSignKey, error) {
}
func (key *PrivSignKey) 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")
}
}
@@ -157,8 +205,11 @@ func (key *PrivSignKey) PubKey() PubSignKey {
if key.Rsa != nil {
return PubSignKey{Rsa: &key.Rsa.PublicKey}
- } else {
+ } else if key.Ec != nil {
return PubSignKey{Ec: &key.Ec.PublicKey}
+ } else {
+ x := PubSignKey{Ed25519: key.Ed25519.Public().(ed25519.PublicKey)}
+ return x
}
}
@@ -173,7 +224,7 @@ func (key *PrivSignKey) 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
@@ -182,15 +233,57 @@ func (key *PrivSignKey) SigLen() uint16 {
default:
return 0
}
+ } else {
+ return ed25519.SignatureSize
}
}
func (key *PubSignKey) AssertValid() {
- if key.Rsa == nil && key.Ec == nil {
- panic("invalid public key; neither RSA nor ECC")
+ if key.Rsa == nil && key.Ec == nil && key.Ed25519 == nil {
+ panic("invalid public key; neither RSA nor ECC nor ED25519")
+ }
+
+ if key.Ed25519 != nil {
+ if _, err := marshalEd25519(key.Ed25519); err != nil {
+ panic("invalid public ed25519 key")
+ }
}
}
+type pkixPublicKey struct {
+ Algo pkix.AlgorithmIdentifier
+ BitString asn1.BitString
+}
+
+func marshalEd25519(pubbytes []uint8) ([]uint8, error) {
+ pkix := pkixPublicKey{
+ Algo: pkix.AlgorithmIdentifier{
+ Algorithm: oidPrivateKeyEd25519,
+ },
+ BitString: asn1.BitString{
+ Bytes: pubbytes,
+ BitLength: 8 * len(pubbytes),
+ },
+ }
+
+ ret, err := asn1.Marshal(pkix)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to encode ed25519 public key")
+ }
+
+ return ret, nil
+}
+
+func unmarshalEd25519(pubbytes []uint8) (pkixPublicKey, error) {
+ var pkix pkixPublicKey
+
+ if _, err := asn1.Unmarshal(pubbytes, &pkix); err != nil {
+ return pkix, errors.Wrapf(err, "failed to parse ed25519 public key")
+ }
+
+ return pkix, nil
+}
+
func (key *PubSignKey) Bytes() ([]byte, error) {
key.AssertValid()
@@ -202,7 +295,7 @@ func (key *PubSignKey) Bytes() ([]byte, error) {
if err != nil {
return nil, err
}
- } else {
+ } else if key.Ec != nil {
switch key.Ec.Curve.Params().Name {
case "P-224":
fallthrough
@@ -211,6 +304,8 @@ func (key *PubSignKey) Bytes() ([]byte, error) {
default:
return nil, errors.Errorf("unsupported ECC curve")
}
+ } else {
+ b, _ = marshalEd25519([]byte(key.Ed25519))
}
return b, nil
@@ -240,6 +335,10 @@ func checkOneKeyOneSig(k PubSignKey, sig Sig, hash []byte) (bool, error) {
"ecdsa signature verification not supported")
}
+ if k.Ed25519 != nil {
+ return ed25519.Verify(k.Ed25519, hash, sig.Data), nil
+ }
+
return false, nil
}
diff --git a/sec/util.go b/sec/util.go
index 4eb7fbe..58b5017 100644
--- a/sec/util.go
+++ b/sec/util.go
@@ -5,6 +5,7 @@ import (
"encoding/pem"
"github.com/apache/mynewt-artifact/errors"
+ "golang.org/x/crypto/ed25519"
)
func parsePubPemKey(data []byte) (interface{}, error) {
@@ -21,7 +22,21 @@ func parsePubPemKey(data []byte) (interface{}, error) {
itf, err := x509.ParsePKIXPublicKey(p.Bytes)
if err != nil {
- return nil, errors.Wrapf(err, "error parsing public key")
+ // Not x509; assume ed25519.
+ pkix, err := unmarshalEd25519(p.Bytes)
+ if err != nil {
+ return nil, errors.Errorf(
+ "error parsing public key: unrecognized format")
+ }
+
+ if len(pkix.BitString.Bytes) != ed25519.PublicKeySize {
+ return nil, errors.Errorf(
+ "error parsing public key: "+
+ "ed25519 public key has wrong size: have=%d want=%d",
+ len(pkix.BitString.Bytes), ed25519.PublicKeySize)
+ }
+
+ itf = ed25519.PublicKey(pkix.BitString.Bytes)
}
return itf, nil