Skip to content

Commit

Permalink
fix(ca): repair to Mozilla CA (#147)
Browse files Browse the repository at this point in the history
Co-authored-by: dyhkwong <50692134+dyhkwong@users.noreply.github.com>
(cherry picked from commit efd0d03)
Signed-off-by: HystericalDragon <HystericalDragons@proton.me>
  • Loading branch information
xchacha20-poly1305 and dyhkwong committed Jul 29, 2024
1 parent eae969f commit f5f9bd4
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 19 deletions.
7 changes: 4 additions & 3 deletions app/src/main/java/io/nekohasekai/sagernet/SagerNet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class SagerNet : Application(),
Seq.setContext(this)
updateNotificationChannels()

// nb4a: init core
// init core
externalAssets.mkdirs()
Libcore.initCore(
process,
Expand All @@ -77,9 +77,10 @@ class SagerNet : Application(),
externalAssets.absolutePath + "/",
DataStore.logBufSize,
DataStore.logLevel > 0,
nativeInterface, nativeInterface,
DataStore.enabledCazilla
nativeInterface,
nativeInterface,
)
Libcore.updateRootCACerts(DataStore.enabledCazilla)

if (isMainProcess) {
Theme.apply(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.nekohasekai.sagernet.bg.proto
import android.util.Log
import io.nekohasekai.sagernet.BuildConfig
import io.nekohasekai.sagernet.bg.GuardedProcessPool
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.ProxyEntity
import io.nekohasekai.sagernet.fmt.buildConfig
import io.nekohasekai.sagernet.ktx.Logs
Expand Down Expand Up @@ -31,6 +32,7 @@ class TestInstance(profile: ProxyEntity, val link: String, private val timeout:
// wait for plugin start
delay(500)
}
Libcore.updateRootCACerts(DataStore.enabledCazilla)
c.tryResume(box.urlTest(link, timeout))
} catch (e: Exception) {
c.tryResumeWithException(e)
Expand Down
28 changes: 28 additions & 0 deletions libcore/ca.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDAEL1EAvGu/IAg
gR1cIZ6QVOpgALx1nUd3ReBdFqyB984NuhZBLBM5uR9Yf2L77ktXfxR+rHLMF4Fy
n5J8YCRRwGyZ6gEekIure1rRCff3hf0RFYolgllDFuQwMnav9B1PfrTo6NK4eK6R
VW9UaHnCvF6nx5ITyjGiOtpVeyfKdXdrtBiCuW1LgYq1EAzsYD0FKSq+68WotPWM
eUOkvzbAH4+g8jWGMql6CJo4KHCNdJb3Sh8Rpc9osbj8dqLIctZHWtORLgc9TF4m
loZrOUQGC+/ILSgaKuW3lrRfA5wbHbtjEQ8EhLQ5hiUM0XGs0j5tJ5lcgle0WKaa
EyyA0JJhAgMBAAECggEABUxw7D9oi3tLzZnCRZhn13OAQ8XBbT05i4DR/79wYuWD
Ob24f3PH0//XbYmWIX0hdvh6iEQZpqe/WnosgGHmnprAZD6gaUdzkveEOeAchyeb
I62EciR2cfNfuDSsMY56gIbuVr6VkaFCr5+7wohfU4/+zIIk9YbOd7tH6rPLFTq8
Du0zhkvJZnHFRthZJtOuOUIYYkVyYuzC1V3dh3LWCQAiX9IGTcl7qyIWmR50FqTy
G6XFnANJulNfNn7+gOCyHn1shA05koAfGdFVco7pceoLVVm1weVvd4+xRtNKlGY4
X1DQ+soQpRxDkuuNc/hx7XV2JLqUm3sE2RiL8Ci7AQKBgQDFJbLYKiu1JdZdixVJ
pVEgEU4wMOq+7taW4Gurf+HMohoNLl/6uMvWaUx2rrUCVoIStGJ4t8r/dlUKEoEK
/jkY0otru/xDJXxBdixd2XI69bzG6E5oVILod3qJUo1bBoYwAIz3m+oMq1/sepbS
OwXEup8PGpAtGvoEHlcCGC6frQKBgQD5Zq0UznTXjEyhv9aD9fM2Tm4Au57zarKC
nlx58LT99qJ7qFHtzW6MLoD9s8emIUddqgBkZjAWg8OLiMwbNNEadN/4nXGJOrAr
I+SZSu4dVguVtBycJXzAge2bZm9CQcnXoKYILCM67bzHaZLsieJLjT1E2aGNbBzj
mY4kpSPEBQKBgEsoC/4MVY1BV29hzkO9Gig3cK8+dr9DHdt2wpUms1XnljbgLwbN
3CdpDRVRlP/HKt8mlUOgDWtGGTU1yKwALpQf77aqe4i9iZkLC+7bLoj7lXPeq8Vq
Ml2c7sHbDrhczFsQWq0qaxdZXcAxG74ZciGFY43GeqA3YIihaFoMDfohAoGANdMz
B4qHLP3ajA4a/d/W3aGPnBjh9SbR397NloOcjDLuXkG1bN0pPpfKvvZN4EzOWiiW
bRSgzDsjuLmNU1HSzyLqM33HQxanbqgQbgT93tbzKRv2EL0Gb4WbAi7ZVDNenGrP
anQcJluoomDmlKYtcKDK2FEfzKXIllZNlxsM3QECgYBJ6/9esr0cmP8jzyh1OvKF
cW9NqA1Ifwanjapy6hlGu6TVFvvOTXsIPRgpRIECNyr3470kKNNzn/h5ojFaEScE
lAVuGaApa25cWq3Fogb4I/rexV7TGKKI8FPjZlKjLe9ea1crdetQtL0mOnQR9jIQ
YXNK6VotYlcuNt85m8vV+A==
-----END PRIVATE KEY-----
18 changes: 18 additions & 0 deletions libcore/ca.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC+TCCAeGgAwIBAgIQC8avJKUFemltDXLL6qouGjANBgkqhkiG9w0BAQsFADAS
MRAwDgYDVQQDEwdodXNpLmZyMCAXDTI0MDcyNzIyMTk0OVoYDzI4NTcxMDI3MjMx
OTQ4WjASMRAwDgYDVQQDEwdodXNpLmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAwBC9RALxrvyAIIEdXCGekFTqYAC8dZ1Hd0XgXRasgffODboWQSwT
ObkfWH9i++5LV38UfqxyzBeBcp+SfGAkUcBsmeoBHpCLq3ta0Qn394X9ERWKJYJZ
QxbkMDJ2r/QdT3606OjSuHiukVVvVGh5wrxep8eSE8oxojraVXsnynV3a7QYgrlt
S4GKtRAM7GA9BSkqvuvFqLT1jHlDpL82wB+PoPI1hjKpegiaOChwjXSW90ofEaXP
aLG4/HaiyHLWR1rTkS4HPUxeJpaGazlEBgvvyC0oGirlt5a0XwOcGx27YxEPBIS0
OYYlDNFxrNI+bSeZXIJXtFimmhMsgNCSYQIDAQABo0kwRzAOBgNVHQ8BAf8EBAMC
BaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADASBgNVHREECzAJ
ggdodXNpLmZyMA0GCSqGSIb3DQEBCwUAA4IBAQCwhr2Du+qNSdFVblBpbnxhFEWf
ozrR/YJrcek9sQsPwg6tVd8C5a8sttjNV620U7ql7q4Rj5fSkayIH8rPTK6Met+l
+xsbQqn/PihRFuKjdmK3rb1zuM6rmRliViCi/aj4MYPX5L+CKEO1wv3/YMv241ps
Dpu++/NQj3DPvktpWAMkuYwGQgWBw+hGHa4XKLv1EJv4oNd9mSskhR71KoQFxsoL
5qrP9lKcLQj3rQ527FvfdS5JYFQGHwIu+IwGw4QeXLqHjPVmf40TyrE8ITmTvvSt
U6ltmvaq8C2ROxTohQPjohI7ktqPImAwIhhfzWfedleEVBtX7t98aal2YFEn
-----END CERTIFICATE-----
91 changes: 91 additions & 0 deletions libcore/cert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package libcore

import (
"crypto/tls"
"net"
"testing"

"github.com/sagernet/sing/common"
N "github.com/sagernet/sing/common/network"
)

func TestUpdateRootCACerts(t *testing.T) {
const (
chinaRailway = "www.12306.cn" // Use CA from China
trustAsiaAddress = chinaRailway + ":443"

husi = "husi.fr"
)
listener := common.Must1(net.Listen(N.NetworkTCP, "127.0.0.1:0"))
defer listener.Close()
listen := listener.Addr().String()

done := make(chan struct{})
go func(listener net.Listener, done chan struct{}) {
cert := common.Must1(tls.LoadX509KeyPair("ca.pem", "ca.key"))
config := &tls.Config{
Certificates: []tls.Certificate{cert},
ServerName: husi,
}
done <- struct{}{}
go func(listener net.Listener, done chan struct{}) {
<-done
_ = listener.Close()
}(listener, done)
for {
select {
case <-done:
return
default:
}
conn, err := listener.Accept()
if err != nil {
return
}
go func(config *tls.Config, conn net.Conn) {
defer conn.Close()
tlsConn := tls.Server(conn, config)
err := tlsConn.Handshake()
if err != nil {
return
}
defer tlsConn.Close()
// Write something to prevent client EOF
_, _ = tlsConn.Write([]byte("hello"))
}(config, conn)
}
}(listener, done)
<-done
defer close(done)

testConnect := func(serverName, address string, wantErr bool, testName string) {
config := &tls.Config{
ServerName: serverName,
}
conn, err := tls.Dial(N.NetworkTCP, address, config)
if err == nil {
_ = conn.Close()
if wantErr {
t.Errorf("[%s] wants error but not", testName)
}
} else {
if !wantErr {
t.Errorf("[%s] got unexpected error: %v", testName, err)
}
}
}

// normal
testConnect(chinaRailway, trustAsiaAddress, false, "normal 12306")
testConnect(husi, listen, true, "normal local")

// Load local cert and Mozilla CA
UpdateRootCACerts(true)
testConnect(chinaRailway, trustAsiaAddress, true, "mozilla 12306")
testConnect(husi, listen, false, "loaded custom")

// Set back but load local
UpdateRootCACerts(false)
testConnect(chinaRailway, trustAsiaAddress, false, "normal 12306 2")
testConnect(husi, listen, false, "loaded custom 2")
}
33 changes: 22 additions & 11 deletions libcore/certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"crypto/x509"
"encoding/pem"
"os"
"path/filepath"
"strings"
_ "unsafe" // for go:linkname

Expand All @@ -19,24 +21,33 @@ import (
//go:linkname systemRoots crypto/x509.systemRoots
var systemRoots *x509.CertPool

func updateRootCACerts(pem []byte, enabledCazilla bool) {
roots := func(useMozilla bool) *x509.CertPool {
if useMozilla {
log.Info("Using cazilla.")
return cazilla.CA
}
// UpdateRootCACerts appends externalAssetsPath/ca.pem to root CA.
// By the way, if enabledCazilla == true, it will use the CA trusted by mozilla.
func UpdateRootCACerts(enabledCazilla bool) {
systemRoots = nil // Clean up old
// https://github.com/golang/go/blob/30b6fd60a63c738c2736e83b6a6886a032e6f269/src/crypto/x509/root.go#L31
// Make sure initialize system cert pool.
// If system cert has not been initialized,
// other place, where using x509.SystemCertPool(), will initialize systemRoots and override out hook.
sysRoots, _ := x509.SystemCertPool()

p, _ := x509.SystemCertPool()
return p
}(enabledCazilla)
var roots *x509.CertPool
if enabledCazilla {
roots = x509.NewCertPool()
_ = roots.AppendCertsFromPEM(cazilla.MozillaIncludedCAPEM) // Must
} else {
roots = sysRoots
}

if len(pem) > 0 {
if roots.AppendCertsFromPEM(pem) {
externalPem, _ := os.ReadFile(filepath.Join(externalAssetsPath, "ca.pem"))
if len(externalPem) > 0 {
if roots.AppendCertsFromPEM(externalPem) {
log.Info("external ca.pem was loaded")
} else {
log.Warn("failed to append certificates from pem")
}
}

systemRoots = roots
}

Expand Down
5 changes: 0 additions & 5 deletions libcore/libcore.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ func NewSocksInfo(port, username, password string) *SocksInfo {
func InitCore(process, cachePath, internalAssets, externalAssets string,
maxLogSizeKb int32, logEnable bool,
if1 GUIInterface, if2 BoxPlatformInterface,
enabledCazilla bool,
) {
defer catchPanic("InitCore", func(panicErr error) { log.Println(panicErr) })
isBgProcess := strings.HasSuffix(process, ":bg")
Expand All @@ -66,10 +65,6 @@ func InitCore(process, cachePath, internalAssets, externalAssets string,
externalAssetsPath = externalAssets
internalAssetsPath = internalAssets

// certs
pem, _ := os.ReadFile(externalAssetsPath + "ca.pem")
updateRootCACerts(pem, enabledCazilla)

// bg
if isBgProcess {
extractAssets()
Expand Down

0 comments on commit f5f9bd4

Please sign in to comment.