@@ -11,7 +11,7 @@ import (
11
11
)
12
12
13
13
// openssl x509 -inform der -in AppleRootCA-G3.cer -out apple_root.pem
14
- const rootPEM = `
14
+ const defaultRootPEM = `
15
15
-----BEGIN CERTIFICATE-----
16
16
MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwS
17
17
QXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9u
@@ -30,106 +30,74 @@ at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM
30
30
`
31
31
32
32
type Cert struct {
33
+ rootCertPool * x509.CertPool
33
34
}
34
35
35
- func (c * Cert ) extractCertByIndex (tokenStr string , index int ) ([]byte , error ) {
36
- if index > 2 {
37
- return nil , errors .New ("invalid index" )
36
+ func newCert (rootCertPool * x509.CertPool ) * Cert {
37
+ if rootCertPool == nil {
38
+ rootCertPool = x509 .NewCertPool ()
39
+ rootCertPool .AppendCertsFromPEM ([]byte (defaultRootPEM ))
38
40
}
41
+ return & Cert {rootCertPool : rootCertPool }
42
+ }
39
43
40
- tokenArr := strings . Split ( tokenStr , "." )
41
- headerByte , err := base64 .RawStdEncoding .DecodeString (tokenArr [ 0 ] )
44
+ func ( c * Cert ) parseCert ( certStr string ) ( * x509. Certificate , error ) {
45
+ certByte , err := base64 .StdEncoding .DecodeString (certStr )
42
46
if err != nil {
43
47
return nil , err
44
48
}
49
+ return x509 .ParseCertificate (certByte )
50
+ }
45
51
46
- type Header struct {
52
+ func (c * Cert ) extractPublicKeyFromToken (token string ) (* ecdsa.PublicKey , error ) {
53
+ headerStr , _ , _ := strings .Cut (token , "." )
54
+ headerByte , err := base64 .RawStdEncoding .DecodeString (headerStr )
55
+ if err != nil {
56
+ return nil , err
57
+ }
58
+
59
+ var header struct {
47
60
Alg string `json:"alg"`
48
61
X5c []string `json:"x5c"`
49
62
}
50
- var header Header
51
63
err = json .Unmarshal (headerByte , & header )
52
64
if err != nil {
53
65
return nil , err
54
66
}
55
-
56
- certByte , err := base64 .StdEncoding .DecodeString (header .X5c [index ])
57
- if err != nil {
58
- return nil , err
67
+ if len (header .X5c ) == 0 {
68
+ return nil , errors .New ("appstore found no certificates in x5c header field" )
59
69
}
60
70
61
- return certByte , nil
62
- }
71
+ opts := x509.VerifyOptions {Roots : c .rootCertPool }
63
72
64
- func (c * Cert ) verifyCert (rootCert , intermediaCert , leafCert * x509.Certificate ) error {
65
- roots := x509 .NewCertPool ()
66
- ok := roots .AppendCertsFromPEM ([]byte (rootPEM ))
67
- if ! ok {
68
- return errors .New ("failed to parse root certificate" )
69
- }
70
-
71
- intermedia := x509 .NewCertPool ()
72
- intermedia .AddCert (intermediaCert )
73
-
74
- opts := x509.VerifyOptions {
75
- Roots : roots ,
76
- Intermediates : intermedia ,
77
- }
78
- _ , err := rootCert .Verify (opts )
73
+ leafCert , err := c .parseCert (header .X5c [0 ])
79
74
if err != nil {
80
- return err
75
+ return nil , fmt . Errorf ( "appstore failed to parse leaf certificate: %w" , err )
81
76
}
77
+ header .X5c = header .X5c [1 :]
82
78
83
- _ , err = leafCert .Verify ( opts )
84
- if err != nil {
85
- return err
79
+ pk , ok : = leafCert .PublicKey .( * ecdsa. PublicKey )
80
+ if ! ok {
81
+ return nil , errors . New ( "appstore public key must be of type ecdsa.PublicKey" )
86
82
}
87
83
88
- // TODO: maybe we need the chains info later
89
- //for _, ch := range chains {
90
- // for _, c := range ch {
91
- // fmt.Printf("%+v, %s, %+v \n", c.AuthorityKeyId, c.Subject.Organization, c.ExtKeyUsage)
92
- // }
93
- //}
84
+ // Build intermediate cert pool if there is more than 1 certificate in the header
85
+ if len (header .X5c ) > 0 {
86
+ opts .Intermediates = x509 .NewCertPool ()
94
87
95
- return nil
96
- }
97
-
98
- func (c * Cert ) extractPublicKeyFromToken (token string ) (* ecdsa.PublicKey , error ) {
99
- rootCertBytes , err := c .extractCertByIndex (token , 2 )
100
- if err != nil {
101
- return nil , err
102
- }
103
- rootCert , err := x509 .ParseCertificate (rootCertBytes )
104
- if err != nil {
105
- return nil , fmt .Errorf ("appstore failed to parse root certificate" )
106
- }
107
-
108
- intermediaCertBytes , err := c .extractCertByIndex (token , 1 )
109
- if err != nil {
110
- return nil , err
111
- }
112
- intermediaCert , err := x509 .ParseCertificate (intermediaCertBytes )
113
- if err != nil {
114
- return nil , fmt .Errorf ("appstore failed to parse intermediate certificate" )
88
+ for i , certStr := range header .X5c {
89
+ cert , err := c .parseCert (certStr )
90
+ if err != nil {
91
+ return nil , fmt .Errorf ("appstore failed to parse intermediate certificate %d: %w" , i , err )
92
+ }
93
+ opts .Intermediates .AddCert (cert )
94
+ }
115
95
}
116
96
117
- leafCertBytes , err := c .extractCertByIndex (token , 0 )
118
- if err != nil {
119
- return nil , err
120
- }
121
- leafCert , err := x509 .ParseCertificate (leafCertBytes )
97
+ _ , err = leafCert .Verify (opts )
122
98
if err != nil {
123
- return nil , fmt .Errorf ("appstore failed to parse leaf certificate" )
124
- }
125
- if err = c .verifyCert (rootCert , intermediaCert , leafCert ); err != nil {
126
- return nil , err
99
+ return nil , fmt .Errorf ("appstore failed to verify leaf certificate: %w" , err )
127
100
}
128
101
129
- switch pk := leafCert .PublicKey .(type ) {
130
- case * ecdsa.PublicKey :
131
- return pk , nil
132
- default :
133
- return nil , errors .New ("appstore public key must be of type ecdsa.PublicKey" )
134
- }
102
+ return pk , nil
135
103
}
0 commit comments