Skip to content

Commit

Permalink
fix(plugins): Reenable writing rejected certificates to a reject folder
Browse files Browse the repository at this point in the history
  • Loading branch information
jpfr committed Nov 4, 2024
1 parent 3faba71 commit a7e3196
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 22 deletions.
3 changes: 0 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,8 @@ if(UA_ENABLE_ENCRYPTION STREQUAL "OFF" OR ${_tmp} GREATER -1)
set(UA_ENABLE_ENCRYPTION_MBEDTLS ON)
elseif(UA_ENABLE_ENCRYPTION STREQUAL "OPENSSL")
set(UA_ENABLE_ENCRYPTION_OPENSSL ON)
set(UA_ENABLE_CERT_REJECTED_DIR OFF)
elseif(UA_ENABLE_ENCRYPTION STREQUAL "LIBRESSL")
set(UA_ENABLE_ENCRYPTION_LIBRESSL ON)
set(UA_ENABLE_CERT_REJECTED_DIR OFF)
endif()
# Only for backward compatability
elseif(UA_ENABLE_ENCRYPTION)
Expand All @@ -181,7 +179,6 @@ else()
if(UA_ENABLE_ENCRYPTION_OPENSSL)
set(UA_ENABLE_ENCRYPTION "OPENSSL")
set(UA_ENABLE_ENCRYPTION_MBEDTLS OFF)
set(UA_ENABLE_CERT_REJECTED_DIR OFF)
endif()
endif()

Expand Down
53 changes: 45 additions & 8 deletions plugins/crypto/mbedtls/ua_pki_mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,9 @@ certificateVerification_verify(const UA_CertificateVerification *cv,
if(!cv || !certificate)
return UA_STATUSCODE_BADINTERNALERROR;

UA_StatusCode ret = UA_STATUSCODE_GOOD;
CertInfo *ci = (CertInfo*)cv->context;
UA_StatusCode ret = UA_STATUSCODE_GOOD;
mbedtls_x509_crt *old_issuers[UA_MBEDTLS_MAX_CHAIN_LENGTH];

#ifdef __linux__ /* Reload certificates if folder paths are specified */
ret = reloadCertificates(cv, ci);
Expand All @@ -444,16 +445,18 @@ certificateVerification_verify(const UA_CertificateVerification *cv,
mbedtls_x509_crt_init(&cert);
int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data,
certificate->length);
if(mbedErr)
return UA_STATUSCODE_BADCERTIFICATEINVALID;
if(mbedErr) {
ret = UA_STATUSCODE_BADCERTIFICATEINVALID;
goto errout;
}

/* Verification Step: Certificate Usage
* Check whether the certificate is a User certificate or a CA certificate.
* Refer the test case CTT/Security/Security Certificate Validation/029.js
* for more details. */
if(mbedtlsCheckCA(&cert)) {
mbedtls_x509_crt_free(&cert);
return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
ret = UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
goto errout;
}

/* These steps are performed outside of this method.
Expand All @@ -464,9 +467,45 @@ certificateVerification_verify(const UA_CertificateVerification *cv,

/* Verification Step: Build Certificate Chain
* We perform the checks for each certificate inside. */
mbedtls_x509_crt *old_issuers[UA_MBEDTLS_MAX_CHAIN_LENGTH];
ret = mbedtlsVerifyChain(ci, &cert, old_issuers, &cert, 0);

errout:
mbedtls_x509_crt_free(&cert);

#ifdef UA_ENABLE_CERT_REJECTED_DIR
if(ret != UA_STATUSCODE_GOOD &&
ci->rejectedListFolder.length > 0) {
char rejectedFileName[256] = {0};
UA_ByteString thumbprint;
UA_ByteString_allocBuffer(&thumbprint, UA_SHA1_LENGTH);
if(mbedtls_thumbprint_sha1(certificate, &thumbprint) == UA_STATUSCODE_GOOD) {
static const char hex2char[] = "0123456789ABCDEF";
for(size_t pos = 0, namePos = 0; pos < thumbprint.length; pos++) {
rejectedFileName[namePos++] = hex2char[(thumbprint.data[pos] & 0xf0) >> 4];
rejectedFileName[namePos++] = hex2char[thumbprint.data[pos] & 0x0f];
}
strcat(rejectedFileName, ".der");
} else {
UA_UInt64 dt = (UA_UInt64) UA_DateTime_now();
sprintf(rejectedFileName, "cert_%" PRIu64 ".der", dt);
}
UA_ByteString_clear(&thumbprint);
char *rejectedFullFileName = (char *)
calloc(ci->rejectedListFolder.length + 1 /* '/' */ + strlen(rejectedFileName) + 1, sizeof(char));
if(!rejectedFullFileName)
return ret;
memcpy(rejectedFullFileName, ci->rejectedListFolder.data, ci->rejectedListFolder.length);
rejectedFullFileName[ci->rejectedListFolder.length] = '/';
memcpy(&rejectedFullFileName[ci->rejectedListFolder.length + 1], rejectedFileName, strlen(rejectedFileName));
FILE * fp_rejectedFile = fopen(rejectedFullFileName, "wb");
if(fp_rejectedFile) {
fwrite(certificate->data, sizeof(certificate->data[0]), certificate->length, fp_rejectedFile);
fclose(fp_rejectedFile);
}
free(rejectedFullFileName);
}
#endif

return ret;
}

Expand Down Expand Up @@ -514,9 +553,7 @@ certificateVerification_clear(UA_CertificateVerification *cv) {
UA_String_clear(&ci->trustListFolder);
UA_String_clear(&ci->issuerListFolder);
UA_String_clear(&ci->revocationListFolder);
#ifdef UA_ENABLE_CERT_REJECTED_DIR
UA_String_clear(&ci->rejectedListFolder);
#endif
UA_free(ci);
cv->context = NULL;
}
Expand Down
2 changes: 2 additions & 0 deletions plugins/crypto/openssl/securitypolicy_openssl_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <openssl/x509.h>
#include <openssl/evp.h>

#define UA_SHA1_LENGTH 20

_UA_BEGIN_DECLS

void saveDataToFile(const char *fileName, const UA_ByteString *str);
Expand Down
66 changes: 55 additions & 11 deletions plugins/crypto/openssl/ua_pki_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ UA_CertificateVerification_Verify(const UA_CertificateVerification *cv,

UA_StatusCode ret = UA_STATUSCODE_GOOD;
CertContext *ctx = (CertContext *)cv->context;
X509 *old_issuers[UA_OPENSSL_MAX_CHAIN_LENGTH];

#ifdef __linux__
ret = UA_ReloadCertFromFolder(ctx);
Expand All @@ -627,9 +628,8 @@ UA_CertificateVerification_Verify(const UA_CertificateVerification *cv,
/* Verification Step: Certificate Structure */
STACK_OF(X509) *stack = openSSLLoadCertificateStack(*certificate);
if(!stack || sk_X509_num(stack) < 1) {
if(stack)
sk_X509_pop_free(stack, X509_free);
return UA_STATUSCODE_BADCERTIFICATEINVALID;
ret = UA_STATUSCODE_BADCERTIFICATEINVALID;
goto errout;
}

/* Verification Step: Certificate Usage
Expand All @@ -638,8 +638,8 @@ UA_CertificateVerification_Verify(const UA_CertificateVerification *cv,
* for more details. */
X509 *leaf = sk_X509_value(stack, 0);
if(openSSLCheckCA(leaf)) {
sk_X509_pop_free(stack, X509_free);
return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
ret = UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
goto errout;
}

/* These steps are performed outside of this method.
Expand All @@ -650,9 +650,46 @@ UA_CertificateVerification_Verify(const UA_CertificateVerification *cv,

/* Verification Step: Build Certificate Chain
* We perform the checks for each certificate inside. */
X509 *old_issuers[UA_OPENSSL_MAX_CHAIN_LENGTH];
ret = openSSL_verifyChain(ctx, stack, old_issuers, leaf, 0);
sk_X509_pop_free(stack, X509_free);

errout:
if(stack)
sk_X509_pop_free(stack, X509_free);

#ifdef UA_ENABLE_CERT_REJECTED_DIR
if(ret != UA_STATUSCODE_GOOD &&
ctx->rejectedListFolder.length > 0) {
char rejectedFileName[256] = {0};
UA_ByteString thumbprint;
UA_ByteString_allocBuffer(&thumbprint, UA_SHA1_LENGTH);
if(UA_Openssl_X509_GetCertificateThumbprint(certificate, &thumbprint, true) == UA_STATUSCODE_GOOD) {
static const char hex2char[] = "0123456789ABCDEF";
for(size_t pos = 0, namePos = 0; pos < thumbprint.length; pos++) {
rejectedFileName[namePos++] = hex2char[(thumbprint.data[pos] & 0xf0) >> 4];
rejectedFileName[namePos++] = hex2char[thumbprint.data[pos] & 0x0f];
}
strcat(rejectedFileName, ".der");
} else {
UA_UInt64 dt = (UA_UInt64) UA_DateTime_now();
sprintf(rejectedFileName, "cert_%" PRIu64 ".der", dt);
}
UA_ByteString_clear(&thumbprint);
char *rejectedFullFileName = (char *)
calloc(ctx->rejectedListFolder.length + 1 /* '/' */ + strlen(rejectedFileName) + 1, sizeof(char));
if(!rejectedFullFileName)
return ret;
memcpy(rejectedFullFileName, ctx->rejectedListFolder.data, ctx->rejectedListFolder.length);
rejectedFullFileName[ctx->rejectedListFolder.length] = '/';
memcpy(&rejectedFullFileName[ctx->rejectedListFolder.length + 1], rejectedFileName, strlen(rejectedFileName));
FILE * fp_rejectedFile = fopen(rejectedFullFileName, "wb");
if(fp_rejectedFile) {
fwrite(certificate->data, sizeof(certificate->data[0]), certificate->length, fp_rejectedFile);
fclose(fp_rejectedFile);
}
free(rejectedFullFileName);
}
#endif

return ret;
}

Expand Down Expand Up @@ -850,10 +887,14 @@ UA_CertificateVerification_Trustlist(UA_CertificateVerification * cv,

#ifdef __linux__ /* Linux only so far */
UA_StatusCode
UA_CertificateVerification_CertFolders(UA_CertificateVerification * cv,
const char * trustListFolder,
const char * issuerListFolder,
const char * revocationListFolder) {
UA_CertificateVerification_CertFolders(UA_CertificateVerification *cv,
const char *trustListFolder,
const char *issuerListFolder,
const char *revocationListFolder
#ifdef UA_ENABLE_CERT_REJECTED_DIR
, const char *rejectedListFolder
#endif
) {
UA_StatusCode ret;
if (cv == NULL) {
return UA_STATUSCODE_BADINTERNALERROR;
Expand Down Expand Up @@ -886,6 +927,9 @@ UA_CertificateVerification_CertFolders(UA_CertificateVerification * cv,
context->trustListFolder = UA_STRING_ALLOC(trustListFolder);
context->issuerListFolder = UA_STRING_ALLOC(issuerListFolder);
context->revocationListFolder = UA_STRING_ALLOC(revocationListFolder);
#ifdef UA_ENABLE_CERT_REJECTED_DIR
context->rejectedListFolder = UA_STRING_ALLOC(rejectedListFolder);
#endif

return UA_STATUSCODE_GOOD;
}
Expand Down

0 comments on commit a7e3196

Please sign in to comment.