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 }