moving to rsa-compat
This commit is contained in:
parent
e0909ad0ca
commit
55707a417d
|
@ -11,7 +11,7 @@ module.exports.create = function (deps) {
|
|||
var NOOP=function () {};
|
||||
var log=NOOP;
|
||||
var request=require('request');
|
||||
var generateSignature=deps.leCrypto.generateSignature;
|
||||
var generateSignature=deps.RSA.signJws;
|
||||
|
||||
function Acme(privateKey) {
|
||||
this.privateKey=privateKey;
|
||||
|
|
|
@ -9,53 +9,13 @@
|
|||
module.exports.create = function (deps) {
|
||||
var request=deps.request;
|
||||
var toStandardB64 = deps.leUtils.toStandardB64;
|
||||
var importPemPrivateKey = deps.leCrypto.importPemPrivateKey;
|
||||
var thumbprinter = deps.leCrypto.thumbprint;
|
||||
var generateCsr = deps.leCrypto.generateCsr || deps.leCrypto.generateCSR;
|
||||
//var importPemPrivateKey = deps.leCrypto.importPemPrivateKey;
|
||||
//var thumbprinter = deps.leCrypto.thumbprint;
|
||||
//var generateCsr = deps.leCrypto.generateCsr || deps.leCrypto.generateCSR;
|
||||
var Acme = deps.Acme;
|
||||
var RSA = deps.RSA;
|
||||
|
||||
function getCert(options, cb) {
|
||||
var NOOP = function () {};
|
||||
var log = options.debug ? console.log : NOOP;
|
||||
var state={
|
||||
validatedDomains:[]
|
||||
, validAuthorizationUrls:[]
|
||||
, newAuthzUrl: options.newAuthzUrl
|
||||
, newCertUrl: options.newCertUrl
|
||||
};
|
||||
|
||||
if (!options.newAuthzUrl) {
|
||||
return handleErr(new Error("options.newAuthzUrl must be the authorization url"));
|
||||
}
|
||||
if (!options.newCertUrl) {
|
||||
return handleErr(new Error("options.newCertUrl must be the new certificate url"));
|
||||
}
|
||||
if (!options.accountPrivateKeyPem) {
|
||||
return handleErr(new Error("options.accountPrivateKeyPem must be an ascii private key pem"));
|
||||
}
|
||||
if (!options.domainPrivateKeyPem) {
|
||||
return handleErr(new Error("options.domainPrivateKeyPem must be an ascii private key pem"));
|
||||
}
|
||||
if (!options.setChallenge) {
|
||||
return handleErr(new Error("options.setChallenge must be function(hostname, challengeKey, tokenValue, done) {}"));
|
||||
}
|
||||
if (!options.removeChallenge) {
|
||||
return handleErr(new Error("options.removeChallenge must be function(hostname, challengeKey, done) {}"));
|
||||
}
|
||||
if (!(options.domains && options.domains.length)) {
|
||||
return handleErr(new Error("options.domains must be an array of domains such as ['example.com', 'www.example.com']"));
|
||||
}
|
||||
|
||||
state.domains = options.domains.slice(0); // copy array
|
||||
try {
|
||||
state.accountKeyPem=options.accountPrivateKeyPem;
|
||||
state.accountKeyPair=importPemPrivateKey(state.accountKeyPem);
|
||||
state.acme=new Acme(state.accountKeyPair);
|
||||
state.certPrivateKeyPem=options.domainPrivateKeyPem;
|
||||
state.certPrivateKey=importPemPrivateKey(state.certPrivateKeyPem);
|
||||
} catch(err) {
|
||||
return handleErr(err, 'Failed to parse privateKey');
|
||||
}
|
||||
|
||||
function bodyToError(res, body) {
|
||||
var err;
|
||||
|
@ -80,7 +40,7 @@ module.exports.create = function (deps) {
|
|||
if (Math.floor(res.statusCode / 100) !== 2) {
|
||||
err = new Error("[Error] letiny-core: not 200 ok");
|
||||
err.code = "E_STATUS_CODE";
|
||||
err.type = body.type
|
||||
err.type = body.type;
|
||||
err.description = body;
|
||||
err.detail = body.detail;
|
||||
console.error("TODO: modules which depend on this module should expose this error properly but since some of them don't, I expose it here directly:");
|
||||
|
@ -101,8 +61,6 @@ module.exports.create = function (deps) {
|
|||
return body;
|
||||
}
|
||||
|
||||
nextDomain();
|
||||
|
||||
function nextDomain() {
|
||||
if (state.domains.length > 0) {
|
||||
getChallenges(state.domains.shift());
|
||||
|
@ -130,44 +88,11 @@ module.exports.create = function (deps) {
|
|||
}
|
||||
}
|
||||
|
||||
getReadyToValidate(err, res, body)
|
||||
getReadyToValidate(err, res, body);
|
||||
});
|
||||
}
|
||||
|
||||
function getReadyToValidate(err, res, body) {
|
||||
var links, authz, httpChallenges, challenge, thumbprint, keyAuthorization, challengePath;
|
||||
|
||||
if (err) {
|
||||
return handleErr(err);
|
||||
}
|
||||
|
||||
if (Math.floor(res.statusCode/100)!==2) {
|
||||
return handleErr(null, 'Authorization request failed ('+res.statusCode+')');
|
||||
}
|
||||
|
||||
links=Acme.parseLink(res.headers.link);
|
||||
if (!links || !('next' in links)) {
|
||||
return handleErr(err, 'Server didn\'t provide information to proceed (2)');
|
||||
}
|
||||
|
||||
state.authorizationUrl=res.headers.location;
|
||||
state.newCertUrl=links.next;
|
||||
|
||||
authz=body;
|
||||
|
||||
httpChallenges=authz.challenges.filter(function(x) {
|
||||
return x.type==='http-01';
|
||||
});
|
||||
if (httpChallenges.length===0) {
|
||||
return handleErr(null, 'Server didn\'t offer any challenge we can handle.');
|
||||
}
|
||||
challenge=httpChallenges[0];
|
||||
|
||||
thumbprint=thumbprinter(state.accountKeyPair.publicKey);
|
||||
keyAuthorization=challenge.token+'.'+thumbprint;
|
||||
state.responseUrl=challenge.uri;
|
||||
|
||||
options.setChallenge(state.domain, challenge.token, keyAuthorization, challengeDone);
|
||||
|
||||
function challengeDone(err) {
|
||||
if (err) {
|
||||
|
@ -200,6 +125,41 @@ module.exports.create = function (deps) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
var links, authz, httpChallenges, challenge, thumbprint, keyAuthorization;
|
||||
|
||||
if (err) {
|
||||
return handleErr(err);
|
||||
}
|
||||
|
||||
if (Math.floor(res.statusCode/100)!==2) {
|
||||
return handleErr(null, 'Authorization request failed ('+res.statusCode+')');
|
||||
}
|
||||
|
||||
links=Acme.parseLink(res.headers.link);
|
||||
if (!links || !('next' in links)) {
|
||||
return handleErr(err, 'Server didn\'t provide information to proceed (2)');
|
||||
}
|
||||
|
||||
state.authorizationUrl=res.headers.location;
|
||||
state.newCertUrl=links.next;
|
||||
|
||||
authz=body;
|
||||
|
||||
httpChallenges=authz.challenges.filter(function(x) {
|
||||
return x.type==='http-01';
|
||||
});
|
||||
if (httpChallenges.length===0) {
|
||||
return handleErr(null, 'Server didn\'t offer any challenge we can handle.');
|
||||
}
|
||||
challenge=httpChallenges[0];
|
||||
|
||||
thumbprint=RSA.thumbprint(state.accountKeyPair);
|
||||
keyAuthorization=challenge.token+'.'+thumbprint;
|
||||
state.responseUrl=challenge.uri;
|
||||
|
||||
options.setChallenge(state.domain, challenge.token, keyAuthorization, challengeDone);
|
||||
|
||||
}
|
||||
|
||||
function ensureValidation(err, res, body, unlink) {
|
||||
|
@ -256,7 +216,7 @@ module.exports.create = function (deps) {
|
|||
}
|
||||
|
||||
function getCertificate() {
|
||||
var csr=generateCsr(state.certPrivateKey, state.validatedDomains);
|
||||
var csr=RSA.generateCsrWeb64(state.certPrivateKey, state.validatedDomains);
|
||||
log('Requesting certificate...');
|
||||
state.acme.post(state.newCertUrl, {
|
||||
resource:'new-cert',
|
||||
|
@ -374,6 +334,50 @@ module.exports.create = function (deps) {
|
|||
log(text, err, info);
|
||||
cb(err || new Error(text));
|
||||
}
|
||||
|
||||
var NOOP = function () {};
|
||||
var log = options.debug ? console.log : NOOP;
|
||||
var state={
|
||||
validatedDomains:[]
|
||||
, validAuthorizationUrls:[]
|
||||
, newAuthzUrl: options.newAuthzUrl
|
||||
, newCertUrl: options.newCertUrl
|
||||
};
|
||||
|
||||
if (!options.newAuthzUrl) {
|
||||
return handleErr(new Error("options.newAuthzUrl must be the authorization url"));
|
||||
}
|
||||
if (!options.newCertUrl) {
|
||||
return handleErr(new Error("options.newCertUrl must be the new certificate url"));
|
||||
}
|
||||
if (!options.accountPrivateKeyPem) {
|
||||
return handleErr(new Error("options.accountPrivateKeyPem must be an ascii private key pem"));
|
||||
}
|
||||
if (!options.domainPrivateKeyPem) {
|
||||
return handleErr(new Error("options.domainPrivateKeyPem must be an ascii private key pem"));
|
||||
}
|
||||
if (!options.setChallenge) {
|
||||
return handleErr(new Error("options.setChallenge must be function(hostname, challengeKey, tokenValue, done) {}"));
|
||||
}
|
||||
if (!options.removeChallenge) {
|
||||
return handleErr(new Error("options.removeChallenge must be function(hostname, challengeKey, done) {}"));
|
||||
}
|
||||
if (!(options.domains && options.domains.length)) {
|
||||
return handleErr(new Error("options.domains must be an array of domains such as ['example.com', 'www.example.com']"));
|
||||
}
|
||||
|
||||
state.domains = options.domains.slice(0); // copy array
|
||||
try {
|
||||
state.accountKeyPem=options.accountPrivateKeyPem;
|
||||
state.accountKeyPair=RSA.import({ privateKeyPem: state.accountKeyPem });
|
||||
state.acme=new Acme(state.accountKeyPair);
|
||||
state.certPrivateKeyPem=options.domainPrivateKeyPem;
|
||||
state.certPrivateKey=RSA.import({ privateKeyPem: state.certPrivateKeyPem });
|
||||
} catch(err) {
|
||||
return handleErr(err, 'Failed to parse privateKey');
|
||||
}
|
||||
|
||||
nextDomain();
|
||||
}
|
||||
|
||||
function certBufferToPem(cert) {
|
||||
|
|
38
lib/node.js
38
lib/node.js
|
@ -6,43 +6,9 @@
|
|||
'use strict';
|
||||
|
||||
var request = require('request');
|
||||
var RSA = require('rsa-compat').RSA;
|
||||
var leUtils = require('./acme-util');
|
||||
var leCrypto = require('./letsencrypt-node-crypto');
|
||||
var leExtra = require('./letsencrypt-forge-extra');
|
||||
var leForge = require('./letsencrypt-forge');
|
||||
var leUrsa;
|
||||
|
||||
try {
|
||||
leUrsa = require('./letsencrypt-ursa');
|
||||
} catch(e) {
|
||||
leUrsa = {};
|
||||
// things will run a little slower on keygen, but it'll work on windows
|
||||
// (but don't try this on raspberry pi - 20+ MINUTES key generation)
|
||||
}
|
||||
|
||||
// order of crypto precdence is
|
||||
// * native
|
||||
// * ursa
|
||||
// * forge extra (the new one aimed to be less-forgey)
|
||||
// * forge (fallback)
|
||||
Object.keys(leUrsa).forEach(function (key) {
|
||||
if (!leCrypto[key]) {
|
||||
leCrypto[key] = leUrsa[key];
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(leExtra).forEach(function (key) {
|
||||
if (!leCrypto[key]) {
|
||||
leCrypto[key] = leExtra[key];
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(leForge).forEach(function (key) {
|
||||
if (!leCrypto[key]) {
|
||||
leCrypto[key] = leForge[key];
|
||||
}
|
||||
});
|
||||
|
||||
module.exports.request = request;
|
||||
module.exports.leCrypto = leCrypto;
|
||||
module.exports.leUtils = leUtils;
|
||||
module.exports.RSA = RSA;
|
||||
|
|
|
@ -9,33 +9,10 @@
|
|||
module.exports.create = function (deps) {
|
||||
var NOOP=function () {}, log=NOOP;
|
||||
var request=deps.request;
|
||||
var importPemPrivateKey=deps.leCrypto.importPemPrivateKey;
|
||||
var RSA = deps.RSA;
|
||||
var Acme = deps.Acme;
|
||||
|
||||
function registerNewAccount(options, cb) {
|
||||
var state = {};
|
||||
|
||||
if (!options.accountPrivateKeyPem) {
|
||||
return handleErr(new Error("options.accountPrivateKeyPem must be an ascii private key pem"));
|
||||
}
|
||||
if (!options.agreeToTerms) {
|
||||
cb(new Error("options.agreeToTerms must be function (tosUrl, fn => (err, true))"));
|
||||
return;
|
||||
}
|
||||
if (!options.newRegUrl) {
|
||||
cb(new Error("options.newRegUrl must be the a new registration url"));
|
||||
return;
|
||||
}
|
||||
if (!options.email) {
|
||||
cb(new Error("options.email must be an email"));
|
||||
return;
|
||||
}
|
||||
|
||||
state.accountKeyPem=options.accountPrivateKeyPem;
|
||||
state.accountKeyPair=importPemPrivateKey(state.accountKeyPem);
|
||||
state.acme=new Acme(state.accountKeyPair);
|
||||
|
||||
register();
|
||||
|
||||
function register() {
|
||||
state.acme.post(options.newRegUrl, {
|
||||
|
@ -123,6 +100,30 @@ module.exports.create = function (deps) {
|
|||
log(text, err, info);
|
||||
cb(err || new Error(text));
|
||||
}
|
||||
|
||||
var state = {};
|
||||
|
||||
if (!options.accountPrivateKeyPem) {
|
||||
return handleErr(new Error("options.accountPrivateKeyPem must be an ascii private key pem"));
|
||||
}
|
||||
if (!options.agreeToTerms) {
|
||||
cb(new Error("options.agreeToTerms must be function (tosUrl, fn => (err, true))"));
|
||||
return;
|
||||
}
|
||||
if (!options.newRegUrl) {
|
||||
cb(new Error("options.newRegUrl must be the a new registration url"));
|
||||
return;
|
||||
}
|
||||
if (!options.email) {
|
||||
cb(new Error("options.email must be an email"));
|
||||
return;
|
||||
}
|
||||
|
||||
state.accountKeyPem=options.accountPrivateKeyPem;
|
||||
state.accountKeyPair=RSA.import({ privateKeyPem: state.accountKeyPem });
|
||||
state.acme=new Acme(state.accountKeyPair);
|
||||
|
||||
register();
|
||||
}
|
||||
|
||||
return registerNewAccount;
|
||||
|
|
2
node.js
2
node.js
|
@ -26,8 +26,6 @@ function create(deps) {
|
|||
LeCore.registerNewAccount = require('./lib/register-new-account').create(deps);
|
||||
LeCore.getCertificate = require('./lib/get-certificate').create(deps);
|
||||
|
||||
LeCore.leCrypto = deps.leCrypto;
|
||||
|
||||
return LeCore;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "letiny-core",
|
||||
"version": "1.0.5",
|
||||
"version": "1.1.0",
|
||||
"description": "A framework for building letsencrypt clients, forked from letiny",
|
||||
"main": "node.js",
|
||||
"browser": "browser.js",
|
||||
|
@ -30,7 +30,8 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"node-forge": "^0.6.38",
|
||||
"request": "^2.55.0"
|
||||
"request": "^2.55.0",
|
||||
"rsa-compat": "^1.0.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"ursa": "^0.9.1"
|
||||
|
|
Loading…
Reference in New Issue