303 lines
11 KiB
Go
303 lines
11 KiB
Go
package utils
|
|
|
|
import (
|
|
"b612.me/starcrypto"
|
|
"crypto"
|
|
"crypto/ecdh"
|
|
"crypto/ed25519"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type GenerateCertParams struct {
|
|
Country string `json:"country"`
|
|
Province string `json:"province"`
|
|
City string `json:"city"`
|
|
Organization string `json:"organization"`
|
|
OrganizationUnit string `json:"organization_unit"`
|
|
CommonName string `json:"common_name"`
|
|
Dns []string `json:"dns"`
|
|
KeyUsage int `json:"key_usage"`
|
|
ExtendedKeyUsage []int `json:"extended_key_usage"`
|
|
IsCA bool `json:"is_ca"`
|
|
StartDate time.Time `json:"start_date"`
|
|
EndDate time.Time `json:"end_date"`
|
|
MaxPathLength int `json:"max_path_length"`
|
|
MaxPathLengthZero bool `json:"max_path_length_zero"`
|
|
Type string `json:"type"` // e.g., "x509", "ssh"
|
|
Bits int `json:"bits"` // e.g., 2048, 4096
|
|
CA *x509.Certificate
|
|
CAPriv any // private key for CA, if nil, use the generated key
|
|
}
|
|
|
|
func GenerateKeys(types string, bits int) (crypto.PublicKey, any, error) {
|
|
|
|
var priv any
|
|
var pub crypto.PublicKey
|
|
var err error
|
|
switch strings.ToLower(types) {
|
|
case "rsa":
|
|
priv, pub, err = starcrypto.GenerateRsaKey(bits)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
case "ecdsa":
|
|
var cr elliptic.Curve
|
|
switch bits {
|
|
case 224:
|
|
cr = elliptic.P224()
|
|
case 256:
|
|
cr = elliptic.P256()
|
|
case 384:
|
|
cr = elliptic.P384()
|
|
case 521:
|
|
cr = elliptic.P521()
|
|
default:
|
|
return nil, nil, errors.New("invalid bits,should be 224,256,384,521")
|
|
}
|
|
priv, pub, err = starcrypto.GenerateEcdsaKey(cr)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
case "ed25519":
|
|
pub, priv, err = ed25519.GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
case "x25519":
|
|
priv, err = ecdh.X25519().GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
pub = priv.(*ecdh.PrivateKey).Public()
|
|
case "ecdh":
|
|
switch bits {
|
|
case 256:
|
|
priv, err = ecdh.P256().GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
pub = priv.(*ecdh.PrivateKey).Public()
|
|
case 384:
|
|
priv, err = ecdh.P384().GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
pub = priv.(*ecdh.PrivateKey).Public()
|
|
case 521:
|
|
priv, err = ecdh.P521().GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
pub = priv.(*ecdh.PrivateKey).Public()
|
|
}
|
|
default:
|
|
return nil, nil, errors.New("invalid key type,only support rsa,ecdsa")
|
|
}
|
|
return pub, priv, nil
|
|
}
|
|
|
|
func getSlice(val string) []string {
|
|
if val == "" {
|
|
return nil
|
|
}
|
|
return []string{val}
|
|
}
|
|
|
|
func GenerateCert(params GenerateCertParams) ([]byte, []byte, error) {
|
|
var needAppendCa bool = true
|
|
pub, priv, err := GenerateKeys(params.Type, params.Bits)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
var extKeyUsage []x509.ExtKeyUsage = nil
|
|
for _, usage := range params.ExtendedKeyUsage {
|
|
if extKeyUsage == nil {
|
|
extKeyUsage = make([]x509.ExtKeyUsage, 0, len(params.ExtendedKeyUsage))
|
|
}
|
|
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsage(usage))
|
|
}
|
|
var trueDNS []string
|
|
var trueIp []net.IP
|
|
for _, v := range params.Dns {
|
|
ip := net.ParseIP(v)
|
|
if ip == nil {
|
|
trueDNS = append(trueDNS, v)
|
|
continue
|
|
}
|
|
trueIp = append(trueIp, ip)
|
|
}
|
|
cert := &x509.Certificate{
|
|
Version: 3,
|
|
SerialNumber: big.NewInt(time.Now().Unix()),
|
|
Subject: pkix.Name{
|
|
Country: getSlice(params.Country),
|
|
Province: getSlice(params.Province),
|
|
Locality: getSlice(params.City),
|
|
Organization: getSlice(params.Organization),
|
|
OrganizationalUnit: getSlice(params.OrganizationUnit),
|
|
CommonName: params.CommonName,
|
|
},
|
|
NotBefore: params.StartDate,
|
|
NotAfter: params.EndDate,
|
|
BasicConstraintsValid: true,
|
|
IsCA: params.IsCA,
|
|
MaxPathLenZero: params.MaxPathLengthZero,
|
|
ExtKeyUsage: extKeyUsage,
|
|
KeyUsage: x509.KeyUsage(params.KeyUsage),
|
|
MaxPathLen: params.MaxPathLength,
|
|
DNSNames: trueDNS,
|
|
IPAddresses: trueIp,
|
|
}
|
|
if params.CA == nil {
|
|
params.CA = cert
|
|
needAppendCa = false
|
|
}
|
|
if params.CAPriv == nil {
|
|
params.CAPriv = priv
|
|
}
|
|
certs, err := x509.CreateCertificate(rand.Reader, cert, params.CA, pub, params.CAPriv)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
certBlock := &pem.Block{
|
|
Type: "CERTIFICATE",
|
|
Bytes: certs,
|
|
}
|
|
pemData := pem.EncodeToMemory(certBlock)
|
|
privData, err := starcrypto.EncodePrivateKey(priv, "")
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if needAppendCa {
|
|
pemData = append(pemData, []byte("\n")...)
|
|
certBlock = &pem.Block{
|
|
Type: "CERTIFICATE",
|
|
Bytes: params.CA.Raw,
|
|
}
|
|
pemData = append(pemData, pem.EncodeToMemory(certBlock)...)
|
|
}
|
|
return pemData, privData, nil
|
|
}
|
|
|
|
func GenerateTlsCert(params GenerateCertParams) (tls.Certificate, error) {
|
|
certPem, privPem, err := GenerateCert(params)
|
|
if err != nil {
|
|
return tls.Certificate{}, err
|
|
}
|
|
return tls.X509KeyPair(certPem, privPem)
|
|
}
|
|
|
|
func ToolCert() (*x509.Certificate, any) {
|
|
certPem := `-----BEGIN CERTIFICATE-----
|
|
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
|
|
EdAtgNNfLagVhHl7yF8TGiLUPgszinPBDd0=
|
|
-----END CERTIFICATE-----`
|
|
privPem := `-----BEGIN RSA PRIVATE KEY-----
|
|
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
|
|
-----END RSA PRIVATE KEY-----`
|
|
block, _ := pem.Decode([]byte(certPem))
|
|
if block == nil || block.Type != "CERTIFICATE" {
|
|
return nil, nil
|
|
}
|
|
cert, err := x509.ParseCertificate(block.Bytes)
|
|
if err != nil {
|
|
return nil, nil
|
|
}
|
|
priv, err := starcrypto.DecodePrivateKey([]byte(privPem), "")
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return nil, nil
|
|
}
|
|
return cert, priv
|
|
}
|