Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Digital Signature of Packs #8

Open
chaws opened this issue Sep 14, 2021 · 22 comments
Open

[DRAFT] Digital Signature of Packs #8

chaws opened this issue Sep 14, 2021 · 22 comments
Labels
Discussion Issue to be discussed before further action is taken

Comments

@chaws
Copy link
Contributor

chaws commented Sep 14, 2021

DRAFT

Pack Signing Motivation

This is a proposal to make cpackget installation more secure through pack signing by tackling the following top use cases:

  1. Integrity: make sure a pack has not been altered during its transport
  2. Authenticity: make sure a pack supposed to be issued by a Vendor is really coming from Vendor
  3. Access Control: accept some packs only if they are coming from some vendors

Design

The fundamental idea is to use keys signed by PKI/x509 certificates to sign packs and be later on validated by cpackget.

Each vendor would be responsible for generating their Root CA, then generate sub-certificates depending on their needs. Example:

  1. ARM Root CA
    1.1. MCU Group Cert
    1.1.1. Joachim Krech's Cert
  2. ST Root CA
    2.1. Software Center Cert
    2.1.1. Le Mans Cert
    2.1.1.1. Frederic Ruelle Cert
  3. NXP Root CA
    3.1. Bob Cert

Aspects of the approach:

  1. All Root CA will be shipped in cpackget's secure store of certs (customizable).
  2. If Frederic Ruelle signed a pack with his key, cpackget can:
    2.1. Check integrity by checking the signature file and the original pack file
    2.2. Validate its authenticity because it has been signed by MCU Group Cert which has been signed by ARM Root CA, present in the certs store.
    2.3. Optionally check access control by matching the key's cert against the specific Root CA.
  3. Because keys and certs can be revoked at any time, the public key should not have any reference in the pdsc file.
  4. Cpackget can be told on the behavior when checking a pack signature via cmdline args, such as --ignore-validity-date or --ignor-ownership

Q&A

The following questions have been asked during discussion of this proposal:

Q1: How to ensure that the pack file has not been modified?
The signature file is just an encrypted hash sum of the pack file, so during signature checking, the hash of the pack will be re-generated and compared against the one embedded in the signature file.

Q2: How to ensure that the pack was created by the vendor?
Because of the nature of X.509 certs, it's possible to track a signing key up to its original ROOT CA. All Root CAs should be in a secure store trusted by cpackget.

Q3: If a pack was signed by a key that is no longer valid, is there a solution without re-signing all packs signed with that key?
No, re-signing is required because the key is no longer trusted by cpackget.

@chaws chaws self-assigned this Sep 20, 2021
@jkrech
Copy link
Member

jkrech commented Sep 22, 2021

Feedback from the project meeting:
a) hash = is the pack file timestamp a reliable thing on Windows -> investigate
b) is there a more scalable alternative to embedding public vendor keys into the cpackget tool? E.g. could we have a signed archive of public keys to be downloaded (independently or as part of index.pidx?) and signed with the open-cmsis-pack key. This would be the only key embedded in cpackget?
c) how about expiring keys or revoked keys. How do we make sure we don't need to update the signature for all packs that have been published already?
...

@chaws
Copy link
Contributor Author

chaws commented Oct 21, 2021

While testing cpackget on all packs from the public index, I've found packs under HTTP domains and packs with expired HTTPS certs. Should these be notified when installing packs? I'd say yes, but don't know if installation should be aborted.

@jkrech
Copy link
Member

jkrech commented Oct 22, 2021

Good points. I suggest that:
a) add a command line option to allow download from http

  • if http is not enabled print error message and exit with error status

b) if an https url has an expired certificate

  • always print a message that the certificate expired
  • ask the user to confirm download
  • add command line option to either
    • download anyway
    • skip download with error status

@fred-r
Copy link

fred-r commented Dec 14, 2021

Hi guys,

as usual I am going to be a bit pedantic and picky on the wording...so please feel free to kick my ass when needed :-)

Concept

To me, GPG is the GNU implementation of the OpenPGP standard: https://www.ietf.org/rfc/rfc4880.txt

So, my first point is: do you really want to rely on GPG which has a GPL-3.0 license ?
I am not comfortable with this license.

Now, coming to OpenPGP.
It describes many things, not only signatures.
Typically it covers both encryption and signatures (even if section 2.5 states that we can need signatures only).
This is more than we need.

To me, what we want is proving the authenticity and integrity of our packs.
So, yes, we need to sign a pack.

But, to do so, we do not need OpenPGP in its wholeness.
We just need asymmetric cryptography and a digest.

To be more precise, we need:

  • RSA signature or ECDSA
  • SHA256 or equivalent

I would vote for ECDSA + SHA256 as we may work with "small" keys compared to RSA.
And we may very well implement this with OpenSSL (Apache license) or ARM mbed TLS (Apache too).
But, please, let's avoid GPL licenses...

Attacks

Forging a fake pack

I understand that you propose to have:

  • the pack containing in the pdsc a path to a public key to verify the pack
  • next to it a .sign artefact containing the signature itself

So, as a hacker I can:

  1. change the public key reference in the pdsc
  2. recompute the hash
  3. encrypt the hash with my private key
  4. publish this as the pack

This would be accepted by the tool if we have no "trusted third party" to certify the origin of the public key.

Countermeasure : we must prove the ownership of the public key.

So, to me, a smart and standard way to solve this issue is to use X.509 certificates to distribute the public keys (no need for a special server to register the authorized keys or hard-code the authorized keys in the cpackget binary).

Besides, with the X.509 certificates chain concept we can easily have a hierarchy of certificates and accept/revoke certificates at any level.

Circumventing cpackget check

As a hacker, I may very well:

  1. Locate CMSIS_PACK_ROOT in my system
  2. Install my pack directly in the appropriate folders and update the appropriate index files

So, I can install any pack on my machine without cpackget checking it.

Countermeasure : the pack authenticity and integrity mustbe checked at usage step, not only at installation step.

So, each time the project manager uses a pack, it verifies its authenticity and integrity.

Public Key Infrastructure

I recommend using X.509 certificates to distribute the public keys.
This gives a great flexibility:

  • add new keys, revoke keys, add a validity period to a key...
  • support various signature and hash algorithms
  • chain of trust : we can trust only few Root certificates
  • responsibility : with the chain of trust we can delegate the signing responsibility and revoke any compromised level without revoking individual keys or revoking all keys from an organisation

The tool would have a secure store of root certificates and it would be easy to maintain it (just like web browsers do).
We just need to make sure a hacker cannot update the store with malicious certificates.
But, tools vendors may maintain their own stores.

Or we may have specific CAs and if you want to publish a pack accepted by the tool then you must first obtain a public certificate signed by this CA.
ST Micro may provide certificates to trusted partners so our implementation of cpackget would accept only these packs.
ARM may do the same...etc...

Or, we may be permissive for some packs (libraries: accept any certificate) and restrictive for some others (device packs: accept only the certificates signed by silicon vendors CA).

Many strategies can be imagined... but X.509 is the building block for this IMO.

@fred-r
Copy link

fred-r commented Dec 17, 2021

Maybe I should have started by this...but probably we need to clarify what we want to achieve here ?

To me what is important is:

  1. Integrity : make sure a pack has not been altered during its transport (better than just the sha1 created by gen_pack.sh)
  2. Authenticity : make sure a pack supposed to be issued by N is really coming from N

That's why digital signature + PKI sounds good to me.

A 3rd goal may be:
3. Access Control : accept some packs only if they are coming from some vendors

For instance, if a pack is a CMSIS pack, then my tool may refuse to use this pack if it is not signed by ARM or a 3rd party whose certificate has been signed by ARM.

What do you think ?

@chaws
Copy link
Contributor Author

chaws commented Jan 18, 2022

Hi Frederic!

Thanks a lot for your comments, I've taken that into re-writing the proposal.

One thing I haven't updated yet is how public keys are distributed. I know GPG public keys can live in key servers such as mit or ubuntu. But don't know yet if X509 keys have something similar.

@fred-r
Copy link

fred-r commented Jan 18, 2022

We may have servers hosting some certificates but I guess it is not mandatory.
The cpackget binary can have a "trusted certificates" store where we have at least the root CAs.

Then, the intermediate certs and leaf certificate signing the pack can be delivered together with the pack.
That means that we would only need to distribute top level certificates to validate the lower level ones.

Of course, certs expiry must be considered.
For the renewal it means we would have to issue a new pack revision with the updated certificates.
But we may have "transition periods" where the tool is permissive.
And also, packs issuer may use very long validity periods I guess.

Then it depends on the tool implementation:

  • the tool might consider that even if the cert is expired then we still trust the pack (can be an option where the user says : i understand the risks and go with it)
  • the tool might consider that we do the full checks only when receiving a new pack, not when using it
  • or the tool can be very strict and refuse to use a pack as soon as the certificate has expired

So, I am more in favor of distributing the public keys together with the packs.
It has the drawback that the pack may have to be republished when the validity period expires but it has the benefit of not requiring servers to distribute the keys (only the top level certs must be known by the tool to validate the certs chain).

@fred-r
Copy link

fred-r commented Jan 19, 2022

The latest recommendations (for the web) seem to be to issue certificates with a one year validity period:
https://www.globalsign.com/en/blog/maximum-ssltls-certificate-validity-now-one-year

But the Root CAs themselves have much longer validity period:
image

So, probably we can go for longer validity periods in our case.

Anyway, we can have a configurable "cpackget" with a permissive mode.

The question is also: should the signature be checked only by cpackget when installing the pack? (so we assume that once the pack is installed on the local machine the security is fine).

Or shall the tool using the pack check the signature too ?
I guess this is not in the direct scope of this repo.

Nevertheless, this may have an impact on the architecture : maybe the service to check the packs should be "externalized" from cpackget (or at least built with an external API?) so that any tool can use it ?

@fred-r
Copy link

fred-r commented Jan 19, 2022

Regarding this point:

Q2: How to ensure that the pack was created by the vendor?
Because of the nature of X.509 certs, it's possible to track a signing key up to its original ROOT CA. All Root CAs should be in a secure store trusted by cpackget.

This is the idea.
Just to be sure we are on the same page if we take the example of ARM CMSIS.

We need in the certs chain an intermediate certificate from ARM.
And, to trust this ARM certificate, we need it to be signed by a root certificate from a Certification Authority.

So one may imagine a certificate chain like this:
Joachim's cert <-- signed by-- ARM certificate <--signed by-- Globalsign Root CA

Then having the "Globalsign Root CA" in your trusted store of certificates (maybe the one from your OS) is sufficient to trust the entire certs chain.

You just need to say:

  • ok, the ARM certificate is indeed valid because signed by a root certificate I trust
  • ok, the ARM certificate allows me to say that the pack is coming from ARM because it has the following attributes:

CN = ARM packs issuing entity
OU = ARM Germany GmbH
O = ARM Ltd
L = Munich
S = Bavaria
C = DE

@fred-r
Copy link

fred-r commented Jan 19, 2022

Another aspect also : to avoid making packs distribution too painful (people may want to distribute packs easily), all these checks must be configurable.

An end-user may say : I do not want any check, I accept any pack from anywhere, even if the pack is not signed at all.

@chaws
Copy link
Contributor Author

chaws commented Jan 21, 2022

Hi @fred-r, let me try to compile your comments' answers in this comment.

We may have servers hosting some certificates but I guess it is not mandatory.

Are there any public certs store out there as MIT or Ubuntu do for GPG public keys? Perhaps these servers will become handy when distributing or keeping the list of CRL.

The cpackget binary can have a "trusted certificates" store where we have at least the root CAs. Then, the intermediate certs and leaf certificate signing the pack can be delivered together with the pack. That means that we would only need to distribute top level certificates to validate the lower level ones.

Ack.

For the renewal it means we would have to issue a new pack revision with the updated certificates.

Do you know if cert renewal also requires new keys? If so, I'm afraid pack re-signing would be a recurring task for vendors.

But we may have "transition periods" where the tool is permissive.
And also, packs issuer may use very long validity periods I guess.

My initial idea was exactly that. But now that I re-read this statement, I think perhaps cpackget could by default check for pack signatures and avoid it via special flags, e.g. --bypass-security or some other wording. This would scream out at anyone who sees that, thus suggesting pack issuers to adopt new security measures sooner.

The question is also: should the signature be checked only by cpackget when installing the pack? ... Nevertheless, this may have an impact on the architecture : maybe the service to check the packs should be "externalized" from cpackget (or at least built with an external API?) so that any tool can use it ?

Agreed! In my initial proposal, I suggested to build a tool ("cpacksec") that could be used to generate keys, sign packs and verify signature. The idea was to have it both as a standalone tool and as a Golang API that cpackget could make use of. I think the principle remains the same for PKI/x509 certs. The upside is that we could customize it as we wish.

We need in the certs chain an intermediate certificate from ARM.
And, to trust this ARM certificate, we need it to be signed by a root certificate from a Certification Authority. So one may imagine a certificate chain like this: Joachim's cert <-- signed by-- ARM certificate <--signed by-- Globalsign Root CA

I remember from one of our email threads that you didn't like the idea of having a single RootCA signing all vendors certs. Or am I missing something? I had in mind that ARM certificate would be the Root cert in this chain, that it would be the one with long expiration dates and that this would be shipped in cpackget's secure certs store.

@fred-r
Copy link

fred-r commented Jan 21, 2022

For the Root CA cert : agree, any vendor must have the freedom to choose the CA signing his certificate. This way, the tool does not need to maintain its own store of root certs and can reuse the OS store.

I do.not think it is mandatory for ARM to play the role of the CA, this would be complex. What I suggest is that the ARM intermediate cert (and it can be any intermediate cert assignef to the subjectcARM Ltd by a CA) is required for packs whose vendor is ARM.

But, we also need to be careful : more security is great but it comes with constraints. Bypassing the security checks must be allowed (one may think that all this signing is overkill and that they want to trust anybody).

@chaws
Copy link
Contributor Author

chaws commented Jan 24, 2022

Let me write a scratch tool to start off on this thread, it'll be useful moving our discussion forward.

@fred-r Let me ask you something that crossed my mind: Do you think Vendors would want to re-use x509 certs? For instance, let's say ARM already has another x509 cert that ARM uses somewhere else in the company, do you think it makes sense for ARM to reuse that to sign packs? Or should we always ensure that the cert to sign packs are created specifically for this use.

@fred-r
Copy link

fred-r commented Jan 24, 2022

Let me write a scratch tool to start off on this thread, it'll be useful moving our discussion forward.

@fred-r Let me ask you something that crossed my mind: Do you think Vendors would want to re-use x509 certs? For instance, let's say ARM already has another x509 cert that ARM uses somewhere else in the company, do you think it makes sense for ARM to reuse that to sign packs? Or should we always ensure that the cert to sign packs are created specifically for this use.

Mmmh....not sure here.
Usually when you send a CSR to a CA you indicate the purpose of your key.
So here we would not ask for an SSL certificate but probably more a code signing certificate...even if we are not publishing an executable but a pack.
So, we would use a code signing certificate but not a standard code signing application, instead I assume we would use your cpacksec application (because we do not need our software to be recognized by the OS).

The difficulty comes when we introduce the intermediate company CA.
Usually, a Root CA restricts what you can do with the certificate it issues for you.
If you were allowed to sign any other certificate then you could misuse it (sign a counterfeit certificate with your valid certificate). So, the CA is likely to issue a certificate with this field:
X509v3 Basic Constraints: critical
CA:FALSE

This being said, your tool may very well accept this scheme (even if CA is set to FALSE), knowing that we do not use it to validate web sites.
Our protection against counterfeiting would be checking that the issuer is also the vendor of the pack to make sure we cannot publish a pack claiming it is from ARM and signing it with a non-ARM certificate.

As you can see, there is still a little bit of thinking to do to make sure we do not reinvent the wheel:-)

@chaws
Copy link
Contributor Author

chaws commented Jan 24, 2022

As you can see, there is still a little bit of thinking to do to make sure we do not reinvent the wheel:-)

It sure does!

It might also be the case that vendors re-use some certs to sign a "Pack-Signer RootCA" and have that one saved in cpackget's secure store. This is getting interesting. The tool will have to be very flexible to accommodate everyone's needs

@fred-r
Copy link

fred-r commented Jan 24, 2022

As you can see, there is still a little bit of thinking to do to make sure we do not reinvent the wheel:-)

It sure does!

It might also be the case that vendors re-use some certs to sign a "Pack-Signer RootCA" and have that one saved in cpackget's secure store. This is getting interesting. The tool will have to be very flexible to accommodate everyone's needs

Yes, and we should also think about people who want to publish a pack without all this signing infrastructure.
Then, users may accept such packs or not.

@chaws
Copy link
Contributor Author

chaws commented Jan 28, 2022

I just saw this tool that might be useful if we ever opt for setting a cert issuer server: https://smallstep.com/

I'm working on a scratch tool that implements things openssl did in @fred-r 's example. I'm not trying to reinvent the wheel here, but instead, by doing so I can really learn about it and properly do the job. For instance, I didn't know you could generate a cert for very specific needs, like signing other certs or simply to encrypt user data.

Just for future reference, I've found this article about x509 & PKI: https://smallstep.com/blog/everything-pki/. It looks very thorough, I haven't finished reading it yet, it's a bit long too.

@Jonny-vb
Copy link

How would this affect local packs? We use software packs for internal libraries and probably don't want to have to start messing around with signing them. Just wanting to make sure this is a use case that isn't forgotten about!

@fred-r
Copy link

fred-r commented May 19, 2022

In my opinion anyway, you should always have the possibility to disable the signature check by default.
This signature check should be optional with the reference tools otherwise many people will be blocked.

But, for people who want more security, then the check could be enabled.

@lud0v1c
Copy link
Contributor

lud0v1c commented Jun 17, 2022

There's now a wiki page for proposals like this, which I added this feature to. Added the proposal Google Doc there for more technical discussion.

@jkrech jkrech added the Discussion Issue to be discussed before further action is taken label Nov 25, 2022
@lud0v1c
Copy link
Contributor

lud0v1c commented Nov 27, 2022

Updated the wiki page regarding the latest implementation and the needed discussion/two possible mechanisms to fully deploy this feature.

@stevep-arm
Copy link

I'm glad to hear that signing is being added to CMSIS packs, I think this will give CMSIS Pack users real benefits.

I have a suggestion that I think will give a more thorough solution than is currently proposed and potentially save time. Many of the concepts of secure package delivery have been implemented by existing systems and the lessons that have been learned from those systems have been written into a project called The Update Framework (TUF).

TUF provides a flexible framework and specification that is designed to allow it to be adopted into any software update system including when retrofitting it as is the case for CMSIS packs. There is a lot of available reading material and videos explaining the benefits of TUF but to understand the potential benefits of implementing TUF over the benefits of implementing the currently proposal TUF's security page gives a list of the attacks and weaknesses it addresses.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Discussion Issue to be discussed before further action is taken
Projects
None yet
Development

No branches or pull requests

6 participants