sassoftware / relic

Relic is a service and a tool for adding digital signatures to operating system packages for Linux and Windows
Apache License 2.0
151 stars 41 forks source link

Breaking change in beevik/etree & RFC3161 support for ClickOnce #4

Closed siliconsheep closed 5 years ago

siliconsheep commented 5 years ago

Hey!

There's been a breaking change in beevik/etree (https://github.com/beevik/etree/releases/tag/v1.0.1), causing the paths starting with "//" to be interpreted as an absolute path. This caused a wrong DigestValue to be picked. Changed that now to ".//DigestValue" so it picks the DigestValue in the Authenticode Signature block as intented.

Microsoft has also moved on to using RFC3161 timestamping servers for their ClickOnce manifests, so requesting an RFC3161 timestamp for those tasks. This does break the verification somehow (probably because that was only applicable to the non-RFC3161 requests), so replaced that with a warning for now. The resulting signed manifests are properly signed and timestamped though.

If you can give me a few pointers on how to verify those timestamps properly, I'll make sure to address that as well!

mtharp commented 5 years ago

Hi! Thank you very much for doing the legwork on identifying the etree issue.

I think you might be right about the RFC 3161 change, as I was able to install an application signed this way. But I can't tell whether the timestamp was actually checked and used, and I'm also not sure when this functionality became available so it's possible there are older platforms I might still need to support, so I'd like to have a flag to revert to the legacy timestamp as needed. You can see signers/pecoff/signer.go for an example of how to do that.

As for why verifying is failing, it's because the legacy timestamp is a signature over just the encrypted digest while the RFC 3161 type is a signature over a timestamp structure. In order to be able to verify both, something like this would work:

var OidTSTInfo = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4} // in lib/pkcs9/structs.go
if timestamp.Content.ContentInfo.ContentType.Equal(pkcs9.OidTSTInfo) {
    // pkcs9 timestamp
    cs, err = pkcs9.Verify(timestamp, encryptedDigest, extraCerts)
} else {
    // legacy timestamp
    cs, err = pkcs9.VerifyMicrosoftToken(timestamp, encryptedDigest)
}

If you pull that out into its own private function, then both the signing self-check and the standalone verifier in lib/appmanifest/verify.go can use it.

Thank you!

siliconsheep commented 5 years ago

Hey,

Thank you for creating this in the first place!

And also thanks for the pointers on how to tackle verification and keeping legacy support available. I’ve got little free time during the work week, but I’ll try to work on this coming weekend a bit.

//Dieter

On Mon, 25 Mar 2019 at 19:52, Michael Tharp notifications@github.com wrote:

Hi! Thank you very much for doing the legwork on identifying the etree issue.

I think you might be right about the RFC 3161 change, as I was able to install an application signed this way. But I can't tell whether the timestamp was actually checked and used, and I'm also not sure when this functionality became available so it's possible there are older platforms I might still need to support, so I'd like to have a flag to revert to the legacy timestamp as needed. You can see signers/pecoff/signer.go for an example of how to do that.

As for why verifying is failing, it's because the legacy timestamp is a signature over just the encrypted digest while the RFC 3161 type is a signature over a timestamp structure. In order to be able to verify both, something like this would work:

var OidTSTInfo = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4} // in lib/pkcs9/structs.goif timestamp.Content.ContentInfo.ContentType.Equal(pkcs9.OidTSTInfo) { // pkcs9 timestamp cs, err = pkcs9.Verify(timestamp, encryptedDigest, extraCerts) } else { // legacy timestamp cs, err = pkcs9.VerifyMicrosoftToken(timestamp, encryptedDigest) }

If you pull that out into its own private function, then both the signing self-check and the standalone verifier in lib/appmanifest/verify.go can use it.

Thank you!

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/sassoftware/relic/pull/4#issuecomment-476331603, or mute the thread https://github.com/notifications/unsubscribe-auth/AYTI3kUNIgp9RV1twTcbjXksOrZXCLu6ks5vaRr4gaJpZM4cFQRl .

siliconsheep commented 5 years ago

Hey Michael,

Thanks again for your inputs! I've added a flag to choose the timestamping model, as well as fixed the verification properly this time.

Tested with a manifest file, it got signed and verified perfectly. I wanted to test the legacy method as well, but couldn't find a legacy timestamping server that still worked. As that code was untouched, that should still work though.

Let me know if anything else needs to be updated!

//Dieter