C · recipe

Set up OPC UA certificates in C

Load a DER certificate and private key, pass them plus your trust list to the encrypted client configuration helper, and set the ApplicationUri to match the certificate's SAN. Without mbedTLS or OpenSSL compiled in, none of this is available.

Stackopen62541
Version1.5.8

The code

#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <open62541/plugin/securitypolicy.h>
#include <stdio.h>
#include <stdlib.h>

static UA_ByteString loadFile(const char *path) {
    UA_ByteString out = UA_BYTESTRING_NULL;
    FILE *f = fopen(path, "rb");
    if (!f) return out;
    fseek(f, 0, SEEK_END);
    long len = ftell(f);
    fseek(f, 0, SEEK_SET);
    out.data = (UA_Byte *)UA_malloc((size_t)len);
    out.length = fread(out.data, 1, (size_t)len, f);
    fclose(f);
    return out;
}

int main(void) {
    /* generate with the SAN entries OPC UA checks:
       openssl req -x509 -newkey rsa:2048 -keyout key.der -outform DER -out cert.der \
         -days 730 -nodes -subj "/CN=my-c-client" \
         -addext "subjectAltName=DNS:my-host,URI:urn:example:my-c-client" \
         -keyform DER   */
    UA_ByteString cert = loadFile("cert.der");
    UA_ByteString key  = loadFile("key.der");
    if (cert.length == 0 || key.length == 0) {
        printf("could not load certificate or key\n"); return 1;
    }

    /* trusted peers and issuers - the same four-store model as every stack */
    UA_ByteString trustList[1];
    trustList[0] = loadFile("server_cert.der");
    size_t trustListSize = trustList[0].length ? 1 : 0;

    UA_Client *client = UA_Client_new();
    UA_ClientConfig *cc = UA_Client_getConfig(client);
    cc->securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;

    UA_StatusCode rc = UA_ClientConfig_setDefaultEncryption(
        cc, cert, key, trustList, trustListSize, NULL, 0);
    if (rc != UA_STATUSCODE_GOOD) {
        printf("encryption setup failed: %s\n", UA_StatusCode_name(rc));
        UA_Client_delete(client); return 1;
    }

    /* must match the URI entry in the certificate SAN */
    UA_String_clear(&cc->clientDescription.applicationUri);
    cc->clientDescription.applicationUri =
        UA_STRING_ALLOC("urn:example:my-c-client");

    rc = UA_Client_connect(client, "opc.tcp://milo.digitalpetri.com:62541/milo");
    printf("connect: %s\n", UA_StatusCode_name(rc));

    UA_ByteString_clear(&cert);
    UA_ByteString_clear(&key);
    UA_ByteString_clear(&trustList[0]);
    UA_Client_disconnect(client);
    UA_Client_delete(client);
    return 0;
}

What it prints

connect: Good
# first attempt against a strict server instead prints:
# connect: BadSecurityChecksFailed   (until an admin trusts your certificate)

Notes

  • open62541 wants DER, not PEM, for both certificate and key. Convert with -outform DER and -keyform DER.
  • Without mbedTLS or OpenSSL compiled into the library, setDefaultEncryption is unavailable and you get policy None only.
  • The applicationUri in the client description must match the URI entry in the certificate SAN exactly, or the server rejects you for a reason that looks unrelated.
  • The first secure attempt normally fails: your certificate lands in the server's rejected store and an administrator has to promote it. That is the designed workflow.
  • On an embedded target, watch the certificate validity window against the device clock. No RTC plus a certificate check equals a device that never connects.

What breaks first

Everything is configured correctly and the handshake still fails BadSecurityChecksFailed
Usually the ApplicationUri and SAN do not match, or the peer certificate is not in your trust list. Check both before touching the policy.

Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.

Free download
OPC UA Troubleshooting & Integration Checklist
The field-tested checklist engineers use to diagnose certificates, ports and namespace problems fast, plus a Python (asyncua) client template.
Get the free checklist →
Free, no course, no login