advance to CSR
This commit is contained in:
parent
d646edf045
commit
6c0aed0491
108
js/app.js
108
js/app.js
|
@ -19,8 +19,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitForm(ev) {
|
function submitForm(ev) {
|
||||||
steps[i].submit(ev);
|
var j = i;
|
||||||
i += 1;
|
i += 1;
|
||||||
|
steps[j].submit(ev);
|
||||||
}
|
}
|
||||||
$qsa('.js-acme-form').forEach(function ($el) {
|
$qsa('.js-acme-form').forEach(function ($el) {
|
||||||
$el.addEventListener('submit', function (ev) {
|
$el.addEventListener('submit', function (ev) {
|
||||||
|
@ -51,7 +52,12 @@
|
||||||
};
|
};
|
||||||
steps[1].submit = function () {
|
steps[1].submit = function () {
|
||||||
info.identifiers = $qs('.js-acme-domains').value.split(/\s*,\s*/g).map(function (hostname) {
|
info.identifiers = $qs('.js-acme-domains').value.split(/\s*,\s*/g).map(function (hostname) {
|
||||||
return { type: 'dns', value: hostname.trim() };
|
return { type: 'dns', value: hostname.toLowerCase().trim() };
|
||||||
|
});
|
||||||
|
info.identifiers.sort(function (a, b) {
|
||||||
|
if (a === b) { return 0; }
|
||||||
|
if (a < b) { return 1; }
|
||||||
|
if (a > b) { return -1; }
|
||||||
});
|
});
|
||||||
|
|
||||||
return BACME.directory($qs('.js-acme-directory-url').value).then(function (directory) {
|
return BACME.directory($qs('.js-acme-directory-url').value).then(function (directory) {
|
||||||
|
@ -59,6 +65,7 @@
|
||||||
return BACME.nonce().then(function (_nonce) {
|
return BACME.nonce().then(function (_nonce) {
|
||||||
nonce = _nonce;
|
nonce = _nonce;
|
||||||
|
|
||||||
|
console.log("MAGIC STEP NUMBER in 1 is:", i);
|
||||||
steps[i]();
|
steps[i]();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -147,6 +154,7 @@
|
||||||
signedOrder: signedOrder
|
signedOrder: signedOrder
|
||||||
}).then(function (order) {
|
}).then(function (order) {
|
||||||
info.finalizeUrl = order.finalize;
|
info.finalizeUrl = order.finalize;
|
||||||
|
info.orderUrl = order.url; // from header Location ???
|
||||||
return BACME.thumbprint({ jwk: jwk }).then(function (thumbprint) {
|
return BACME.thumbprint({ jwk: jwk }).then(function (thumbprint) {
|
||||||
return BACME.challenges.all().then(function (claims) {
|
return BACME.challenges.all().then(function (claims) {
|
||||||
console.log('claims:');
|
console.log('claims:');
|
||||||
|
@ -176,7 +184,7 @@
|
||||||
, challengeDomain: hostname
|
, challengeDomain: hostname
|
||||||
});
|
});
|
||||||
return BACME.challenges['dns-01']({
|
return BACME.challenges['dns-01']({
|
||||||
keyAuth: keyAuth
|
keyAuth: keyAuth.value
|
||||||
, challengeDomain: hostname
|
, challengeDomain: hostname
|
||||||
}).then(function (dnsAuth) {
|
}).then(function (dnsAuth) {
|
||||||
var data = {
|
var data = {
|
||||||
|
@ -230,6 +238,7 @@
|
||||||
|
|
||||||
updateChallengeType();
|
updateChallengeType();
|
||||||
|
|
||||||
|
console.log("MAGIC STEP NUMBER in 2 is:", i);
|
||||||
steps[i]();
|
steps[i]();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -249,23 +258,44 @@
|
||||||
$qs('.js-acme-form-challenges').hidden = false;
|
$qs('.js-acme-form-challenges').hidden = false;
|
||||||
};
|
};
|
||||||
steps[3].submit = function () {
|
steps[3].submit = function () {
|
||||||
var chType = $qs('.js-acme-challenge-type').value;
|
// for now just show the next page immediately (its a spinner)
|
||||||
var ps = [];
|
console.log("MAGIC STEP NUMBER is:", i);
|
||||||
|
|
||||||
|
var chType;
|
||||||
|
Array.prototype.some.call($qsa('.js-acme-challenge-type'), function ($el) {
|
||||||
|
if ($el.checked) {
|
||||||
|
chType = $el.value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('chType is:', chType);
|
||||||
|
var chs = [];
|
||||||
|
|
||||||
// do each wildcard, if any
|
// do each wildcard, if any
|
||||||
// do each challenge, by selected type only
|
// do each challenge, by selected type only
|
||||||
[ 'wildcard', chType].forEach(function (typ) {
|
[ 'wildcard', chType].forEach(function (typ) {
|
||||||
info.challenges[typ].forEach(function (ch) {
|
info.challenges[typ].forEach(function (ch) {
|
||||||
// { jwk, challengeUrl, accountId (kid) }
|
// { jwk, challengeUrl, accountId (kid) }
|
||||||
ps.push(BACME.challenges.accept({
|
chs.push({
|
||||||
jwk: info.jwk
|
jwk: info.jwk
|
||||||
, challengeUrl: ch.url
|
, challengeUrl: ch.url
|
||||||
, accountId: info.kid
|
, accountId: info.kid
|
||||||
}));
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(ps).then(function (results) {
|
var results = [];
|
||||||
|
function nextChallenge() {
|
||||||
|
var ch = chs.pop();
|
||||||
|
if (!ch) { return results; }
|
||||||
|
return BACME.challenges.accept(ch).then(function (result) {
|
||||||
|
results.push(result);
|
||||||
|
return nextChallenge();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
steps[i]();
|
||||||
|
return nextChallenge().then(function (results) {
|
||||||
console.log('challenge status:', results);
|
console.log('challenge status:', results);
|
||||||
var polls = results.slice(0);
|
var polls = results.slice(0);
|
||||||
var allsWell = true;
|
var allsWell = true;
|
||||||
|
@ -276,7 +306,9 @@
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
return Promise.all(polls.map(function (poll) {
|
return Promise.all(polls.map(function (poll) {
|
||||||
return BACME.challenges.check({ challengePollUrl: poll.url });
|
return BACME.challenges.check({ challengePollUrl: poll.url });
|
||||||
})).then(function () {
|
})).then(function (polls) {
|
||||||
|
console.log(polls);
|
||||||
|
|
||||||
polls = polls.filter(function (poll) {
|
polls = polls.filter(function (poll) {
|
||||||
//return 'valid' !== poll.status && 'invalid' !== poll.status;
|
//return 'valid' !== poll.status && 'invalid' !== poll.status;
|
||||||
if ('pending' === poll.status) {
|
if ('pending' === poll.status) {
|
||||||
|
@ -312,7 +344,63 @@
|
||||||
}
|
}
|
||||||
steps[4].submit = function () {
|
steps[4].submit = function () {
|
||||||
console.log('Congrats! Auto advancing...');
|
console.log('Congrats! Auto advancing...');
|
||||||
return BACME.order
|
var key = info.identifiers.map(function (ident) { return ident.value; }).join(',');
|
||||||
|
var serverJwk = JSON.parse(localStorage.getItem('server:' + key) || 'null');
|
||||||
|
var p;
|
||||||
|
|
||||||
|
function createKeypair() {
|
||||||
|
return BACME.accounts.generateKeypair({
|
||||||
|
type: 'ECDSA'
|
||||||
|
, bitlength: '256'
|
||||||
|
}).then(function (serverJwk) {
|
||||||
|
localStorage.setItem('server:' + key, JSON.stringify(serverJwk));
|
||||||
|
return serverJwk;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverJwk) {
|
||||||
|
p = Promise.resolve(serverJwk);
|
||||||
|
} else {
|
||||||
|
p = createKeypair();
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.then(function (_serverJwk) {
|
||||||
|
serverJwk = _serverJwk;
|
||||||
|
// { serverJwk, domains }
|
||||||
|
return BACME.orders.generateCsr({
|
||||||
|
serverJwk: serverJwk
|
||||||
|
, domains: info.identifiers.map(function (ident) {
|
||||||
|
return ident.value;
|
||||||
|
})
|
||||||
|
}).then(function (csrweb64) {
|
||||||
|
return BACME.order.finalize({
|
||||||
|
csr: csrweb64
|
||||||
|
, jwk: info.jwk
|
||||||
|
, finalizeUrl: info.finalizeUrl
|
||||||
|
, accountId: info.kid
|
||||||
|
});
|
||||||
|
}).then(function () {
|
||||||
|
function checkCert() {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
setTimeout(resolve, 1000);
|
||||||
|
}).then(function () {
|
||||||
|
return BACME.order.check({ orderUrl: info.orderUrl });
|
||||||
|
}).then(function (reply) {
|
||||||
|
if ('processing' === reply) {
|
||||||
|
return checkCert();
|
||||||
|
}
|
||||||
|
return reply;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkCert();
|
||||||
|
}).then(function (reply) {
|
||||||
|
return BACME.order.receive({ certificateUrl: reply.certificate });
|
||||||
|
}).then(function (certs) {
|
||||||
|
console.log('WINNING!');
|
||||||
|
console.log(certs);
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
steps[5] = function () {
|
steps[5] = function () {
|
||||||
|
|
68
js/bacme.js
68
js/bacme.js
|
@ -102,6 +102,8 @@ BACME.accounts.generateKeypair = function (opts) {
|
||||||
console.log('private jwk:');
|
console.log('private jwk:');
|
||||||
console.log(JSON.stringify(privJwk, null, 2));
|
console.log(JSON.stringify(privJwk, null, 2));
|
||||||
|
|
||||||
|
return privJwk;
|
||||||
|
/*
|
||||||
return webCrypto.subtle.exportKey(
|
return webCrypto.subtle.exportKey(
|
||||||
"pkcs8"
|
"pkcs8"
|
||||||
, result.privateKey
|
, result.privateKey
|
||||||
|
@ -112,6 +114,7 @@ BACME.accounts.generateKeypair = function (opts) {
|
||||||
return privJwk;
|
return privJwk;
|
||||||
//return accountKeypair;
|
//return accountKeypair;
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -335,6 +338,7 @@ BACME.orders.create = function (opts) {
|
||||||
finalizeUrl = result.finalize;
|
finalizeUrl = result.finalize;
|
||||||
BACME._logBody(result);
|
BACME._logBody(result);
|
||||||
|
|
||||||
|
result.url = currentOrderUrl;
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -404,9 +408,9 @@ BACME.thumbprint = function (opts) {
|
||||||
var keys;
|
var keys;
|
||||||
|
|
||||||
if (/^EC/i.test(opts.jwk.kty)) {
|
if (/^EC/i.test(opts.jwk.kty)) {
|
||||||
keys = [ 'e', 'kty', 'n' ];
|
|
||||||
} else if (/^RS/i.test(opts.jwk.kty)) {
|
|
||||||
keys = [ 'crv', 'kty', 'x', 'y' ];
|
keys = [ 'crv', 'kty', 'x', 'y' ];
|
||||||
|
} else if (/^RS/i.test(opts.jwk.kty)) {
|
||||||
|
keys = [ 'e', 'kty', 'n' ];
|
||||||
}
|
}
|
||||||
|
|
||||||
var accountPublicStr = '{' + keys.map(function (key) {
|
var accountPublicStr = '{' + keys.map(function (key) {
|
||||||
|
@ -416,12 +420,14 @@ BACME.thumbprint = function (opts) {
|
||||||
return window.crypto.subtle.digest(
|
return window.crypto.subtle.digest(
|
||||||
{ name: "SHA-256" } // SHA-256 is spec'd, non-optional
|
{ name: "SHA-256" } // SHA-256 is spec'd, non-optional
|
||||||
, textEncoder.encode(accountPublicStr)
|
, textEncoder.encode(accountPublicStr)
|
||||||
).then(function(hash){
|
).then(function (hash) {
|
||||||
thumbprint = btoa(Array.prototype.map.call(new Uint8Array(hash), function (ch) {
|
thumbprint = btoa(Array.prototype.map.call(new Uint8Array(hash), function (ch) {
|
||||||
return String.fromCharCode(ch);
|
return String.fromCharCode(ch);
|
||||||
}).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
}).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
||||||
|
|
||||||
console.log('Thumbprint:');
|
console.log('Thumbprint:');
|
||||||
|
console.log(opts);
|
||||||
|
console.log(accountPublicStr);
|
||||||
console.log(thumbprint);
|
console.log(thumbprint);
|
||||||
|
|
||||||
return thumbprint;
|
return thumbprint;
|
||||||
|
@ -446,10 +452,12 @@ BACME.challenges['http-01'] = function (opts) {
|
||||||
|
|
||||||
// { keyAuth }
|
// { keyAuth }
|
||||||
BACME.challenges['dns-01'] = function (opts) {
|
BACME.challenges['dns-01'] = function (opts) {
|
||||||
|
console.log('opts.keyAuth for DNS:');
|
||||||
|
console.log(opts.keyAuth);
|
||||||
return window.crypto.subtle.digest(
|
return window.crypto.subtle.digest(
|
||||||
{ name: "SHA-256", }
|
{ name: "SHA-256", }
|
||||||
, textEncoder.encode(opts.keyAuth)
|
, textEncoder.encode(opts.keyAuth)
|
||||||
).then(function(hash){
|
).then(function (hash) {
|
||||||
dnsAuth = btoa(Array.prototype.map.call(new Uint8Array(hash), function (ch) {
|
dnsAuth = btoa(Array.prototype.map.call(new Uint8Array(hash), function (ch) {
|
||||||
return String.fromCharCode(ch);
|
return String.fromCharCode(ch);
|
||||||
}).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
}).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
||||||
|
@ -478,8 +486,7 @@ BACME.challenges.accept = function (opts) {
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|
||||||
nonce = null;
|
return BACME._importKey(opts.jwk).then(function (abstractKey) {
|
||||||
return BACME._import(opts.jwk).then(function (abstractKey) {
|
|
||||||
var protected64 = BACME._jsto64(
|
var protected64 = BACME._jsto64(
|
||||||
{ nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: opts.challengeUrl, kid: opts.accountId }
|
{ nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: opts.challengeUrl, kid: opts.accountId }
|
||||||
);
|
);
|
||||||
|
@ -490,6 +497,7 @@ BACME.challenges.accept = function (opts) {
|
||||||
});
|
});
|
||||||
}).then(function (signedAccept) {
|
}).then(function (signedAccept) {
|
||||||
|
|
||||||
|
nonce = null;
|
||||||
return window.fetch(
|
return window.fetch(
|
||||||
opts.challengeUrl
|
opts.challengeUrl
|
||||||
, { mode: 'cors'
|
, { mode: 'cors'
|
||||||
|
@ -555,8 +563,11 @@ BACME.domains.generateKeypair = function () {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
BACME.orders.generateCsr = function (keypair, domains) {
|
// { serverJwk, domains }
|
||||||
return Promise.resolve(CSR.generate(keypair, domains));
|
BACME.orders.generateCsr = function (opts) {
|
||||||
|
return BACME._importKey(opts.serverJwk).then(function (abstractKey) {
|
||||||
|
return Promise.resolve(CSR.generate({ keypair: abstractKey.wcKey, domains: opts.domains }));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var certificateUrl;
|
var certificateUrl;
|
||||||
|
@ -567,8 +578,7 @@ BACME.orders.finalize = function (opts) {
|
||||||
{ csr: opts.csr }
|
{ csr: opts.csr }
|
||||||
);
|
);
|
||||||
|
|
||||||
nonce = null;
|
return BACME._importKey(opts.jwk).then(function (abstractKey) {
|
||||||
return BACME._import(opts.jwk).then(function (abstractKey) {
|
|
||||||
var protected64 = BACME._jsto64(
|
var protected64 = BACME._jsto64(
|
||||||
{ nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: opts.finalizeUrl, kid: opts.accountId }
|
{ nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: opts.finalizeUrl, kid: opts.accountId }
|
||||||
);
|
);
|
||||||
|
@ -579,8 +589,9 @@ BACME.orders.finalize = function (opts) {
|
||||||
});
|
});
|
||||||
}).then(function (signedFinal) {
|
}).then(function (signedFinal) {
|
||||||
|
|
||||||
|
nonce = null;
|
||||||
return window.fetch(
|
return window.fetch(
|
||||||
finalizeUrl
|
opts.finalizeUrl
|
||||||
, { mode: 'cors'
|
, { mode: 'cors'
|
||||||
, method: 'POST'
|
, method: 'POST'
|
||||||
, headers: { 'Content-Type': 'application/jose+json' }
|
, headers: { 'Content-Type': 'application/jose+json' }
|
||||||
|
@ -600,4 +611,39 @@ BACME.orders.finalize = function (opts) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BACME.orders.receive = function (opts) {
|
||||||
|
return window.fetch(
|
||||||
|
opts.certificateUrl
|
||||||
|
, { mode: 'cors'
|
||||||
|
, method: 'GET'
|
||||||
|
}
|
||||||
|
).then(function (resp) {
|
||||||
|
BACME._logHeaders(resp);
|
||||||
|
nonce = resp.headers.get('replay-nonce');
|
||||||
|
|
||||||
|
return resp.json().then(function (reply) {
|
||||||
|
BACME._logBody(reply);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
BACME.orders.check = function (opts) {
|
||||||
|
return window.fetch(
|
||||||
|
opts.orderUrl
|
||||||
|
, { mode: 'cors'
|
||||||
|
, method: 'GET'
|
||||||
|
}
|
||||||
|
).then(function (resp) {
|
||||||
|
BACME._logHeaders(resp);
|
||||||
|
|
||||||
|
return resp.json().then(function (reply) {
|
||||||
|
BACME._logBody(reply);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}(window));
|
}(window));
|
||||||
|
|
Loading…
Reference in New Issue