How to validate clients certificate from opcua server using node library

178 Views Asked by At

Im creating a opcua server using node-opcua. The user validation by user and password works, but now im trying to add certificates and i dont get how to do it.

I understand the server has its own certificate and privatekey, and each client has its own certificates. Also i know that the clients need to know the server's certificate, but i dont know how the server can identify each client through the sended certificate, where the server saves it.

I created server certificates:

    const serverCertificateManager = new OPCUACertificateManager({
        automaticallyAcceptUnknownCertificate: true,
        name: "PKI",
        rootFolder: "./certificates/server/PKI",
        keySize: 2048
    })
    await serverCertificateManager.initialize()

    if (!fs.existsSync(certificateFile)) {

        console.log("Creating self-signed certificate");
    
        await serverCertificateManager.createSelfSignedCertificate({
          applicationUri: `urn:${hostname}:NodeOPCUA-Server`,
          dns: hostname ? [hostname, fqdn] : [fqdn],
          outputFile: certificateFile,
          subject: "/CN=Sterfive/DC=Test",
          startDate: new Date(),
          validity: 365 * 10
        })
      }

and from the server i created user certificates:

    const userCertificateManager = new OPCUACertificateManager({
        automaticallyAcceptUnknownCertificate: false,
        name: "UserPki",
        rootFolder: "./certificates/clients/PKI",
        keySize: 2048
    })
    await userCertificateManager.initialize()

That creates in the certificates folder, a clients and a server folder, each one with issuers, own, rejected and trusted. In the path server/PKI/certs/ the certificate and the private key are created by running the above managers. And in clientsthere are created some certificates in trusted, and when i connect a client without any certificate (just with user-password), another trust certificate is created with its session name.

Next, i created the server:

    const server = new OPCUAServer({
        port: port,
        serverInfo: {
            applicationName: { text: "Enterprise", locale: "en" },
            applicationUri: `urn:${hostname}:NodeOPCUA-Server`,
            productUri: "NodeOPCUA-Server"
        },
        buildInfo: {
            productName: "Enterprise",
            buildNumber: "1002",
            buildDate: new Date(),
        },
        userManager: {

            isValidUserAsync: function (userName: string, password: string, callback: Callback<boolean>) {
                setImmediate(function () {
                    const authorized = clientsData.some((client:Client )=> client.username === userName && client.password === password)
                    callback(null, authorized);
                })
            },

            getUserRoles: function (user: string): NodeId[] {
                return [makeNodeId(user, 1)];
            }

        },
        serverCertificateManager,
        userCertificateManager,
        certificateFile: certificateFile,
        privateKeyFile: privateKeyFile,
        securityPolicies: [SecurityPolicy.Basic256Sha256],
        securityModes: [MessageSecurityMode.Sign],
        serverCapabilities: {
            maxSessions: 10,
            maxSubscriptionsPerSession: 10,
            maxMonitoredItemsPerSubscription: 30,
            operationLimits: {
                maxNodesPerRead: 10,
                maxNodesPerMethodCall: 10
            }
        },
        maxConnectionsPerEndpoint: 10,
        hostname: hostname,
        allowAnonymous: false
    })

This is my server code, but when I try to connect a client using the same library, the process fails. The client has this code:

const client = OPCUAClient.create({
    clientName: username,
    applicationName: username,
    connectionStrategy: connectionStrategy,
    securityMode: MessageSecurityMode.Sign,
    securityPolicy: SecurityPolicy.Basic256Sha256,
    endpointMustExist: true,
    serverCertificate: serverCertificateBuffer,
    certificateFile: certificateFile,
    privateKeyFile: privateKeyFile
});

const session = await client.createSession({
    type: UserTokenType.Certificate,
            certificateData: fs.readFileSync(certificateFile),
            privateKey: fs.readFileSync(privateKeyFile, 'utf-8')
    })

Where the server certificate is the created in the server folder, the privatekey is the created by the server manager in the clients folder and the certificate is created by using the OPCUACertificateManager. When i try to connect to server, client throw this error: Error: The connection may have been rejected by server.

I suspect that the certificate implementation is not working because im missing something. Im really new in opcua. Some one know how to correctly implementate the certificate comunication? also i need to create a certificate per user, so i can verify and recognized every user to track the clients activity.

I hope ur help, im stuck

1

There are 1 best solutions below

1
On

You need to store your client public certificate (.der) into the trust folder of your server.

This should be either server\PKI\trusted or server\PKI\trusted\certs