njs
njs copied to clipboard
Is it possible generate x509 certificate using njs?
What mkcert does. Or @peculiar/x509 npm library has support for. ex: https://codesandbox.io/s/generate-cert-fjwfh?file=/index.html
Hi @sarim, thank you for a great question.
A short answer is Yes, it is possible. A longer answer, it is a bit complicated.
The acme-njs repo contains some code that uses pkijs
library to create Certificate Signature Request here. it is a bit tricky to get pkijs working in NJS/NGINX runtime, and required extra work (e.g. this).
Similarly to CertificationRequest that I was using you can follow the example of creating a self-signed request here
We open-sourced a new repo that enables ACME integration for NGINX. Please check it out: njs-acme. I hope you'll be able to use a similar approach to address your problem of creating a Certificate.
Wow thank you very much. Thats a lot of good resources to explore. Previously I tried using https://www.npmjs.com/package/@peculiar/x509, but packaging it to one file and fighting with babel to compile it to njs acceptable syntax failed. as njs doesn't have promise, class etc...
I also tried https://github.com/mdn/dom-examples/blob/main/web-crypto/sign-verify/rsassa-pkcs1.js from MDN examples, but it also didn't work.
My goal is to automatically make self signed ssl certs when browsing my local development domains ( https://project-name.test ) . njs-acme looks promising, Hopefully I can get the babel/rollup/tsc configurations from there and make it work this time. Thanks again 🚀
Thanks for sharing your use case. Let's encrypt has https://github.com/letsencrypt/pebble for testing integrations. We are using it in integration testing for njs-acme. So you can spin up a pebble instance in your environment and configure NGINX with njs-acme to use that ACME and it would generate certs self-signed certs. you may just need that part of njs-acme, then I guess your use case can be covered partially already. Check out https://github.com/nginxinc/njs-acme/tree/main/integration-tests folder for more info and explore. Feel free to raise an issue if you got any.
Previously I tried using https://www.npmjs.com/package/@peculiar/x509, but packaging it to one file and fighting with babel to compile it to njs acceptable syntax failed. as njs doesn't have promise, class etc...
Yes, I feel your pain. I ran into exactly those issues when writing njs-acme code. I haven't used https://www.npmjs.com/package/@peculiar/x509 yet. will try it out in some time.
Yes, I feel your pain. I ran into exactly those issues when writing njs-acme code
yeah :(.
I digged up my old code. I see I had these polyfills,
import 'weakmap-polyfill';
import 'smap/smap-shim';
import "core-js/actual/set";
I started fresh from njs-typescript-starter project, maybe those polyfills aren't needed anymore, or I haven't managed to reach the code-path that needs those polyfills not sure.
So this code:
import * as x509 from "@peculiar/x509";
x509.cryptoProvider.set(crypto);
yarn test
results in
----- Error Log -----
2023/08/11 07:45:45 [error] 22310#22310: *2 js exception: RangeError: Maximum call stack size exceeded
at main (/home/gittu/njs-ssl/integration-tests/:1)
So maybe I'm getting stuck in these maximum call size exceeded error, and actual code haven't been called yet. So those polyfills maybe will be needed.
Then I tried to use pkijs, seeing it in your repo.
import querystring from 'querystring'
import * as pkijs from 'pkijs'
// import * as asn1js from 'asn1js'
// workaround for PKI.JS to work
globalThis.unescape = querystring.unescape
// make PKI.JS to work with webcrypto
pkijs.setEngine(
'webcrypto',
new pkijs.CryptoEngine({ name: 'webcrypto', crypto: crypto })
)
yarn test
[emerg] 31478#31478: SyntaxError: await in arguments not supported in /home/gittu/njs-ssl/dist/main.js:5487
line 5487 is basically whole pkijs in one line. import * as pkijs from 'pkijs' this line.
Any idea?
Update
Seems like I have to use 0.2.1 of babel-preset-njs. The latest 0.7.0 removed couple of plugins as its not needed anymore but I guess its actually needed. pkijs.setEngine call successes with 0.2.1 of babel-preset-njs.
Update 2
Possibility related to https://github.com/jirutka/nginx-binaries/issues/15 nginx-typescript-starter uses nginx binaries from jirutka/nginx-binaries to run tests, and those binaries includes old 0.7 njs. Not latest 0.8.
The latest 0.7.0 removed couple of plugins as its not needed anymore but I guess its actually needed. pkijs.setEngine call successes with 0.2.1 of babel-preset-njs.
Can you please investigate where’s the problem? babel-preset-njs 0.7.0 should be compatible with njs 0.7. I would start with tweaking compiler assumptions (you can override them in your babel config). There are optimised for the best performance, not compatibility with every npm library.
and those binaries includes old 0.7 njs. Not latest 0.8.
The periodic CI workflow was stuck due to changes in the latest njs that needed some adjustment of the build scripts. I fixed it now and the new versions will be available shortly.
Can you please investigate where’s the problem? babel-preset-njs 0.7.0 should be compatible with njs 0.7
From my previous comment: [emerg] 31478#31478: SyntaxError: await in arguments not supported in /home/gittu/njs-ssl/dist/main.js:5487
Googling that error code I find this: https://github.com/nginx/njs/commit/455f6d4f0447a60329c21928d67f61c79ac3b243
{ njs_str("async function f1() {try {f(await f1)} catch(e) {}}"),
njs_str("SyntaxError: await in arguments not supported in 1") },
So thats the error. await isn't 100% supported, so when you remove async-await polyfill, it errors. So I guess it needs to be transpiled, maybe
fn(await fn2());
To
var r1 = await fn2();
fn(r1);
Another observation njs-acme project also uses "^0.2.1" https://github.com/nginx/njs-acme/blob/main/package.json#L57C6-L57C34
{ njs_str("async function f1() {try {f(await f1)} catch(e) {}}"), njs_str("SyntaxError: await in arguments not supported in 1") },
Hm, the problem is that it’s not documented, I had no idea that it’s not supported. /cc @xeioex