33using System . Security . Cryptography . X509Certificates ;
44using System . Text ;
55using Newtonsoft . Json . Linq ;
6+ using Org . BouncyCastle . Asn1 ;
67using Org . BouncyCastle . Asn1 . X509 ;
8+ using Org . BouncyCastle . Security ;
9+
710
811namespace PassValidator . Validator ;
912
1013public class Validator
1114{
1215 private const string G4WwdrCertificateSerialNumber = "13DC77955271E53DC632E8CCFFE521F3CCC5CED2" ;
1316
17+ private const string ApplePassTypeOid = "1.2.840.113635.100.6.1.16" ;
18+
1419 public ValidationResult Validate ( byte [ ] passContent )
1520 {
1621 var result = new ValidationResult ( ) ;
@@ -137,7 +142,7 @@ public ValidationResult Validate(byte[] passContent)
137142 zipToOpen . Close ( ) ;
138143 if ( ! result . HasManifest ) return result ;
139144
140- var contentInfo = new ContentInfo ( manifestFile ) ;
145+ var contentInfo = new ContentInfo ( manifestFile ! ) ;
141146 var signedCms = new SignedCms ( contentInfo , true ) ;
142147
143148 signedCms . Decode ( signatureFile ) ;
@@ -155,10 +160,12 @@ public ValidationResult Validate(byte[] passContent)
155160
156161 // There are two certificates attached. One is the PassType certificate. One is the WWDR certificate.
157162 //
158- X509Certificate2 ? passKitCertificate = null ;
163+ Org . BouncyCastle . X509 . X509Certificate ? passKitCertificate = null ;
159164
160165 foreach ( var cert in signedCms . Certificates )
161166 {
167+ var bcCert = DotNetUtilities . FromX509Certificate ( cert ) ;
168+
162169 if ( cert . SerialNumber == G4WwdrCertificateSerialNumber )
163170 {
164171 result . SignedByApple = true ;
@@ -168,8 +175,7 @@ public ValidationResult Validate(byte[] passContent)
168175 else
169176 {
170177 // Find another cert issued by Apple Inc.
171- var issuerName = new X509Name ( cert . Issuer ) ;
172-
178+ var issuerName = bcCert . IssuerDN ;
173179 var issuerCommonName = issuerName . GetValueList ( X509Name . CN ) ;
174180 var issuerOrganisation = issuerName . GetValueList ( X509Name . O ) ;
175181
@@ -178,7 +184,7 @@ public ValidationResult Validate(byte[] passContent)
178184 if ( ( string ) issuerOrganisation [ 0 ] == "Apple Inc." && ( string ) issuerCommonName [ 0 ] ==
179185 "Apple Worldwide Developer Relations Certification Authority" )
180186 {
181- passKitCertificate = cert ;
187+ passKitCertificate = bcCert ;
182188 }
183189 }
184190 }
@@ -187,25 +193,20 @@ public ValidationResult Validate(byte[] passContent)
187193 if ( passKitCertificate != null )
188194 {
189195 result . PassKitCertificateFound = true ;
190-
191- foreach ( var extension in passKitCertificate . Extensions )
192- {
193- // 1.2.840.113635.100.6.1.16 is the OID of the problematic part I think.
194- // This is an Apple custom extension (1.2.840.113635.100.6.1.16) and in good passes,
195- // the value matches the pass type identifier.
196- //
197- if ( extension . Oid ? . Value != "1.2.840.113635.100.6.1.16" ) continue ;
198-
199- var value = Encoding . ASCII . GetString ( extension . RawData ) ;
196+ // This is an Apple custom extension (1.2.840.113635.100.6.1.16) and in good passes,
197+ // the value matches the pass type identifier.
198+ var extValue = passKitCertificate . GetExtensionValue ( new DerObjectIdentifier ( ApplePassTypeOid ) ) ;
199+
200+ if ( extValue != null ) {
201+ var octet = ( Asn1OctetString ) extValue ;
202+ var raw = octet . GetOctets ( ) ;
203+ var value = Encoding . ASCII . GetString ( raw ) ;
200204 value = value . Substring ( 2 , value . Length - 2 ) ;
201-
202205 result . PassKitCertificateNameCorrect = value == manifestPassTypeIdentifier ;
203- break ;
204206 }
205207
206- result . PassKitCertificateExpired = passKitCertificate . NotAfter < DateTime . UtcNow ;
207-
208- var issuerName = new X509Name ( passKitCertificate . Issuer ) ;
208+ result . PassKitCertificateExpired = passKitCertificate . NotAfter . ToUniversalTime ( ) < DateTime . UtcNow ;
209+ var issuerName = passKitCertificate . IssuerDN ;
209210 var passKitIssuerOrg = issuerName . GetValueList ( X509Name . O ) [ 0 ] as string ;
210211 var passKitIssuerCommonName = issuerName . GetValueList ( X509Name . CN ) [ 0 ] as string ;
211212
@@ -217,8 +218,8 @@ public ValidationResult Validate(byte[] passContent)
217218 }
218219
219220 // Now check the subject and type identifier match.
220- //
221- var certName = new X509Name ( signer . Certificate ? . Subject ) ;
221+ var bcSignerCert = DotNetUtilities . FromX509Certificate ( signer . Certificate ) ;
222+ var certName = bcSignerCert . SubjectDN ;
222223
223224 var certificateCommonName = certName . GetValueList ( X509Name . CN ) [ 0 ] as string ;
224225 string signaturePassTypeIdentifier ;
@@ -241,8 +242,8 @@ public ValidationResult Validate(byte[] passContent)
241242 certificateOrganisationUnit = organisationUnits [ 0 ] as string ;
242243 }
243244
244- result . HasSignatureExpired = signer . Certificate . NotAfter < DateTime . UtcNow ;
245- result . SignatureExpirationDate = signer . Certificate . NotAfter . ToString ( "yyyy-MM-dd HH:mm:ss" ) ;
245+ result . HasSignatureExpired = bcSignerCert . NotAfter . ToUniversalTime ( ) < DateTime . UtcNow ;
246+ result . SignatureExpirationDate = bcSignerCert . NotAfter . ToString ( "yyyy-MM-dd HH:mm:ss" ) ;
246247
247248 result . PassTypeIdentifierMatches = manifestPassTypeIdentifier == signaturePassTypeIdentifier ;
248249 result . TeamIdentifierMatches = manifestTeamIdentifier == certificateOrganisationUnit ;
0 commit comments