normalize all *Pem *Key* etc to keypair and *Keypair
This commit is contained in:
parent
2c7b7e1bcf
commit
ee48f4a477
41
README.md
41
README.md
|
@ -77,7 +77,9 @@ LeCore.registerNewAccount(options, cb) // returns "regr" registration dat
|
||||||
|
|
||||||
{ newRegUrl: '<url>' // no defaults, specify acmeUrls.newAuthz
|
{ newRegUrl: '<url>' // no defaults, specify acmeUrls.newAuthz
|
||||||
, email: '<email>' // valid email (server checks MX records)
|
, email: '<email>' // valid email (server checks MX records)
|
||||||
, accountPrivateKeyPem: '<ASCII PEM>' // callback to allow user interaction for tosUrl
|
, accountKeypair: { // privateKeyPem or privateKeyJwt
|
||||||
|
privateKeyPem: '<ASCII PEM>'
|
||||||
|
}
|
||||||
, agreeToTerms: fn (tosUrl, cb) {} // must specify agree=tosUrl to continue (or falsey to end)
|
, agreeToTerms: fn (tosUrl, cb) {} // must specify agree=tosUrl to continue (or falsey to end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,8 +89,12 @@ LeCore.getCertificate(options, cb) // returns (err, pems={ key, cert,
|
||||||
{ newAuthzUrl: '<url>' // specify acmeUrls.newAuthz
|
{ newAuthzUrl: '<url>' // specify acmeUrls.newAuthz
|
||||||
, newCertUrl: '<url>' // specify acmeUrls.newCert
|
, newCertUrl: '<url>' // specify acmeUrls.newCert
|
||||||
|
|
||||||
, domainPrivateKeyPem: '<ASCII PEM>'
|
, domainKeypair: {
|
||||||
, accountPrivateKeyPem: '<ASCII PEM>'
|
privateKeyPem: '<ASCII PEM>'
|
||||||
|
}
|
||||||
|
, accountKeypair: {
|
||||||
|
privateKeyPem: '<ASCII PEM>'
|
||||||
|
}
|
||||||
, domains: ['example.com']
|
, domains: ['example.com']
|
||||||
|
|
||||||
, setChallenge: fn (hostname, key, val, cb)
|
, setChallenge: fn (hostname, key, val, cb)
|
||||||
|
@ -118,19 +124,6 @@ LeCore.Acme // Signs requests with JWK
|
||||||
acme.post(url, body, cb) // POST with signature
|
acme.post(url, body, cb) // POST with signature
|
||||||
acme.parseLinks(link) // (internal) parses 'link' header
|
acme.parseLinks(link) // (internal) parses 'link' header
|
||||||
acme.getNonce(url, cb) // (internal) HEAD request to get 'replay-nonce' strings
|
acme.getNonce(url, cb) // (internal) HEAD request to get 'replay-nonce' strings
|
||||||
|
|
||||||
// Note: some of these are not async,
|
|
||||||
// but they will be soon. Don't rely
|
|
||||||
// on their API yet.
|
|
||||||
|
|
||||||
// Crypto Helpers
|
|
||||||
LeCore.leCrypto
|
|
||||||
generateRsaKeypair(bitLen, exponent, cb); // returns { privateKeyPem, privateKeyJwk, publicKeyPem, publicKeyMd5 }
|
|
||||||
thumbprint(lePubKey) // generates public key thumbprint
|
|
||||||
generateSignature(lePrivKey, bodyBuf, nonce) // generates a signature
|
|
||||||
privateJwkToPems(jwk) // { n: '...', e: '...', iq: '...', ... } to PEMs
|
|
||||||
privatePemToJwk // PEM to JWK (see line above)
|
|
||||||
importPemPrivateKey(privateKeyPem) // (internal) returns abstract private key
|
|
||||||
```
|
```
|
||||||
|
|
||||||
For testing and development, you can also inject the dependencies you want to use:
|
For testing and development, you can also inject the dependencies you want to use:
|
||||||
|
@ -161,16 +154,18 @@ This is how you **register an ACME account** and **get an HTTPS certificate**
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var LeCore = require('letiny-core');
|
var LeCore = require('letiny-core');
|
||||||
|
var RSA = require('rsa-compat').RSA;
|
||||||
|
|
||||||
var email = 'user@example.com'; // CHANGE TO YOUR EMAIL
|
var email = 'user@example.com'; // CHANGE TO YOUR EMAIL
|
||||||
var domains = 'example.com'; // CHANGE TO YOUR DOMAIN
|
var domains = 'example.com'; // CHANGE TO YOUR DOMAIN
|
||||||
var acmeDiscoveryUrl = LeCore.stagingServerUrl; // CHANGE to production, when ready
|
var acmeDiscoveryUrl = LeCore.stagingServerUrl; // CHANGE to production, when ready
|
||||||
|
|
||||||
var accountPrivateKeyPem = null;
|
var accountKeypair = null; // { privateKeyPem: null, privateKeyJwk: null };
|
||||||
var domainPrivateKeyPem = null;
|
var domainKeypair = null; // same as above
|
||||||
var acmeUrls = null;
|
var acmeUrls = null;
|
||||||
|
|
||||||
LeCore.leCrypto.generateRsaKeypair(2048, 65537, function (err, pems) {
|
RSA.generateKeypair(2048, 65537, function (err, keypair) {
|
||||||
|
accountKeypair = keypair;
|
||||||
// ...
|
// ...
|
||||||
LeCore.getAcmeUrls(acmeDiscoveryUrl, function (err, urls) {
|
LeCore.getAcmeUrls(acmeDiscoveryUrl, function (err, urls) {
|
||||||
// ...
|
// ...
|
||||||
|
@ -182,7 +177,7 @@ function runDemo() {
|
||||||
LeCore.registerNewAccount(
|
LeCore.registerNewAccount(
|
||||||
{ newRegUrl: acmeUrls.newReg
|
{ newRegUrl: acmeUrls.newReg
|
||||||
, email: email
|
, email: email
|
||||||
, accountPrivateKeyPem: accountPrivateKeyPem
|
, accountKeypair: accountKeypair
|
||||||
, agreeToTerms: function (tosUrl, done) {
|
, agreeToTerms: function (tosUrl, done) {
|
||||||
|
|
||||||
// agree to the exact version of these terms
|
// agree to the exact version of these terms
|
||||||
|
@ -195,8 +190,8 @@ function runDemo() {
|
||||||
{ newAuthzUrl: acmeUrls.newAuthz
|
{ newAuthzUrl: acmeUrls.newAuthz
|
||||||
, newCertUrl: acmeUrls.newCert
|
, newCertUrl: acmeUrls.newCert
|
||||||
|
|
||||||
, domainPrivateKeyPem: domainPrivateKeyPem
|
, domainKeypair: domainKeypair
|
||||||
, accountPrivateKeyPem: accountPrivateKeyPem
|
, accountKeypair: accountKeypair
|
||||||
, domains: domains
|
, domains: domains
|
||||||
|
|
||||||
, setChallenge: challengeStore.set
|
, setChallenge: challengeStore.set
|
||||||
|
@ -323,4 +318,4 @@ MPL 2.0
|
||||||
All of the code is available under the MPL-2.0.
|
All of the code is available under the MPL-2.0.
|
||||||
|
|
||||||
Some of the files are original work not modified from `letiny`
|
Some of the files are original work not modified from `letiny`
|
||||||
and are made available under MIT as well (check file headers).
|
and are made available under MIT and Apache-2.0 as well (check file headers).
|
||||||
|
|
|
@ -19,9 +19,6 @@ function _toStandardBase64(str) {
|
||||||
|
|
||||||
module.exports.create = function (deps) {
|
module.exports.create = function (deps) {
|
||||||
var request=deps.request;
|
var request=deps.request;
|
||||||
//var importPemPrivateKey = deps.leCrypto.importPemPrivateKey;
|
|
||||||
//var thumbprinter = deps.leCrypto.thumbprint;
|
|
||||||
//var generateCsr = deps.leCrypto.generateCsr || deps.leCrypto.generateCSR;
|
|
||||||
var Acme = deps.Acme;
|
var Acme = deps.Acme;
|
||||||
var RSA = deps.RSA;
|
var RSA = deps.RSA;
|
||||||
|
|
||||||
|
@ -164,7 +161,7 @@ module.exports.create = function (deps) {
|
||||||
}
|
}
|
||||||
challenge=httpChallenges[0];
|
challenge=httpChallenges[0];
|
||||||
|
|
||||||
thumbprint=RSA.thumbprint(state.accountKeyPair);
|
thumbprint=RSA.thumbprint(state.accountKeypair);
|
||||||
keyAuthorization=challenge.token+'.'+thumbprint;
|
keyAuthorization=challenge.token+'.'+thumbprint;
|
||||||
state.responseUrl=challenge.uri;
|
state.responseUrl=challenge.uri;
|
||||||
|
|
||||||
|
@ -226,7 +223,7 @@ module.exports.create = function (deps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCertificate() {
|
function getCertificate() {
|
||||||
var csr=RSA.generateCsrWeb64(state.certPrivateKey, state.validatedDomains);
|
var csr=RSA.generateCsrWeb64(RSA.exportPrivateKeyPem(state.certKeypair), state.validatedDomains);
|
||||||
log('Requesting certificate...');
|
log('Requesting certificate...');
|
||||||
state.acme.post(state.newCertUrl, {
|
state.acme.post(state.newCertUrl, {
|
||||||
resource:'new-cert',
|
resource:'new-cert',
|
||||||
|
@ -325,7 +322,7 @@ module.exports.create = function (deps) {
|
||||||
var cert;
|
var cert;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cert=certBufferToPem(state.certificate);
|
cert = certBufferToPem(state.certificate);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(e.stack);
|
console.error(e.stack);
|
||||||
//cb(new Error("Could not write output files. Please check permissions!"));
|
//cb(new Error("Could not write output files. Please check permissions!"));
|
||||||
|
@ -335,7 +332,7 @@ module.exports.create = function (deps) {
|
||||||
|
|
||||||
cb(null, {
|
cb(null, {
|
||||||
cert: cert
|
cert: cert
|
||||||
, key: state.certPrivateKeyPem
|
, key: RSA.exportPrivateKeyPem(state.certKeypair)
|
||||||
, ca: state.caCert
|
, ca: state.caCert
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -360,11 +357,11 @@ module.exports.create = function (deps) {
|
||||||
if (!options.newCertUrl) {
|
if (!options.newCertUrl) {
|
||||||
return handleErr(new Error("options.newCertUrl must be the new certificate url"));
|
return handleErr(new Error("options.newCertUrl must be the new certificate url"));
|
||||||
}
|
}
|
||||||
if (!options.accountPrivateKeyPem) {
|
if (!options.accountKeypair) {
|
||||||
return handleErr(new Error("options.accountPrivateKeyPem must be an ascii private key pem"));
|
return handleErr(new Error("options.accountKeypair must be an object with `privateKeyPem` and/or `privateKeyJwk`"));
|
||||||
}
|
}
|
||||||
if (!options.domainPrivateKeyPem) {
|
if (!options.domainKeypair) {
|
||||||
return handleErr(new Error("options.domainPrivateKeyPem must be an ascii private key pem"));
|
return handleErr(new Error("options.domainKeypair must be an object with `privateKeyPem` and/or `privateKeyJwk`"));
|
||||||
}
|
}
|
||||||
if (!options.setChallenge) {
|
if (!options.setChallenge) {
|
||||||
return handleErr(new Error("options.setChallenge must be function(hostname, challengeKey, tokenValue, done) {}"));
|
return handleErr(new Error("options.setChallenge must be function(hostname, challengeKey, tokenValue, done) {}"));
|
||||||
|
@ -378,11 +375,9 @@ module.exports.create = function (deps) {
|
||||||
|
|
||||||
state.domains = options.domains.slice(0); // copy array
|
state.domains = options.domains.slice(0); // copy array
|
||||||
try {
|
try {
|
||||||
state.accountKeyPem=options.accountPrivateKeyPem;
|
state.acme = new Acme(state.accountKeypair);
|
||||||
state.accountKeyPair=RSA.import({ privateKeyPem: state.accountKeyPem });
|
state.accountKeypair = options.accountKeypair;
|
||||||
state.acme=new Acme(state.accountKeyPair);
|
state.certKeypair = options.domainKeypair;
|
||||||
state.certPrivateKeyPem=options.domainPrivateKeyPem;
|
|
||||||
state.certPrivateKey=RSA.import({ privateKeyPem: state.certPrivateKeyPem });
|
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
return handleErr(err, 'Failed to parse privateKey');
|
return handleErr(err, 'Failed to parse privateKey');
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,8 +103,8 @@ module.exports.create = function (deps) {
|
||||||
|
|
||||||
var state = {};
|
var state = {};
|
||||||
|
|
||||||
if (!options.accountPrivateKeyPem) {
|
if (!options.accountKeypair) {
|
||||||
return handleErr(new Error("options.accountPrivateKeyPem must be an ascii private key pem"));
|
return handleErr(new Error("options.accountKeypair must be an object with `privateKeyPem` and/or `privateKeyJwk`"));
|
||||||
}
|
}
|
||||||
if (!options.agreeToTerms) {
|
if (!options.agreeToTerms) {
|
||||||
cb(new Error("options.agreeToTerms must be function (tosUrl, fn => (err, true))"));
|
cb(new Error("options.agreeToTerms must be function (tosUrl, fn => (err, true))"));
|
||||||
|
@ -119,9 +119,8 @@ module.exports.create = function (deps) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.accountKeyPem=options.accountPrivateKeyPem;
|
state.accountKeypair = options.accountKeypair;
|
||||||
state.accountKeyPair=RSA.import({ privateKeyPem: state.accountKeyPem });
|
state.acme=new Acme(state.accountKeypair);
|
||||||
state.acme=new Acme(state.accountKeyPair);
|
|
||||||
|
|
||||||
register();
|
register();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue