template-archive
template-archive copied to clipboard
Signed Cicero Template Archives
Add support for signed template archives.
References: https://docs.oracle.com/javase/tutorial/deployment/jar/signindex.html https://medium.com/ios-os-x-development/ios-code-signing-provisioning-in-a-nutshell-d5b247760bef
Hello,
I have started to investigate this issue and I would like your feedback before I go too far in one direction or another.
Given the current archive format being zip and to avoid a separate signature file I think a solution similar to JAR signing makes sense.
- create a simple manifest containing a collection of file paths and hashes in the archive
- digitally sign that manifest and place the signature in a separate file
- place both manifest and signature in the zip in special locations
I am planning to use PKCS#7 digital signatures. This gives signers the option of using the global PKI allowing for easy verification of signatures while not precluding the use of self-signed certificates if a firm is unable or unwilling to purchase a code signing certificate.
Your thoughts?
That sounds great. FYI we already have a method in the template that computes a content-based hash which might be useful: https://github.com/accordproject/cicero/blob/master/packages/cicero-core/src/template.js#L143
I ended up creating a manifest with individual file hashes to more easily detect what file changed, if any. I'm finishing up the verification bits now; although I've used node-forge in the past, I didn't notice PKCS#7 verification was missing so I had to add it.
While we wait for the node-forge PR to be reviewed and (hopefully) merged, it is worth mentioning a few items and discussing as necessary.
- Linux platforms are assumed with the CA list I grabbed from Go
- an invalid signature aborts processing; is this acceptable?
Also, some limitations of this PR:
- as signing is optional there is no way to prevent a malicious MitM from removing the signature and manifest
- it isn't possible to use the signing half of this PR with an EV code-signing certificate as those are required to be stored in hardware
- the subject of the signer certificate is displayed during verification but users could be tricked by a malicious actor incorporating an identically named entity in a different legal jurisdiction
I reviewed the code in the fork - it looks great. Looking forward to the pull request!
Thanks @roysjosh, great work! Some thoughts on your comments above...
Linux platforms are assumed with the CA list I grabbed from Go
Can you explain the platform limitation a little more, please? What does this mean in practice?
an invalid signature aborts processing; is this acceptable?
Yes, IMO. We can handle this gracefully higher up the stack
as signing is optional there is no way to prevent a malicious MitM from removing the signature and manifest
So, we rely upon tools to alert users to the use of unsigned templates/templates that were previously signed? Analogous to TLS and HSTS in browsers?
it isn't possible to use the signing half of this PR with an EV code-signing certificate as those are required to be stored in hardware
If I understand this correctly, the use of EV certificates in browsers has lost traction recently. I assume that the same criticisms of EV certificates for domains are also relevant to us. In this case, I'm comfortable with this limitation.
the subject of the signer certificate is displayed during verification but users could be tricked by a malicious actor incorporating an identically named entity in a different legal jurisdiction
Analogous to a malicious website choosing a similar domain name , i.e. accordproject.us rather than accordproject.org? I wonder what lessons we can learn from other domains to reduce the risk of this. Regardless, this sounds like a reasonable limitation to begin with.
Looks great. Besides Matt’s comments, I’m am wondering if you could explain/motivate the specific choice of PKCS#7.
Linux platforms are assumed with the CA list I grabbed from Go
Can you explain the platform limitation a little more, please? What does this mean in practice?
I had to implement CA loading as I couldn't find a solution inside node.js itself (outside of TLS verification) or a community module. To start, I grabbed the list of file paths that the Go language uses to search for system CAs under Linux systems. If more platform support is necessary, that can be added.
an invalid signature aborts processing; is this acceptable?
Yes, IMO. We can handle this gracefully higher up the stack
as signing is optional there is no way to prevent a malicious MitM from removing the signature and manifest
So, we rely upon tools to alert users to the use of unsigned templates/templates that were previously signed? Analogous to TLS and HSTS in browsers?
Right, tooling could be modified to display warnings for various scenarios: no signature, a signature by an untrusted CA, etc. If the tooling had knowledge of historical archives it could warn on the "previously signed" scenario (Firm A has always sent signed archives and now version 2.0.0-final isn't signed?).
it isn't possible to use the signing half of this PR with an EV code-signing certificate as those are required to be stored in hardware
If I understand this correctly, the use of EV certificates in browsers has lost traction recently. I assume that the same criticisms of EV certificates for domains are also relevant to us. In this case, I'm comfortable with this limitation.
Agreed.
the subject of the signer certificate is displayed during verification but users could be tricked by a malicious actor incorporating an identically named entity in a different legal jurisdiction
Analogous to a malicious website choosing a similar domain name , i.e.
accordproject.usrather thanaccordproject.org? I wonder what lessons we can learn from other domains to reduce the risk of this. Regardless, this sounds like a reasonable limitation to begin with.
Right. Most users won't notice that a signature is suddenly coming from /C=US/ST=Missouri/L=Kansas City/CN=Firm A/ vs /C=US/ST=Kansas/L=Kansas City/CN=Firm A/.
Looks great. Besides Matt’s comments, I’m am wondering if you could explain/motivate the specific choice of PKCS#7.
When I started on this issue, I thought for a while on the pros and cons of a solution using the global CA vs one more like GPG. Although using a GPG-like model would have given more freedom with crypto primitives, as there has been some advancement of hash algorithms and digital signature schemes, it would have introduced the GPG issue of trust. Given the choice between making it a little easier for signers (generate my own keys on demand at no cost!) vs a little easier for verifiers (did this cert/signature really come from firm A?) I went with the latter. Also, generating your own keys outside of the global CA isn't precluded by this solution if you want to go that route.
PKCS#7 specifically was selected because it was an existing digital signature standard and some tooling was already available.
@roysjosh Any update on this? Last time I had seen an update it looked almost completed?
I'll go ahead and open a PR here so it can be reviewed. I'm waiting to hear back on my latest changes for digitalbazaar/forge#706.
I'll go ahead and open a PR here so it can be reviewed. I'm waiting to hear back on my latest changes for digitalbazaar/forge#706.
Sounds great!
It looks like forge has now implemented PKCS#7 - but not merged your PR @roysjosh. Can you re-implement the PR on top of their implementation?
https://github.com/digitalbazaar/forge#pkcs7