Skip to content

Commit bc762d2

Browse files
Merge pull request #30 from embray/subject-dn-issue
fix: Unknown object id - userId - passed to distinguished name on certain versions of .NET framework
2 parents 9263aeb + e53b616 commit bc762d2

1 file changed

Lines changed: 25 additions & 24 deletions

File tree

PassValidator.Validator/Validator.cs

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33
using System.Security.Cryptography.X509Certificates;
44
using System.Text;
55
using Newtonsoft.Json.Linq;
6+
using Org.BouncyCastle.Asn1;
67
using Org.BouncyCastle.Asn1.X509;
8+
using Org.BouncyCastle.Security;
9+
710

811
namespace PassValidator.Validator;
912

1013
public 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

Comments
 (0)