213 lines
6.0 KiB
Go
213 lines
6.0 KiB
Go
package cmd
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"math/big"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/spf13/cobra"
|
|
"gitlink.org.cn/cloudream/jcs-pub/common/pkgs/rpc"
|
|
)
|
|
|
|
func init() {
|
|
certCmd := cobra.Command{
|
|
Use: "cert",
|
|
}
|
|
RootCmd.AddCommand(&certCmd)
|
|
|
|
certRoot := cobra.Command{
|
|
Use: "root [outputDir]",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
certRoot(args[0])
|
|
},
|
|
}
|
|
certCmd.AddCommand(&certRoot)
|
|
|
|
var certFilePath string
|
|
var keyFilePath string
|
|
|
|
certServer := cobra.Command{
|
|
Use: "server [outputDir]",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
certServer(certFilePath, keyFilePath, args[0])
|
|
},
|
|
}
|
|
certServer.Flags().StringVar(&certFilePath, "cert", "", "CA certificate file path")
|
|
certServer.Flags().StringVar(&keyFilePath, "key", "", "CA key file path")
|
|
certCmd.AddCommand(&certServer)
|
|
|
|
certClient := cobra.Command{
|
|
Use: "client [outputDir]",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
certClient(certFilePath, keyFilePath, args[0])
|
|
},
|
|
}
|
|
certClient.Flags().StringVar(&certFilePath, "cert", "", "CA certificate file path")
|
|
certClient.Flags().StringVar(&keyFilePath, "key", "", "CA key file path")
|
|
certCmd.AddCommand(&certClient)
|
|
}
|
|
|
|
func certRoot(output string) {
|
|
caPriv, _ := rsa.GenerateKey(rand.Reader, 2048)
|
|
|
|
// 创建 CA 证书模板
|
|
caTemplate := &x509.Certificate{
|
|
SerialNumber: big.NewInt(1),
|
|
Subject: pkix.Name{
|
|
Organization: []string{"JCS"},
|
|
},
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().AddDate(10, 0, 0), // 有效期10年
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
|
|
BasicConstraintsValid: true,
|
|
IsCA: true,
|
|
}
|
|
|
|
// 自签名 CA 证书
|
|
caCertDER, _ := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caPriv.PublicKey, caPriv)
|
|
|
|
// 保存 CA 证书和私钥
|
|
writePem(filepath.Join(output, "ca_cert.pem"), "CERTIFICATE", caCertDER)
|
|
writePem(filepath.Join(output, "ca_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(caPriv))
|
|
fmt.Println("CA certificate and key saved to", output)
|
|
}
|
|
|
|
func certServer(certFile string, keyFile string, output string) {
|
|
// 读取 CA 证书和私钥
|
|
caCertPEM, err := os.ReadFile(certFile)
|
|
if err != nil {
|
|
fmt.Println("Failed to read CA certificate:", err)
|
|
return
|
|
}
|
|
caKeyPEM, err := os.ReadFile(keyFile)
|
|
if err != nil {
|
|
fmt.Println("Failed to read CA key:", err)
|
|
return
|
|
}
|
|
caCertPEMBlock, _ := pem.Decode(caCertPEM)
|
|
if caCertPEMBlock == nil {
|
|
fmt.Println("Failed to decode CA certificate")
|
|
return
|
|
}
|
|
caKeyPEMBlock, _ := pem.Decode(caKeyPEM)
|
|
if caKeyPEMBlock == nil {
|
|
fmt.Println("Failed to decode CA key")
|
|
return
|
|
}
|
|
|
|
caCert, err := x509.ParseCertificate(caCertPEMBlock.Bytes)
|
|
if err != nil {
|
|
fmt.Println("Failed to parse CA certificate:", err)
|
|
return
|
|
}
|
|
|
|
caKey, err := x509.ParsePKCS1PrivateKey(caKeyPEMBlock.Bytes)
|
|
if err != nil {
|
|
fmt.Println("Failed to parse CA key:", err)
|
|
return
|
|
}
|
|
|
|
// 生成服务端私钥
|
|
serverPriv, _ := rsa.GenerateKey(rand.Reader, 2048)
|
|
|
|
// 服务端证书模板
|
|
serverTemplate := &x509.Certificate{
|
|
SerialNumber: big.NewInt(2),
|
|
Subject: pkix.Name{
|
|
CommonName: "localhost",
|
|
},
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().AddDate(1, 0, 0), // 有效期1年
|
|
KeyUsage: x509.KeyUsageDigitalSignature,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
BasicConstraintsValid: true,
|
|
}
|
|
|
|
// 添加主机名/IP 到证书
|
|
serverTemplate.DNSNames = []string{rpc.ClientAPISNIV1, rpc.InternalAPISNIV1}
|
|
|
|
// 用 CA 签发服务端证书
|
|
serverCertDER, _ := x509.CreateCertificate(rand.Reader, serverTemplate, caCert, &serverPriv.PublicKey, caKey)
|
|
|
|
// 保存服务端证书和私钥
|
|
writePem(filepath.Join(output, "server_cert.pem"), "CERTIFICATE", serverCertDER)
|
|
writePem(filepath.Join(output, "server_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(serverPriv))
|
|
fmt.Println("Server certificate and key saved to", output)
|
|
}
|
|
|
|
func certClient(certFile string, keyFile string, output string) {
|
|
// 读取 CA 证书和私钥
|
|
caCertPEM, err := os.ReadFile(certFile)
|
|
if err != nil {
|
|
fmt.Println("Failed to read CA certificate:", err)
|
|
return
|
|
}
|
|
caKeyPEM, err := os.ReadFile(keyFile)
|
|
if err != nil {
|
|
fmt.Println("Failed to read CA key:", err)
|
|
return
|
|
}
|
|
caCertPEMBlock, _ := pem.Decode(caCertPEM)
|
|
if caCertPEMBlock == nil {
|
|
fmt.Println("Failed to decode CA certificate")
|
|
return
|
|
}
|
|
caKeyPEMBlock, _ := pem.Decode(caKeyPEM)
|
|
if caKeyPEMBlock == nil {
|
|
fmt.Println("Failed to decode CA key")
|
|
return
|
|
}
|
|
|
|
caCert, err := x509.ParseCertificate(caCertPEMBlock.Bytes)
|
|
if err != nil {
|
|
fmt.Println("Failed to parse CA certificate:", err)
|
|
return
|
|
}
|
|
|
|
caKey, err := x509.ParsePKCS1PrivateKey(caKeyPEMBlock.Bytes)
|
|
if err != nil {
|
|
fmt.Println("Failed to parse CA key:", err)
|
|
return
|
|
}
|
|
|
|
// 生成客户端私钥
|
|
clientPriv, _ := rsa.GenerateKey(rand.Reader, 2048)
|
|
|
|
// 客户端证书模板
|
|
clientTemplate := &x509.Certificate{
|
|
SerialNumber: big.NewInt(3),
|
|
Subject: pkix.Name{
|
|
CommonName: "client",
|
|
},
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().AddDate(1, 0, 0), // 有效期1年
|
|
KeyUsage: x509.KeyUsageDigitalSignature,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
|
BasicConstraintsValid: true,
|
|
}
|
|
|
|
// 用 CA 签发客户端证书
|
|
clientCertDER, _ := x509.CreateCertificate(rand.Reader, clientTemplate, caCert, &clientPriv.PublicKey, caKey)
|
|
|
|
// 保存客户端证书和私钥
|
|
writePem(filepath.Join(output, "client_cert.pem"), "CERTIFICATE", clientCertDER)
|
|
writePem(filepath.Join(output, "client_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(clientPriv))
|
|
fmt.Println("Client certificate and key saved to", output)
|
|
}
|
|
|
|
func writePem(filename, pemType string, bytes []byte) {
|
|
f, _ := os.Create(filename)
|
|
pem.Encode(f, &pem.Block{Type: pemType, Bytes: bytes})
|
|
f.Close()
|
|
}
|