Browse Source

appears to work

master
AJ ONeal 2 years ago
parent
commit
510a367135
4 changed files with 132 additions and 31 deletions
  1. +8
    -5
      index.html
  2. +1
    -1
      install.sh
  3. +73
    -8
      js/app.js
  4. +50
    -17
      js/bacme.js

+ 8
- 5
index.html View File

@@ -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>



+ 1
- 1
install.sh View File

@@ -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

+ 73
- 8
js/app.js View File

@@ -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);
});
});
});
};


+ 50
- 17
js/bacme.js View File

@@ -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…
Cancel
Save