From d477733e23e84c44cd687ba67d7e16e0d3458143 Mon Sep 17 00:00:00 2001 From: shy Date: Sat, 30 Mar 2024 22:09:25 +0800 Subject: [PATCH] add some --- base/aaa/aaa.go | 3 +- base/aaa/user.go | 1 + misc/ssh/cert.go | 161 ++++++++++++++++++++++++++++++++++++++++ misc/ssh/relay/relay.go | 5 +- 4 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 misc/ssh/cert.go diff --git a/base/aaa/aaa.go b/base/aaa/aaa.go index 794910e5..14963a16 100644 --- a/base/aaa/aaa.go +++ b/base/aaa/aaa.go @@ -5,6 +5,7 @@ import ice "shylinux.com/x/icebergs" const ( RSA = "rsa" SIGN = "sign" + CERT = "cert" VERIFY = "verify" BASE64 = "base64" ) @@ -12,4 +13,4 @@ const AAA = "aaa" var Index = &ice.Context{Name: AAA, Help: "认证模块"} -func init() { ice.Index.Register(Index, nil, APPLY, OFFER, EMAIL, USER, TOTP, SESS, ROLE, RSA) } +func init() { ice.Index.Register(Index, nil, APPLY, OFFER, EMAIL, USER, TOTP, SESS, ROLE, CERT, RSA) } diff --git a/base/aaa/user.go b/base/aaa/user.go index fc9a8934..669f9770 100644 --- a/base/aaa/user.go +++ b/base/aaa/user.go @@ -30,6 +30,7 @@ const ( LOCATION = "location" LONGITUDE = "longitude" LATITUDE = "latitude" + COMPANY = "company" PROVINCE = "province" COUNTRY = "country" CITY = "city" diff --git a/misc/ssh/cert.go b/misc/ssh/cert.go new file mode 100644 index 00000000..8862ecf0 --- /dev/null +++ b/misc/ssh/cert.go @@ -0,0 +1,161 @@ +package ssh + +import ( + "bytes" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "encoding/pem" + "math/big" + "path" + "strings" + "time" + + ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/aaa" + "shylinux.com/x/icebergs/base/lex" + "shylinux.com/x/icebergs/base/mdb" + "shylinux.com/x/icebergs/base/nfs" + kit "shylinux.com/x/toolkits" +) + +const ( + ETC_CERT = "etc/cert/" + PEM = "pem" + KEY = "key" + + SIGN = "sign" + VERIFY = "verify" + ENCRYPT = "encrypt" + DECRYPT = "decrypt" +) +const CERT = "cert" + +func init() { + aaa.Index.MergeCommands(ice.Commands{ + CERT: {Name: "cert path auto", Help: "证书", Actions: ice.MergeActions(ice.Actions{ + mdb.CREATE: {Name: "create name* country province city street postal company year month=1 day", Hand: func(m *ice.Message, arg ...string) { + if nfs.Exists(m, filepath(m, m.Option(mdb.NAME)+nfs.PT+PEM)) { + m.Push(PEM, filepath(m, m.Option(mdb.NAME)+nfs.PT+PEM)) + m.Push(KEY, filepath(m, m.Option(mdb.NAME)+nfs.PT+KEY)) + return + } + cert := &x509.Certificate{ + SerialNumber: big.NewInt(time.Now().Unix()), + Subject: pkix.Name{ + CommonName: m.Option(mdb.NAME), Organization: []string{m.Option(aaa.COMPANY)}, + Country: []string{m.Option(aaa.COUNTRY)}, Province: []string{m.Option(aaa.PROVINCE)}, Locality: []string{m.Option(aaa.CITY)}, + StreetAddress: []string{m.Option("street")}, PostalCode: []string{m.Option("postal")}, + }, + NotBefore: time.Now(), NotAfter: time.Now().AddDate(kit.Int(m.Option("year")), kit.Int(m.Option("month")), kit.Int(m.Option("day"))), + KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + } + certKey, _ := rsa.GenerateKey(rand.Reader, 4096) + ca, caKey, err := LoadCertKey(m) + kit.If(err != nil, func() { ca, caKey, cert.KeyUsage = cert, certKey, x509.KeyUsageDigitalSignature|x509.KeyUsageCertSign }) + if certBuf, err := x509.CreateCertificate(rand.Reader, cert, ca, certKey.Public(), caKey); !m.Warn(err) { + SaveCertKey(m, m.Option(mdb.NAME)+nfs.PT+KEY, "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(certKey)) + SaveCertKey(m, m.Option(mdb.NAME)+nfs.PT+PEM, "CERTIFICATE", certBuf) + } + }}, + nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) { nfs.Trash(m, m.Option(nfs.PATH)) }}, + ENCRYPT: {Name: "encrypt text", Help: "加密", Hand: func(m *ice.Message, arg ...string) { + if cert, err := loadCert(m, m.Option(nfs.PATH)); err == nil { + data, _ := rsa.EncryptPKCS1v15(rand.Reader, cert.PublicKey.(*rsa.PublicKey), []byte(m.Option(mdb.TEXT))) + m.Echo(base64.StdEncoding.EncodeToString(data)).ProcessInner() + } + }}, + DECRYPT: {Name: "decrypt text", Help: "解密", Hand: func(m *ice.Message, arg ...string) { + if key, err := loadKey(m, m.Option(nfs.PATH)); err == nil { + text, _ := base64.StdEncoding.DecodeString(m.Option(mdb.TEXT)) + if data, err := rsa.DecryptPKCS1v15(rand.Reader, key, text); !m.Warn(err) { + m.Echo(string(data)).ProcessInner() + } + } + }}, + SIGN: {Name: "sign text", Help: "签名", Hand: func(m *ice.Message, arg ...string) { + if key, err := loadKey(m, m.Option(nfs.PATH)); err == nil { + hash := sha256.New() + hash.Write([]byte(strings.TrimSpace(m.Option(mdb.TEXT)))) + data, _ := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hash.Sum(nil)) + m.Echo(base64.StdEncoding.EncodeToString(data) + lex.SP + m.Option(mdb.TEXT)).ProcessInner() + } + }}, + VERIFY: {Name: "verify text", Help: "验签", Hand: func(m *ice.Message, arg ...string) { + if cert, err := loadCert(m, m.Option(nfs.PATH)); err == nil { + ls := strings.SplitN(strings.TrimSpace(m.Option(mdb.TEXT)), lex.SP, 2) + hash := sha256.New() + hash.Write([]byte(ls[1])) + sign, _ := base64.StdEncoding.DecodeString(ls[0]) + if !m.Warn(rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.SHA256, hash.Sum(nil), sign)) { + m.Echo(ice.OK).ProcessInner() + } + } + }}, + }, mdb.HashAction(PEM, nfs.ETC_CERT_PEM, KEY, nfs.ETC_CERT_KEY)), Hand: func(m *ice.Message, arg ...string) { + if len(arg) == 0 { + m.Cmdy(nfs.DIR, ETC_CERT).Table(func(value ice.Maps) { + switch kit.Ext(value[nfs.PATH]) { + case PEM: + m.PushButton(ENCRYPT, VERIFY, nfs.TRASH) + case KEY: + m.PushButton(DECRYPT, SIGN, nfs.TRASH) + default: + m.PushButton(nfs.TRASH) + } + }).Action(mdb.CREATE) + } else { + switch block, _ := pem.Decode([]byte(m.Cmdx(nfs.CAT, arg[0]))); block.Type { + case "CERTIFICATE": + cert, _ := x509.ParseCertificate(block.Bytes) + m.Push("NotAfter", cert.NotAfter.Format(ice.MOD_TIME)).Push("Subject", cert.Subject.CommonName) + m.Push("Issuer", kit.Select(cert.Issuer.CommonName, cert.Issuer.Organization, 0)) + m.Echo(kit.Formats(cert)) + case "RSA PRIVATE KEY": + key, _ := x509.ParsePKCS1PrivateKey(block.Bytes) + m.Echo(kit.Formats(key)) + } + } + }}, + }) +} +func filepath(m *ice.Message, file string) string { + return path.Join(ETC_CERT + file) +} +func loadBlock(m *ice.Message, p string) []byte { + block, _ := pem.Decode([]byte(m.Cmdx(nfs.CAT, p))) + return block.Bytes +} +func loadCert(m *ice.Message, p string) (*x509.Certificate, error) { + if cert, err := x509.ParseCertificate(loadBlock(m, p)); m.Warn(err) { + return nil, err + } else { + return cert, nil + } +} +func loadKey(m *ice.Message, p string) (*rsa.PrivateKey, error) { + if key, err := x509.ParsePKCS1PrivateKey(loadBlock(m, p)); m.Warn(err) { + return nil, err + } else { + return key, nil + } +} +func LoadCertKey(m *ice.Message) (*x509.Certificate, *rsa.PrivateKey, error) { + if cert, err := loadCert(m, mdb.Config(m, PEM)); m.Warn(err) { + return nil, nil, err + } else if key, err := loadKey(m, mdb.Config(m, KEY)); m.Warn(err) { + return nil, nil, err + } else { + return cert, key, nil + } +} +func SaveCertKey(m *ice.Message, file, Type string, Bytes []byte) { + certPEM := new(bytes.Buffer) + pem.Encode(certPEM, &pem.Block{Type: Type, Bytes: Bytes}) + p := path.Join(ETC_CERT + file) + m.Push(kit.Ext(file), p).Cmd(nfs.SAVE, p, certPEM.String()) +} diff --git a/misc/ssh/relay/relay.go b/misc/ssh/relay/relay.go index fe0c5fb5..61286533 100644 --- a/misc/ssh/relay/relay.go +++ b/misc/ssh/relay/relay.go @@ -285,8 +285,9 @@ func (s relay) Pushbin(m *ice.Message, arg ...string) { }) m.Cmd(SSH_TRANS, tcp.SEND) if m.Option(web.PORTAL) == tcp.PORT_443 { - m.Cmd(SSH_TRANS, tcp.SEND, nfs.FROM, nfs.ETC_CERT_KEY, nfs.PATH, m.Option(web.DREAM), nfs.FILE, nfs.ETC_CERT_KEY) - m.Cmd(SSH_TRANS, tcp.SEND, nfs.FROM, nfs.ETC_CERT_PEM, nfs.PATH, m.Option(web.DREAM), nfs.FILE, nfs.ETC_CERT_PEM) + msg := m.Cmd(ssh.CERT, mdb.CREATE, m.Option(tcp.HOST)) + m.Cmd(SSH_TRANS, tcp.SEND, nfs.FROM, msg.Append(ssh.KEY), nfs.PATH, m.Option(web.DREAM), nfs.FILE, nfs.ETC_CERT_KEY) + m.Cmd(SSH_TRANS, tcp.SEND, nfs.FROM, msg.Append(ssh.PEM), nfs.PATH, m.Option(web.DREAM), nfs.FILE, nfs.ETC_CERT_PEM) } cmd := m.Template(PUSHBIN_SH) + lex.SP + kit.JoinCmds(ice.DEV, m.Option(ice.DEV), tcp.PORT, m.Option(web.PORTAL), tcp.NODENAME, m.OptionDefault(tcp.NODENAME, m.Option(MACHINE))) s.shell(m, cmd, arg...)