user924
user924

Reputation: 12293

How to verify Apple PKPASS's manifest.json with signature file?

So signature in .pkpass file (zip) is used for validation of .pkpass's manifest.json file.

Somehow I need to verify it (I guess using the following Apple certificate https://developer.apple.com/certificationauthority/AppleWWDRCA.cer)

import java.io.File
import java.nio.file.Files
import java.security.MessageDigest
import java.security.Signature
import java.security.cert.CertificateFactory

fun main() {
    val appleCertificateFile = File("AppleWWDRCA.cer")
    val manifestJsonFile = File("manifest.json") // from .pkpass file
    val signatureFile = File("signature") // from .pkpass file

    println(
        verifyManifestSignature(
            manifestJsonFile = manifestJsonFile,
            signatureFile = signatureFile,
            certificateFile = appleCertificateFile
        )
    )
}

fun verifyManifestSignature(
    manifestJsonFile: File,
    signatureFile: File,
    certificateFile: File
): Boolean {
    // Step 1: Read the content of manifest.json
    val manifestBytes = manifestJsonFile.readBytes()

    // Step 2: Compute the SHA-256 hash of manifest.json
    val messageDigest = MessageDigest.getInstance("SHA-256")
    val computedHash = messageDigest.digest(manifestBytes)

    println("computedHash ${computedHash.joinToString("") { "%02x".format(it) }}")

    // Step 3: Extract the signature
    val signatureBytes = signatureFile.readBytes()

    // Step 4: Load the public key from the certificate
    val certificateFactory = CertificateFactory.getInstance("X.509")
    val certInputStream = Files.newInputStream(certificateFile.toPath())
    val certificate = certificateFactory.generateCertificate(certInputStream)
    val publicKey = certificate.publicKey

    // Step 5: Verify the signature using the public key
    val signature = Signature.getInstance("SHA256withRSA")
    signature.initVerify(publicKey)
    signature.update(computedHash)

    // Verify the signature against the data (manifest.json)
    val isVerified = signature.verify(signatureBytes)
    return isVerified
}

But I get the error:

Exception in thread "main" java.security.SignatureException: Bad signature length: got 3347 but was expecting 256
    at java.base/sun.security.rsa.RSASignature.engineVerify(RSASignature.java:215)
    at java.base/java.security.Signature$Delegate.engineVerify(Signature.java:1435)
    at java.base/java.security.Signature.verify(Signature.java:789)
    at PassSignatureKt.verifyManifestSignature(PassSignature.kt:50)
    at PassSignatureKt.main(PassSignature.kt:13)
    at PassSignatureKt.main(PassSignature.kt)

I haven't really worked with certificates, so what's the correct way to verify all of it?

Update

I have found the following example in C# but it's hard for me to rewritten it to Java/Kotlin version:

https://github.com/tomasmcguinness/pkpassvalidator/blob/master/PassValidator.Validator/Validator.cs

Upvotes: 0

Views: 36

Answers (0)

Related Questions