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

PKCS7 data support #7282

Merged
merged 7 commits into from
Jun 9, 2021
Merged

PKCS7 data support #7282

merged 7 commits into from
Jun 9, 2021

Conversation

jpk233
Copy link
Contributor

@jpk233 jpk233 commented Jun 1, 2021

Problem

  • We're lacking support within the cryptoPAL libraries for certificate data in PKCS7 format.

Change overview

What's in this PR

  • Introduces new set of APIs - with OpenSSL - for working with PKCS7 data.

Testing

How was this tested? (at least one bullet point required)
* Unit tests were added for validating certificate extraction from PKCS7 format.
* An additional test file was added, X509_PKCS7Extraction_test_vectors.h, containing dummy certificate data to be used for the added unit test.

@todo
Copy link

todo bot commented Jun 1, 2021

-> error value

// TODO -> error value
VerifyOrExit(p7 != nullptr, err = CHIP_ERROR_WRONG_CERT_TYPE);
p7_type = OBJ_obj2nid(p7->type);
if (p7_type == NID_pkcs7_signed)
{
certs = p7->d.sign->cert;
}
else if (p7_type == NID_pkcs7_signedAndEnveloped)
{
certs = p7->d.signed_and_enveloped->cert;


This comment was generated by todo based on a TODO comment in a0256fc in #7282. cc @jpk233.

@boring-cyborg boring-cyborg bot added the crypto label Jun 1, 2021
@todo
Copy link

todo bot commented Jun 1, 2021

-> error value

// TODO -> error value
VerifyOrExit(certs != NULL, err = CHIP_ERROR_WRONG_CERT_TYPE);
VerifyOrExit(static_cast<uint32_t>(sk_X509_num(certs)) <= *max_certs, err = CHIP_ERROR_WRONG_CERT_TYPE);
*max_certs = static_cast<uint32_t>(sk_X509_num(certs));
certs = X509_chain_up_ref(certs);
for (uint32_t i = 0; i < *max_certs; ++i)
{
size_t bytes_written = 0;


This comment was generated by todo based on a TODO comment in a0256fc in #7282. cc @jpk233.

@todo
Copy link

todo bot commented Jun 1, 2021

-> error value

// TODO -> error value
VerifyOrExit(p7 != nullptr, err = CHIP_ERROR_WRONG_CERT_TYPE);
p7_type = OBJ_obj2nid(p7->type);
if (p7_type == NID_pkcs7_signed)
{
certs = p7->d.sign->cert;
}
else if (p7_type == NID_pkcs7_signedAndEnveloped)
{
certs = p7->d.signed_and_enveloped->cert;


This comment was generated by todo based on a TODO comment in a0256fc in #7282. cc @jpk233.

@todo
Copy link

todo bot commented Jun 1, 2021

-> error value

// TODO -> error value
VerifyOrExit(certs != NULL, err = CHIP_ERROR_WRONG_CERT_TYPE);
VerifyOrExit(n_cert < static_cast<uint32_t>(sk_X509_num(certs)), err = CHIP_ERROR_INVALID_ARGUMENT);
certs = X509_chain_up_ref(certs);
{
size_t bytes_written = 0;
unsigned char * pX509ListEnd = reinterpret_cast<unsigned char *>(x509list);
unsigned char ** pX509ListAux = &pX509ListEnd;


This comment was generated by todo based on a TODO comment in a0256fc in #7282. cc @jpk233.

@todo
Copy link

todo bot commented Jun 1, 2021

-> error value

// TODO -> error value
VerifyOrExit(p7 != nullptr, err = CHIP_ERROR_WRONG_CERT_TYPE);
p7_type = OBJ_obj2nid(p7->type);
if (p7_type == NID_pkcs7_signed)
{
certs = p7->d.sign->cert;
}
else if (p7_type == NID_pkcs7_signedAndEnveloped)
{
certs = p7->d.signed_and_enveloped->cert;


This comment was generated by todo based on a TODO comment in a0256fc in #7282. cc @jpk233.

@todo
Copy link

todo bot commented Jun 1, 2021

-> error value

// TODO -> error value
VerifyOrExit(certs != NULL, err = CHIP_ERROR_WRONG_CERT_TYPE);
*n_certs = static_cast<uint32_t>(sk_X509_num(certs));
exit:
BIO_free_all(bio_cert);
PKCS7_free(p7);
return err;
}


This comment was generated by todo based on a TODO comment in a0256fc in #7282. cc @jpk233.

@woody-apple
Copy link
Contributor

/rebase

@todo
Copy link

todo bot commented Jun 2, 2021

-> error value

// TODO -> error value
VerifyOrExit(p7 != nullptr, err = CHIP_ERROR_WRONG_CERT_TYPE);
p7_type = OBJ_obj2nid(p7->type);
if (p7_type == NID_pkcs7_signed)
{
certs = p7->d.sign->cert;
}
else if (p7_type == NID_pkcs7_signedAndEnveloped)
{
certs = p7->d.signed_and_enveloped->cert;


This comment was generated by todo based on a TODO comment in a36794b in #7282. cc @jpk233.

@todo
Copy link

todo bot commented Jun 2, 2021

-> error value

// TODO -> error value
VerifyOrExit(certs != NULL, err = CHIP_ERROR_WRONG_CERT_TYPE);
VerifyOrExit(static_cast<uint32_t>(sk_X509_num(certs)) <= *max_certs, err = CHIP_ERROR_WRONG_CERT_TYPE);
*max_certs = static_cast<uint32_t>(sk_X509_num(certs));
certs = X509_chain_up_ref(certs);
for (uint32_t i = 0; i < *max_certs; ++i)
{
size_t bytes_written = 0;


This comment was generated by todo based on a TODO comment in a36794b in #7282. cc @jpk233.

@todo
Copy link

todo bot commented Jun 2, 2021

-> error value

// TODO -> error value
VerifyOrExit(p7 != nullptr, err = CHIP_ERROR_WRONG_CERT_TYPE);
p7_type = OBJ_obj2nid(p7->type);
if (p7_type == NID_pkcs7_signed)
{
certs = p7->d.sign->cert;
}
else if (p7_type == NID_pkcs7_signedAndEnveloped)
{
certs = p7->d.signed_and_enveloped->cert;


This comment was generated by todo based on a TODO comment in a36794b in #7282. cc @jpk233.

@todo
Copy link

todo bot commented Jun 2, 2021

-> error value

// TODO -> error value
VerifyOrExit(certs != NULL, err = CHIP_ERROR_WRONG_CERT_TYPE);
VerifyOrExit(n_cert < static_cast<uint32_t>(sk_X509_num(certs)), err = CHIP_ERROR_INVALID_ARGUMENT);
certs = X509_chain_up_ref(certs);
{
size_t bytes_written = 0;
unsigned char * pX509ListEnd = reinterpret_cast<unsigned char *>(x509list);
unsigned char ** pX509ListAux = &pX509ListEnd;


This comment was generated by todo based on a TODO comment in a36794b in #7282. cc @jpk233.

@todo
Copy link

todo bot commented Jun 2, 2021

-> error value

// TODO -> error value
VerifyOrExit(p7 != nullptr, err = CHIP_ERROR_WRONG_CERT_TYPE);
p7_type = OBJ_obj2nid(p7->type);
if (p7_type == NID_pkcs7_signed)
{
certs = p7->d.sign->cert;
}
else if (p7_type == NID_pkcs7_signedAndEnveloped)
{
certs = p7->d.signed_and_enveloped->cert;


This comment was generated by todo based on a TODO comment in a36794b in #7282. cc @jpk233.

@todo
Copy link

todo bot commented Jun 2, 2021

-> error value

// TODO -> error value
VerifyOrExit(certs != NULL, err = CHIP_ERROR_WRONG_CERT_TYPE);
*n_certs = static_cast<uint32_t>(sk_X509_num(certs));
exit:
BIO_free_all(bio_cert);
PKCS7_free(p7);
return err;
}


This comment was generated by todo based on a TODO comment in a36794b in #7282. cc @jpk233.

@@ -36,6 +36,8 @@
namespace chip {
namespace Crypto {

const size_t kMax_x509_Certificate_Length = 1024;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this come from?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it appears the CSR (or elements thereof) is limited to 1024 bytes. I'm not seeing the actual certificate size limit in the spec though. I assume there has to be a limit. I'm just looking for confirmation that this is correctly set to that limit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So now I see that this was changed to 600 bytes. And indeed, the spec does clarify that the root CA certificate must be 600 or fewer bytes. But do we have different limits for ICA or NOC? This part wasn't clear to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, only root certificates have a defined max length, but this ensures standard compact sizing when dealing with a full certificate chain.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I guess then I don't understand how we're supposed to succeed in this PR. It looks like the PR attempts to also store CA and leaf certs within kMax_x509_Certificate_Length bytes, even though this is only guaranteed to fit the root cert.

This doesn't seem like it will work. Am I missing something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 600 limit is for DAC and PAI and PAA which are DER.

For opcerts, RCAC, ICAC and NOC are supposed to be TLV certs and max 400 bytes.

@todo
Copy link

todo bot commented Jun 2, 2021

Add mbedTLS implementation for PKCS7 and Pubkey Extraction methods

// TODO: Add mbedTLS implementation for PKCS7 and Pubkey Extraction methods
#if CHIP_CRYPTO_OPENSSL
static void TestX509_PKCS7Extraction(nlTestSuite * inSuite, void * inContext)
{
CHIP_ERROR err = CHIP_NO_ERROR;
X509DerCertificate x509list[3];
uint32_t max_certs = sizeof(x509list) / sizeof(X509DerCertificate);
err = LoadCertsFromPKCS7(reinterpret_cast<const uint8_t *>(pem_pkcs7_blob), x509list, &max_certs);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);


This comment was generated by todo based on a TODO comment in 9136fa8 in #7282. cc @jpk233.

Copy link
Contributor

@tcarmelveilleux tcarmelveilleux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • PKCS Fixing company for Chris #7 is not called-out anywhere in spec
  • OpCSR response has a CSR in PKCS Update cxx_rules #10
  • Credentials on device are supposed to be Matter TLV certificates (see 6.4. Operational Certificate Encoding in 0.7-core ballot version.

So the question really is: why is PKCS #7 format entering the picture at this time? What is the usage expected of introducing this in the codebase?

@hawk248
Copy link

hawk248 commented Jun 4, 2021

So the question really is: why is PKCS #7 format entering the picture at this time? What is the usage expected of introducing this in the codebase?

Most PKI systems deliver cert chain in PKCS7 format ... spec does not specify that but most Commissioners will benefit from this API.

@tcarmelveilleux
Copy link
Contributor

So the question really is: why is PKCS #7 format entering the picture at this time? What is the usage expected of introducing this in the codebase?

Most PKI systems deliver cert chain in PKCS7 format ... spec does not specify that but most Commissioners will benefit from this API.

So is the point of this PR to add optional implementation-specific things that only some commissioners will use? Why would this code not only exist in a particular commissioning example? The code for how the chain resulting from a CSR comes in can be illustrated, but is really code that will be particular to every implementation. The PKCS 7 code added here does not appear to be used, just added to the library. Is there a subsequent PR that will introduce code depending on it?

@hawk248
Copy link

hawk248 commented Jun 4, 2021

So the question really is: why is PKCS #7 format entering the picture at this time? What is the usage expected of introducing this in the codebase?

Most PKI systems deliver cert chain in PKCS7 format ... spec does not specify that but most Commissioners will benefit from this API.

So is the point of this PR to add optional implementation-specific things that only some commissioners will use? Why would this code not only exist in a particular commissioning example? The code for how the chain resulting from a CSR comes in can be illustrated, but is really code that will be particular to every implementation. The PKCS 7 code added here does not appear to be used, just added to the library. Is there a subsequent PR that will introduce code depending on it?

PKCS7 is a generic standard to encode chain certificates just as pkcs10 provides a standard way to request a certificate. We also know that commissioners will not be just apps but can also be devices. So this will have utility across many implementations - otherwise we are paving the way for forks early on in the project. Do you propose a way for a comissioner to receive a certificate chain other than pkcs7 ? We will be happy to look at it if you provide implementation example.

And yes, we will push additional PR's that will make use of this function.

@woody-apple
Copy link
Contributor

/rebase

@hawk248 hawk248 requested a review from tcarmelveilleux June 6, 2021 21:08
Copy link
Contributor

@tcarmelveilleux tcarmelveilleux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I approve this PR, conditional on ensuring that commissionee devices (accessories) do not see an increase flash cost due to the insertion of PKCS7 support, which only commissioner <-> CA communication would ever use, and only in some cases.

@hawk248
Copy link

hawk248 commented Jun 8, 2021

I approve this PR, conditional on ensuring that commissionee devices (accessories) do not see an increase flash cost due to the insertion of PKCS7 support, which only commissioner <-> CA communication would ever use, and only in some cases.

Thanks. Makes sense.

@restyled-io restyled-io bot mentioned this pull request Jun 8, 2021
Copy link

@hawk248 hawk248 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@hawk248 hawk248 merged commit 77e727c into project-chip:master Jun 9, 2021
nikita-s-wrk pushed a commit to nikita-s-wrk/connectedhomeip that referenced this pull request Sep 23, 2021
* Add APIs to work with PKCS7 data

* Initial mbedTLS function support, not yet implemented as mbedtls does not currently support pkcs7

* Update mbedTLS tests, define certificate size as per spec

* Update with Andy's suggestions

* Fixed duplicate changes in cryptopal

* Restyle changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants