Skip to content

Commit

Permalink
feat(plugin): Add CertificateGroup function to retrieve all CRLs asso…
Browse files Browse the repository at this point in the history
…ciated with a certificate.
  • Loading branch information
NoelGraf authored and jpfr committed Oct 16, 2024
1 parent b75eac4 commit fc74493
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/open62541/plugin/certificategroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ struct UA_CertificateGroup {
UA_StatusCode (*removeFromTrustList)(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList);

UA_StatusCode (*getRejectedList)(UA_CertificateGroup *certGroup, UA_ByteString **rejectedList, size_t *rejectedListSize);
/* Provides all associated CRLs for a CA certificate. */
UA_StatusCode (*getCertificateCrls)(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
const UA_Boolean isTrusted, UA_ByteString **crls, size_t *crlsSize);

UA_StatusCode (*verifyCertificate)(UA_CertificateGroup *certGroup, const UA_ByteString *certificate);

Expand Down
104 changes: 104 additions & 0 deletions plugins/crypto/mbedtls/certificategroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ struct MemoryCertStore {
mbedtls_x509_crl issuerCrls;
};

static UA_Boolean mbedtlsCheckCA(mbedtls_x509_crt *cert);

static UA_StatusCode
MemoryCertStore_removeFromTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
/* Check parameter */
Expand Down Expand Up @@ -132,6 +134,107 @@ MemoryCertStore_getRejectedList(UA_CertificateGroup *certGroup, UA_ByteString **
return retval;
}

static UA_StatusCode
mbedtlsCheckCrlMatch(mbedtls_x509_crt *cert, mbedtls_x509_crl *crl) {
UA_StatusCode retval = UA_STATUSCODE_GOOD;

/* Check if the certificate is a CA certificate.
* Only a CA certificate can have a CRL. */
if(!mbedtlsCheckCA(cert))
return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;

char certSubject[MBEDTLS_X509_MAX_DN_NAME_SIZE];
char crlIssuer[MBEDTLS_X509_MAX_DN_NAME_SIZE];

mbedtls_x509_dn_gets(certSubject, sizeof(certSubject), &cert->subject);
mbedtls_x509_dn_gets(crlIssuer, sizeof(crlIssuer), &crl->issuer);

if(strncmp(certSubject, crlIssuer, MBEDTLS_X509_MAX_DN_NAME_SIZE) == 0) {
retval = UA_STATUSCODE_GOOD;
} else {
retval = UA_STATUSCODE_BADNOMATCH;
}

return retval;
}

static UA_StatusCode
mbedtlsFindCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
const UA_ByteString *crlList, const size_t crlListSize,
UA_ByteString **crls, size_t *crlsSize) {
mbedtls_x509_crt cert;
mbedtls_x509_crt_init(&cert);
UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SERVER,
"An error occurred while parsing the certificate.");
return retval;
}
UA_Boolean foundMatch = false;
for(size_t i = 0; i < crlListSize; i++) {
mbedtls_x509_crl crl;
mbedtls_x509_crl_init(&crl);
retval = UA_mbedTLS_LoadCrl(&crlList[i], &crl);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SERVER,
"An error occurred while parsing the crl.");
mbedtls_x509_crt_free(&cert);
return retval;
}

retval = mbedtlsCheckCrlMatch(&cert, &crl);
mbedtls_x509_crl_free(&crl);

if(retval == UA_STATUSCODE_BADNOMATCH) {
continue;
}
/* If it is not a CA certificate, there is no crl list. */
if(retval == UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED) {
UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SERVER,
"The certificate is not a CA certificate and therefore does not have a CRL.");
mbedtls_x509_crt_free(&cert);
return retval;
}
/* Continue the search, as a certificate may be associated with multiple CRLs. */
foundMatch = true;
retval = UA_Array_appendCopy((void **)crls, crlsSize, &crlList[i],
&UA_TYPES[UA_TYPES_BYTESTRING]);
if(retval != UA_STATUSCODE_GOOD) {
mbedtls_x509_crt_free(&cert);
return retval;
}
}
mbedtls_x509_crt_free(&cert);

if(!foundMatch)
return UA_STATUSCODE_BADNOMATCH;

return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
MemoryCertStore_getCertificateCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
const UA_Boolean isTrusted, UA_ByteString **crls,
size_t *crlsSize) {
/* Check parameter */
if(certGroup == NULL || certificate == NULL || crls == NULL) {
return UA_STATUSCODE_BADINTERNALERROR;
}

MemoryCertStore *context = (MemoryCertStore *)certGroup->context;

if(isTrusted) {
return mbedtlsFindCrls(certGroup, certificate,
context->trustList.trustedCrls,
context->trustList.trustedCrlsSize, crls,
crlsSize);
}
return mbedtlsFindCrls(certGroup, certificate,
context->trustList.issuerCrls,
context->trustList.issuerCrlsSize, crls,
crlsSize);
}

static UA_StatusCode
MemoryCertStore_addToRejectedList(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
/* Check parameter */
Expand Down Expand Up @@ -521,6 +624,7 @@ UA_CertificateGroup_Memorystore(UA_CertificateGroup *certGroup,
certGroup->addToTrustList = MemoryCertStore_addToTrustList;
certGroup->removeFromTrustList = MemoryCertStore_removeFromTrustList;
certGroup->getRejectedList = MemoryCertStore_getRejectedList;
certGroup->getCertificateCrls = MemoryCertStore_getCertificateCrls;
certGroup->verifyCertificate = MemoryCertStore_verifyCertificate;
certGroup->clear = MemoryCertStore_clear;

Expand Down
108 changes: 108 additions & 0 deletions plugins/crypto/openssl/certificategroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,113 @@ MemoryCertStore_getRejectedList(UA_CertificateGroup *certGroup, UA_ByteString **
return retval;
}

static UA_StatusCode
openSSLCheckCrlMatch(X509 *cert, X509_CRL *crl) {
UA_StatusCode retval = UA_STATUSCODE_GOOD;

/* Check if the certificate is a CA certificate.
* Only a CA certificate can have a CRL. */
BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS*)X509_get_ext_d2i(cert, NID_basic_constraints, NULL, NULL);
if(!bs || bs->ca == 0) {
/* The certificate is not a CA or the extension is missing */
BASIC_CONSTRAINTS_free(bs);
return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
}
BASIC_CONSTRAINTS_free(bs);

X509_NAME *certSubject = X509_get_subject_name(cert);
if(!certSubject)
return UA_STATUSCODE_BADINTERNALERROR;

X509_NAME *crlIssuer = X509_CRL_get_issuer(crl);
if(!crlIssuer) {
return UA_STATUSCODE_BADINTERNALERROR;
}

if(X509_NAME_cmp(certSubject, crlIssuer) == 0) {
retval = UA_STATUSCODE_GOOD;
} else {
retval = UA_STATUSCODE_BADNOMATCH;
}

return retval;
}

static UA_StatusCode
openSSLFindCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
const UA_ByteString *crlList, const size_t crlListSize,
UA_ByteString **crls, size_t *crlsSize) {
UA_StatusCode retval = UA_STATUSCODE_GOOD;

X509 *cert = UA_OpenSSL_LoadCertificate(certificate);
if(!cert)
return UA_STATUSCODE_BADINTERNALERROR;

UA_Boolean foundMatch = false;
for(size_t i = 0; i < crlListSize; i++) {
X509_CRL *crl = UA_OpenSSL_LoadCrl(&crlList[i]);
if(!crl) {
X509_free(cert);
return UA_STATUSCODE_BADINTERNALERROR;
}

retval = openSSLCheckCrlMatch(cert, crl);
X509_CRL_free(crl);
if(retval == UA_STATUSCODE_BADNOMATCH) {
continue;
}
/* If it is not a CA certificate, there is no crl list. */
if(retval == UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED) {
UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SERVER,
"The certificate is not a CA certificate and therefore does not have a CRL.");
X509_free(cert);
return retval;
}
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SERVER,
"An error occurred while determining the appropriate CRL.");
X509_free(cert);
return retval;
}
/* Continue the search, as a certificate may be associated with multiple CRLs. */
foundMatch = true;
retval = UA_Array_appendCopy((void **)crls, crlsSize, &crlList[i],
&UA_TYPES[UA_TYPES_BYTESTRING]);
if(retval != UA_STATUSCODE_GOOD) {
X509_free(cert);
return retval;
}
}
X509_free(cert);
if(!foundMatch)
return UA_STATUSCODE_BADNOMATCH;

return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
MemoryCertStore_getCertificateCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
const UA_Boolean isTrusted, UA_ByteString **crls,
size_t *crlsSize) {
/* Check parameter */
if(certGroup == NULL || certificate == NULL || crls == NULL) {
return UA_STATUSCODE_BADINTERNALERROR;
}

MemoryCertStore *context = (MemoryCertStore *)certGroup->context;

if(isTrusted) {
return openSSLFindCrls(certGroup, certificate,
context->trustList.trustedCrls,
context->trustList.trustedCrlsSize, crls,
crlsSize);
}
return openSSLFindCrls(certGroup, certificate,
context->trustList.issuerCrls,
context->trustList.issuerCrlsSize, crls,
crlsSize);
}

static UA_StatusCode
MemoryCertStore_addToRejectedList(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
/* Check parameter */
Expand Down Expand Up @@ -574,6 +681,7 @@ UA_CertificateGroup_Memorystore(UA_CertificateGroup *certGroup,
certGroup->addToTrustList = MemoryCertStore_addToTrustList;
certGroup->removeFromTrustList = MemoryCertStore_removeFromTrustList;
certGroup->getRejectedList = MemoryCertStore_getRejectedList;
certGroup->getCertificateCrls = MemoryCertStore_getCertificateCrls;
certGroup->verifyCertificate = MemoryCertStore_verifyCertificate;
certGroup->clear = MemoryCertStore_clear;

Expand Down
18 changes: 18 additions & 0 deletions plugins/crypto/ua_certificategroup_filestore.c
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,23 @@ FileCertStore_getRejectedList(UA_CertificateGroup *certGroup, UA_ByteString **re
return context->store->getRejectedList(context->store, rejectedList, rejectedListSize);
}

static UA_StatusCode
FileCertStore_getCertificateCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
const UA_Boolean isTrusted, UA_ByteString **crls,
size_t *crlsSize) {
/* Check parameter */
if(certGroup == NULL || certificate == NULL || crls == NULL) {
return UA_STATUSCODE_BADINTERNALERROR;
}
FileCertStore *context = (FileCertStore *)certGroup->context;
/* It will only re-read the Cert store on the file system if there have been changes to files. */
UA_StatusCode retval = reloadTrustStore(certGroup);
if(retval != UA_STATUSCODE_GOOD)
return retval;

return context->store->getCertificateCrls(context->store, certificate, isTrusted, crls, crlsSize);
}

static UA_StatusCode
FileCertStore_verifyCertificate(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
/* Check parameter */
Expand Down Expand Up @@ -678,6 +695,7 @@ UA_CertificateGroup_Filestore(UA_CertificateGroup *certGroup,
certGroup->addToTrustList = FileCertStore_addToTrustList;
certGroup->removeFromTrustList = FileCertStore_removeFromTrustList;
certGroup->getRejectedList = FileCertStore_getRejectedList;
certGroup->getCertificateCrls = FileCertStore_getCertificateCrls;
certGroup->verifyCertificate = FileCertStore_verifyCertificate;
certGroup->clear = FileCertStore_clear;

Expand Down
2 changes: 2 additions & 0 deletions plugins/crypto/ua_certificategroup_none.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ void UA_CertificateGroup_AcceptAll(UA_CertificateGroup *certGroup) {
certGroup->setTrustList = NULL;
certGroup->addToTrustList = NULL;
certGroup->removeFromTrustList = NULL;
certGroup->getRejectedList = NULL;
certGroup->getCertificateCrls = NULL;
}

#ifndef UA_ENABLE_ENCRYPTION
Expand Down

0 comments on commit fc74493

Please sign in to comment.