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)
 |