Skip to content

IEC 62443 Compliance Guide

SolidSyslog provides audit logging infrastructure for industrial automation and control systems (IACS) targeting IEC 62443 compliance. This document maps library components to IEC 62443-3-3 system requirements and IEC 62443-4-2 component requirements at each Security Level (SL).

Security Levels Overview

Level Threat model Attacker profile
SL1 Casual or coincidental violation No intent, accidental misconfiguration
SL2 Intentional violation using simple means Low motivation, general skills
SL3 Sophisticated attack with moderate resources IACS-specific skills, moderate motivation
SL4 State-level attack with extensive resources Nation-state, dedicated team, advanced tools

Control Implementation

The IEC 62443 Component Requirements (CR) and System Requirements (SR) below are the audit-logging-relevant subset of IEC 62443-4-2 and IEC 62443-3-3. Each row maps a control to (a) the SL at which IEC requires it, (b) the SolidSyslog components that satisfy it at any SL the integrator chooses to ship them, and (c) any current capability gaps.

The components are not bound to specific Security Levels; any of them can be linked at any SL. The SL distinction is which controls a deployment must address, not which components it may use. See Choosing components by Security Level for recommended starter component sets and the drivers behind each choice.

CR / SR Description Required at Components & configuration Gaps
CR 1.5 Authenticator management SL4 SolidSyslogTlsStream mTLS — caller supplies clientCertChainPath / clientKeyPath; SSL_CTX_check_private_key validates the key/cert pair before any bytes hit the wire. Rotation by file replacement plus reconnect (natural reconnect or explicit SolidSyslogSender_Disconnect) Library ships no default authenticators; at-rest key protection (filesystem permissions, HSM) is the integrator's responsibility
CR 1.8 Public key infrastructure certificates SL4 SolidSyslogTlsStreamcaBundlePath loads trust anchors via SSL_CTX_load_verify_locations; SSL_VERIFY_PEER pinned on the CTX; hostname verification via SSL_set1_host. CTX rebuilt on every Open so file replacement + reconnect refreshes trust anchors Revocation (CRL / OCSP) deferred to the OS trust store; enrolment is the caller's PKI process
CR 2.8 Auditable events SL1+ SolidSyslog_Log formats events per RFC 5424. Structured data attached via SolidSyslogMetaSd / SolidSyslogTimeQualitySd / SolidSyslogOriginSd, or caller-supplied SD. Application defines what to log None
CR 2.9 Audit storage capacity SL1+ SolidSyslogBlockStore — rotating blocks, configurable max-blocks and max-block-size, configurable discard policy (oldest / newest / halt). Backed by SolidSyslogFileBlockDevice over SolidSyslogPosixFile (POSIX) or SolidSyslogWindowsFile (Windows). Size to the deployment's outage budget. Configurable early-warning threshold via SolidSyslogStoreThresholdFunction + SolidSyslogStoreThresholdCallback — edge-triggered, fires once when used-bytes crosses the threshold, re-arms when usage falls back below None
CR 2.10 Response to audit processing failures SL1+ SolidSyslogStoreFullCallback (halt policy) and the discard-policy enum. Caller picks the policy that fits the deployment's audit-loss tolerance. The early-warning threshold callback (CR 2.9) fires before discard / halt engages, giving the application time to act (notify operator, reduce verbosity, tighten retention); at 100% with HALT both fire on the same Write with threshold first then onStoreFull None
CR 2.11 Timestamps SL2+ Caller-injected SolidSyslogClockFunctionSolidSyslogPosixClock_GetTimestamp (POSIX) or SolidSyslogWindowsClock_GetTimestamp (Windows). Quality metadata via SolidSyslogTimeQualitySd (tzKnown / isSynced / syncAccuracy) None
CR 2.12 Non-repudiation SL3+ At the wire: SolidSyslogTlsStream mutual TLS cryptographically identifies the sender. End-to-end loss detection: SolidSyslogMetaSd sequenceId, gap detection at the SIEM. At rest: cryptographic integrity via SolidSyslog{OpenSsl,MbedTls}HmacSha256Policy, or authenticated encryption via SolidSyslog{OpenSsl,MbedTls}AesGcmPolicy; SolidSyslogCrc16Policy remains for accidental-corruption detection Cryptographic at-rest policies are keyed — key custody, rotation, and tamper-evident storage are integrator responsibilities. See at-rest cryptography
CR 3.9 Audit information protection SL2+ Protect audit information from unauthorized access, modification and deletion — met by filesystem permissions on the store and, where the medium is exposed, an at-rest integrity policy (SolidSyslogCrc16Policy, or keyed SolidSyslog{OpenSsl,MbedTls}HmacSha256Policy). This control's own SL4 enhancement is write-once media. Related but distinct controls: in-transit confidentiality is SR 4.1 RE 1 (over untrusted networks), realisable with SolidSyslogTlsStream; at-rest confidentiality is SolidSyslog{OpenSsl,MbedTls}AesGcmPolicy. See at-rest cryptography The cryptographic mechanisms are integrator choices, not CR 3.9 mandates; key management is the integrator's responsibility
SR 6.1 Audit log accessibility SL1+ Two wirings, two cost models. Single-task (SolidSyslogPassthroughBuffer): SolidSyslog_Log performs the transport Send synchronously on the caller's thread. The TCP socket is non-blocking from the moment it is opened (see SolidSyslogPosixTcpStream.c and SolidSyslogWinsockTcpStream.c), so Send returns immediately on a wedged peer or a full kernel buffer; the bounded blocking surface is the initial connect(), sized by SOLIDSYSLOG_TCP_CONNECT_TIMEOUT_MS (default 200 ms) or runtime-overridable per Stream via GetConnectTimeoutMs(ConnectTimeoutContext). On the TLS path the same applies to the handshake, via SOLIDSYSLOG_TLS_HANDSHAKE_TIMEOUT_MS (default 5000 ms) or GetHandshakeTimeoutMs(HandshakeTimeoutContext) for both OpenSSL and Mbed TLS adapters. Long-term silent peer death is detected out-of-band via kernel TCP_KEEPALIVE + TCP_USER_TIMEOUT. Suitable when the application has no real-time deadline or the transport latency is known to be sub-millisecond. Buffered (SolidSyslogCircularBuffer with an injected SolidSyslogMutex — Posix / Windows / FreeRTOS / Null / caller-supplied RTOS primitive — or SolidSyslogPosixMessageQueueBuffer): SolidSyslog_Log is non-blocking: it formats and enqueues, returning before any I/O. SolidSyslog_Service, called on the integrator's chosen thread (typically a dedicated service thread), performs the transport I/O against the same non-blocking socket; the bounded surface is the same connect / handshake budget as the single-task wiring. Caller picks the wiring that fits the deployment's audit-loss / latency trade-off None
SR 6.2 Continuous monitoring SL2+ TCP / TLS delivery confirmation via SolidSyslogStreamSender. Replay across outages via SolidSyslogBlockStore store-and-forward. SIEM-side gap detection via SolidSyslogMetaSd sequenceId None

Important

The Security Level cells for the identity controls (CR 1.5, CR 1.8) and the point at which mutual / device authentication first applies are being confirmed against IEC 62443-4-2:2019 Annex A. Current indications are that device self-authentication (CR 1.2) is an SL2 capability, with unique per-device identity and hardware-protected keys arriving at SL3, so mutual TLS is likely introduced below SL4, not only at it. Treat the CR 1.5 / CR 1.8 rows above as provisional pending that check.

Comprehensive error guards across the library are not a single CR, but they support the IEC 62443-4-1 secure development lifecycle baseline that underpins SL3+ deployments.

SL4 TLS substrate

SolidSyslogTlsStream (the OpenSSL-backed client-side TLS substrate) ships with the SL4 controls that depend on the client:

  • Hostname verification. SolidSyslogTlsStreamConfig.serverName is forwarded to both SNI (SSL_set_tlsext_host_name) and the cert check (SSL_set1_host). Both return values are checked; handshake is aborted on any setup failure, preventing a silent "handshake succeeded without checking the name" bypass.
  • Trust chain. caBundlePath loads trust anchors via SSL_CTX_load_verify_locations; SSL_VERIFY_PEER is pinned on the CTX.
  • TLS 1.2 floor. SSL_CTX_set_min_proto_version(TLS1_2_VERSION) is return-checked; Open fails if libssl refuses the floor.
  • Cipher pinning. SolidSyslogTlsStreamConfig.cipherList is forwarded to SSL_CTX_set_cipher_list. The library ships no baked-in list: the SL4-appropriate cipher policy lives with the caller, which understands its security profile. A reasonable starting point is "ECDHE+AESGCM:ECDHE+CHACHA20" (TLS 1.2 AEAD with forward secrecy); tune to match the libssl build on the target platform.
  • Mutual TLS (non-repudiation, CR 2.12). Optional clientCertChainPath / clientKeyPath load a client cert and private key via SSL_CTX_use_certificate_chain_file + SSL_CTX_use_PrivateKey_file, with SSL_CTX_check_private_key confirming the pairing locally before any bytes hit the wire. Both fields are opt-in and all-or-nothing: supply both to enable mTLS, leave both NULL for server-auth TLS. Supplying only one is rejected at Open time, no silent downgrade.
  • Certificate rotation (CR 1.5 authenticator refresh, CR 1.8 PKI update). SolidSyslogTlsStream rebuilds the SSL_CTX on every Open, re-reading the cert material from caBundlePath / clientCertChainPath / clientKeyPath from disk each time. Rotation is therefore a deployment operation: replace the files on disk, and the new material takes effect on the next reconnect, via natural churn (retry, outage recovery) or by calling SolidSyslogSender_Disconnect to force one. No library-level callback or version-fingerprint API is needed to satisfy the capability requirement.
  • Resource lifecycle. Close/Destroy release SSL_CTX, SSL, and BIO_METHOD idempotently: no leaks on partial Open failure, no double frees if both are called.

Embedded SL4: SolidSyslogMbedTlsStream

SolidSyslogMbedTlsStream is the Mbed TLS-backed reference adapter for embedded / FreeRTOS / bare-metal SL4 deployments where OpenSSL is too heavy. It satisfies the same CR 1.5 / CR 1.8 / CR 2.12 / CR 3.9 controls as SolidSyslogTlsStream and surfaces the same SolidSyslogStream vtable, so the rest of the wiring (SolidSyslogStreamSender, buffer, store) is unchanged.

  • Hostname verification. SolidSyslogMbedTlsStreamConfig.ServerName is forwarded to both SNI (mbedtls_ssl_set_hostname) and the cert SAN check (mbedTLS verifies the peer cert against the same string by default with MBEDTLS_SSL_VERIFY_REQUIRED).
  • Trust chain. CaChain is a caller-built mbedtls_x509_crt* passed through dependency injection; there is no filesystem coupling inside the adapter (MBEDTLS_FS_IO is typically off on embedded targets). mbedtls_ssl_conf_authmode is pinned to MBEDTLS_SSL_VERIFY_REQUIRED.
  • TLS 1.2+ floor. Inherited from mbedtls_ssl_config_defaults(... PRESET_DEFAULT). TLS 1.3 negotiates automatically when both peers support it.
  • Mutual TLS (non-repudiation, CR 2.12). Optional ClientCertChain / ClientKey handles. Both NULL = server-auth-only. Both non-NULL = mTLS. Supplying only one is treated as "no client cert": no silent half-configuration.
  • Certificate rotation (CR 1.5 / CR 1.8). Because the adapter consumes pre-built handles rather than file paths, rotation is "parse a new mbedtls_x509_crt, destroy and recreate the adapter (or the parent SolidSyslogStreamSender so the next Connect picks it up)." A deployment running a vendor key-rotation service drives this via its existing reload hook.
  • Coexistence with an existing Mbed TLS integration. Auditable contract: Platform/MbedTls/Source/ never calls mbedtls_platform_setup / _teardown, never installs threading-alt hooks, never calls psa_crypto_init itself, never resets the global RNG, never replaces the integrator's debug callback. Devices that already wire Mbed TLS for another subsystem (cloud, OTA, vendor framework) keep that wiring intact.
  • Resource lifecycle. Close / Destroy invoke mbedtls_ssl_close_notify / _ssl_free / _ssl_config_free idempotently and never free integrator-owned handles.

Integrator guide: docs/integrating-mbedtls.md. Reference wiring: the FreeRTOS QEMU mps2-an385 BDD target at Bdd/Targets/Common/BddTargetTlsSender_MbedTls_PlusTcpTcp.c.

Architecture for Security

SolidSyslog's architecture directly supports IEC 62443-4-1 (secure development lifecycle) principles:

Dependency injection: every external dependency (transport, storage, clock, file I/O) is injected via vtable structs. No component has a hard dependency on a specific platform or network stack. This enables:

  • Complete unit testing without hardware or network
  • Formal verification of individual components
  • Replacement of any component without modifying the library

Interface segregation: public headers are split by audience. Application code that calls Log() never sees configuration, transport, or storage types. This minimises the attack surface exposed to each code module.

No dynamic allocation: the library uses caller-owned storage throughout. No malloc, no heap fragmentation, no allocation failure paths. The SolidSyslogFormatterStorage pattern provides opaque stack-allocated buffers with compile-time sizing.

Single overflow protection point: all formatted output flows through a single Formatter_WriteChar function with bounds checking. Buffer overflows are structurally prevented regardless of input data.

Composition over configuration: optional features are composed at link time by selecting concrete implementations. No #ifdef feature flags, no runtime feature toggles. The binary contains exactly the code paths that are linked. Dead code elimination removes unused components.

Deployment Considerations

Minimal footprint (bare-metal / RTOS)

For resource-constrained targets, SL1 or SL2 can operate with:

  • No heap allocation
  • No POSIX dependency (provide your own clock, hostname, and transport)
  • Single-task operation with SolidSyslogPassthroughBuffer, or multi-task on bare-metal / RTOS with SolidSyslogCircularBuffer driven by a SolidSyslogMutex you supply (the library ships SolidSyslogPosixMutex, SolidSyslogWindowsMutex, SolidSyslogFreeRtosMutex, and SolidSyslogNullMutex)
  • Flash-based store-and-forward via an integrator-supplied SolidSyslogBlockDevice driving SolidSyslogBlockStore. The library ships SolidSyslogFileBlockDevice as a file-backed reference; flash hardware drivers are out-of-scope and supplied by the platform.

RTOS integration

SolidSyslogCircularBuffer is the portable choice for the producer / consumer seam between the application thread (calling Log()) and the service thread (calling Service()): caller-allocated ring memory, mutex injected via the SolidSyslogMutex vtable, no POSIX dependency. Wrap your RTOS mutex primitive in the vtable and you're done. SolidSyslogPosixMessageQueueBuffer remains available where a POSIX mqueue is preferred for kernel-level back-pressure semantics.

SIEM integration

All output is RFC 5424 compliant structured syslog. Compatible with:

  • syslog-ng
  • rsyslog
  • Splunk
  • Elastic / ELK stack
  • Any RFC 5424 compliant collector

The sequenceId structured data element enables SIEM-side gap detection: the collector can alert on missing sequence numbers without polling the device.

sequenceId is assigned at the point of message raise (application-layer originator), so gaps observed by the SIEM reflect any drop in the full audit pipeline (internal buffer, store-and-forward, and transport), not just transport-level loss. This contributes to FR 3 (system integrity) and SR 6.1 (audit log accessibility) by giving the SIEM a single end-to-end loss-detection signal that does not depend on the transport layer being lossless. Cross-reference: RFC 5424 §7.3.1 in the compliance matrix.

Choosing components by Security Level

For advice on which SolidSyslog components to select for a good story at each Security Level (the choices you make, what should drive each one, and worked starter combinations), see Choosing components by Security Level. That guidance is framed around your deployment's drivers (network trust, outage tolerance, non-repudiation needs); the control-by-control table above is the map underneath it.