Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error 'Data does not match to Certificate ASN1 schema. undefined' with serverCertificateManager #1289

Closed
sseiber opened this issue Aug 15, 2023 · 3 comments
Assignees
Labels

Comments

@sseiber
Copy link

sseiber commented Aug 15, 2023

Current behavior

When attempting to use the serverCertificateManager.createSelfSignedCertificate method I get the error:
'Data does not match to Certificate ASN1 schema. undefined'

Describe the bug

I am using the node-opcua package with my server implementation in container and deploying it to a local Kubernetes cluster. I have a persistent volume mapped to the host storage system which contains the root PKI folder.

I am creating the serverCertificateManager:

this.serverCertificateManager = new OPCUACertificateManager({
    automaticallyAcceptUnknownCertificate: true,
    rootFolder: pkiRoot
});

await this.serverCertificateManager.initialize();

I am attempting to create the certificate with this code:

try {
    if (!fse.pathExistsSync(opcuaServerOptions.certificateFile)) {
        this.server.log([ModuleName, 'info'], `Creating new certificate file:`);

        const certFileRequest = {
            applicationUri: opcuaServerOptions.serverInfo.applicationUri,
            dns: [getHostname()],
            // ip: await getIpAddresses(),
            outputFile: selfSignedCertificatePath,
            subject: `/CN=${appName}/O=TestHome/L=Midway/C=US`,
            startDate: new Date(),
            validity: 365 * 10
        };

        this.server.log([ModuleName, 'info'], `Self-signed certificate file request params:\n${JSON.stringify(certFileRequest, null, 2)}\n`);

        await this.serverCertificateManager.createSelfSignedCertificate(certFileRequest);
    }
    else {
        this.server.log([ModuleName, 'info'], `Using existing certificate file at: ${opcuaServerOptions.certificateFile}`);
    }
}
catch (ex) {
    this.server.log([ModuleName, 'error'], `Error creating server self signed certificate: ${ex.message}`);
}

The values used in the call are this (from logs):

{
    "applicationUri": "urn:rpi-plc-deployment-55cc7bbc64-r89h4:RpiPlc",
    "dns": [
        "rpi-plc-deployment-55cc7bbc64-r89h4"
    ],
    "outputFile": "/rpi-plc/data/.config/PKI/certificate.pem",
    "subject": "/CN=RpiPlc/O=TestSHome/L=Midway/C=US",
    "startDate": "2023-08-15T06:16:15.077Z",
    "validity": 3650
}

The exception is caught on the last line with the error. The call stack for the exception is this:

Error: Data does not match to Certificate ASN1 schema. undefined
    at AsnParser.fromASN (/app/node_modules/@peculiar/asn1-schema/build/cjs/parser.js:43:23)
    at AsnParser.parse (/app/node_modules/@peculiar/asn1-schema/build/cjs/parser.js:16:26)
    at AsnConvert.parse (/app/node_modules/@peculiar/asn1-schema/build/cjs/convert.js:13:35)
    at new AsnData (/app/node_modules/@peculiar/x509/build/x509.cjs.js:447:47)
    at new PemData (/app/node_modules/@peculiar/x509/build/x509.cjs.js:1251:13)
    at new X509Certificate (/app/node_modules/@peculiar/x509/build/x509.cjs.js:1369:13)
    at X509CertificateGenerator.create (/app/node_modules/@peculiar/x509/build/x509.cjs.js:2421:16) {schemas: Array(1), stack: 'Error: Data does not match to Certificate ASN…les/@peculiar/x509/build/x509.cjs.js:2421:16)', message: 'Data does not match to Certificate ASN1 schema. undefined'}

The host directory looks like this after the call:

drwxr-xr-x 6 root root 4096 Aug 15 06:16 .
drwxr-xr-x 3 root root 4096 Aug 15 06:15 ..
drwxr-xr-x 4 root root 4096 Aug 15 06:15 issuers
-rw-r--r-- 1 root root    0 Aug 15 06:15 mutex.lock
drwxr-xr-x 4 root root 4096 Aug 15 06:15 own
drwxr-xr-x 2 root root 4096 Aug 15 06:15 rejected
drwxr-xr-x 4 root root 4096 Aug 15 06:15 trusted

However; after letting the server continue to initialize the directory looks like this:

drwxr-xr-x 6 root root  4096 Aug 15 06:37 .
drwxr-xr-x 3 root root  4096 Aug 15 06:15 ..
-rw-r--r-- 1 root root 12594 Aug 15 06:37 certificate.pem
-rw-r--r-- 1 root root     0 Aug 15 06:37 certificate.pem.mutex
drwxr-xr-x 4 root root  4096 Aug 15 06:15 issuers
-rw-r--r-- 1 root root     0 Aug 15 06:15 mutex.lock
drwxr-xr-x 4 root root  4096 Aug 15 06:15 own
drwxr-xr-x 2 root root  4096 Aug 15 06:37 rejected
drwxr-xr-x 4 root root  4096 Aug 15 06:15 trusted

I think the default server certificate creation might be happening after my failed attempt.

Step by step instruction to reproduce

Steps to reproduce the behavior:

  1. Use the code above and start the server

Expected behavior

I expect to see a "certificate.pem" file created in the persistent volume.

Context

  • ( ) my request is related to node-opcua acting as an OPCUA CLIENT

  • (X) my request is related to node-opcua acting as an OPCUA SERVER

  • ( ) I have installed node-opcua from source ( using git clone)

  • (X) I have installed node-opcua as a package ( using npm install )

  • ( ) I am using an application that uses node-opcua

    • ( ) node-red
    • ( ) other : please specify
  • Device: Rasberry Pi4 4Gb RAM

  • OS version: Ubuntu 22.04, MicroK8s 1.27.4

    • ( ) Windows : version : ______
    • (X) Linux : version : 22.04
    • ( ) MacOs : version : ______
    • ( ) Raspbian: version : ______
    • ( ) Other : specify : ______
  • Description of the other OPCUA system I am trying to connect to:

    • Name: ______
    • Version: ______
    • Manufacturer/Software vendor: ______
    • link to the manufacturer or product site: https://
  • node-opcua version: :

    2.108.0

  • Node:

    node --version = v18.17.0

@erossignon
Copy link
Member

erossignon commented Aug 15, 2023

Thank you for reporting, I was working on this bug that has been reported several time already, but I was not able to reproduce;
Thanks to your detailed information with the exact environement you are working on and the code sample, I can now nail it down.

I am able to reproduce the problem using this script that I have adatped from your snippet above, on node 18.17.0, or nodejs 20.04
however, everything works find with nodejs 16.20 or with nodejs 20.5.1

Also to note that this behavior only happens with node-opcua @2.107/108 that introduced for the first time the creation of private keys and certificate without the need of an external openssl command.

This is only possible thanks to nodeJS now implementing the sutble WebCrypto API. and the help of a third party module that complement the functinality @peculiar/crypto.

However, it appears that the suble API in nodeJS is not stable yet in nodejs and its behavior still updating from version to version...

I would not like to revert to use external openssl

The workaround for now, as I am working on a better fix in node-opcua would be for you to either:

  • pre-generate the certificate/ private key externally using a different tool
  • or, may be easier: downgrade temporarily to nodejs 16.20, or use nodejs 20.5.1 if you can.
  • package.json
{
  "name": "issue_1289",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test:18.17": "docker run -it -v $PWD:/home node:18.17 /usr/local/bin/node /home/github_1289.mjs",
    "test:18.17.1": "docker run -it -v $PWD:/home node:18.17.1 /usr/local/bin/node /home/github_1289.mjs",
    "test:16.20": "docker run -it -v $PWD:/home node:16.20 /usr/local/bin/node /home/github_1289.mjs",
    "test:20.5.1": "docker run -it -v $PWD:/home node:20.5.1 /usr/local/bin/node /home/github_1289.mjs",
    "test:20.5.0": "docker run -it -v $PWD:/home node:20.5.0 /usr/local/bin/node /home/github_1289.mjs",
    "test:20.4": "docker run -it -v $PWD:/home node:20.4 /usr/local/bin/node /home/github_1289.mjs"
  },
  "dependencies": {
    "node-opcua": "2.108.0"
  }
}
// github_1289.mjs
import fs from "fs";
import path from "path";
import { OPCUACertificateManager } from "node-opcua";

const pkiRoot = "/tmp/pki1289";
const certificateFile = path.join(pkiRoot, "server_selfsigned_cert_2048.pem");
const selfSignedCertificatePath = certificateFile;
const appName = "RpiPlc";

const data = {
    "applicationUri": "urn:rpi-plc-deployment-55cc7bbc64-r89h4:RpiPlc",
    "dns": [
        "rpi-plc-deployment-55cc7bbc64-r89h4"
    ],
    "outputFile": "/rpi-plc/data/.config/PKI/certificate.pem",
    "subject": "/CN=RpiPlc/O=TestSHome/L=Midway/C=US",
    "startDate": "2023-08-15T06:16:15.077Z",
    "validity": 3650
};


const ModuleName = "";
(async () => {


    console.log("starting from fresh:  deleting existing pki folder")
    if (fs.existsSync(pkiRoot)) {
        fs.rmdirSync(pkiRoot, { recursive: true });
    }

    const serverCertificateManager = new OPCUACertificateManager({
        automaticallyAcceptUnknownCertificate: true,
        rootFolder: pkiRoot
    });
    try {

        await serverCertificateManager.initialize();

        if (!fs.existsSync(certificateFile)) {
            console.log([ModuleName, 'info'], `Creating new certificate file:`);

            const certFileRequest = {
                applicationUri: data.applicationUri,
                dns: data.dns,
                // ip: await getIpAddresses(),
                outputFile: selfSignedCertificatePath,
                subject: `/CN=${appName}/O=TestHome/L=Midway/C=US`,
                startDate: new Date(),
                validity: 365 * 10
            };

            console.log([ModuleName, 'info'], `Self-signed certificate file request params:\n${JSON.stringify(certFileRequest, null, 2)}\n`);

            await serverCertificateManager.createSelfSignedCertificate(certFileRequest);
        }
        else {
            console.log([ModuleName, 'info'], `Using existing certificate file at: ${certificateFile}`);
        }
    }
    catch (ex) {
        console.log(ex);
        console.log([ModuleName, 'error'], `Error creating server self signed certificate: ${ex.message}`);
    }
})();

@erossignon
Copy link
Member

update:

It appears that the issue also shows up with NodeJS20.5.
The cause was a misused of @peculiar/x509 createX509Certificate api when passing the non standard attribute netscapeComment.

This has been fixed in node-opcua-crypto@4.2.0 and is currently being deployed in node-opcua.

@erossignon
Copy link
Member

Fixed in node-opcua@2.110.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants