I need some help on this issue. I'm trying to provision a digital card to be added to Apple wallet. I get the encrypted activation data from a third party. My job is to encrypt the card details using KDF function. The encryption process goes smooth, I don't see any errors in it, but when I try to actually provision a card, Apple is not able to add it to Wallet. There is no error reported. I reached out to Apple but they have been less than helpful. This is what is happening
- Extract the apple public key from the leaf certificate:
var certParser = new X509CertificateParser();
var cert = certParser.ReadCertificate(certificateBytes);
// Extract the public key
var publicKey = cert.GetPublicKey();
// Ensure it's an EC key (which it should be for Apple Wallet)
if (publicKey is ECPublicKeyParameters ecPublicKey)
{
// Encode the public key in the format expected by your encryption method
var encodedPublicKey = SubjectPublicKeyInfoEncoder.GetEncoded(ecPublicKey);
return Convert.ToBase64String(encodedPublicKey);
}
- Create Card details
var cardDetails = new CardDetails
{
PrimaryAccountNumber = "*************",
Expiration = "03/27",
Name = Settings.Account?.CustName,
Nonce = Convert.ToHexString(nonce.ToArray()),
NonceSignature = Convert.ToHexString(nonceSignature.ToArray()),
};
- Decode and parse Apple's public key
// 1. Decode and parse Apple's public key
var applePublicKeyBytes = Convert.FromBase64String(applePublicKeyBase64);
var applePublicKey = PublicKeyFactory.CreateKey(applePublicKeyBytes);
var ecPublicKey = (ECPublicKeyParameters)applePublicKey;
// 2. Generate an ephemeral key pair using the same curve as Apple's key
var curveParameters = ecPublicKey.Parameters;
var curveName = GetCurveName(ecPublicKey);
//2.1 Generate ephemeral key pair
var keyGen = new ECKeyPairGenerator();
keyGen.Init(new ECKeyGenerationParameters(curveParameters, new SecureRandom()));
var ephemeralKeyPair = keyGen.GenerateKeyPair();
var ephemeralPrivateKey = (ECPrivateKeyParameters)ephemeralKeyPair.Private;
var ephemeralPublicKey = (ECPublicKeyParameters)ephemeralKeyPair.Public;
// 3. Perform ECDH key agreement
var agreement = new ECDHBasicAgreement();
agreement.Init(ephemeralPrivateKey);
var sharedSecret = agreement.CalculateAgreement(ecPublicKey);
// 4. Generate a symmetric key using SHA-256
var sharedSecretBytes = sharedSecret.ToByteArrayUnsigned();
var symmetricKey = DeriveSymmetricKey(sharedSecretBytes);
// 5. Generate a random nonce/IV for AES-GCM
var nonce = GenerateRandomBytes(AesGcmIvLengthBytes);
// 6. Prepare the card data for encryption (convert to JSON)
var cardDataBytes = SerializeCardDetails(cardDetails);
// 7. Encrypt the card data using AES-GCM
var encryptionResult = EncryptWithAesGcm(cardDataBytes, symmetricKey, nonce);
// 8. Encode the ephemeral public key
var ephemeralPublicKeyEncoded = SubjectPublicKeyInfoEncoder.GetEncoded(ephemeralPublicKey);
// 9. Create the encrypted data structure
if (encryptionResult is { Ciphertext: not null, AuthTag: not null })
return new EncryptedCardData
{
EncryptedData = Convert.ToBase64String(encryptionResult.Ciphertext),
EphemeralPublicKey = Convert.ToBase64String(ephemeralPublicKeyEncoded),
Tag = Convert.ToBase64String(encryptionResult.AuthTag),
Nonce = Convert.ToBase64String(nonce),
// The ActivationData field is optional and depends on your implementation needs
ActivationData = GenerateActivationData()
};
//and then finally
// Create the payment pass request to be returned to Apple
if (encryptedData is { EncryptedData: not null, EphemeralPublicKey: not null })
{
var request = new PKAddPaymentPassRequest
{
EncryptedPassData = NSData.FromString(encryptedData.EncryptedData, NSStringEncoding.UTF8),
ActivationData = string.IsNullOrEmpty(encryptedData.ActivationData) ? null :
NSData.FromString(encryptedData.ActivationData, NSStringEncoding.UTF8),
EphemeralPublicKey = NSData.FromString(encryptedData.EphemeralPublicKey, NSStringEncoding.UTF8)
};
// Return the request to Apple via the completion handler
handler(request);
}
When the handler is called, I get this: enter image description here Not sure what is going on.
Any idea what could be happening. I'm provisioned with apple. All entitlements are set and I'm testing it on TestFlight.
I have tried reaching out to apple, reimplementing it about 3 times I think. Looked in to ChatGPT, Grok and Claude. Nothing has worked.