- Added steps in both Linux and macOS workflows to inject commercial license root certificates from GitHub Secrets during the build process. - Updated the `inspect` and `load` packages to include license information, enhancing the application's licensing capabilities. - Included license metadata in the OpenAPI response for better visibility of licensing status.
177 lines
4.8 KiB
Go
177 lines
4.8 KiB
Go
package commercial
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"math/big"
|
|
"time"
|
|
)
|
|
|
|
// testCA holds a generated CA certificate and its private key.
|
|
type testCA struct {
|
|
Cert *x509.Certificate
|
|
Key *ecdsa.PrivateKey
|
|
CertPEM []byte
|
|
}
|
|
|
|
// testLicenseCert holds a generated leaf (license) certificate.
|
|
type testLicenseCert struct {
|
|
Cert *x509.Certificate
|
|
CertPEM []byte
|
|
}
|
|
|
|
// generateRootCA creates a self-signed ECDSA P-384 root CA for testing.
|
|
func generateRootCA(cn string, validity time.Duration) (*testCA, error) {
|
|
key, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
serial, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
|
|
tmpl := &x509.Certificate{
|
|
SerialNumber: serial,
|
|
Subject: pkix.Name{
|
|
CommonName: cn,
|
|
Organization: []string{"Infinite Wisdom Software"},
|
|
Country: []string{"CN"},
|
|
},
|
|
NotBefore: time.Now().Add(-1 * time.Hour),
|
|
NotAfter: time.Now().Add(validity),
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
|
BasicConstraintsValid: true,
|
|
IsCA: true,
|
|
MaxPathLen: 1,
|
|
}
|
|
|
|
certDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cert, err := x509.ParseCertificate(certDER)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
|
|
return &testCA{Cert: cert, Key: key, CertPEM: certPEM}, nil
|
|
}
|
|
|
|
// generateIntermediateCA creates an intermediate CA signed by the given parent.
|
|
func generateIntermediateCA(cn string, validity time.Duration, parent *testCA) (*testCA, error) {
|
|
key, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
serial, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
|
|
tmpl := &x509.Certificate{
|
|
SerialNumber: serial,
|
|
Subject: pkix.Name{
|
|
CommonName: cn,
|
|
Organization: []string{"Test Partner Inc."},
|
|
Country: []string{"US"},
|
|
},
|
|
NotBefore: time.Now().Add(-1 * time.Hour),
|
|
NotAfter: time.Now().Add(validity),
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
|
BasicConstraintsValid: true,
|
|
IsCA: true,
|
|
MaxPathLen: 0,
|
|
MaxPathLenZero: true,
|
|
}
|
|
|
|
certDER, err := x509.CreateCertificate(rand.Reader, tmpl, parent.Cert, &key.PublicKey, parent.Key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cert, err := x509.ParseCertificate(certDER)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
|
|
return &testCA{Cert: cert, Key: key, CertPEM: certPEM}, nil
|
|
}
|
|
|
|
// licenseOpts configures a test license certificate.
|
|
type licenseOpts struct {
|
|
CN string
|
|
Org string
|
|
Country string
|
|
Email string
|
|
NotBefore time.Time
|
|
NotAfter time.Time
|
|
Serial *big.Int
|
|
Extensions []ExtensionValue
|
|
}
|
|
|
|
func defaultLicenseOpts() licenseOpts {
|
|
return licenseOpts{
|
|
CN: "Test Corp",
|
|
Org: "Test Inc.",
|
|
Country: "CN",
|
|
Email: "test@example.com",
|
|
NotBefore: time.Now().Add(-1 * time.Hour),
|
|
NotAfter: time.Now().Add(365 * 24 * time.Hour),
|
|
Serial: big.NewInt(10042),
|
|
Extensions: []ExtensionValue{
|
|
{OID: OIDProduct, Value: "yao"},
|
|
{OID: OIDEdition, Value: "pro"},
|
|
{OID: OIDMaxUsers, Value: "500"},
|
|
{OID: OIDMaxTaiNodes, Value: "10"},
|
|
{OID: OIDMaxAgents, Value: "50"},
|
|
{OID: OIDMaxSandboxes, Value: "20"},
|
|
{OID: OIDMaxAPIRPM, Value: "10000"},
|
|
{OID: OIDMaxStorageGB, Value: "100"},
|
|
{OID: OIDSupportLevel, Value: "priority"},
|
|
},
|
|
}
|
|
}
|
|
|
|
// generateLicenseCert creates a leaf license certificate signed by the given CA.
|
|
func generateLicenseCert(signer *testCA, opts licenseOpts) (*testLicenseCert, error) {
|
|
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tmpl := &x509.Certificate{
|
|
SerialNumber: opts.Serial,
|
|
Subject: pkix.Name{
|
|
CommonName: opts.CN,
|
|
Organization: []string{opts.Org},
|
|
Country: []string{opts.Country},
|
|
},
|
|
EmailAddresses: []string{opts.Email},
|
|
NotBefore: opts.NotBefore,
|
|
NotAfter: opts.NotAfter,
|
|
KeyUsage: x509.KeyUsageDigitalSignature,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
|
}
|
|
|
|
for _, ext := range opts.Extensions {
|
|
tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, pkix.Extension{
|
|
Id: ext.OID,
|
|
Value: []byte(ext.Value),
|
|
})
|
|
}
|
|
|
|
certDER, err := x509.CreateCertificate(rand.Reader, tmpl, signer.Cert, &key.PublicKey, signer.Key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cert, err := x509.ParseCertificate(certDER)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
|
|
return &testLicenseCert{Cert: cert, CertPEM: certPEM}, nil
|
|
}
|