优化结构
This commit is contained in:
@@ -4,10 +4,12 @@ import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"testing"
|
||||
@@ -16,7 +18,8 @@ import (
|
||||
|
||||
func TestValidateAppleJWSChain(t *testing.T) {
|
||||
chain := testAppleCertificateChain(t)
|
||||
if err := validateAppleJWSChain(testAppleJWS(t, "ES256", chain, time.Now())); err != nil {
|
||||
jws := testAppleJWS(t, "ES256", chain, time.Now())
|
||||
if err := validateAppleJWSChainWithRoots(jws, testAppleTrustedRoots(t, chain)); err != nil {
|
||||
t.Fatalf("validateAppleJWSChain() error = %v", err)
|
||||
}
|
||||
}
|
||||
@@ -25,17 +28,30 @@ func TestValidateAppleJWSChainRejectsUnrelatedLeaf(t *testing.T) {
|
||||
chain := testAppleCertificateChain(t)
|
||||
attackerChain := testAppleCertificateChain(t)
|
||||
chain[0] = attackerChain[0]
|
||||
if err := validateAppleJWSChain(testAppleJWS(t, "ES256", chain, time.Now())); err == nil {
|
||||
if err := validateAppleJWSChainWithRoots(testAppleJWS(t, "ES256", chain, time.Now()), testAppleTrustedRoots(t, chain)); err == nil {
|
||||
t.Fatal("validateAppleJWSChain() accepted a leaf outside the declared chain")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAppleJWSChainRejectsInvalidSignature(t *testing.T) {
|
||||
chain := testAppleCertificateChain(t)
|
||||
jws := testAppleJWS(t, "ES256", chain, time.Now())
|
||||
header, payload, _, err := splitAppleJWS(jws)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tampered := header + "." + payload + "." + base64.RawURLEncoding.EncodeToString(make([]byte, 64))
|
||||
if err = validateAppleJWSChainWithRoots(tampered, testAppleTrustedRoots(t, chain)); err == nil {
|
||||
t.Fatal("validateAppleJWSChain accepted an invalid ES256 signature")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAppleJWSChainRejectsUnexpectedAlgorithmAndShape(t *testing.T) {
|
||||
chain := testAppleCertificateChain(t)
|
||||
if err := validateAppleJWSChain(testAppleJWS(t, "ES384", chain, time.Now())); err == nil {
|
||||
if err := validateAppleJWSChainWithRoots(testAppleJWS(t, "ES384", chain, time.Now()), testAppleTrustedRoots(t, chain)); err == nil {
|
||||
t.Fatal("validateAppleJWSChain() accepted a non-ES256 algorithm")
|
||||
}
|
||||
if err := validateAppleJWSChain(testAppleJWS(t, "ES256", chain[:2], time.Now())); err == nil {
|
||||
if err := validateAppleJWSChainWithRoots(testAppleJWS(t, "ES256", chain[:2], time.Now()), nil); err == nil {
|
||||
t.Fatal("validateAppleJWSChain() accepted an incomplete x5c chain")
|
||||
}
|
||||
}
|
||||
@@ -43,14 +59,14 @@ func TestValidateAppleJWSChainRejectsUnexpectedAlgorithmAndShape(t *testing.T) {
|
||||
func TestValidateAppleJWSChainRejectsAdditionalCertificates(t *testing.T) {
|
||||
chain := testAppleCertificateChain(t)
|
||||
chain = append(chain, chain[2])
|
||||
if err := validateAppleJWSChain(testAppleJWS(t, "ES256", chain, time.Now())); err == nil {
|
||||
if err := validateAppleJWSChainWithRoots(testAppleJWS(t, "ES256", chain, time.Now()), testAppleTrustedRoots(t, chain[:3])); err == nil {
|
||||
t.Fatal("validateAppleJWSChain() accepted additional x5c certificates")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAppleJWSChainRejectsNonAppleSigningCertificates(t *testing.T) {
|
||||
chain := testAppleCertificateChainWithoutAppleExtensions(t)
|
||||
if err := validateAppleJWSChain(testAppleJWS(t, "ES256", chain, time.Now())); err == nil {
|
||||
if err := validateAppleJWSChainWithRoots(testAppleJWS(t, "ES256", chain, time.Now()), testAppleTrustedRoots(t, chain)); err == nil {
|
||||
t.Fatal("validateAppleJWSChain() accepted certificates without Apple signing extensions")
|
||||
}
|
||||
}
|
||||
@@ -58,7 +74,7 @@ func TestValidateAppleJWSChainRejectsNonAppleSigningCertificates(t *testing.T) {
|
||||
func TestValidateAppleJWSChainUsesSignedDateForHistoricalPayload(t *testing.T) {
|
||||
signedAt := time.Now().AddDate(-2, 0, 0)
|
||||
chain := testAppleCertificateChainAt(t, signedAt, true)
|
||||
if err := validateAppleJWSChain(testAppleJWS(t, "ES256", chain, signedAt)); err != nil {
|
||||
if err := validateAppleJWSChainWithRoots(testAppleJWS(t, "ES256", chain, signedAt), testAppleTrustedRoots(t, chain)); err != nil {
|
||||
t.Fatalf("validateAppleJWSChain() rejected historical payload: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -78,17 +94,17 @@ func TestValidateAppleJWSChainUsesNestedSignedDateForNotification(t *testing.T)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
outer := base64.RawURLEncoding.EncodeToString(header) + "." + base64.RawURLEncoding.EncodeToString(payload) + ".signature"
|
||||
if err := validateAppleJWSChain(outer); err != nil {
|
||||
outer := testAppleSignedJWS(t, header, payload, chain)
|
||||
if err := validateAppleJWSChainWithRoots(outer, testAppleTrustedRoots(t, chain)); err != nil {
|
||||
t.Fatalf("validateAppleJWSChain() rejected historical notification: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAppleJWSChainAcceptsExpiredChainWithoutSignedDate(t *testing.T) {
|
||||
func TestValidateAppleJWSChainRejectsExpiredChainWithoutSignedDate(t *testing.T) {
|
||||
signedAt := time.Now().AddDate(-2, 0, 0)
|
||||
chain := testAppleCertificateChainAt(t, signedAt, true)
|
||||
if err := validateAppleJWSChain(testAppleJWSWithoutDate(t, chain)); err != nil {
|
||||
t.Fatalf("validateAppleJWSChain() rejected an expired chain without signedDate: %v", err)
|
||||
if err := validateAppleJWSChainWithRoots(testAppleJWSWithoutDate(t, chain), testAppleTrustedRoots(t, chain)); err == nil {
|
||||
t.Fatal("validateAppleJWSChain() accepted an expired chain without signedDate")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +112,7 @@ func TestValidateAppleJWSChainRejectsBrokenChainWithoutSignedDate(t *testing.T)
|
||||
chain := testAppleCertificateChain(t)
|
||||
attackerChain := testAppleCertificateChain(t)
|
||||
chain[0] = attackerChain[0]
|
||||
if err := validateAppleJWSChain(testAppleJWSWithoutDate(t, chain)); err == nil {
|
||||
if err := validateAppleJWSChainWithRoots(testAppleJWSWithoutDate(t, chain), testAppleTrustedRoots(t, chain)); err == nil {
|
||||
t.Fatal("validateAppleJWSChain() accepted a broken chain without signedDate")
|
||||
}
|
||||
}
|
||||
@@ -169,11 +185,13 @@ func testAppleCertificateChainAt(t *testing.T, validAt time.Time, includeAppleEx
|
||||
}}
|
||||
}
|
||||
leafDER := testAppleCertificate(t, leafTemplate, intermediate, &leafKey.PublicKey, intermediateKey)
|
||||
return []string{
|
||||
chain := []string{
|
||||
base64.StdEncoding.EncodeToString(leafDER),
|
||||
base64.StdEncoding.EncodeToString(intermediateDER),
|
||||
base64.StdEncoding.EncodeToString(rootDER),
|
||||
}
|
||||
testAppleLeafKeys[chain[0]] = leafKey
|
||||
return chain
|
||||
}
|
||||
|
||||
func testAppleECDSAKey(t *testing.T) *ecdsa.PrivateKey {
|
||||
@@ -204,7 +222,7 @@ func testAppleJWS(t *testing.T, algorithm string, chain []string, signedAt time.
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(header) + "." + base64.RawURLEncoding.EncodeToString(payload) + ".signature"
|
||||
return testAppleSignedJWS(t, header, payload, chain)
|
||||
}
|
||||
|
||||
func testAppleJWSWithoutDate(t *testing.T, chain []string) string {
|
||||
@@ -217,5 +235,36 @@ func testAppleJWSWithoutDate(t *testing.T, chain []string) string {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(header) + "." + base64.RawURLEncoding.EncodeToString(payload) + ".signature"
|
||||
return testAppleSignedJWS(t, header, payload, chain)
|
||||
}
|
||||
|
||||
var testAppleLeafKeys = map[string]*ecdsa.PrivateKey{}
|
||||
|
||||
func testAppleSignedJWS(t *testing.T, header, payload []byte, chain []string) string {
|
||||
t.Helper()
|
||||
headerSegment := base64.RawURLEncoding.EncodeToString(header)
|
||||
payloadSegment := base64.RawURLEncoding.EncodeToString(payload)
|
||||
key := testAppleLeafKeys[chain[0]]
|
||||
if key == nil {
|
||||
t.Fatal("missing test Apple leaf key")
|
||||
}
|
||||
digest := sha256.Sum256([]byte(headerSegment + "." + payloadSegment))
|
||||
r, s, err := ecdsa.Sign(rand.Reader, key, digest[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
signature := make([]byte, 64)
|
||||
r.FillBytes(signature[:32])
|
||||
s.FillBytes(signature[32:])
|
||||
return headerSegment + "." + payloadSegment + "." + base64.RawURLEncoding.EncodeToString(signature)
|
||||
}
|
||||
|
||||
func testAppleTrustedRoots(t *testing.T, chain []string) map[string]struct{} {
|
||||
t.Helper()
|
||||
rootDER, err := base64.StdEncoding.DecodeString(chain[2])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fingerprint := sha256.Sum256(rootDER)
|
||||
return map[string]struct{}{hex.EncodeToString(fingerprint[:]): {}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user