appears to work

This commit is contained in:
AJ ONeal 2018-05-04 11:10:43 +00:00
parent 6c0aed0491
commit 510a367135
4 changed files with 132 additions and 31 deletions

View File

@ -120,19 +120,22 @@
<button type="submit">Next</button> <button type="submit">Next</button>
</form> </form>
<!-- Step 4 Process Challanges --> <!-- Step 5 Get Certs -->
<form class="js-acme-form js-acme-form-download"> <form class="js-acme-form js-acme-form-download">
<label>privkey.pem</label> <label>privkey.pem</label>
<textarea>-</textarea> <textarea class="js-privkey">-</textarea>
<label>fullchain.pem</label> <label>fullchain.pem</label>
<textarea>-</textarea> <textarea class="js-fullchain">-</textarea>
<!--
TODO
<label>cert.pem</label> <label>cert.pem</label>
<textarea>-</textarea> <textarea class="js-cert">-</textarea>
<label>chain.pem</label> <label>chain.pem</label>
<textarea>-</textarea> <textarea class="js-chain">-</textarea>
-->
<button type="button">Download SSL Certificates</button> <button type="button">Download SSL Certificates</button>

View File

@ -10,5 +10,5 @@ popd
mkdir -p js/browser-csr/v1.0.0-alpha/ mkdir -p js/browser-csr/v1.0.0-alpha/
pushd js/browser-csr/v1.0.0-alpha/ pushd js/browser-csr/v1.0.0-alpha/
wget -c https://git.coolaj86.com/coolaj86/browser-csr.js/raw/commit/c513a862a4e016794da800f0c2eec858b80837ab/csr.js wget -c https://git.coolaj86.com/coolaj86/browser-csr.js/raw/commit/01cdc0e91b5bf03f12e1b25b4129e3cde927987c/csr.js
popd popd

View File

@ -30,7 +30,9 @@
}); });
}); });
function updateChallengeType() { function updateChallengeType() {
var input = this || $qs('.js-acme-challenge-type'); var input = this || Array.prototype.filter.call(
$qsa('.js-acme-challenge-type'), function ($el) { return $el.checked; }
)[0];
console.log('ch type radio:', input.value); console.log('ch type radio:', input.value);
$qs('.js-acme-table-wildcard').hidden = true; $qs('.js-acme-table-wildcard').hidden = true;
$qs('.js-acme-table-http-01').hidden = true; $qs('.js-acme-table-http-01').hidden = true;
@ -200,7 +202,6 @@
, dnsAnswer: dnsAuth.answer , dnsAnswer: dnsAuth.answer
}; };
obj[c.type].push(data);
console.log(''); console.log('');
console.log('CHALLENGE'); console.log('CHALLENGE');
console.log(claim); console.log(claim);
@ -258,9 +259,6 @@
$qs('.js-acme-form-challenges').hidden = false; $qs('.js-acme-form-challenges').hidden = false;
}; };
steps[3].submit = function () { steps[3].submit = function () {
// for now just show the next page immediately (its a spinner)
console.log("MAGIC STEP NUMBER is:", i);
var chType; var chType;
Array.prototype.some.call($qsa('.js-acme-challenge-type'), function ($el) { Array.prototype.some.call($qsa('.js-acme-challenge-type'), function ($el) {
if ($el.checked) { if ($el.checked) {
@ -283,6 +281,7 @@
}); });
}); });
}); });
console.log("INFO.challenges !!!!!", info.challenges);
var results = []; var results = [];
function nextChallenge() { function nextChallenge() {
@ -294,6 +293,7 @@
}); });
} }
// for now just show the next page immediately (its a spinner)
steps[i](); steps[i]();
return nextChallenge().then(function (results) { return nextChallenge().then(function (results) {
console.log('challenge status:', results); console.log('challenge status:', results);
@ -366,6 +366,7 @@
return p.then(function (_serverJwk) { return p.then(function (_serverJwk) {
serverJwk = _serverJwk; serverJwk = _serverJwk;
info.serverJwk = serverJwk;
// { serverJwk, domains } // { serverJwk, domains }
return BACME.orders.generateCsr({ return BACME.orders.generateCsr({
serverJwk: serverJwk serverJwk: serverJwk
@ -373,7 +374,7 @@
return ident.value; return ident.value;
}) })
}).then(function (csrweb64) { }).then(function (csrweb64) {
return BACME.order.finalize({ return BACME.orders.finalize({
csr: csrweb64 csr: csrweb64
, jwk: info.jwk , jwk: info.jwk
, finalizeUrl: info.finalizeUrl , finalizeUrl: info.finalizeUrl
@ -384,7 +385,7 @@
return new Promise(function (resolve) { return new Promise(function (resolve) {
setTimeout(resolve, 1000); setTimeout(resolve, 1000);
}).then(function () { }).then(function () {
return BACME.order.check({ orderUrl: info.orderUrl }); return BACME.orders.check({ orderUrl: info.orderUrl });
}).then(function (reply) { }).then(function (reply) {
if ('processing' === reply) { if ('processing' === reply) {
return checkCert(); return checkCert();
@ -395,10 +396,74 @@
return checkCert(); return checkCert();
}).then(function (reply) { }).then(function (reply) {
return BACME.order.receive({ certificateUrl: reply.certificate }); return BACME.orders.receive({ certificateUrl: reply.certificate });
}).then(function (certs) { }).then(function (certs) {
console.log('WINNING!'); console.log('WINNING!');
console.log(certs); console.log(certs);
$qs('.js-fullchain').value = certs;
// https://stackoverflow.com/questions/40314257/export-webcrypto-key-to-pem-format
function spkiToPEM(keydata){
var keydataS = arrayBufferToString(keydata);
var keydataB64 = window.btoa(keydataS);
var keydataB64Pem = formatAsPem(keydataB64);
return keydataB64Pem;
}
function arrayBufferToString( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return binary;
}
function formatAsPem(str) {
var finalString = '-----BEGIN ' + pemName + ' PRIVATE KEY-----\n';
while(str.length > 0) {
finalString += str.substring(0, 64) + '\n';
str = str.substring(64);
}
finalString = finalString + '-----END ' + pemName + ' PRIVATE KEY-----';
return finalString;
}
var wcOpts;
var pemName;
if (/^R/.test(info.serverJwk.kty)) {
pemName = 'RSA';
wcOpts = {
name: "RSASSA-PKCS1-v1_5"
, hash: { name: "SHA-256" }
};
} else {
pemName = 'EC';
wcOpts = {
name: "ECDSA"
, namedCurve: "P-256"
}
}
return crypto.subtle.importKey(
"jwk"
, info.serverJwk
, wcOpts
, true
, ["sign"]
).then(function (privateKey) {
return window.crypto.subtle.exportKey("pkcs8", privateKey);
}).then (function (keydata) {
var pem = spkiToPEM(keydata);
$qs('.js-privkey').value = pem;
steps[i]();
}).catch(function(err){
console.error(err);
});
}); });
}); });
}; };

View File

@ -129,13 +129,24 @@ var textEncoder = new TextEncoder();
BACME._importKey = function (jwk) { BACME._importKey = function (jwk) {
var alg; // I think the 256 refers to the hash var alg; // I think the 256 refers to the hash
var wcOpts = {}; var wcOpts = {};
var extractable = false; var extractable = true; // TODO make optionally false?
var priv = jwk;
var pub;
// ECDSA // ECDSA
if (/^EC/i.test(jwk.kty)) { if (/^EC/i.test(jwk.kty)) {
wcOpts.name = 'ECDSA'; wcOpts.name = 'ECDSA';
wcOpts.namedCurve = jwk.crv; wcOpts.namedCurve = jwk.crv;
alg = 'ES256'; alg = 'ES256';
pub = {
crv: priv.crv
, kty: priv.kty
, x: priv.x
, y: priv.y
};
if (!priv.d) {
priv = null;
}
} }
// RSA // RSA
@ -143,28 +154,50 @@ BACME._importKey = function (jwk) {
wcOpts.name = 'RSASSA-PKCS1-v1_5'; wcOpts.name = 'RSASSA-PKCS1-v1_5';
wcOpts.hash = { name: "SHA-256" }; wcOpts.hash = { name: "SHA-256" };
alg = 'RS256'; alg = 'RS256';
pub = {
e: priv.e
, kty: priv.kty
, n: priv.n
}
if (!priv.p) {
priv = null;
}
} }
return window.crypto.subtle.importKey( return window.crypto.subtle.importKey(
"jwk" "jwk"
, jwk , pub
, wcOpts , wcOpts
, extractable , extractable
, [ "sign"/*, "verify"*/ ] , [ "verify" ]
).then(function (keypair) { ).then(function (publicKey) {
return { function give(privateKey) {
wcKey: keypair return {
, meta: { wcPub: publicKey
alg: alg , wcKey: privateKey
, name: wcOpts.name , wcKeypair: { publicKey: publicKey, privateKey: privateKey }
, hash: wcOpts.hash , meta: {
} alg: alg
, jwk: jwk , name: wcOpts.name
}; , hash: wcOpts.hash
}
, jwk: jwk
};
}
if (!priv) {
return give();
}
return window.crypto.subtle.importKey(
"jwk"
, priv
, wcOpts
, extractable
, [ "sign"/*, "verify"*/ ]
).then(give);
}); });
}; };
BACME._sign = function (opts) { BACME._sign = function (opts) {
var wcPrivKey = opts.abstractKey.wcKey; var wcPrivKey = opts.abstractKey.wcKeypair.privateKey;
var wcOpts = opts.abstractKey.meta; var wcOpts = opts.abstractKey.meta;
var alg = opts.abstractKey.meta.alg; // I think the 256 refers to the hash var alg = opts.abstractKey.meta.alg; // I think the 256 refers to the hash
var signHash; var signHash;
@ -508,6 +541,7 @@ BACME.challenges.accept = function (opts) {
).then(function (resp) { ).then(function (resp) {
BACME._logHeaders(resp); BACME._logHeaders(resp);
nonce = resp.headers.get('replay-nonce'); nonce = resp.headers.get('replay-nonce');
console.log("ACCEPT NONCE:", nonce);
return resp.json().then(function (reply) { return resp.json().then(function (reply) {
challengePollUrl = reply.url; challengePollUrl = reply.url;
@ -523,7 +557,6 @@ BACME.challenges.accept = function (opts) {
BACME.challenges.check = function (opts) { BACME.challenges.check = function (opts) {
return window.fetch(opts.challengePollUrl, { mode: 'cors' }).then(function (resp) { return window.fetch(opts.challengePollUrl, { mode: 'cors' }).then(function (resp) {
BACME._logHeaders(resp); BACME._logHeaders(resp);
nonce = resp.headers.get('replay-nonce');
return resp.json().then(function (reply) { return resp.json().then(function (reply) {
challengePollUrl = reply.url; challengePollUrl = reply.url;
@ -566,7 +599,7 @@ BACME.domains.generateKeypair = function () {
// { serverJwk, domains } // { serverJwk, domains }
BACME.orders.generateCsr = function (opts) { BACME.orders.generateCsr = function (opts) {
return BACME._importKey(opts.serverJwk).then(function (abstractKey) { return BACME._importKey(opts.serverJwk).then(function (abstractKey) {
return Promise.resolve(CSR.generate({ keypair: abstractKey.wcKey, domains: opts.domains })); return Promise.resolve(CSR.generate({ keypair: abstractKey.wcKeypair, domains: opts.domains }));
}); });
}; };
@ -621,7 +654,7 @@ BACME.orders.receive = function (opts) {
BACME._logHeaders(resp); BACME._logHeaders(resp);
nonce = resp.headers.get('replay-nonce'); nonce = resp.headers.get('replay-nonce');
return resp.json().then(function (reply) { return resp.text().then(function (reply) {
BACME._logBody(reply); BACME._logBody(reply);
return reply; return reply;