package main import ( "crypto/rand" "crypto/rsa" "crypto/sha1" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/pem" "math/big" "os" "path/filepath" "testing" "time" "github.com/sagernet/sing/common/rw" "github.com/stretchr/testify/require" ) func createSelfSignedCertificate(t *testing.T, domain string) (caPem, certPem, keyPem string) { const userAndHostname = "sekai@nekohasekai.local" tempDir, err := os.MkdirTemp("", "sing-box-test") require.NoError(t, err) t.Cleanup(func() { os.RemoveAll(tempDir) }) caKey, err := rsa.GenerateKey(rand.Reader, 3072) require.NoError(t, err) spkiASN1, err := x509.MarshalPKIXPublicKey(caKey.Public()) var spki struct { Algorithm pkix.AlgorithmIdentifier SubjectPublicKey asn1.BitString } _, err = asn1.Unmarshal(spkiASN1, &spki) require.NoError(t, err) skid := sha1.Sum(spki.SubjectPublicKey.Bytes) caTpl := &x509.Certificate{ SerialNumber: randomSerialNumber(t), Subject: pkix.Name{ Organization: []string{"sing-box test CA"}, OrganizationalUnit: []string{userAndHostname}, CommonName: "sing-box " + userAndHostname, }, SubjectKeyId: skid[:], NotAfter: time.Now().AddDate(10, 0, 0), NotBefore: time.Now(), KeyUsage: x509.KeyUsageCertSign, BasicConstraintsValid: true, IsCA: true, MaxPathLenZero: true, } caCert, err := x509.CreateCertificate(rand.Reader, caTpl, caTpl, caKey.Public(), caKey) require.NoError(t, err) err = rw.WriteFile(filepath.Join(tempDir, "ca.pem"), pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caCert})) require.NoError(t, err) key, err := rsa.GenerateKey(rand.Reader, 2048) domainTpl := &x509.Certificate{ SerialNumber: randomSerialNumber(t), Subject: pkix.Name{ Organization: []string{"sing-box test certificate"}, OrganizationalUnit: []string{"sing-box " + userAndHostname}, }, NotBefore: time.Now(), NotAfter: time.Now().AddDate(0, 0, 30), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, } domainTpl.DNSNames = append(domainTpl.DNSNames, domain) cert, err := x509.CreateCertificate(rand.Reader, domainTpl, caTpl, key.Public(), caKey) require.NoError(t, err) certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert}) privDER, err := x509.MarshalPKCS8PrivateKey(key) require.NoError(t, err) privPEM := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privDER}) err = rw.WriteFile(filepath.Join(tempDir, domain+".pem"), certPEM) require.NoError(t, err) err = rw.WriteFile(filepath.Join(tempDir, domain+".key.pem"), privPEM) require.NoError(t, err) return filepath.Join(tempDir, "ca.pem"), filepath.Join(tempDir, domain+".pem"), filepath.Join(tempDir, domain+".key.pem") } func randomSerialNumber(t *testing.T) *big.Int { serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) require.NoError(t, err) return serialNumber }