mkcert.go 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package main
  2. import (
  3. "crypto/rand"
  4. "crypto/rsa"
  5. "crypto/sha1"
  6. "crypto/x509"
  7. "crypto/x509/pkix"
  8. "encoding/asn1"
  9. "encoding/pem"
  10. "math/big"
  11. "os"
  12. "path/filepath"
  13. "testing"
  14. "time"
  15. "github.com/sagernet/sing/common/rw"
  16. "github.com/stretchr/testify/require"
  17. )
  18. func createSelfSignedCertificate(t *testing.T, domain string) (caPem, certPem, keyPem string) {
  19. const userAndHostname = "[email protected]"
  20. tempDir, err := os.MkdirTemp("", "sing-box-test")
  21. require.NoError(t, err)
  22. t.Cleanup(func() {
  23. os.RemoveAll(tempDir)
  24. })
  25. caKey, err := rsa.GenerateKey(rand.Reader, 3072)
  26. require.NoError(t, err)
  27. spkiASN1, err := x509.MarshalPKIXPublicKey(caKey.Public())
  28. var spki struct {
  29. Algorithm pkix.AlgorithmIdentifier
  30. SubjectPublicKey asn1.BitString
  31. }
  32. _, err = asn1.Unmarshal(spkiASN1, &spki)
  33. require.NoError(t, err)
  34. skid := sha1.Sum(spki.SubjectPublicKey.Bytes)
  35. caTpl := &x509.Certificate{
  36. SerialNumber: randomSerialNumber(t),
  37. Subject: pkix.Name{
  38. Organization: []string{"sing-box test CA"},
  39. OrganizationalUnit: []string{userAndHostname},
  40. CommonName: "sing-box " + userAndHostname,
  41. },
  42. SubjectKeyId: skid[:],
  43. NotAfter: time.Now().AddDate(10, 0, 0),
  44. NotBefore: time.Now(),
  45. KeyUsage: x509.KeyUsageCertSign,
  46. BasicConstraintsValid: true,
  47. IsCA: true,
  48. MaxPathLenZero: true,
  49. }
  50. caCert, err := x509.CreateCertificate(rand.Reader, caTpl, caTpl, caKey.Public(), caKey)
  51. require.NoError(t, err)
  52. err = rw.WriteFile(filepath.Join(tempDir, "ca.pem"), pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caCert}))
  53. require.NoError(t, err)
  54. key, err := rsa.GenerateKey(rand.Reader, 2048)
  55. domainTpl := &x509.Certificate{
  56. SerialNumber: randomSerialNumber(t),
  57. Subject: pkix.Name{
  58. Organization: []string{"sing-box test certificate"},
  59. OrganizationalUnit: []string{"sing-box " + userAndHostname},
  60. },
  61. NotBefore: time.Now(), NotAfter: time.Now().AddDate(0, 0, 30),
  62. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
  63. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  64. }
  65. domainTpl.DNSNames = append(domainTpl.DNSNames, domain)
  66. cert, err := x509.CreateCertificate(rand.Reader, domainTpl, caTpl, key.Public(), caKey)
  67. require.NoError(t, err)
  68. certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert})
  69. privDER, err := x509.MarshalPKCS8PrivateKey(key)
  70. require.NoError(t, err)
  71. privPEM := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privDER})
  72. err = rw.WriteFile(filepath.Join(tempDir, domain+".pem"), certPEM)
  73. require.NoError(t, err)
  74. err = rw.WriteFile(filepath.Join(tempDir, domain+".key.pem"), privPEM)
  75. require.NoError(t, err)
  76. return filepath.Join(tempDir, "ca.pem"), filepath.Join(tempDir, domain+".pem"), filepath.Join(tempDir, domain+".key.pem")
  77. }
  78. func randomSerialNumber(t *testing.T) *big.Int {
  79. serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
  80. serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
  81. require.NoError(t, err)
  82. return serialNumber
  83. }