215 lines
6.5 KiB
Markdown
215 lines
6.5 KiB
Markdown
|
[RSA-CSR.js](https://git.coolaj86.com/coolaj86/rsa-csr.js)
|
||
|
==========
|
||
|
|
||
|
Sponsored by [Root](https://therootcompany.com),
|
||
|
built for [ACME.js](https://git.coolaj86.com/coolaj86/acme.js)
|
||
|
and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock-express.js)
|
||
|
|
||
|
A focused, **zero-dependency** library that can do exactly one thing really, really well:
|
||
|
* Generate a Certificate Signing Requests (CSR), and sign it!
|
||
|
|
||
|
| < 300 lines of code | 1.7k gzipped | 4.7k minified | 8.5k with comments |
|
||
|
|
||
|
Need JWK-to-PEM? Try [Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js)
|
||
|
|
||
|
Need to generate an EC CSR? Try [ECSDA-CSR.js](https://git.coolaj86.com/coolaj86/ecdsa-csr.js)
|
||
|
|
||
|
Features
|
||
|
========
|
||
|
|
||
|
* [x] Universal CSR support (RSA signing) that Just Works™
|
||
|
* Common Name (CN) Subject
|
||
|
* Subject Alternative Names (SANs / altnames)
|
||
|
* 2048, 3072, and 4096 bit JWK RSA
|
||
|
* RSASSA PKCS1 v1.5
|
||
|
* [x] Zero Dependencies
|
||
|
* (no ASN1.js, PKI.js, forge, jrsasign - not even elliptic.js!)
|
||
|
* [x] Quality
|
||
|
* Focused
|
||
|
* Lightweight
|
||
|
* Well-Commented, Well-Documented
|
||
|
* Secure
|
||
|
* [x] Vanilla Node.js
|
||
|
* no school like the old school
|
||
|
* easy to read and understand
|
||
|
|
||
|
Usage
|
||
|
-----
|
||
|
|
||
|
Given an array of domains it uses the first for the Common Name (CN),
|
||
|
also known as Subject, and all of them as the Subject Alternative Names (SANs or altnames).
|
||
|
|
||
|
```js
|
||
|
'use strict';
|
||
|
|
||
|
var rsacsr = require('rsa-csr');
|
||
|
var key = {
|
||
|
"kty": "RSA",
|
||
|
"n": "m2tt...-CNw",
|
||
|
"e": "AQAB",
|
||
|
"d": "Cpfo...HMQQ",
|
||
|
"p": "ynG-...sTCE",
|
||
|
"q": "xIkA...1Q1c",
|
||
|
"dp": "tzDG...B1QE",
|
||
|
"dq": "kh5d...aL48",
|
||
|
"qi": "AlHW...HhFU"
|
||
|
};
|
||
|
var domains = [ 'example.com', 'www.example.com' ];
|
||
|
|
||
|
return rsacsr({ key: key, domains: domains }).then(function (csr) {
|
||
|
console.log('CSR PEM:');
|
||
|
console.log(csr);
|
||
|
});
|
||
|
```
|
||
|
|
||
|
The output will look something like this (but much longer):
|
||
|
|
||
|
```
|
||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||
|
MIIClTCCAX0CAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3
|
||
|
DQEBAQUAA4IBDwAwggEKAoIBAQCba21UHE+VbDTpmYYFZUOV+OQ8AngOCdjROsPC
|
||
|
0KiEfMvEaEM3NQl58u6QL7G7QsEr.....3pIpUUkx5WbwJY6xDrCyFKG8ktpnee6
|
||
|
WjpTOBnpgHUI1/5ydnf0v29L9N+ALIJGKQxhub3iqB6EhCl93iiQtf4e7M/lzX7l
|
||
|
c1xqsSwVZ3RQVY9bRP9NdGuW4hVvscy5ypqRtXPXQpxMnYwfi9qW5Uo=
|
||
|
-----END CERTIFICATE REQUEST-----
|
||
|
```
|
||
|
|
||
|
#### PEM-to-JWK
|
||
|
|
||
|
If you need to convert a PEM to JWK first, do so:
|
||
|
|
||
|
```js
|
||
|
var Rasha = require('rasha');
|
||
|
|
||
|
Rasha.import({ pem: "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAI..." }).then(function (jwk) {
|
||
|
console.log(jwk);
|
||
|
})
|
||
|
```
|
||
|
|
||
|
#### CLI
|
||
|
|
||
|
You're probably better off using OpenSSL for most commandline tasks,
|
||
|
but the `rsa-csr` and `rasha` CLIs are useful for testing and debugging.
|
||
|
|
||
|
```bash
|
||
|
npm install -g rsa-csr
|
||
|
npm install -g rasha
|
||
|
|
||
|
rasha ./privkey.pem > ./privkey.jwk.json
|
||
|
rsa-csr ./privkey.jwk.json example.com,www.example.com > csr.pem
|
||
|
```
|
||
|
|
||
|
### Options
|
||
|
|
||
|
* `key` should be a JWK
|
||
|
* Need PEM support? Use [Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js).
|
||
|
* (supports PEM, DER, PKCS#1 and PKCS#8)
|
||
|
* `domains` must be a list of strings representing domain names
|
||
|
* correctly handles utf-8
|
||
|
* you may also use punycoded, if needed
|
||
|
* `subject` will be `domains[0]` by default
|
||
|
* you shouldn't use this unless you need to
|
||
|
* you may need to if you need utf-8 for domains, but punycode for the subject
|
||
|
|
||
|
### Testing
|
||
|
|
||
|
You can double check that the CSR you get out is actually valid:
|
||
|
|
||
|
```bash
|
||
|
# Generate a key, if needed
|
||
|
openssl genrsa -out ./privkey-rsa.pkcs1.pem $keysize
|
||
|
|
||
|
# Convert to JWK
|
||
|
rasha ./privkey-rsa.pkcs1.pem > ./privkey-rsa.jwk.json
|
||
|
|
||
|
# Create a CSR with your domains
|
||
|
npx rsa-csr ./privkey-rsa.jwk.json example.com,www.example.com > csr.pem
|
||
|
|
||
|
# Verify
|
||
|
openssl req -text -noout -verify -in csr.pem
|
||
|
```
|
||
|
|
||
|
New to Crypto?
|
||
|
--------------
|
||
|
|
||
|
Just a heads up in case you have no idea what you're doing:
|
||
|
|
||
|
First of all, [don't panic](https://coolaj86.com/articles/dont-panic.html).
|
||
|
|
||
|
Next:
|
||
|
|
||
|
* RSA stands for... well, that doesn't matter, actually.
|
||
|
* DSA stands for _Digital Signing Algorithm_.
|
||
|
* RSA a separate standard from EC/ECDSA, but both are *asymmetric*
|
||
|
* Private keys are actually keypairs (they contain the public key)
|
||
|
|
||
|
In many cases the terms get used (and misused) interchangably,
|
||
|
which can be confusing. You'll survive, I promise.
|
||
|
|
||
|
* PEM is just a Base64-encoded DER (think JSON as hex or base64)
|
||
|
* DER is an binary _object notation_ for ASN.1 (think actual stringified JSON or XML)
|
||
|
* ASN.1 is _object notation_ standard (think JSON, the standard)
|
||
|
* X.509 is a suite of schemas (think XLST or json-schema.org)
|
||
|
* PKCS#8, PKIK, SPKI are all X.509 schemas (think defining `firstName` vs `first_name` vs `firstname`)
|
||
|
|
||
|
Now forget about all that and just know this:
|
||
|
|
||
|
**This library solves your problem if** you need RSA _something-or-other_ and CSR _something-or-other_
|
||
|
in order to deal with SSL certificates in an internal organization.
|
||
|
|
||
|
If that's not what you're doing, you may want HTTPS and SSL through
|
||
|
[Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock-express.js),
|
||
|
or you may be looking for something else entirely.
|
||
|
|
||
|
Goals vs Non-Goals
|
||
|
-----
|
||
|
|
||
|
This was built for use by [ACME.js](https://git.coolaj86.com/coolaj86/acme.js)
|
||
|
and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock-express.js).
|
||
|
|
||
|
Rather than trying to make a generic implementation that works with everything under the sun,
|
||
|
this library is intentionally focused on around the use case of generating certificates for
|
||
|
ACME services (such as Let's Encrypt).
|
||
|
|
||
|
That said, [please tell me](https://git.coolaj86.com/coolaj86/rsa-csr.js/issues) if it doesn't
|
||
|
do what you need, it may make sense to add it (or otherwise, perhaps to help you create a fork).
|
||
|
|
||
|
The primary goal of this project is for this code to do exactly (and all of)
|
||
|
what it needs to do - No more, no less.
|
||
|
|
||
|
* Support RSA JWKs
|
||
|
* 2048-bit
|
||
|
* 3072-bit
|
||
|
* 4096-bit
|
||
|
* Support PEM and DER via Rasha.js
|
||
|
* PKCS#1 (traditional)
|
||
|
* PKCS#8
|
||
|
* RSASSA-PKCS1-v1_5
|
||
|
* Vanilla node.js (ECMAScript 5.1)
|
||
|
* No babel
|
||
|
* No dependencies
|
||
|
|
||
|
However, there are a few areas where I'd be willing to stretch:
|
||
|
|
||
|
* Type definition files for altscript languages
|
||
|
|
||
|
It is not a goal of this project to support any RSA profiles
|
||
|
except those that are universally supported by browsers and
|
||
|
are sufficiently secure (overkill is overkill).
|
||
|
|
||
|
> A little copying is better than a little dependency. - [Go Proverbs](https://go-proverbs.github.io) by Rob Pike
|
||
|
|
||
|
This code is considered small and focused enough that,
|
||
|
rather than making it a dependency in other small projects,
|
||
|
I personally just copy over the code.
|
||
|
|
||
|
Hence, all of these projects are MPL-2.0 licensed.
|
||
|
|
||
|
Legal
|
||
|
-----
|
||
|
|
||
|
[RSA-CSR.js](https://git.coolaj86.com/coolaj86/rsa-csr.js) |
|
||
|
MPL-2.0 |
|
||
|
[Terms of Use](https://therootcompany.com/legal/#terms) |
|
||
|
[Privacy Policy](https://therootcompany.com/legal/#privacy)
|