mirror of
https://github.com/MengMengCode/VoCat.git
synced 2026-08-20 14:53:42 +08:00
Merge branch 'master' of https://github.com/MengMengCode/VoCat
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICSTCCAe+gAwIBAgIQbmhWeneg7nyF7hg5Y9+qejAKBggqhkjOPQQDAjBEMRgw
|
||||
FgYDVQQKEw9HU00gQXNzb2NpYXRpb24xKDAmBgNVBAMTH0dTTSBBc3NvY2lhdGlv
|
||||
biAtIFJTUDIgUm9vdCBDSTEwIBcNMTcwMjIyMDAwMDAwWhgPMjA1MjAyMjEyMzU5
|
||||
NTlaMEQxGDAWBgNVBAoTD0dTTSBBc3NvY2lhdGlvbjEoMCYGA1UEAxMfR1NNIEFz
|
||||
c29jaWF0aW9uIC0gUlNQMiBSb290IENJMTBZMBMGByqGSM49AgEGCCqGSM49AwEH
|
||||
A0IABJ1qutL0HCMX52GJ6/jeibsAqZfULWj/X10p/Min6seZN+hf5llovbCNuB2n
|
||||
unLz+O8UD0SUCBUVo8e6n9X1TuajgcAwgb0wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wEwYDVR0RBAwwCogIKwYBBAGC6WAwFwYDVR0gAQH/BA0wCzAJ
|
||||
BgdngRIBAgEAME0GA1UdHwRGMEQwQqBAoD6GPGh0dHA6Ly9nc21hLWNybC5zeW1h
|
||||
dXRoLmNvbS9vZmZsaW5lY2EvZ3NtYS1yc3AyLXJvb3QtY2kxLmNybDAdBgNVHQ4E
|
||||
FgQUgTcPUSXQsdQI1MOyMubSXnlb6/swCgYIKoZIzj0EAwIDSAAwRQIgIJdYsOMF
|
||||
WziPK7l8nh5mu0qiRiVf25oa9ullG/OIASwCIQDqCmDrYf+GziHXBOiwJwnBaeBO
|
||||
aFsiLzIEOaUuZwdNUw==
|
||||
-----END CERTIFICATE-----
|
||||
+32
-1
@@ -3,6 +3,7 @@ package device
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -14,9 +15,24 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"vocat/internal/netguard"
|
||||
)
|
||||
|
||||
// GSM Association RSP2 Root CI1; SHA-256 fingerprint:
|
||||
// 5E:3E:91:FD:45:43:27:C3:AF:5D:32:A7:A7:3B:BC:59:FE:43:AA:7D:85:FD:32:D5:DB:44:42:3F:80:A5:6B:B3.
|
||||
//
|
||||
//go:embed certs/gsma-rsp2-root-ci1.pem
|
||||
var gsmaRSP2RootCI1PEM []byte
|
||||
|
||||
var gsmaRSP2RootCI1SHA256 = [32]byte{
|
||||
0x5e, 0x3e, 0x91, 0xfd, 0x45, 0x43, 0x27, 0xc3,
|
||||
0xaf, 0x5d, 0x32, 0xa7, 0xa7, 0x3b, 0xbc, 0x59,
|
||||
0xfe, 0x43, 0xaa, 0x7d, 0x85, 0xfd, 0x32, 0xd5,
|
||||
0xdb, 0x44, 0x42, 0x3f, 0x80, 0xa5, 0x6b, 0xb3,
|
||||
}
|
||||
|
||||
// es9pClient speaks SGP.22 ES9+ — JSON over HTTPS — to one SM-DP+. It is the
|
||||
// network half of the LPA download flow: the host authenticates nothing itself
|
||||
// (the eUICC does all certificate verification on-card); it only shuttles the
|
||||
@@ -50,13 +66,28 @@ func newES9PClient(ctx context.Context, smdp string) (*es9pClient, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("esim: unsafe SM-DP+ address: %w", err)
|
||||
}
|
||||
roots, err := es9pRootCAs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &es9pClient{
|
||||
smdp: validated.Host,
|
||||
endpoint: validated,
|
||||
http: netguard.NewPublicHTTPClient(90*time.Second, true),
|
||||
http: netguard.NewPublicHTTPClientWithRootCAs(90*time.Second, true, roots),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func es9pRootCAs() (*x509.CertPool, error) {
|
||||
roots, err := x509.SystemCertPool()
|
||||
if err != nil || roots == nil {
|
||||
roots = x509.NewCertPool()
|
||||
}
|
||||
if !roots.AppendCertsFromPEM(gsmaRSP2RootCI1PEM) {
|
||||
return nil, errors.New("esim: load GSMA RSP2 Root CI1 certificate")
|
||||
}
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
// es9pError is a failed ES9+ functionExecutionStatus. Message is the SM-DP+'s
|
||||
// own explanation (surfaced verbatim, as the reference implementation does).
|
||||
type es9pError struct {
|
||||
|
||||
@@ -3,8 +3,11 @@ package device
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
@@ -12,6 +15,30 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestES9PRootCAsIncludeGSMARSP2RootCI1(t *testing.T) {
|
||||
roots, err := es9pRootCAs()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block, _ := pem.Decode(gsmaRSP2RootCI1PEM)
|
||||
if block == nil {
|
||||
t.Fatal("GSMA Root CI1 PEM did not decode")
|
||||
}
|
||||
certificate, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if actual := sha256.Sum256(certificate.Raw); actual != gsmaRSP2RootCI1SHA256 {
|
||||
t.Fatalf("GSMA root SHA-256 = %X, want %X", actual, gsmaRSP2RootCI1SHA256)
|
||||
}
|
||||
if certificate.Subject.CommonName != "GSM Association - RSP2 Root CI1" || !certificate.IsCA {
|
||||
t.Fatalf("unexpected GSMA root certificate: subject=%q ca=%v", certificate.Subject.CommonName, certificate.IsCA)
|
||||
}
|
||||
if _, err := certificate.Verify(x509.VerifyOptions{Roots: roots}); err != nil {
|
||||
t.Fatalf("GSMA root is not trusted by the ES9+ pool: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// newTestES9P routes an es9pClient at a throwaway TLS server.
|
||||
func newTestES9P(t *testing.T, handler http.HandlerFunc) *es9pClient {
|
||||
t.Helper()
|
||||
|
||||
@@ -3,6 +3,7 @@ package netguard
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
@@ -48,6 +49,13 @@ func ValidatePublicURL(ctx context.Context, raw string, requireHTTPS bool) (*url
|
||||
// rejects private/special-use destinations at dial time, and validates every
|
||||
// redirect before following it.
|
||||
func NewPublicHTTPClient(timeout time.Duration, requireHTTPS bool) *http.Client {
|
||||
return NewPublicHTTPClientWithRootCAs(timeout, requireHTTPS, nil)
|
||||
}
|
||||
|
||||
// NewPublicHTTPClientWithRootCAs creates the same guarded client while using
|
||||
// the supplied trust pool for protocols whose standards define additional
|
||||
// public roots beyond the host operating system's CA bundle.
|
||||
func NewPublicHTTPClientWithRootCAs(timeout time.Duration, requireHTTPS bool, roots *x509.CertPool) *http.Client {
|
||||
if timeout <= 0 {
|
||||
timeout = 30 * time.Second
|
||||
}
|
||||
@@ -60,6 +68,7 @@ func NewPublicHTTPClient(timeout time.Duration, requireHTTPS bool) *http.Client
|
||||
ExpectContinueTimeout: time.Second,
|
||||
TLSClientConfig: &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
RootCAs: roots,
|
||||
},
|
||||
}
|
||||
return &http.Client{
|
||||
|
||||
Reference in New Issue
Block a user