OK I have spent many days trying to figure this out. This is what I have come to :-
Build the library with encryption enabled (I chose OpenSSL).
Use create_self-signed.py script to generate the certificate and key for the client with the argument --uri urn:open62541.client <your client uri>
The URI in the cert must the same as clientDescription.applicationUri in the client itself.
Get the server certificate from your server in .der format, this needs to be added to the trust list on connection.
I was playing around with the examples provided in the open62541 library and I finally got a connection working that sent back the server time.
The example provided was ran as follows ./client_encryption opc.tcp://<IP>:4840 client_cert.der client_key.der server-certificate.der
The code in c is
const char *endpointUrl = argv[1];
/* Load certificate and private key */
UA_ByteString certificate = loadFile(argv[2]);
UA_ByteString privateKey = loadFile(argv[3]);
size_t trustListSize = 0;
if(argc > MIN_ARGS)
trustListSize = (size_t)argc-MIN_ARGS;
UA_STACKARRAY(UA_ByteString, trustList, trustListSize+1);
for(size_t trustListCount = 0; trustListCount < trustListSize; trustListCount++)
trustList[trustListCount] = loadFile(argv[trustListCount+4]);
UA_ByteString *revocationList = NULL;
size_t revocationListSize = 0;
UA_Client *client = UA_Client_new();
UA_ClientConfig *cc = UA_Client_getConfig(client);
cc->securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
UA_ClientConfig_setDefaultEncryption(cc, certificate, privateKey,
trustList, trustListSize,
revocationList, revocationListSize);
UA_ByteString_clear(&certificate);
UA_ByteString_clear(&privateKey);
for(size_t deleteCount = 0; deleteCount < trustListSize; deleteCount++) {
UA_ByteString_clear(&trustList[deleteCount]);
}
cc->clientDescription.applicationUri = UA_STRING_ALLOC("urn:open62541.client");
UA_StatusCode retval = UA_Client_connectUsername(client, endpointUrl, "user", "password");
Moving across to Pascal, this is what I ended up with, I get 'Good' as the response and I can now read data from the server.
function LoadStringFromFile(const FileName: string): string;
var
FS: TFileStream;
Len: Int64;
begin
Result := '';
if FileExists(FileName) then
begin
FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
Len := FS.Size;
SetLength(Result, Len);
FS.Read(Pointer(Result)^, Len);
finally
FS.Free;
end;
end;
end;
Var certificate, privateKey, TrustList : UA_ByteString;
cc: PUA_ClientConfig;
Client : PUA_Client;
begin
certificate := _UA_STRING_ALLOC(LoadStringFromFile('client_cert.der'));
privateKey := _UA_STRING_ALLOC(LoadStringFromFile('client_key.der'));
TrustList := _UA_STRING_ALLOC(LoadStringFromFile('server-certificate.der'));
client := UA_Client_new();
cc := UA_Client_getConfig(client);
cc^.securityMode:= UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
UA_ClientConfig_setDefaultEncryption(cc, certificate, privateKey, @TrustList, 1, nil, 0);
cc^.clientDescription.applicationUri := _UA_STRING_ALLOC('urn:open62541.client');
res := UA_Client_connectUsername(client, 'opc.tcp://'<IPAddress>:4840' , 'user', 'password');
end;
I hope this helps someone else.