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
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/credentials/tests/CHIPCert_test_vectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ CHIP_ERROR GetTestCert(uint8_t certType, BitFlags<TestCertLoadFlags> certLoadFla
SELECT_CERT(Node02_05);
SELECT_CERT(Node02_06);
SELECT_CERT(Node02_07);
#undef SELECT_CERT

err = CHIP_ERROR_CA_CERT_NOT_FOUND;

Expand Down Expand Up @@ -133,6 +134,44 @@ const char * GetTestCertName(uint8_t certType)
return nullptr;
}

CHIP_ERROR GetTestCertPubkey(uint8_t certType, const uint8_t *& certPubkey, uint32_t & certPubkeyLen)
{
CHIP_ERROR err;

#define SELECT_CERT(NAME) \
do \
{ \
if (certType == TestCert::k##NAME) \
{ \
certPubkey = sTestCert_##NAME##_PublicKey; \
certPubkeyLen = sTestCert_##NAME##_PublicKey_Len; \
ExitNow(err = CHIP_NO_ERROR); \
} \
} while (0)

SELECT_CERT(Root01);
SELECT_CERT(Root02);
SELECT_CERT(ICA01);
SELECT_CERT(ICA02);
SELECT_CERT(ICA01_1);
SELECT_CERT(FWSign01);
SELECT_CERT(Node01_01);
SELECT_CERT(Node01_02);
SELECT_CERT(Node02_01);
SELECT_CERT(Node02_02);
SELECT_CERT(Node02_03);
SELECT_CERT(Node02_04);
SELECT_CERT(Node02_05);
SELECT_CERT(Node02_06);
SELECT_CERT(Node02_07);
#undef SELECT_CERT

err = CHIP_ERROR_CA_CERT_NOT_FOUND;

exit:
return err;
}

CHIP_ERROR LoadTestCert(ChipCertificateSet & certSet, uint8_t certType, BitFlags<TestCertLoadFlags> certLoadFlags,
BitFlags<CertDecodeFlags> decodeFlags)
{
Expand Down
1 change: 1 addition & 0 deletions src/credentials/tests/CHIPCert_test_vectors.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ enum class TestCertLoadFlags : uint8_t
extern CHIP_ERROR GetTestCert(uint8_t certType, BitFlags<TestCertLoadFlags> certLoadFlags, const uint8_t *& certData,
uint32_t & certDataLen);
extern const char * GetTestCertName(uint8_t certType);
extern CHIP_ERROR GetTestCertPubkey(uint8_t certType, const uint8_t *& certPubkey, uint32_t & certPubkeyLen);
extern CHIP_ERROR LoadTestCert(ChipCertificateSet & certSet, uint8_t certType, BitFlags<TestCertLoadFlags> certLoadFlags,
BitFlags<CertDecodeFlags> decodeFlags);

Expand Down
16 changes: 16 additions & 0 deletions src/crypto/CHIPCryptoPAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@

#include <core/CHIPError.h>
#include <support/CodeUtils.h>
#include <support/Span.h>

#include <stddef.h>
#include <string.h>

namespace chip {
namespace Crypto {

const size_t kMax_x509_Certificate_Length = 600;

const size_t kP256_FE_Length = 32;
const size_t kP256_Point_Length = (2 * kP256_FE_Length + 1);
const size_t kSHA256_Hash_Length = 32;
Expand Down Expand Up @@ -898,6 +901,19 @@ class Spake2p_P256_SHA256_HKDF_HMAC : public Spake2p
**/
void ClearSecretData(uint8_t * buf, uint32_t len);

typedef CapacityBoundBuffer<kMax_x509_Certificate_Length> X509DerCertificate;

CHIP_ERROR LoadCertsFromPKCS7(const char * pkcs7, X509DerCertificate * x509list, uint32_t * max_certs);

CHIP_ERROR LoadCertFromPKCS7(const char * pkcs7, X509DerCertificate * x509list, uint32_t n_cert);

CHIP_ERROR GetNumberOfCertsFromPKCS7(const char * pkcs7, uint32_t * n_certs);

CHIP_ERROR ValidateCertificateChain(const uint8_t * rootCertificate, size_t rootCertificateLen, const uint8_t * caCertificate,
size_t caCertificateLen, const uint8_t * leafCertificate, size_t leafCertificateLen);

CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256PublicKey & pubkey);

} // namespace Crypto
} // namespace chip

Expand Down
230 changes: 230 additions & 0 deletions src/crypto/CHIPCryptoPALOpenSSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ namespace Crypto {

#define kKeyLengthInBits 256

typedef struct stack_st_X509 X509_LIST;

enum class DigestType
{
SHA256
Expand Down Expand Up @@ -1560,5 +1562,233 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointIsValid(void * R)
return error;
}

static void security_free_cert_list(X509_LIST * certs)
{
if (certs)
{
sk_X509_pop_free(certs, X509_free);
}
}

CHIP_ERROR LoadCertsFromPKCS7(const char * pkcs7, X509DerCertificate * x509list, uint32_t * max_certs)
{
CHIP_ERROR err = CHIP_NO_ERROR;
X509_LIST * certs = NULL;
BIO * bio_cert = NULL;
PKCS7 * p7 = NULL;
int p7_type = 0;

VerifyOrExit(x509list != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(max_certs != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);

bio_cert = BIO_new_mem_buf(pkcs7, -1);
jpk233 marked this conversation as resolved.
Show resolved Hide resolved

p7 = PEM_read_bio_PKCS7(bio_cert, NULL, NULL, NULL);
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;
}

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;
unsigned char * pX509ListEnd = x509list[i];
unsigned char ** pX509ListAux = &pX509ListEnd;

bytes_written = static_cast<size_t>(i2d_X509(sk_X509_value(certs, static_cast<int>(i)), pX509ListAux));

VerifyOrExit(bytes_written <= x509list[i].Capacity(), err = CHIP_ERROR_NO_MEMORY);

x509list[i].SetLength(bytes_written);
}

exit:
BIO_free_all(bio_cert);
PKCS7_free(p7);
security_free_cert_list(certs);

return err;
}

CHIP_ERROR LoadCertFromPKCS7(const char * pkcs7, X509DerCertificate * x509list, uint32_t n_cert)
{
CHIP_ERROR err = CHIP_NO_ERROR;
X509_LIST * certs = NULL;
BIO * bio_cert = NULL;
PKCS7 * p7 = NULL;
int p7_type = 0;

VerifyOrExit(x509list != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);

bio_cert = BIO_new_mem_buf(pkcs7, -1);

p7 = PEM_read_bio_PKCS7(bio_cert, NULL, NULL, NULL);
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;
}

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;

bytes_written = static_cast<size_t>(i2d_X509(sk_X509_value(certs, static_cast<int>(n_cert)), pX509ListAux));

VerifyOrExit(bytes_written <= x509list->Capacity(), err = CHIP_ERROR_NO_MEMORY);

x509list->SetLength(bytes_written);
}

exit:
BIO_free_all(bio_cert);
PKCS7_free(p7);
security_free_cert_list(certs);

return err;
}

CHIP_ERROR GetNumberOfCertsFromPKCS7(const char * pkcs7, uint32_t * n_certs)
{
CHIP_ERROR err = CHIP_NO_ERROR;
X509_LIST * certs = NULL;
BIO * bio_cert = NULL;
PKCS7 * p7 = NULL;
int p7_type = 0;

VerifyOrExit(n_certs != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);

bio_cert = BIO_new_mem_buf(pkcs7, -1);

p7 = PEM_read_bio_PKCS7(bio_cert, NULL, NULL, NULL);
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;
}

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;
}

CHIP_ERROR ValidateCertificateChain(const uint8_t * rootCertificate, size_t rootCertificateLen, const uint8_t * caCertificate,
size_t caCertificateLen, const uint8_t * leafCertificate, size_t leafCertificateLen)
{
CHIP_ERROR err = CHIP_NO_ERROR;
X509_STORE_CTX * verifyCtx = nullptr;
X509_STORE * store = nullptr;
X509 * x509RootCertificate = nullptr;
X509 * x509CACertificate = nullptr;
X509 * x509LeafCertificate = nullptr;

store = X509_STORE_new();
VerifyOrExit(store != nullptr, err = CHIP_ERROR_NO_MEMORY);

verifyCtx = X509_STORE_CTX_new();
VerifyOrExit(verifyCtx != nullptr, err = CHIP_ERROR_NO_MEMORY);

x509RootCertificate = d2i_X509(NULL, &rootCertificate, static_cast<long>(rootCertificateLen));
VerifyOrExit(x509RootCertificate != nullptr, err = CHIP_ERROR_NO_MEMORY);

err = X509_STORE_add_cert(store, x509RootCertificate);
VerifyOrExit(err == 1, err = CHIP_ERROR_INTERNAL);

x509CACertificate = d2i_X509(NULL, &caCertificate, static_cast<long>(caCertificateLen));
VerifyOrExit(x509CACertificate != nullptr, err = CHIP_ERROR_NO_MEMORY);

err = X509_STORE_add_cert(store, x509CACertificate);
VerifyOrExit(err == 1, err = CHIP_ERROR_INTERNAL);

x509LeafCertificate = d2i_X509(NULL, &leafCertificate, static_cast<long>(leafCertificateLen));
VerifyOrExit(x509LeafCertificate != nullptr, err = CHIP_ERROR_NO_MEMORY);

err = X509_STORE_CTX_init(verifyCtx, store, x509LeafCertificate, NULL);
VerifyOrExit(err == 1, err = CHIP_ERROR_INTERNAL);

err = X509_verify_cert(verifyCtx);
VerifyOrExit(err == 1, err = CHIP_ERROR_CERT_NOT_TRUSTED);

err = CHIP_NO_ERROR;

exit:
X509_free(x509LeafCertificate);
X509_free(x509CACertificate);
X509_free(x509RootCertificate);
X509_STORE_CTX_free(verifyCtx);
X509_STORE_free(store);

return err;
}

CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256PublicKey & pubkey)
{
CHIP_ERROR err = CHIP_NO_ERROR;
EVP_PKEY * pkey = nullptr;
X509 * x509certificate = nullptr;
const unsigned char * pCertificate = certificate.data();
const unsigned char ** ppCertificate = &pCertificate;
unsigned char * pPubkey = pubkey;
unsigned char ** ppPubkey = &pPubkey;
int pkeyLen;

x509certificate = d2i_X509(NULL, ppCertificate, static_cast<long>(certificate.size()));
VerifyOrExit(x509certificate != nullptr, err = CHIP_ERROR_NO_MEMORY);

pkey = X509_get_pubkey(x509certificate);
VerifyOrExit(pkey != nullptr, err = CHIP_ERROR_INTERNAL);
VerifyOrExit(EVP_PKEY_base_id(pkey) == EVP_PKEY_EC, err = CHIP_ERROR_INTERNAL);
VerifyOrExit(EVP_PKEY_bits(pkey) == 256, err = CHIP_ERROR_INTERNAL);

pkeyLen = i2d_PublicKey(pkey, NULL);
VerifyOrExit(pkeyLen == static_cast<int>(pubkey.Length()), err = CHIP_ERROR_INTERNAL);

VerifyOrExit(i2d_PublicKey(pkey, ppPubkey) == pkeyLen, err = CHIP_ERROR_INTERNAL);

exit:
EVP_PKEY_free(pkey);
X509_free(x509certificate);

return err;
}

} // namespace Crypto
} // namespace chip
26 changes: 26 additions & 0 deletions src/crypto/CHIPCryptoPALmbedTLS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1198,5 +1198,31 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointIsValid(void * R)
return CHIP_NO_ERROR;
}

CHIP_ERROR LoadCertsFromPKCS7(const char * pkcs7, X509DerCertificate * x509list, uint32_t * max_certs)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}

CHIP_ERROR LoadCertFromPKCS7(const char * pkcs7, X509DerCertificate * x509list, uint32_t n_cert)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}

CHIP_ERROR GetNumberOfCertsFromPKCS7(const char * pkcs7, uint32_t * n_certs)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}

CHIP_ERROR ValidateCertificateChain(const uint8_t * rootCertificate, size_t rootCertificateLen, const uint8_t * caCertificate,
size_t caCertificateLen, const uint8_t * leafCertificate, size_t leafCertificateLen)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}

CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256PublicKey & pubkey)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}

} // namespace Crypto
} // namespace chip
1 change: 1 addition & 0 deletions src/crypto/tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ chip_test_suite("tests") {
cflags = [ "-Wconversion" ]

public_deps = [
"${chip_root}/src/credentials/tests:cert_test_vectors",
"${chip_root}/src/crypto",
"${chip_root}/src/lib/core",
"${chip_root}/src/platform",
Expand Down
Loading