diff --git a/go.mod b/go.mod index f2a7266d..88bfc606 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/grantae/certinfo v0.0.0-20170412194111-59d56a35515b github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2 - github.com/hyperledger/fabric-lib-go v1.1.2 + github.com/hyperledger/fabric-lib-go v1.1.3-0.20240523144151-25edd1eaf5f5 github.com/jinzhu/copier v0.3.5 github.com/jmoiron/sqlx v1.2.0 github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 @@ -84,3 +84,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) + diff --git a/go.sum b/go.sum index d6d27cc9..da6fdad2 100644 --- a/go.sum +++ b/go.sum @@ -272,8 +272,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2 h1:B1Nt8hKb//KvgGRprk0h1t4lCnwhE9/ryb1WqfZbV+M= github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE= -github.com/hyperledger/fabric-lib-go v1.1.2 h1:3eHwudGZC5Ex7go5UAzVKhpF34gypPZGfSZksBKLWvE= -github.com/hyperledger/fabric-lib-go v1.1.2/go.mod h1:SHNCq8AB0VpHAmvJEtdbzabv6NNV1F48JdmDihasBjc= +github.com/hyperledger/fabric-lib-go v1.1.3-0.20240523144151-25edd1eaf5f5 h1:RPWTL5wxAb+xDOrsCU3QYZP65305F8v3PaOyzdbPVMU= +github.com/hyperledger/fabric-lib-go v1.1.3-0.20240523144151-25edd1eaf5f5/go.mod h1:SHNCq8AB0VpHAmvJEtdbzabv6NNV1F48JdmDihasBjc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= diff --git a/lib/ca.go b/lib/ca.go index f89ba3d1..458a939b 100644 --- a/lib/ca.go +++ b/lib/ca.go @@ -10,6 +10,7 @@ import ( "bytes" "crypto/dsa" "crypto/ecdsa" + "crypto/ed25519" "crypto/rsa" "crypto/x509" "encoding/pem" @@ -1179,6 +1180,16 @@ func validateMatchingKeys(cert *x509.Certificate, keyFile string) error { if privKey.PublicKey.X.Cmp(pubKey.X) != 0 { return errors.New("Public key and private key do not match") } + case ed25519.PublicKey: + privKey, err := util.GetEd25519PrivateKey(keyPEM) + if err != nil { + return err + } + + publicFromPriv := privKey.Public().(ed25519.PublicKey) + if !publicFromPriv.Equal(pubKey) { + return errors.New("Public key and private key do not match") + } } return nil diff --git a/util/csp.go b/util/csp.go index 9203348a..b1af9ca6 100644 --- a/util/csp.go +++ b/util/csp.go @@ -9,6 +9,7 @@ package util import ( "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/rsa" "crypto/tls" "crypto/x509" @@ -135,6 +136,8 @@ func getBCCSPKeyOpts(kr *csr.KeyRequest, ephemeral bool) (opts bccsp.KeyGenOpts, default: return nil, errors.Errorf("Invalid ECDSA key size: %d", kr.Size()) } + case "ed25519": + return &bccsp.ED25519KeyGenOpts{Temporary: ephemeral}, nil default: return nil, errors.Errorf("Invalid algorithm: %s", kr.Algo()) } @@ -228,6 +231,16 @@ func ImportBCCSPKeyFromPEM(keyFile string, myCSP bccsp.BCCSP, temporary bool) (b return sk, nil case *rsa.PrivateKey: return nil, errors.Errorf("Failed to import RSA key from %s; RSA private key import is not supported", keyFile) + case ed25519.PrivateKey: + priv, err := PrivateKeyToDER(&key) + if err != nil { + return nil, errors.WithMessage(err, fmt.Sprintf("Failed to convert Ed25519 private key for '%s'", keyFile)) + } + sk, err := myCSP.KeyImport(priv, &bccsp.ED25519PrivateKeyImportOpts{Temporary: temporary}) + if err != nil { + return nil, errors.WithMessage(err, fmt.Sprintf("Failed to import Ed25519 private key for '%s'", keyFile)) + } + return sk, nil default: return nil, errors.Errorf("Failed to import key from %s: invalid secret key type", keyFile) } diff --git a/util/keys.go b/util/keys.go index 24a71497..cc717fbf 100644 --- a/util/keys.go +++ b/util/keys.go @@ -17,7 +17,9 @@ limitations under the License. package util import ( + "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" @@ -66,12 +68,20 @@ func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { } // PrivateKeyToDER marshals a private key to der -func PrivateKeyToDER(privateKey *ecdsa.PrivateKey) ([]byte, error) { +func PrivateKeyToDER(privateKey crypto.PrivateKey) ([]byte, error) { if privateKey == nil { return nil, errors.New("Invalid ecdsa private key. It must be different from nil") } - return x509.MarshalECPrivateKey(privateKey) + switch key := privateKey.(type) { + // Fabric supports ECDSA and ED25519 at the moment. + case *ecdsa.PrivateKey: + return x509.MarshalECPrivateKey(privateKey.(*ecdsa.PrivateKey)) + case *ed25519.PrivateKey: + return x509.MarshalPKCS8PrivateKey(*privateKey.(*ed25519.PrivateKey)) + default: + return nil, fmt.Errorf("found unknown private key type (%T) in marshaling", key) + } } // PrivateKeyToPEM converts the private key to PEM format. @@ -122,7 +132,22 @@ func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { pkcs8Bytes, err := asn1.Marshal(pkcs8Key) if err != nil { - return nil, fmt.Errorf("error marshaling EC key to asn1 [%s]", err) + return nil, fmt.Errorf("error marshaling EC key to asn1: [%s]", err) + } + return pem.EncodeToMemory( + &pem.Block{ + Type: "PRIVATE KEY", + Bytes: pkcs8Bytes, + }, + ), nil + case *ed25519.PrivateKey: + if k == nil { + return nil, errors.New("invalid ed25519 private key. It must be different from nil") + } + + pkcs8Bytes, err := x509.MarshalPKCS8PrivateKey(*k) + if err != nil { + return nil, fmt.Errorf("error marshaling ED key to asn1: [%s]", err) } return pem.EncodeToMemory( &pem.Block{ @@ -130,6 +155,7 @@ func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { Bytes: pkcs8Bytes, }, ), nil + case *rsa.PrivateKey: if k == nil { return nil, errors.New("Invalid rsa private key. It must be different from nil") @@ -143,7 +169,7 @@ func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { }, ), nil default: - return nil, errors.New("Invalid key type. It must be *ecdsa.PrivateKey or *rsa.PrivateKey") + return nil, errors.New("Invalid key type. It must be *ecdsa.PrivateKey or *ed25519.PrivateKey or *rsa.PrivateKey") } } @@ -170,7 +196,26 @@ func PrivateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error raw, pwd, x509.PEMCipherAES256) + if err != nil { + return nil, err + } + + return pem.EncodeToMemory(block), nil + case *ed25519.PrivateKey: + if k == nil { + return nil, errors.New("Invalid ed25519 private key. It must be different from nil") + } + raw, err := x509.MarshalPKCS8PrivateKey(*k) + if err != nil { + return nil, err + } + block, err := x509.EncryptPEMBlock( + rand.Reader, + "PRIVATE KEY", + raw, + pwd, + x509.PEMCipherAES256) if err != nil { return nil, err } @@ -178,7 +223,7 @@ func PrivateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error return pem.EncodeToMemory(block), nil default: - return nil, errors.New("Invalid key type. It must be *ecdsa.PrivateKey") + return nil, errors.New("invalid key type. It must be *ecdsa.PrivateKey or *ed25519.PrivateKey") } } @@ -193,6 +238,8 @@ func DERToPrivateKey(der []byte) (key interface{}, err error) { switch key.(type) { case *rsa.PrivateKey, *ecdsa.PrivateKey: return + case ed25519.PrivateKey: + return default: return nil, errors.New("Found unknown private key type in PKCS#8 wrapping") } @@ -202,7 +249,7 @@ func DERToPrivateKey(der []byte) (key interface{}, err error) { return } - return nil, errors.New("Invalid key type. The DER must contain an rsa.PrivateKey or ecdsa.PrivateKey") + return nil, errors.New("invalid key type. The DER must contain an rsa.PrivateKey or ecdsa.PrivateKey or an ed25519.PrivateKey") } // PEMtoPrivateKey unmarshals a pem to private key @@ -320,6 +367,22 @@ func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) { Bytes: PubASN1, }, ), nil + case *ed25519.PublicKey: + if k == nil { + return nil, errors.New("invalid ed25519 public key. It must be different from nil") + } + PubASN1, err := x509.MarshalPKIXPublicKey(*k) + if err != nil { + return nil, err + } + + return pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: PubASN1, + }, + ), nil + case *rsa.PublicKey: if k == nil { return nil, errors.New("Invalid rsa public key. It must be different from nil") @@ -337,7 +400,7 @@ func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) { ), nil default: - return nil, errors.New("Invalid key type. It must be *ecdsa.PublicKey or *rsa.PublicKey") + return nil, errors.New("invalid key type. It must be *ecdsa.PublicKey or *ed25519.PublicKey or *rsa.PublicKey") } } @@ -376,6 +439,7 @@ func PublicKeyToDER(publicKey interface{}) ([]byte, error) { } // PublicKeyToEncryptedPEM converts a public key to encrypted pem +// TODO: johann, refactor this later func PublicKeyToEncryptedPEM(publicKey interface{}, pwd []byte) ([]byte, error) { if publicKey == nil { return nil, errors.New("Invalid public key. It must be different from nil") @@ -394,6 +458,26 @@ func PublicKeyToEncryptedPEM(publicKey interface{}, pwd []byte) ([]byte, error) return nil, err } + block, err := x509.EncryptPEMBlock( + rand.Reader, + "PUBLIC KEY", + raw, + pwd, + x509.PEMCipherAES256) + if err != nil { + return nil, err + } + + return pem.EncodeToMemory(block), nil + case *ed25519.PublicKey: + if k == nil { + return nil, errors.New("invalid ed25519 public key. It must be different from nil") + } + raw, err := x509.MarshalPKIXPublicKey(*k) + if err != nil { + return nil, err + } + block, err := x509.EncryptPEMBlock( rand.Reader, "PUBLIC KEY", @@ -408,7 +492,7 @@ func PublicKeyToEncryptedPEM(publicKey interface{}, pwd []byte) ([]byte, error) return pem.EncodeToMemory(block), nil default: - return nil, errors.New("Invalid key type. It must be *ecdsa.PublicKey") + return nil, errors.New("invalid key type. It must be *ecdsa.PublicKey or *ed25519.PublicKey") } } diff --git a/util/util.go b/util/util.go index 2430934d..fe985169 100644 --- a/util/util.go +++ b/util/util.go @@ -9,6 +9,7 @@ package util import ( "bytes" "crypto/ecdsa" + "crypto/ed25519" "crypto/rsa" "crypto/x509" "encoding/base64" @@ -291,6 +292,8 @@ func GetECPrivateKey(raw []byte) (*ecdsa.PrivateKey, error) { return key, nil case *rsa.PrivateKey: return nil, errors.New("Expecting EC private key but found RSA private key") + case ed25519.PrivateKey: + return nil, errors.New("Expecting EC private key but found Ed25519 private key") default: return nil, errors.New("Invalid private key type in PKCS#8 wrapping") } @@ -315,6 +318,8 @@ func GetRSAPrivateKey(raw []byte) (*rsa.PrivateKey, error) { return nil, errors.New("Expecting RSA private key but found EC private key") case *rsa.PrivateKey: return key, nil + case ed25519.PrivateKey: + return nil, errors.New("Expecting RSA private key but found Ed25519 private key") default: return nil, errors.New("Invalid private key type in PKCS#8 wrapping") } @@ -322,6 +327,27 @@ func GetRSAPrivateKey(raw []byte) (*rsa.PrivateKey, error) { return nil, errors.Wrap(err, "Failed parsing RSA private key") } +func GetEd25519PrivateKey(raw []byte) (ed25519.PrivateKey, error) { + decoded, _ := pem.Decode(raw) + if decoded == nil { + return nil, errors.New("Failed to decode the PEM-encoded ECDSA key") + } + key, err2 := x509.ParsePKCS8PrivateKey(decoded.Bytes) + if err2 == nil { + switch key := key.(type) { + case ed25519.PrivateKey: + return key, nil + case *ecdsa.PrivateKey: + return nil, errors.New("Expecting Ed25519 private key but found EC private key") + case *rsa.PrivateKey: + return nil, errors.New("Expecting Ed25519 private key but found RSA private key") + default: + return nil, errors.New("Invalid private key type in PKCS#8 wrapping") + } + } + return nil, errors.Wrap(err2, "Failed parsing EC private key") +} + // B64Encode base64 encodes bytes func B64Encode(buf []byte) string { return base64.StdEncoding.EncodeToString(buf) diff --git a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/opts.go b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/opts.go index 135ffa49..647cff2c 100644 --- a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/opts.go +++ b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/opts.go @@ -22,6 +22,9 @@ const ( // ECDSAReRand ECDSA key re-randomization ECDSAReRand = "ECDSA_RERAND" + // ED25519 Algorithm + ED25519 = "ED25519" + // RSA at the default security level. // Each BCCSP may or may not support default security level. If not supported than // an error will be returned. @@ -90,6 +93,21 @@ func (opts *ECDSAKeyGenOpts) Ephemeral() bool { return opts.Temporary } +type ED25519KeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *ED25519KeyGenOpts) Algorithm() string { + return ED25519 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *ED25519KeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + // ECDSAPKIXPublicKeyImportOpts contains options for ECDSA public key importation in PKIX format type ECDSAPKIXPublicKeyImportOpts struct { Temporary bool @@ -139,6 +157,38 @@ func (opts *ECDSAGoPublicKeyImportOpts) Ephemeral() bool { return opts.Temporary } +// ED25519PrivateKeyImportOpts contains options for ED25519 key importation from ed25519.PublicKey +type ED25519PrivateKeyImportOpts struct { + Temporary bool +} + +// Algorithm returns the key importation algorithm identifier (to be used). +func (opts *ED25519PrivateKeyImportOpts) Algorithm() string { + return ED25519 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *ED25519PrivateKeyImportOpts) Ephemeral() bool { + return opts.Temporary +} + +// ED25519GoPublicKeyImportOpts contains options for ED25519 key importation from ed25519.PublicKey +type ED25519GoPublicKeyImportOpts struct { + Temporary bool +} + +// Algorithm returns the key importation algorithm identifier (to be used). +func (opts *ED25519GoPublicKeyImportOpts) Algorithm() string { + return ED25519 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *ED25519GoPublicKeyImportOpts) Ephemeral() bool { + return opts.Temporary +} + // ECDSAReRandKeyOpts contains options for ECDSA key re-randomization. type ECDSAReRandKeyOpts struct { Temporary bool diff --git a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/signer/signer.go b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/signer/signer.go index 4cc50cdf..cdd25422 100644 --- a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/signer/signer.go +++ b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/signer/signer.go @@ -61,9 +61,16 @@ func (s *bccspCryptoSigner) Public() crypto.PublicKey { return s.pk } -// Sign signs digest with the private key, possibly using entropy from rand. +// Sign signs digest or the full message with the private key, +// possibly using entropy from rand. // For an (EC)DSA key, it should be a DER-serialised, ASN.1 signature -// structure. +// structure.For an ED25519 key, it should be a signature compatible +// to the with the RFC 8032. +// +// If (EC)DSA signature, the hash must be passed as the "digestOrMsg" +// parameter. Golang requires the full message to sign with the +// built-in ED25519 library. Therefore, the full message must be +// passed as the "digestOrMsg" parameter. // // Hash implements the SignerOpts interface and, in most cases, one can // simply pass in the hash function used as opts. Sign may also attempt @@ -73,6 +80,6 @@ func (s *bccspCryptoSigner) Public() crypto.PublicKey { // Note that when a signature of a hash of a larger message is needed, // the caller is responsible for hashing the larger message and passing // the hash (as digest) and the hash function (as opts) to Sign. -func (s *bccspCryptoSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { - return s.csp.Sign(s.key, digest, opts) +func (s *bccspCryptoSigner) Sign(rand io.Reader, digestOrMsg []byte, opts crypto.SignerOpts) ([]byte, error) { + return s.csp.Sign(s.key, digestOrMsg, opts) } diff --git a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/ed25519.go b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/ed25519.go new file mode 100644 index 00000000..c8586ef3 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/ed25519.go @@ -0,0 +1,40 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package sw + +import ( + "crypto/ed25519" + + "github.com/hyperledger/fabric-lib-go/bccsp" +) + +func signED25519(k *ed25519.PrivateKey, msg []byte, opts bccsp.SignerOpts) ([]byte, error) { + signature := ed25519.Sign(*k, msg) + return signature, nil +} + +func verifyED25519(k *ed25519.PublicKey, signature, msg []byte, opts bccsp.SignerOpts) (bool, error) { + return ed25519.Verify(*k, msg, signature), nil +} + +type ed25519Signer struct{} + +func (s *ed25519Signer) Sign(k bccsp.Key, msg []byte, opts bccsp.SignerOpts) ([]byte, error) { + return signED25519(k.(*ed25519PrivateKey).privKey, msg, opts) +} + +type ed25519PrivateKeyVerifier struct{} + +func (v *ed25519PrivateKeyVerifier) Verify(k bccsp.Key, signature, msg []byte, opts bccsp.SignerOpts) (bool, error) { + castedKey, _ := (k.(*ed25519PrivateKey).privKey.Public()).(ed25519.PublicKey) + return verifyED25519(&castedKey, signature, msg, opts) +} + +type ed25519PublicKeyKeyVerifier struct{} + +func (v *ed25519PublicKeyKeyVerifier) Verify(k bccsp.Key, signature, msg []byte, opts bccsp.SignerOpts) (bool, error) { + return verifyED25519(k.(*ed25519PublicKey).pubKey, signature, msg, opts) +} diff --git a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/ed25519key.go b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/ed25519key.go new file mode 100644 index 00000000..6de3231e --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/ed25519key.go @@ -0,0 +1,109 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package sw + +import ( + "crypto/ed25519" + "crypto/sha256" + "crypto/x509" + "errors" + "fmt" + + "github.com/hyperledger/fabric-lib-go/bccsp" +) + +type ed25519PrivateKey struct { + privKey *ed25519.PrivateKey +} + +// Bytes converts this key to its byte representation, +// if this operation is allowed. +func (k *ed25519PrivateKey) Bytes() ([]byte, error) { + return nil, errors.New("Not supported.") +} + +// SKI returns the subject key identifier of this key. +func (k *ed25519PrivateKey) SKI() []byte { + if k.privKey == nil { + return nil + } + + // Marshall the public key + raw := k.privKey.Public().(ed25519.PublicKey) + + // Hash it + hash := sha256.New() + hash.Write(raw) + return hash.Sum(nil) +} + +// Symmetric returns true if this key is a symmetric key, +// false if this key is asymmetric +func (k *ed25519PrivateKey) Symmetric() bool { + return false +} + +// Private returns true if this key is a private key, +// false otherwise. +func (k *ed25519PrivateKey) Private() bool { + return true +} + +// PublicKey returns the corresponding public key part of an asymmetric public/private key pair. +// This method returns an error in symmetric key schemes. +func (k *ed25519PrivateKey) PublicKey() (bccsp.Key, error) { + castedKey, ok := k.privKey.Public().(ed25519.PublicKey) + if !ok { + return nil, errors.New("Error casting ed25519 public key") + } + return &ed25519PublicKey{&castedKey}, nil +} + +type ed25519PublicKey struct { + pubKey *ed25519.PublicKey +} + +// Bytes converts this key to its byte representation, +// if this operation is allowed. +func (k *ed25519PublicKey) Bytes() (raw []byte, err error) { + raw, err = x509.MarshalPKIXPublicKey(*k.pubKey) + if err != nil { + return nil, fmt.Errorf("Failed marshalling key [%s]", err) + } + return +} + +// SKI returns the subject key identifier of this key. +func (k *ed25519PublicKey) SKI() []byte { + if k.pubKey == nil { + return nil + } + + raw := *(k.pubKey) + + // Hash it + hash := sha256.New() + hash.Write(raw) + return hash.Sum(nil) +} + +// Symmetric returns true if this key is a symmetric key, +// false if this key is asymmetric +func (k *ed25519PublicKey) Symmetric() bool { + return false +} + +// Private returns true if this key is a private key, +// false otherwise. +func (k *ed25519PublicKey) Private() bool { + return false +} + +// PublicKey returns the corresponding public key part of an asymmetric public/private key pair. +// This method returns an error in symmetric key schemes. +func (k *ed25519PublicKey) PublicKey() (bccsp.Key, error) { + return k, nil +} diff --git a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/fileks.go b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/fileks.go index 6835a139..1b5621e7 100644 --- a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/fileks.go +++ b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/fileks.go @@ -9,6 +9,7 @@ package sw import ( "bytes" "crypto/ecdsa" + "crypto/ed25519" "crypto/rsa" "encoding/hex" "errors" @@ -142,6 +143,8 @@ func (ks *fileBasedKeyStore) GetKey(ski []byte) (bccsp.Key, error) { switch k := key.(type) { case *ecdsa.PrivateKey: return &ecdsaPrivateKey{k}, nil + case ed25519.PrivateKey: + return &ed25519PrivateKey{&k}, nil case *rsa.PrivateKey: return &rsaPrivateKey{k}, nil default: @@ -157,6 +160,8 @@ func (ks *fileBasedKeyStore) GetKey(ski []byte) (bccsp.Key, error) { switch k := key.(type) { case *ecdsa.PublicKey: return &ecdsaPublicKey{k}, nil + case ed25519.PublicKey: + return &ed25519PublicKey{&k}, nil case *rsa.PublicKey: return &rsaPublicKey{k}, nil default: @@ -190,6 +195,18 @@ func (ks *fileBasedKeyStore) StoreKey(k bccsp.Key) (err error) { return fmt.Errorf("failed storing ECDSA public key [%s]", err) } + case *ed25519PrivateKey: + err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey) + if err != nil { + return fmt.Errorf("failed storing ED25519 private key [%s]", err) + } + + case *ed25519PublicKey: + err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey) + if err != nil { + return fmt.Errorf("failed storing ED25519 public key [%s]", err) + } + case *rsaPrivateKey: err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey) @@ -246,6 +263,8 @@ func (ks *fileBasedKeyStore) searchKeystoreForSKI(ski []byte) (k bccsp.Key, err switch kk := key.(type) { case *ecdsa.PrivateKey: k = &ecdsaPrivateKey{kk} + case ed25519.PrivateKey: + k = &ed25519PrivateKey{&kk} case *rsa.PrivateKey: k = &rsaPrivateKey{kk} default: diff --git a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keygen.go b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keygen.go index 8a87563d..d7fcbcca 100644 --- a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keygen.go +++ b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keygen.go @@ -8,6 +8,7 @@ package sw import ( "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" @@ -29,6 +30,17 @@ func (kg *ecdsaKeyGenerator) KeyGen(opts bccsp.KeyGenOpts) (bccsp.Key, error) { return &ecdsaPrivateKey{privKey}, nil } +type ed25519KeyGenerator struct{} + +func (kg *ed25519KeyGenerator) KeyGen(opts bccsp.KeyGenOpts) (bccsp.Key, error) { + _, privKey, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf("Failed generating ED25519 key: [%s]", err) + } + + return &ed25519PrivateKey{&privKey}, nil +} + type aesKeyGenerator struct { length int } diff --git a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keyimport.go b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keyimport.go index fca33fd6..025c4d13 100644 --- a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keyimport.go +++ b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keyimport.go @@ -8,6 +8,7 @@ package sw import ( "crypto/ecdsa" + "crypto/ed25519" "crypto/rsa" "crypto/x509" "errors" @@ -101,6 +102,31 @@ func (*ecdsaPrivateKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bcc return &ecdsaPrivateKey{ecdsaSK}, nil } +type ed25519PrivateKeyImportOptsKeyImporter struct{} + +func (*ed25519PrivateKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (bccsp.Key, error) { + der, ok := raw.([]byte) + if !ok { + return nil, errors.New("[ED25519DERPrivateKeyImportOpts] Invalid raw material. Expected byte array.") + } + + if len(der) == 0 { + return nil, errors.New("[ED25519DERPrivateKeyImportOpts] Invalid raw. It must not be nil.") + } + + lowLevelKey, err := derToPrivateKey(der) + if err != nil { + return nil, fmt.Errorf("Failed converting PKIX to ED25519 public key [%s]", err) + } + + ed25519SK, ok := lowLevelKey.(ed25519.PrivateKey) + if !ok { + return nil, errors.New("Failed casting to ED25519 private key. Invalid raw material.") + } + + return &ed25519PrivateKey{&ed25519SK}, nil +} + type ecdsaGoPublicKeyImportOptsKeyImporter struct{} func (*ecdsaGoPublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (bccsp.Key, error) { @@ -112,6 +138,17 @@ func (*ecdsaGoPublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bc return &ecdsaPublicKey{lowLevelKey}, nil } +type ed25519GoPublicKeyImportOptsKeyImporter struct{} + +func (*ed25519GoPublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (bccsp.Key, error) { + lowLevelKey, ok := raw.(ed25519.PublicKey) + if !ok { + return nil, errors.New("Invalid raw material. Expected *ed25519.PublicKey.") + } + + return &ed25519PublicKey{&lowLevelKey}, nil +} + type rsaGoPublicKeyImportOptsKeyImporter struct{} func (*rsaGoPublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (bccsp.Key, error) { @@ -140,12 +177,16 @@ func (ki *x509PublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bc return ki.bccsp.KeyImporters[reflect.TypeOf(&bccsp.ECDSAGoPublicKeyImportOpts{})].KeyImport( pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) + case ed25519.PublicKey: + return ki.bccsp.KeyImporters[reflect.TypeOf(&bccsp.ED25519GoPublicKeyImportOpts{})].KeyImport( + pk, + &bccsp.ED25519GoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) case *rsa.PublicKey: // This path only exists to support environments that use RSA certificate - // authorities to issue ECDSA certificates. + // authorities to issue ECDSA and ed25519 certificates. return &rsaPublicKey{pubKey: pk}, nil default: - return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]") + return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, ED25519, RSA]") } } diff --git a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keys.go b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keys.go index 6a7f3880..cdc9a671 100644 --- a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keys.go +++ b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/keys.go @@ -7,7 +7,9 @@ SPDX-License-Identifier: Apache-2.0 package sw import ( + "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" @@ -54,12 +56,20 @@ func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { return nil, false } -func privateKeyToDER(privateKey *ecdsa.PrivateKey) ([]byte, error) { +func privateKeyToDER(privateKey crypto.PrivateKey) ([]byte, error) { if privateKey == nil { - return nil, errors.New("invalid ecdsa private key. It must be different from nil") + return nil, errors.New("invalid private key. It must be different from nil") } - return x509.MarshalECPrivateKey(privateKey) + switch key := privateKey.(type) { + // Fabric supports ECDSA and ED25519 at the moment. + case *ecdsa.PrivateKey: + return x509.MarshalECPrivateKey(privateKey.(*ecdsa.PrivateKey)) + case *ed25519.PrivateKey: + return x509.MarshalPKCS8PrivateKey(*privateKey.(*ed25519.PrivateKey)) + default: + return nil, fmt.Errorf("found unknown private key type (%T) in marshaling", key) + } } func privateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { @@ -114,6 +124,21 @@ func privateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { Bytes: pkcs8Bytes, }, ), nil + case *ed25519.PrivateKey: + if k == nil { + return nil, errors.New("invalid ed25519 private key. It must be different from nil") + } + + pkcs8Bytes, err := x509.MarshalPKCS8PrivateKey(*k) + if err != nil { + return nil, fmt.Errorf("error marshaling ED key to asn1: [%s]", err) + } + return pem.EncodeToMemory( + &pem.Block{ + Type: "PRIVATE KEY", + Bytes: pkcs8Bytes, + }, + ), nil case *rsa.PrivateKey: if k == nil { @@ -129,7 +154,7 @@ func privateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { ), nil default: - return nil, errors.New("invalid key type. It must be *ecdsa.PrivateKey or *rsa.PrivateKey") + return nil, errors.New("invalid key type. It must be *ecdsa.PrivateKey, *ed25519.PrivateKey or *rsa.PrivateKey") } } @@ -158,10 +183,30 @@ func privateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error return nil, err } + return pem.EncodeToMemory(block), nil + case *ed25519.PrivateKey: + if k == nil { + return nil, errors.New("invalid ed25519 private key. It must be different from nil") + } + raw, err := x509.MarshalPKCS8PrivateKey(*k) + if err != nil { + return nil, err + } + + block, err := x509.EncryptPEMBlock( + rand.Reader, + "PRIVATE KEY", + raw, + pwd, + x509.PEMCipherAES256) + if err != nil { + return nil, err + } + return pem.EncodeToMemory(block), nil default: - return nil, errors.New("invalid key type. It must be *ecdsa.PrivateKey") + return nil, errors.New("invalid key type. It must be *ecdsa.PrivateKey or *ed25519.PrivateKey") } } @@ -174,6 +219,8 @@ func derToPrivateKey(der []byte) (key interface{}, err error) { switch key.(type) { case *ecdsa.PrivateKey: return + case ed25519.PrivateKey: + return default: return nil, errors.New("found unknown private key type in PKCS#8 wrapping") } @@ -183,7 +230,7 @@ func derToPrivateKey(der []byte) (key interface{}, err error) { return } - return nil, errors.New("invalid key type. The DER must contain an ecdsa.PrivateKey") + return nil, errors.New("invalid key type. The DER must contain an ecdsa.PrivateKey or an ed25519.PrivateKey") } func pemToPrivateKey(raw []byte, pwd []byte) (interface{}, error) { @@ -286,6 +333,21 @@ func publicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) { return nil, err } + return pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: PubASN1, + }, + ), nil + case *ed25519.PublicKey: + if k == nil { + return nil, errors.New("invalid ed25519 public key. It must be different from nil") + } + PubASN1, err := x509.MarshalPKIXPublicKey(*k) + if err != nil { + return nil, err + } + return pem.EncodeToMemory( &pem.Block{ Type: "PUBLIC KEY", @@ -310,7 +372,7 @@ func publicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) { ), nil default: - return nil, errors.New("invalid key type. It must be *ecdsa.PublicKey or *rsa.PublicKey") + return nil, errors.New("invalid key type. It must be *ecdsa.PublicKey, *ed25519.PublicKey or *rsa.PublicKey") } } @@ -335,9 +397,29 @@ func publicKeyToEncryptedPEM(publicKey interface{}, pwd []byte) ([]byte, error) return nil, err } + return pem.EncodeToMemory(block), nil + case *ed25519.PublicKey: + if k == nil { + return nil, errors.New("invalid ed25519 public key. It must be different from nil") + } + raw, err := x509.MarshalPKIXPublicKey(*k) + if err != nil { + return nil, err + } + + block, err := x509.EncryptPEMBlock( + rand.Reader, + "PUBLIC KEY", + raw, + pwd, + x509.PEMCipherAES256) + if err != nil { + return nil, err + } + return pem.EncodeToMemory(block), nil default: - return nil, errors.New("invalid key type. It must be *ecdsa.PublicKey") + return nil, errors.New("invalid key type. It must be *ecdsa.PublicKey or *ed25519.PublicKey") } } diff --git a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/new.go b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/new.go index 4dc65bd5..c85e9279 100644 --- a/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/new.go +++ b/vendor/github.com/hyperledger/fabric-lib-go/bccsp/sw/new.go @@ -60,11 +60,14 @@ func NewWithParams(securityLevel int, hashFamily string, keyStore bccsp.KeyStore // Set the Signers swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPrivateKey{}), &ecdsaSigner{}) + swbccsp.AddWrapper(reflect.TypeOf(&ed25519PrivateKey{}), &ed25519Signer{}) swbccsp.AddWrapper(reflect.TypeOf(&rsaPrivateKey{}), &rsaSigner{}) // Set the Verifiers swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPrivateKey{}), &ecdsaPrivateKeyVerifier{}) swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPublicKey{}), &ecdsaPublicKeyKeyVerifier{}) + swbccsp.AddWrapper(reflect.TypeOf(&ed25519PrivateKey{}), &ed25519PrivateKeyVerifier{}) + swbccsp.AddWrapper(reflect.TypeOf(&ed25519PublicKey{}), &ed25519PublicKeyKeyVerifier{}) swbccsp.AddWrapper(reflect.TypeOf(&rsaPrivateKey{}), &rsaPrivateKeyVerifier{}) swbccsp.AddWrapper(reflect.TypeOf(&rsaPublicKey{}), &rsaPublicKeyKeyVerifier{}) @@ -83,6 +86,7 @@ func NewWithParams(securityLevel int, hashFamily string, keyStore bccsp.KeyStore swbccsp.AddWrapper(reflect.TypeOf(&bccsp.AES256KeyGenOpts{}), &aesKeyGenerator{length: 32}) swbccsp.AddWrapper(reflect.TypeOf(&bccsp.AES192KeyGenOpts{}), &aesKeyGenerator{length: 24}) swbccsp.AddWrapper(reflect.TypeOf(&bccsp.AES128KeyGenOpts{}), &aesKeyGenerator{length: 16}) + swbccsp.AddWrapper(reflect.TypeOf(&bccsp.ED25519KeyGenOpts{}), &ed25519KeyGenerator{}) swbccsp.AddWrapper(reflect.TypeOf(&bccsp.RSAKeyGenOpts{}), &rsaKeyGenerator{length: conf.rsaBitLength}) swbccsp.AddWrapper(reflect.TypeOf(&bccsp.RSA1024KeyGenOpts{}), &rsaKeyGenerator{length: 1024}) swbccsp.AddWrapper(reflect.TypeOf(&bccsp.RSA2048KeyGenOpts{}), &rsaKeyGenerator{length: 2048}) @@ -93,6 +97,8 @@ func NewWithParams(securityLevel int, hashFamily string, keyStore bccsp.KeyStore swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPrivateKey{}), &ecdsaPrivateKeyKeyDeriver{}) swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPublicKey{}), &ecdsaPublicKeyKeyDeriver{}) swbccsp.AddWrapper(reflect.TypeOf(&aesPrivateKey{}), &aesPrivateKeyKeyDeriver{conf: conf}) + // TODO: Ed25519 KeyDeriver + // swbccsp.AddWrapper(reflect.TypeOf(&ed25519PrivateKey{}), &ed25519PrivateKeyKeyDeriver{}) // Set the key importers swbccsp.AddWrapper(reflect.TypeOf(&bccsp.AES256ImportKeyOpts{}), &aes256ImportKeyOptsKeyImporter{}) @@ -102,6 +108,8 @@ func NewWithParams(securityLevel int, hashFamily string, keyStore bccsp.KeyStore swbccsp.AddWrapper(reflect.TypeOf(&bccsp.ECDSAGoPublicKeyImportOpts{}), &ecdsaGoPublicKeyImportOptsKeyImporter{}) swbccsp.AddWrapper(reflect.TypeOf(&bccsp.RSAGoPublicKeyImportOpts{}), &rsaGoPublicKeyImportOptsKeyImporter{}) swbccsp.AddWrapper(reflect.TypeOf(&bccsp.X509PublicKeyImportOpts{}), &x509PublicKeyImportOptsKeyImporter{bccsp: swbccsp}) + swbccsp.AddWrapper(reflect.TypeOf(&bccsp.ED25519PrivateKeyImportOpts{}), &ed25519PrivateKeyImportOptsKeyImporter{}) + swbccsp.AddWrapper(reflect.TypeOf(&bccsp.ED25519GoPublicKeyImportOpts{}), &ed25519GoPublicKeyImportOptsKeyImporter{}) return swbccsp, nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index 712a08c1..5198e4a2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -148,7 +148,7 @@ github.com/hyperledger/fabric-amcl/amcl github.com/hyperledger/fabric-amcl/amcl/FP256BN github.com/hyperledger/fabric-amcl/core github.com/hyperledger/fabric-amcl/core/FP256BN -# github.com/hyperledger/fabric-lib-go v1.1.2 +# github.com/hyperledger/fabric-lib-go v1.1.3-0.20240523144151-25edd1eaf5f5 ## explicit; go 1.20 github.com/hyperledger/fabric-lib-go/bccsp github.com/hyperledger/fabric-lib-go/bccsp/factory @@ -472,3 +472,4 @@ gopkg.in/yaml.v3 ## explicit; go 1.17 rsc.io/tmplfunc rsc.io/tmplfunc/internal/parse +# github.com/hyperledger/fabric v1.4.11 => github.com/johannww/fabric-1 v0.0.0-20221130143147-4c6de157c5c4