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

Creating X509 self signed CA cert via PKCS11 module #4269

Open
jacobschloss opened this issue Jul 28, 2024 · 7 comments
Open

Creating X509 self signed CA cert via PKCS11 module #4269

jacobschloss opened this issue Jul 28, 2024 · 7 comments
Labels
enhancement Enhancement or new feature

Comments

@jacobschloss
Copy link

jacobschloss commented Jul 28, 2024

I'm trying to make a self signed CA cert for a private key held on a ATECC608C-TNGTLS chip via PKCS11. ATECC608* chips only support secp256r1 ECC keys.

This chip has a factory burned master key I want to make a self/internally signed CA cert for, and 3 internal key slots for short term rotating keys. I want to make X509 certs for the rotating keys, a CA key for the master key, and sign the rotating keys's certificates with the master key. The on-chip master key also has x509 certs traceable to a Microchip Inc. root key.

Loading a key pair (eg a Botan::PKCS11::PKCS11_ECDSA_PrivateKey) and on-chip raw signing seems to be working using Microchip's cryptoauthlib's PKCS11 interface.

I am wondering if my issue is somewhat similar to #3891, where the SoftHSM does not support multipart signing.

The PKCS11 provider lib only seems to support signatures in "Raw" mode without offloaded SHA-256 checksum calculation. The ATECC608C-TNGTLS supports SHA-256, but only as a separate operation and not part of the sign command which only supports signing an externally created 32b digest.

Eg,
Botan::PK_Signer signer(priv_key_handle, m_rng, "Raw", Botan::Signature_Format::Standard, "pkcs11");
signing a 32byte pre-calculated digest message works, but
Botan::PK_Signer signer(priv_key_handle, m_rng, "SHA-256", Botan::Signature_Format::Standard, "pkcs11");
returns a PKCS11 error.

Trying to call
Botan::X509_Certificate ca_cert = Botan::X509::create_self_signed_cert(ca_cert_opt, *pkcs11_priv_key, "SHA-256", rng);
returns the same error as a Botan::PK_Signer in SHA-256 mode.
Botan::X509_Certificate ca_cert = Botan::X509::create_self_signed_cert(ca_cert_opt, *pkcs11_priv_key, "Raw", rng);
returns a Botan error "No OID associated with name 'ECDSA/Raw'", which seems reasonable I suppose.

I can attach my full code if it helps, need to extract it to a new mini demo if needed.

I am using Botan 3.5.0, built locally from github sources.

Is there a way to get the X509 signing machinery to do the SHA-256 hash in software host side before asking the PKCS11 module to do the signature?

@jacobschloss
Copy link
Author

jacobschloss commented Jul 28, 2024

I also was looking at a workflow using

Botan::X509::create_cert_req

and then

Botan::X509_Object::make_signed

with an external PK_Signer, but ran into similar issues with a PKCS11 error. I was planning on using Botan::X509::create_cert_req for the rotating keys which I'd then sign with the master / X509_CA key.

@jacobschloss
Copy link
Author

The supported mechanism types are

0x00000250
0x00000251
0x00000252
0x00001040
0x00001041
0x00001081
0x00001082
0x00001085
0x00001086
0x00001087
0x00001088
0x0000108A
0x0000108B
0x00001104
0x00001105

eg CKM_ECDSA but not CKM_ECDSA_SHA256

@randombit
Copy link
Owner

Quite an interesting situation.

I think this can be made to work with the code as it stands, but it's a bit hairy

  • Define a new Private_Key type which holds internally your PKCS11_ECDSA_PrivateKey
  • This private key implements create_signature_op and returns from there a PK_Ops::Signature. Basically this outer/wrapper Signature impl would create a PK_Ops::Signature of the inner key (using "Raw"), prehash its input on the CPU, and then forward the final hash to the PKCS11 implementation.

We should be able to do better here. A couple of options that come to mind off the top of my head

  • Define some naming convention for prehashing. Say "SHA-256/Raw" or whatever.
  • If a PKCS11 signing/verification operation sees this, it knows to use a Raw mechanism with the PKCS11 library and prehashes on the CPU.

This might well be useful even when the device does support the hash since you don't have to send the entire message you're signing over potentially slow device links.

Alternately we could support a fallback option

  • Given a request to sign using "SHA-256", try precisely that.
  • If the mechanism fails, retry with "Raw" and prehashing.

This would be nicer in some ways; things would just work in the obvious way. But it eliminates being able to opt into prehashing as a performance optimization if the device does support signing with a hash, and it's also kind of magic/potentially surprising, which I like to avoid where possible.

@jacobschloss
Copy link
Author

jacobschloss commented Jul 29, 2024

  • Define a new Private_Key type which holds internally your PKCS11_ECDSA_PrivateKey
  • This private key implements create_signature_op and returns from there a PK_Ops::Signature. Basically this outer/wrapper Signature impl would create a PK_Ops::Signature of the inner key (using "Raw"), prehash its input on the CPU, and then forward the final hash to the PKCS11 implementation.

Ok thanks - I made a custom child of Botan::PK_Ops::Signature and Botan::Private_Key, wrapped my PKCS11 object, and passed these to Botan::X509::create_self_signed_cert and was able to get it to output a cert I could pass to the Botan::X509_CA constructor.

This probably works ok for the time being. I /might/ just use the native SDK for the ATECC608 chip in a child class like this instead of going through PKCS11, it makes debugging easier although it is perhaps less generic.

I probably have some bug somewhere still, the generated certificate signature is failing verification (X509_Certificate::check_signature returns false).

I will do some more checking to make sure I am actually getting the correct data in and out of the chip / MCP's SDK to see if that is the cause of the signature verification failure.

  • If a PKCS11 signing/verification operation sees this, it knows to use a Raw mechanism with the PKCS11 library and prehashes on the CPU.

This might be nice, on pretty much any platform I'm likely to use it will be faster to hash on the host than transfer the whole message over the I2C bus.

Alternately we could support a fallback option

  • Given a request to sign using "SHA-256", try precisely that.
  • If the mechanism fails, retry with "Raw" and prehashing.

This would be nicer in some ways; things would just work in the obvious way. But it eliminates being able to opt into prehashing as a performance optimization if the device does support signing with a hash, and it's also kind of magic/potentially surprising, which I like to avoid where possible.

Yeah, I'd lean towards manual mode selection personally. I also like to avoid potential unexpected magic. Also the bus is slow enough that the latency of an extra failed sign attempt might be noticeable, or at least undesired. (At 100kbit/s, we only get to send 32 Bytes about 400 times a second, and the bus is shared with other things).

@jacobschloss
Copy link
Author

Got a good verification for the signature now - The inner Botan::PK_Signer needed to use Botan::Signature_Format::DerSequence format, I had Standard.

@reneme
Copy link
Collaborator

reneme commented Jul 29, 2024

Define some naming convention for prehashing. Say "SHA-256/Raw" or whatever.

As a side-note: We're currently working on signing support for TPM 2.0 (#3877). For that, such an agreed-upon naming convention would be beneficial as well. I.e. to switch between on-chip and software-based hashing and/or padding.

@reneme
Copy link
Collaborator

reneme commented Jul 29, 2024

We should be able to do better here. A couple of options that come to mind off the top of my head

Apart from (or additionally to) a raw-signing naming convention, we should also be able to use PKCS11::Slot::get_mechanism_list() to figure out what the specific token is capable of and automagically select raw or on-chip hashing. That feels much better than the suggested try-and-fallback approach.

@randombit randombit added the enhancement Enhancement or new feature label Jul 29, 2024
@reneme reneme mentioned this issue Aug 13, 2024
18 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Enhancement or new feature
Projects
None yet
Development

No branches or pull requests

3 participants