Skip to content

Commit c1b204a

Browse files
authored
fix(region): support more scheme keypair (#23195)
1 parent 313224f commit c1b204a

File tree

6 files changed

+96
-28
lines changed

6 files changed

+96
-28
lines changed

pkg/apis/compute/keypair.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ import "yunion.io/x/onecloud/pkg/apis"
1818

1919
var KEYPAIR_SCHEMAS = []string{
2020
KEYPAIRE_SCHEME_RSA,
21+
// OpenSSH deprecated DSA keys
22+
//KEYPAIRE_SCHEME_DSA,
23+
KEYPAIRE_SCHEME_ECDSA,
24+
KEYPAIRE_SCHEME_ED25519,
2125
}
2226

2327
type KeypairCreateInput struct {

pkg/apis/compute/keypair_const.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package compute
1616

1717
const (
18-
KEYPAIRE_SCHEME_RSA = "RSA"
19-
KEYPAIRE_SCHEME_DSA = "DSA"
18+
KEYPAIRE_SCHEME_RSA = "RSA"
19+
KEYPAIRE_SCHEME_DSA = "DSA"
20+
KEYPAIRE_SCHEME_ECDSA = "ECDSA"
21+
KEYPAIRE_SCHEME_ED25519 = "ED25519"
2022
)

pkg/compute/models/keypairs.go

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"yunion.io/x/pkg/errors"
2525
"yunion.io/x/pkg/gotypes"
2626
"yunion.io/x/pkg/util/rbacscope"
27-
"yunion.io/x/pkg/utils"
2827
"yunion.io/x/sqlchemy"
2928

3029
"yunion.io/x/onecloud/pkg/apis"
@@ -230,36 +229,42 @@ func (self *SKeypair) GetLinkedGuestsCount() (int, error) {
230229
return GuestManager.Query().Equals("keypair_id", self.Id).CountWithError()
231230
}
232231

233-
func (manager *SKeypairManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.KeypairCreateInput) (api.KeypairCreateInput, error) {
232+
func (manager *SKeypairManager) ValidateCreateData(
233+
ctx context.Context,
234+
userCred mcclient.TokenCredential,
235+
ownerId mcclient.IIdentityProvider,
236+
query jsonutils.JSONObject,
237+
input *api.KeypairCreateInput,
238+
) (*api.KeypairCreateInput, error) {
234239
input.PublicKey = strings.TrimSpace(input.PublicKey)
235240
if len(input.PublicKey) == 0 {
236241
if len(input.Scheme) == 0 {
237242
input.Scheme = api.KEYPAIRE_SCHEME_RSA
238243
}
239-
if !utils.IsInStringArray(input.Scheme, api.KEYPAIR_SCHEMAS) {
240-
return input, httperrors.NewInputParameterError("Unsupported scheme %s", input.Scheme)
241-
}
242244

243245
var err error
244-
if input.Scheme == api.KEYPAIRE_SCHEME_RSA {
246+
switch input.Scheme {
247+
case api.KEYPAIRE_SCHEME_RSA:
245248
input.PrivateKey, input.PublicKey, err = seclib2.GenerateRSASSHKeypair()
246-
} else {
249+
case api.KEYPAIRE_SCHEME_DSA:
247250
input.PrivateKey, input.PublicKey, err = seclib2.GenerateDSASSHKeypair()
251+
case api.KEYPAIRE_SCHEME_ECDSA:
252+
input.PrivateKey, input.PublicKey, err = seclib2.GenerateECDSASHAP521SSHKeypair()
253+
case api.KEYPAIRE_SCHEME_ED25519:
254+
input.PrivateKey, input.PublicKey, err = seclib2.GenerateED25519SSHKeypair()
255+
default:
256+
return nil, httperrors.NewInputParameterError("Unsupported scheme %s", input.Scheme)
248257
}
249258
if err != nil {
250-
return input, httperrors.NewGeneralError(errors.Wrapf(err, "Generate%sSSHKeypair", input.Scheme))
259+
return nil, httperrors.NewGeneralError(errors.Wrapf(err, "Generate%sSSHKeypair", input.Scheme))
251260
}
252261
}
253262
pubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(input.PublicKey))
254263
if err != nil {
255264
return input, httperrors.NewInputParameterError("invalid public error: %v", err)
256265
}
257266

258-
// 只允许上传RSA格式密钥。PS: AWS只支持RSA格式。
259267
input.Scheme = seclib2.GetPublicKeyScheme(pubKey)
260-
if input.Scheme != api.KEYPAIRE_SCHEME_RSA {
261-
return input, httperrors.NewInputParameterError("Unsupported scheme %s", input.Scheme)
262-
}
263268

264269
input.Fingerprint = ssh.FingerprintLegacyMD5(pubKey)
265270
input.UserResourceCreateInput, err = manager.SUserResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.UserResourceCreateInput)

pkg/mcclient/options/compute/keypairs.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
type KeypairList struct {
2424
options.BaseListOptions
25+
Scheme string `help:"Scheme of keypair, default is RSA" choices:"RSA|DSA|ECDSA|ED25519"`
2526
}
2627

2728
func (self *KeypairList) Params() (jsonutils.JSONObject, error) {
@@ -30,7 +31,7 @@ func (self *KeypairList) Params() (jsonutils.JSONObject, error) {
3031

3132
type KeypairCreate struct {
3233
NAME string `help:"Name of keypair to be created"`
33-
Scheme string `help:"Scheme of keypair, default is RSA" choices:"RSA" default:"RSA"`
34+
Scheme string `help:"Scheme of keypair, default is RSA" choices:"RSA|DSA|ECDSA|ED25519" default:"RSA"`
3435
PublicKey string `help:"Publickey of keypair"`
3536
Desc string `help:"Short description of keypair"`
3637
}

pkg/util/seclib2/ssh.go

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
package seclib2
1616

1717
import (
18+
"crypto"
1819
"crypto/dsa"
20+
"crypto/ecdsa"
21+
"crypto/ed25519"
22+
"crypto/elliptic"
1923
"crypto/rand"
2024
"crypto/rsa"
2125
"crypto/x509"
@@ -25,22 +29,65 @@ import (
2529

2630
"golang.org/x/crypto/ssh"
2731

28-
"yunion.io/x/log"
32+
"yunion.io/x/pkg/errors"
2933
)
3034

3135
func GenerateRSASSHKeypair() (string, string, error) {
3236
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
3337
if err != nil {
34-
log.Errorf("generate rsa key error %s", err)
35-
return "", "", err
38+
return "", "", errors.Wrapf(err, "generate rsa key")
3639
}
3740

3841
privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
3942
privateStr := string(pem.EncodeToMemory(privateKeyPEM))
4043

4144
pub, err := exportSshPublicKey(&privateKey.PublicKey)
4245
if err != nil {
43-
return "", "", err
46+
return "", "", errors.Wrapf(err, "export ssh public key")
47+
}
48+
publicStr := string(pub)
49+
50+
return privateStr, publicStr, nil
51+
}
52+
53+
func GenerateED25519SSHKeypair() (string, string, error) {
54+
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
55+
if err != nil {
56+
return "", "", errors.Wrapf(err, "generate ed25519 key")
57+
}
58+
59+
pemBlock, err := ssh.MarshalPrivateKey(crypto.PrivateKey(privateKey), "")
60+
if err != nil {
61+
return "", "", errors.Wrapf(err, "marshal pkix private key")
62+
}
63+
64+
privateStr := string(pem.EncodeToMemory(pemBlock))
65+
66+
pub, err := exportSshPublicKey(publicKey)
67+
if err != nil {
68+
return "", "", errors.Wrapf(err, "export ssh public key")
69+
}
70+
publicStr := string(pub)
71+
72+
return privateStr, publicStr, nil
73+
}
74+
75+
func GenerateECDSASHAP521SSHKeypair() (string, string, error) {
76+
privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
77+
if err != nil {
78+
return "", "", errors.Wrapf(err, "generate ecdsa key")
79+
}
80+
81+
pemBlock, err := ssh.MarshalPrivateKey(crypto.PrivateKey(privateKey), "")
82+
if err != nil {
83+
return "", "", errors.Wrapf(err, "marshal pkix private key")
84+
}
85+
86+
privateStr := string(pem.EncodeToMemory(pemBlock))
87+
88+
pub, err := exportSshPublicKey(&privateKey.PublicKey)
89+
if err != nil {
90+
return "", "", errors.Wrapf(err, "export ssh public key")
4491
}
4592
publicStr := string(pub)
4693

@@ -53,13 +100,11 @@ func GenerateDSASSHKeypair() (string, string, error) {
53100
params := &privateKey.Parameters
54101
err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160)
55102
if err != nil {
56-
log.Errorf("generateParameter error %s", err)
57-
return "", "", err
103+
return "", "", errors.Wrapf(err, "generate dsa key")
58104
}
59105
err = dsa.GenerateKey(&privateKey, rand.Reader)
60106
if err != nil {
61-
log.Errorf("generate key error %s", err)
62-
return "", "", err
107+
return "", "", errors.Wrapf(err, "generate dsa key")
63108
}
64109

65110
type DsaASN1 struct {
@@ -80,16 +125,15 @@ func GenerateDSASSHKeypair() (string, string, error) {
80125

81126
privBytes, err := asn1.Marshal(k)
82127
if err != nil {
83-
log.Errorf("asn1 marshal error %s", err)
84-
return "", "", err
128+
return "", "", errors.Wrapf(err, "asn1 marshal")
85129
}
86130

87131
privateKeyPEM := &pem.Block{Type: "DSA PRIVATE KEY", Bytes: privBytes}
88132
privateStr := string(pem.EncodeToMemory(privateKeyPEM))
89133

90134
pub, err := exportSshPublicKey(&privateKey.PublicKey)
91135
if err != nil {
92-
return "", "", err
136+
return "", "", errors.Wrapf(err, "export ssh public key")
93137
}
94138
publicStr := string(pub)
95139

@@ -104,8 +148,8 @@ func GetPublicKeyScheme(pubkey ssh.PublicKey) string {
104148
return "DSA"
105149
case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
106150
return "ECDSA"
107-
// case ssh.KeyAlgoED25519:
108-
// return "ED"
151+
case ssh.KeyAlgoED25519:
152+
return "ED25519"
109153
}
110154
return "UNKNOWN"
111155
}

pkg/util/seclib2/ssh_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ func TestGenerateDSASSHKeypair(t *testing.T) {
3535
t.Logf("%s", pub)
3636
}
3737

38+
func TestGenerateECDSASHAP521SSHKeypair(t *testing.T) {
39+
priv, pub, _ := GenerateECDSASHAP521SSHKeypair()
40+
t.Logf("%s", priv)
41+
t.Logf("%s", pub)
42+
}
43+
44+
func TestGenerateED25519SSHKeypair(t *testing.T) {
45+
priv, pub, _ := GenerateED25519SSHKeypair()
46+
t.Logf("%s", priv)
47+
t.Logf("%s", pub)
48+
}
49+
3850
func getPublicKeyPem(privateKey string) ([]byte, error) {
3951
block, _ := pem.Decode([]byte(privateKey))
4052
if block == nil {

0 commit comments

Comments
 (0)