Closed ueman closed 2 months ago
There's some code at which may help with it: https://github.com/tomasmcguinness/dotnet-passbook/blob/master/Passbook.Generator/PassGenerator.cs
// How to create a `RSAPrivateKey` from a pem file
import 'dart:typed_data';
import 'package:passkit/src/apple_wwdr_certificate.dart';
import 'package:pem/pem.dart';
import 'package:pkcs7/pkcs7.dart';
import 'package:pointycastle/pointycastle.dart';
RSAPrivateKey _createPrivateKey(String userCertificate) {
final pem = decodePemBlocks(PemLabel.privateKey, userCertificate);
final modulus =
ASN1Object.fromBytes(Uint8List.fromList(pem[1])) as ASN1Integer;
final exponent =
ASN1Object.fromBytes(Uint8List.fromList(pem[3])) as ASN1Integer;
final p = ASN1Object.fromBytes(Uint8List.fromList(pem[4])) as ASN1Integer;
final q = ASN1Object.fromBytes(Uint8List.fromList(pem[5])) as ASN1Integer;
return RSAPrivateKey(
modulus.integer!,
exponent.integer!,
p.integer,
q.integer,
);
}
As a temporary solution, we could provide a callback for writing the signature. There are multiple examples for signing PKPass files with OpenSSL, and there are also OpenSSL bindings for Dart/Flutter. I however intend this library (and it's dependencies) to be Dart only.
Pseudo code example:
final pass = PkPass(...);
final pkPassFile = pass.create(signatureWriter: (contentHashes) {
// create signature here based on the contentHashes
return signature;
});
Maybe something like this could work?
import 'dart:typed_data';
import 'package:passkit/src/apple_wwdr_certificate.dart';
import 'package:pem/pem.dart';
import 'package:pkcs7/pkcs7.dart';
import 'package:pointycastle/pointycastle.dart';
Uint8List writeSignature(
String userCertificate, // this is private key and certificate in one file
Uint8List manifestBytes, // I'm guessing this should be the manifest content, not the hash of the manifest
) {
final privateKey = _createPrivateKey(userCertificate);
final issuer = X509.fromPem(userCertificate);
final pkcs7Builder = Pkcs7Builder();
pkcs7Builder.addCertificate(issuer);
pkcs7Builder.addCertificate(wwdrG4);
final signerInfo = Pkcs7SignerInfoBuilder.rsa(
issuer: issuer,
privateKey: privateKey,
digestAlgorithm: HashAlgorithm.sha1,
);
signerInfo.addSMimeDigest(digest: manifestBytes, signingTime: DateTime.now());
pkcs7Builder.addSignerInfo(signerInfo);
final pkcs7 = pkcs7Builder.build();
return pkcs7.der;
}
RSAPrivateKey _createPrivateKey(String certificate) {
final pem = decodePemBlocks(PemLabel.privateKey, certificate);
final modulus =
ASN1Object.fromBytes(Uint8List.fromList(pem[1])) as ASN1Integer;
final exponent =
ASN1Object.fromBytes(Uint8List.fromList(pem[3])) as ASN1Integer;
final p = ASN1Object.fromBytes(Uint8List.fromList(pem[4])) as ASN1Integer;
final q = ASN1Object.fromBytes(Uint8List.fromList(pem[5])) as ASN1Integer;
return RSAPrivateKey(
modulus.integer!,
exponent.integer!,
p.integer,
q.integer,
);
}
https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/YourFirst.html#//apple_ref/doc/uid/TP40012195-CH2-SW1
https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html#//apple_ref/doc/uid/TP40012195-CH4-SW1
https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/DistributingPasses.html#//apple_ref/doc/uid/TP40012195-CH11-SW1
[ ] To create the signature file, make a
PKCS #7
detached signature of the manifest file, using the private key associated with your signing certificate. Include the WWDR intermediate certificate as part of the signature. You can download this certificate from Apple’s website. Write the signature to the file signature at the top level of the pass package. Include the date and time that the pass was signed using the S/MIME signing-time attribute.pointycastle
andpkcs7
to sign the pass in pure Dart code