aboutsummaryrefslogtreecommitdiffstats
path: root/readme.md
blob: f6a791671e35a0fe3bf0c5f2f1731f9c07e92d11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# OPC UA Discovery

A small C project that demonstrates OPC UA server discovery using the
[open62541](https://www.open62541.org/) library. Three programs work together:

- **ServerLDS** — Local Discovery Server that other servers register with
- **ServerRegister** — a server that periodically registers itself with the LDS
- **Client** — queries the LDS for servers, lists endpoints, or reads the current time from a server

## Prerequisites

- CMake 4.0+
- A C11 compiler (GCC or Clang)
- OpenSSL development libraries (`libssl-dev` / `openssl-devel`)
- `openssl` CLI (for generating certificates)

## Getting started

Clone the repository with its submodule:

```sh
git clone --recursive https://git.tvcloud.fr/opcua_c
cd opcua_c
```

### Generate certificates

The programs use TLS certificates for mutual authentication. ServerLDS and
ServerRegister can also run without certificates (SecurityPolicy#None only) by
omitting the `certificate`, `privateKey`, and `trustStore` keys from their
config files.

For encrypted operation, four identities are needed. Each call to
`tools/generate_certificate.sh` creates a self-signed RSA-2048 certificate
(`<name>_cert.der`) and private key (`<name>_key.der`) in the given directory:

```sh
tools/generate_certificate.sh certs ServerLDS
tools/generate_certificate.sh certs ServerRegister
tools/generate_certificate.sh certs ServerRegisterClient
tools/generate_certificate.sh certs Client
```

| Identity | Used by | Purpose |
|----------|---------|---------|
| `ServerLDS` | ServerLDS | Server certificate for the LDS |
| `ServerRegister` | ServerRegister | Server certificate for the registering server |
| `ServerRegisterClient` | ServerRegister | Client certificate used when connecting to the LDS |
| `Client` | Client | Client certificate for all client operations |

### Populate the trust stores

OPC UA applications only accept connections from peers whose certificate is in
their trust store. Create the trust store directories and symlink each peer's
certificate:

```sh
mkdir -p certs/trust/{server_lds,server_register,server_register_client,client}

ln -s ../../ServerRegisterClient_cert.der ../../Client_cert.der \
   certs/trust/server_lds/

ln -s ../../ServerLDS_cert.der ../../Client_cert.der \
   certs/trust/server_register/

ln -s ../../ServerLDS_cert.der \
   certs/trust/server_register_client/

ln -s ../../ServerLDS_cert.der ../../ServerRegister_cert.der \
   certs/trust/client/
```

### Build

```sh
cmake -B build
cmake --build build --parallel
```

open62541 is fetched from the submodule and built automatically — the first
build takes a bit longer.

## Running

Start the programs in order, each in its own terminal, from the project root.
Configuration files live in `tests/` (one directory per test scenario — see
[Tests](#tests) below). The examples below use `tests/secure_user/`:

```sh
# 1. Local Discovery Server
build/ServerLDS tests/secure_user/server_lds.conf

# 2. Register Server (connects to the LDS on port 14840)
build/ServerRegister tests/secure_user/server_register.conf \
  tests/secure_user/server_register_client.conf opc.tcp://localhost:14840

# 3. Find registered servers via the LDS
build/Client tests/secure_user/client.conf find-servers opc.tcp://localhost:14840

# 4. List endpoints on the registered server
build/Client tests/secure_user/client.conf get-endpoints opc.tcp://localhost:14841

# 5. Read the current time from the registered server
build/Client tests/secure_user/client.conf read-time opc.tcp://localhost:14841
```

All three programs accept an optional log level as the last argument
(`trace`, `debug`, `info`, `warning`, `error`, `fatal`). The default is `info`.

## Tests

Integration tests exercise four combinations of security and authentication:

| Test | Security | Auth |
|------|----------|------|
| `unsecure_anonymous` | None / None | anonymous |
| `secure_anonymous` | SignAndEncrypt / Aes256_Sha256_RsaPss | anonymous |
| `secure_user` | SignAndEncrypt / Aes256_Sha256_RsaPss | user/password |
| `secure_cert` | SignAndEncrypt / Aes256_Sha256_RsaPss | X509 certificate |

Run all tests:

```sh
ctest --test-dir build --output-on-failure
```

### Memory leak check

Rebuild with AddressSanitizer, run the tests, then switch back:

```sh
# ASan build
cmake -B build \
  -DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
  -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address"
cmake --build build --parallel

ASAN_OPTIONS="detect_leaks=1" ctest --test-dir build --output-on-failure

# Restore normal build
cmake -B build -DCMAKE_C_FLAGS="" -DCMAKE_EXE_LINKER_FLAGS=""
cmake --build build --parallel
```

## Configuration

Programs are configured through plain text files (`key = value`, one per line).
See the `tests/` directories for working examples.

Three authentication modes are supported via the `authMode` key:

- **anonymous** — no user identity
- **user** — username and password (requires `username` and `password` keys)
- **cert** — X509 certificate identity token (reuses the application certificate; requires encryption to be configured)