appears to work
This commit is contained in:
parent
6c0aed0491
commit
510a367135
13
index.html
13
index.html
|
@ -120,19 +120,22 @@
|
|||
<button type="submit">Next</button>
|
||||
</form>
|
||||
|
||||
<!-- Step 4 Process Challanges -->
|
||||
<!-- Step 5 Get Certs -->
|
||||
<form class="js-acme-form js-acme-form-download">
|
||||
<label>privkey.pem</label>
|
||||
<textarea>-</textarea>
|
||||
<textarea class="js-privkey">-</textarea>
|
||||
|
||||
<label>fullchain.pem</label>
|
||||
<textarea>-</textarea>
|
||||
<textarea class="js-fullchain">-</textarea>
|
||||
|
||||
<!--
|
||||
TODO
|
||||
<label>cert.pem</label>
|
||||
<textarea>-</textarea>
|
||||
<textarea class="js-cert">-</textarea>
|
||||
|
||||
<label>chain.pem</label>
|
||||
<textarea>-</textarea>
|
||||
<textarea class="js-chain">-</textarea>
|
||||
-->
|
||||
|
||||
<button type="button">Download SSL Certificates</button>
|
||||
|
||||
|
|
|
@ -10,5 +10,5 @@ popd
|
|||
|
||||
mkdir -p 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
|
||||
|
|
81
js/app.js
81
js/app.js
|
@ -30,7 +30,9 @@
|
|||
});
|
||||
});
|
||||
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);
|
||||
$qs('.js-acme-table-wildcard').hidden = true;
|
||||
$qs('.js-acme-table-http-01').hidden = true;
|
||||
|
@ -200,7 +202,6 @@
|
|||
, dnsAnswer: dnsAuth.answer
|
||||
};
|
||||
|
||||
obj[c.type].push(data);
|
||||
console.log('');
|
||||
console.log('CHALLENGE');
|
||||
console.log(claim);
|
||||
|
@ -258,9 +259,6 @@
|
|||
$qs('.js-acme-form-challenges').hidden = false;
|
||||
};
|
||||
steps[3].submit = function () {
|
||||
// for now just show the next page immediately (its a spinner)
|
||||
console.log("MAGIC STEP NUMBER is:", i);
|
||||
|
||||
var chType;
|
||||
Array.prototype.some.call($qsa('.js-acme-challenge-type'), function ($el) {
|
||||
if ($el.checked) {
|
||||
|
@ -283,6 +281,7 @@
|
|||
});
|
||||
});
|
||||
});
|
||||
console.log("INFO.challenges !!!!!", info.challenges);
|
||||
|
||||
var results = [];
|
||||
function nextChallenge() {
|
||||
|
@ -294,6 +293,7 @@
|
|||
});
|
||||
}
|
||||
|
||||
// for now just show the next page immediately (its a spinner)
|
||||
steps[i]();
|
||||
return nextChallenge().then(function (results) {
|
||||
console.log('challenge status:', results);
|
||||
|
@ -366,6 +366,7 @@
|
|||
|
||||
return p.then(function (_serverJwk) {
|
||||
serverJwk = _serverJwk;
|
||||
info.serverJwk = serverJwk;
|
||||
// { serverJwk, domains }
|
||||
return BACME.orders.generateCsr({
|
||||
serverJwk: serverJwk
|
||||
|
@ -373,7 +374,7 @@
|
|||
return ident.value;
|
||||
})
|
||||
}).then(function (csrweb64) {
|
||||
return BACME.order.finalize({
|
||||
return BACME.orders.finalize({
|
||||
csr: csrweb64
|
||||
, jwk: info.jwk
|
||||
, finalizeUrl: info.finalizeUrl
|
||||
|
@ -384,7 +385,7 @@
|
|||
return new Promise(function (resolve) {
|
||||
setTimeout(resolve, 1000);
|
||||
}).then(function () {
|
||||
return BACME.order.check({ orderUrl: info.orderUrl });
|
||||
return BACME.orders.check({ orderUrl: info.orderUrl });
|
||||
}).then(function (reply) {
|
||||
if ('processing' === reply) {
|
||||
return checkCert();
|
||||
|
@ -395,10 +396,74 @@
|
|||
|
||||
return checkCert();
|
||||
}).then(function (reply) {
|
||||
return BACME.order.receive({ certificateUrl: reply.certificate });
|
||||
return BACME.orders.receive({ certificateUrl: reply.certificate });
|
||||
}).then(function (certs) {
|
||||
console.log('WINNING!');
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
67
js/bacme.js
67
js/bacme.js
|
@ -129,13 +129,24 @@ var textEncoder = new TextEncoder();
|
|||
BACME._importKey = function (jwk) {
|
||||
var alg; // I think the 256 refers to the hash
|
||||
var wcOpts = {};
|
||||
var extractable = false;
|
||||
var extractable = true; // TODO make optionally false?
|
||||
var priv = jwk;
|
||||
var pub;
|
||||
|
||||
// ECDSA
|
||||
if (/^EC/i.test(jwk.kty)) {
|
||||
wcOpts.name = 'ECDSA';
|
||||
wcOpts.namedCurve = jwk.crv;
|
||||
alg = 'ES256';
|
||||
pub = {
|
||||
crv: priv.crv
|
||||
, kty: priv.kty
|
||||
, x: priv.x
|
||||
, y: priv.y
|
||||
};
|
||||
if (!priv.d) {
|
||||
priv = null;
|
||||
}
|
||||
}
|
||||
|
||||
// RSA
|
||||
|
@ -143,28 +154,50 @@ BACME._importKey = function (jwk) {
|
|||
wcOpts.name = 'RSASSA-PKCS1-v1_5';
|
||||
wcOpts.hash = { name: "SHA-256" };
|
||||
alg = 'RS256';
|
||||
pub = {
|
||||
e: priv.e
|
||||
, kty: priv.kty
|
||||
, n: priv.n
|
||||
}
|
||||
if (!priv.p) {
|
||||
priv = null;
|
||||
}
|
||||
}
|
||||
|
||||
return window.crypto.subtle.importKey(
|
||||
"jwk"
|
||||
, jwk
|
||||
, pub
|
||||
, wcOpts
|
||||
, extractable
|
||||
, [ "sign"/*, "verify"*/ ]
|
||||
).then(function (keypair) {
|
||||
return {
|
||||
wcKey: keypair
|
||||
, meta: {
|
||||
alg: alg
|
||||
, name: wcOpts.name
|
||||
, hash: wcOpts.hash
|
||||
}
|
||||
, jwk: jwk
|
||||
};
|
||||
, [ "verify" ]
|
||||
).then(function (publicKey) {
|
||||
function give(privateKey) {
|
||||
return {
|
||||
wcPub: publicKey
|
||||
, wcKey: privateKey
|
||||
, wcKeypair: { publicKey: publicKey, privateKey: privateKey }
|
||||
, meta: {
|
||||
alg: alg
|
||||
, 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) {
|
||||
var wcPrivKey = opts.abstractKey.wcKey;
|
||||
var wcPrivKey = opts.abstractKey.wcKeypair.privateKey;
|
||||
var wcOpts = opts.abstractKey.meta;
|
||||
var alg = opts.abstractKey.meta.alg; // I think the 256 refers to the hash
|
||||
var signHash;
|
||||
|
@ -508,6 +541,7 @@ BACME.challenges.accept = function (opts) {
|
|||
).then(function (resp) {
|
||||
BACME._logHeaders(resp);
|
||||
nonce = resp.headers.get('replay-nonce');
|
||||
console.log("ACCEPT NONCE:", nonce);
|
||||
|
||||
return resp.json().then(function (reply) {
|
||||
challengePollUrl = reply.url;
|
||||
|
@ -523,7 +557,6 @@ BACME.challenges.accept = function (opts) {
|
|||
BACME.challenges.check = function (opts) {
|
||||
return window.fetch(opts.challengePollUrl, { mode: 'cors' }).then(function (resp) {
|
||||
BACME._logHeaders(resp);
|
||||
nonce = resp.headers.get('replay-nonce');
|
||||
|
||||
return resp.json().then(function (reply) {
|
||||
challengePollUrl = reply.url;
|
||||
|
@ -566,7 +599,7 @@ BACME.domains.generateKeypair = function () {
|
|||
// { serverJwk, 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 }));
|
||||
return Promise.resolve(CSR.generate({ keypair: abstractKey.wcKeypair, domains: opts.domains }));
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -621,7 +654,7 @@ BACME.orders.receive = function (opts) {
|
|||
BACME._logHeaders(resp);
|
||||
nonce = resp.headers.get('replay-nonce');
|
||||
|
||||
return resp.json().then(function (reply) {
|
||||
return resp.text().then(function (reply) {
|
||||
BACME._logBody(reply);
|
||||
|
||||
return reply;
|
||||
|
|
Loading…
Reference in New Issue