AJ ONeal
5 years ago
3 changed files with 553 additions and 396 deletions
@ -1,274 +1,340 @@ |
|||
/*global Promise*/ |
|||
(function () { |
|||
'use strict'; |
|||
(function() { |
|||
'use strict'; |
|||
|
|||
var Keypairs = window.Keypairs; |
|||
var Rasha = window.Rasha; |
|||
var Eckles = window.Eckles; |
|||
var x509 = window.x509; |
|||
var CSR = window.CSR; |
|||
var ACME = window.ACME; |
|||
var accountStuff = {}; |
|||
var Keypairs = window.Keypairs; |
|||
var Rasha = window.Rasha; |
|||
var Eckles = window.Eckles; |
|||
var x509 = window.x509; |
|||
var CSR = window.CSR; |
|||
var ACME = window.ACME; |
|||
var accountStuff = {}; |
|||
|
|||
function $(sel) { |
|||
return document.querySelector(sel); |
|||
} |
|||
function $$(sel) { |
|||
return Array.prototype.slice.call(document.querySelectorAll(sel)); |
|||
} |
|||
function $(sel) { |
|||
return document.querySelector(sel); |
|||
} |
|||
function $$(sel) { |
|||
return Array.prototype.slice.call(document.querySelectorAll(sel)); |
|||
} |
|||
|
|||
function checkTos(tos) { |
|||
if ($('input[name="tos"]:checked')) { |
|||
return tos; |
|||
} else { |
|||
return ''; |
|||
} |
|||
} |
|||
function checkTos(tos) { |
|||
if ($('input[name="tos"]:checked')) { |
|||
return tos; |
|||
} else { |
|||
return ''; |
|||
} |
|||
} |
|||
|
|||
function run() { |
|||
console.log('hello'); |
|||
function run() { |
|||
console.log('hello'); |
|||
|
|||
// Show different options for ECDSA vs RSA
|
|||
$$('input[name="kty"]').forEach(function ($el) { |
|||
$el.addEventListener('change', function (ev) { |
|||
console.log(this); |
|||
console.log(ev); |
|||
if ("RSA" === ev.target.value) { |
|||
$('.js-rsa-opts').hidden = false; |
|||
$('.js-ec-opts').hidden = true; |
|||
} else { |
|||
$('.js-rsa-opts').hidden = true; |
|||
$('.js-ec-opts').hidden = false; |
|||
} |
|||
}); |
|||
}); |
|||
// Show different options for ECDSA vs RSA
|
|||
$$('input[name="kty"]').forEach(function($el) { |
|||
$el.addEventListener('change', function(ev) { |
|||
console.log(this); |
|||
console.log(ev); |
|||
if ('RSA' === ev.target.value) { |
|||
$('.js-rsa-opts').hidden = false; |
|||
$('.js-ec-opts').hidden = true; |
|||
} else { |
|||
$('.js-rsa-opts').hidden = true; |
|||
$('.js-ec-opts').hidden = false; |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
// Generate a key on submit
|
|||
$('form.js-keygen').addEventListener('submit', function (ev) { |
|||
ev.preventDefault(); |
|||
ev.stopPropagation(); |
|||
$('.js-loading').hidden = false; |
|||
$('.js-jwk').hidden = true; |
|||
$('.js-toc-der-public').hidden = true; |
|||
$('.js-toc-der-private').hidden = true; |
|||
$$('.js-toc-pem').forEach(function ($el) { |
|||
$el.hidden = true; |
|||
}); |
|||
$$('input').map(function ($el) { $el.disabled = true; }); |
|||
$$('button').map(function ($el) { $el.disabled = true; }); |
|||
var opts = { |
|||
kty: $('input[name="kty"]:checked').value |
|||
, namedCurve: $('input[name="ec-crv"]:checked').value |
|||
, modulusLength: $('input[name="rsa-len"]:checked').value |
|||
}; |
|||
var then = Date.now(); |
|||
console.log('opts', opts); |
|||
Keypairs.generate(opts).then(function (results) { |
|||
console.log("Key generation time:", (Date.now() - then) + "ms"); |
|||
var pubDer; |
|||
var privDer; |
|||
if (/EC/i.test(opts.kty)) { |
|||
privDer = x509.packPkcs8(results.private); |
|||
pubDer = x509.packSpki(results.public); |
|||
Eckles.export({ jwk: results.private, format: 'sec1' }).then(function (pem) { |
|||
$('.js-input-pem-sec1-private').innerText = pem; |
|||
$('.js-toc-pem-sec1-private').hidden = false; |
|||
}); |
|||
Eckles.export({ jwk: results.private, format: 'pkcs8' }).then(function (pem) { |
|||
$('.js-input-pem-pkcs8-private').innerText = pem; |
|||
$('.js-toc-pem-pkcs8-private').hidden = false; |
|||
}); |
|||
Eckles.export({ jwk: results.public, public: true }).then(function (pem) { |
|||
$('.js-input-pem-spki-public').innerText = pem; |
|||
$('.js-toc-pem-spki-public').hidden = false; |
|||
}); |
|||
} else { |
|||
privDer = x509.packPkcs8(results.private); |
|||
pubDer = x509.packSpki(results.public); |
|||
Rasha.export({ jwk: results.private, format: 'pkcs1' }).then(function (pem) { |
|||
$('.js-input-pem-pkcs1-private').innerText = pem; |
|||
$('.js-toc-pem-pkcs1-private').hidden = false; |
|||
}); |
|||
Rasha.export({ jwk: results.private, format: 'pkcs8' }).then(function (pem) { |
|||
$('.js-input-pem-pkcs8-private').innerText = pem; |
|||
$('.js-toc-pem-pkcs8-private').hidden = false; |
|||
}); |
|||
Rasha.export({ jwk: results.public, format: 'pkcs1' }).then(function (pem) { |
|||
$('.js-input-pem-pkcs1-public').innerText = pem; |
|||
$('.js-toc-pem-pkcs1-public').hidden = false; |
|||
}); |
|||
Rasha.export({ jwk: results.public, format: 'spki' }).then(function (pem) { |
|||
$('.js-input-pem-spki-public').innerText = pem; |
|||
$('.js-toc-pem-spki-public').hidden = false; |
|||
}); |
|||
} |
|||
// Generate a key on submit
|
|||
$('form.js-keygen').addEventListener('submit', function(ev) { |
|||
ev.preventDefault(); |
|||
ev.stopPropagation(); |
|||
$('.js-loading').hidden = false; |
|||
$('.js-jwk').hidden = true; |
|||
$('.js-toc-der-public').hidden = true; |
|||
$('.js-toc-der-private').hidden = true; |
|||
$$('.js-toc-pem').forEach(function($el) { |
|||
$el.hidden = true; |
|||
}); |
|||
$$('input').map(function($el) { |
|||
$el.disabled = true; |
|||
}); |
|||
$$('button').map(function($el) { |
|||
$el.disabled = true; |
|||
}); |
|||
var opts = { |
|||
kty: $('input[name="kty"]:checked').value, |
|||
namedCurve: $('input[name="ec-crv"]:checked').value, |
|||
modulusLength: $('input[name="rsa-len"]:checked').value |
|||
}; |
|||
var then = Date.now(); |
|||
console.log('opts', opts); |
|||
Keypairs.generate(opts).then(function(results) { |
|||
console.log('Key generation time:', Date.now() - then + 'ms'); |
|||
var pubDer; |
|||
var privDer; |
|||
if (/EC/i.test(opts.kty)) { |
|||
privDer = x509.packPkcs8(results.private); |
|||
pubDer = x509.packSpki(results.public); |
|||
Eckles.export({ |
|||
jwk: results.private, |
|||
format: 'sec1' |
|||
}).then(function(pem) { |
|||
$('.js-input-pem-sec1-private').innerText = pem; |
|||
$('.js-toc-pem-sec1-private').hidden = false; |
|||
}); |
|||
Eckles.export({ |
|||
jwk: results.private, |
|||
format: 'pkcs8' |
|||
}).then(function(pem) { |
|||
$('.js-input-pem-pkcs8-private').innerText = pem; |
|||
$('.js-toc-pem-pkcs8-private').hidden = false; |
|||
}); |
|||
Eckles.export({ jwk: results.public, public: true }).then( |
|||
function(pem) { |
|||
$('.js-input-pem-spki-public').innerText = pem; |
|||
$('.js-toc-pem-spki-public').hidden = false; |
|||
} |
|||
); |
|||
} else { |
|||
privDer = x509.packPkcs8(results.private); |
|||
pubDer = x509.packSpki(results.public); |
|||
Rasha.export({ |
|||
jwk: results.private, |
|||
format: 'pkcs1' |
|||
}).then(function(pem) { |
|||
$('.js-input-pem-pkcs1-private').innerText = pem; |
|||
$('.js-toc-pem-pkcs1-private').hidden = false; |
|||
}); |
|||
Rasha.export({ |
|||
jwk: results.private, |
|||
format: 'pkcs8' |
|||
}).then(function(pem) { |
|||
$('.js-input-pem-pkcs8-private').innerText = pem; |
|||
$('.js-toc-pem-pkcs8-private').hidden = false; |
|||
}); |
|||
Rasha.export({ jwk: results.public, format: 'pkcs1' }).then( |
|||
function(pem) { |
|||
$('.js-input-pem-pkcs1-public').innerText = pem; |
|||
$('.js-toc-pem-pkcs1-public').hidden = false; |
|||
} |
|||
); |
|||
Rasha.export({ jwk: results.public, format: 'spki' }).then( |
|||
function(pem) { |
|||
$('.js-input-pem-spki-public').innerText = pem; |
|||
$('.js-toc-pem-spki-public').hidden = false; |
|||
} |
|||
); |
|||
} |
|||
|
|||
$('.js-der-public').innerText = pubDer; |
|||
$('.js-toc-der-public').hidden = false; |
|||
$('.js-der-private').innerText = privDer; |
|||
$('.js-toc-der-private').hidden = false; |
|||
$('.js-jwk').innerText = JSON.stringify(results, null, 2); |
|||
$('.js-loading').hidden = true; |
|||
$('.js-jwk').hidden = false; |
|||
$$('input').map(function ($el) { $el.disabled = false; }); |
|||
$$('button').map(function ($el) { $el.disabled = false; }); |
|||
$('.js-toc-jwk').hidden = false; |
|||
$('.js-der-public').innerText = pubDer; |
|||
$('.js-toc-der-public').hidden = false; |
|||
$('.js-der-private').innerText = privDer; |
|||
$('.js-toc-der-private').hidden = false; |
|||
$('.js-jwk').innerText = JSON.stringify(results, null, 2); |
|||
$('.js-loading').hidden = true; |
|||
$('.js-jwk').hidden = false; |
|||
$$('input').map(function($el) { |
|||
$el.disabled = false; |
|||
}); |
|||
$$('button').map(function($el) { |
|||
$el.disabled = false; |
|||
}); |
|||
$('.js-toc-jwk').hidden = false; |
|||
|
|||
$('.js-create-account').hidden = false; |
|||
$('.js-create-csr').hidden = false; |
|||
}); |
|||
}); |
|||
$('.js-create-account').hidden = false; |
|||
$('.js-create-csr').hidden = false; |
|||
}); |
|||
}); |
|||
|
|||
$('form.js-acme-account').addEventListener('submit', function (ev) { |
|||
ev.preventDefault(); |
|||
ev.stopPropagation(); |
|||
$('.js-loading').hidden = false; |
|||
var acme = ACME.create({ |
|||
Keypairs: Keypairs |
|||
, CSR: CSR |
|||
}); |
|||
acme.init('https://acme-staging-v02.api.letsencrypt.org/directory').then(function (result) { |
|||
console.log('acme result', result); |
|||
var privJwk = JSON.parse($('.js-jwk').innerText).private; |
|||
var email = $('.js-email').value; |
|||
return acme.accounts.create({ |
|||
email: email |
|||
, agreeToTerms: checkTos |
|||
, accountKeypair: { privateKeyJwk: privJwk } |
|||
}).then(function (account) { |
|||
console.log("account created result:", account); |
|||
accountStuff.account = account; |
|||
accountStuff.privateJwk = privJwk; |
|||
accountStuff.email = email; |
|||
accountStuff.acme = acme; |
|||
$('.js-create-order').hidden = false; |
|||
$('.js-toc-acme-account-response').hidden = false; |
|||
$('.js-acme-account-response').innerText = JSON.stringify(account, null, 2); |
|||
}).catch(function (err) { |
|||
console.error("A bad thing happened:"); |
|||
console.error(err); |
|||
window.alert(err.message || JSON.stringify(err, null, 2)); |
|||
}); |
|||
}); |
|||
}); |
|||
$('form.js-acme-account').addEventListener('submit', function(ev) { |
|||
ev.preventDefault(); |
|||
ev.stopPropagation(); |
|||
$('.js-loading').hidden = false; |
|||
var acme = ACME.create({ |
|||
Keypairs: Keypairs, |
|||
CSR: CSR |
|||
}); |
|||
acme.init( |
|||
'https://acme-staging-v02.api.letsencrypt.org/directory' |
|||
).then(function(result) { |
|||
console.log('acme result', result); |
|||
var privJwk = JSON.parse($('.js-jwk').innerText).private; |
|||
var email = $('.js-email').value; |
|||
return acme.accounts |
|||
.create({ |
|||
email: email, |
|||
agreeToTerms: checkTos, |
|||
accountKeypair: { privateKeyJwk: privJwk } |
|||
}) |
|||
.then(function(account) { |
|||
console.log('account created result:', account); |
|||
accountStuff.account = account; |
|||
accountStuff.privateJwk = privJwk; |
|||
accountStuff.email = email; |
|||
accountStuff.acme = acme; |
|||
$('.js-create-order').hidden = false; |
|||
$('.js-toc-acme-account-response').hidden = false; |
|||
$( |
|||
'.js-acme-account-response' |
|||
).innerText = JSON.stringify(account, null, 2); |
|||
}) |
|||
.catch(function(err) { |
|||
console.error('A bad thing happened:'); |
|||
console.error(err); |
|||
window.alert( |
|||
err.message || JSON.stringify(err, null, 2) |
|||
); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
$('form.js-csr').addEventListener('submit', function (ev) { |
|||
ev.preventDefault(); |
|||
ev.stopPropagation(); |
|||
generateCsr(); |
|||
}); |
|||
$('form.js-csr').addEventListener('submit', function(ev) { |
|||
ev.preventDefault(); |
|||
ev.stopPropagation(); |
|||
generateCsr(); |
|||
}); |
|||
|
|||
$('form.js-acme-order').addEventListener('submit', function (ev) { |
|||
ev.preventDefault(); |
|||
ev.stopPropagation(); |
|||
var account = accountStuff.account; |
|||
var privJwk = accountStuff.privateJwk; |
|||
var email = accountStuff.email; |
|||
var acme = accountStuff.acme; |
|||
$('form.js-acme-order').addEventListener('submit', function(ev) { |
|||
ev.preventDefault(); |
|||
ev.stopPropagation(); |
|||
var account = accountStuff.account; |
|||
var privJwk = accountStuff.privateJwk; |
|||
var email = accountStuff.email; |
|||
var acme = accountStuff.acme; |
|||
|
|||
var domains = ($('.js-domains').value || 'example.com').split( |
|||
/[, ]+/g |
|||
); |
|||
return getDomainPrivkey().then(function(domainPrivJwk) { |
|||
console.log('Has CSR already?'); |
|||
console.log(accountStuff.csr); |
|||
return acme.certificates |
|||
.create({ |
|||
accountKeypair: { privateKeyJwk: privJwk }, |
|||
account: account, |
|||
serverKeypair: { privateKeyJwk: domainPrivJwk }, |
|||
csr: accountStuff.csr, |
|||
domains: domains, |
|||
skipDryRun: |
|||
$('input[name="skip-dryrun"]:checked') && true, |
|||
agreeToTerms: checkTos, |
|||
challenges: { |
|||
'dns-01': { |
|||
set: function(opts) { |
|||
console.info('dns-01 set challenge:'); |
|||
console.info('TXT', opts.dnsHost); |
|||
console.info(opts.dnsAuthorization); |
|||
return new Promise(function(resolve) { |
|||
while ( |
|||
!window.confirm( |
|||
'Did you set the challenge?' |
|||
) |
|||
) {} |
|||
resolve(); |
|||
}); |
|||
}, |
|||
remove: function(opts) { |
|||
console.log('dns-01 remove challenge:'); |
|||
console.info('TXT', opts.dnsHost); |
|||
console.info(opts.dnsAuthorization); |
|||
return new Promise(function(resolve) { |
|||
while ( |
|||
!window.confirm( |
|||
'Did you delete the challenge?' |
|||
) |
|||
) {} |
|||
resolve(); |
|||
}); |
|||
} |
|||
}, |
|||
'http-01': { |
|||
set: function(opts) { |
|||
console.info('http-01 set challenge:'); |
|||
console.info(opts.challengeUrl); |
|||
console.info(opts.keyAuthorization); |
|||
return new Promise(function(resolve) { |
|||
while ( |
|||
!window.confirm( |
|||
'Did you set the challenge?' |
|||
) |
|||
) {} |
|||
resolve(); |
|||
}); |
|||
}, |
|||
remove: function(opts) { |
|||
console.log('http-01 remove challenge:'); |
|||
console.info(opts.challengeUrl); |
|||
console.info(opts.keyAuthorization); |
|||
return new Promise(function(resolve) { |
|||
while ( |
|||
!window.confirm( |
|||
'Did you delete the challenge?' |
|||
) |
|||
) {} |
|||
resolve(); |
|||
}); |
|||
} |
|||
} |
|||
}, |
|||
challengeTypes: [ |
|||
$('input[name="acme-challenge-type"]:checked').value |
|||
] |
|||
}) |
|||
.then(function(results) { |
|||
console.log('Got Certificates:'); |
|||
console.log(results); |
|||
$('.js-toc-acme-order-response').hidden = false; |
|||
$('.js-acme-order-response').innerText = JSON.stringify( |
|||
results, |
|||
null, |
|||
2 |
|||
); |
|||
}) |
|||
.catch(function(err) { |
|||
console.error('challenge failed:'); |
|||
console.error(err); |
|||
window.alert( |
|||
'failed! ' + err.message || JSON.stringify(err) |
|||
); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
var domains = ($('.js-domains').value||'example.com').split(/[, ]+/g); |
|||
return getDomainPrivkey().then(function (domainPrivJwk) { |
|||
console.log('Has CSR already?'); |
|||
console.log(accountStuff.csr); |
|||
return acme.certificates.create({ |
|||
accountKeypair: { privateKeyJwk: privJwk } |
|||
, account: account |
|||
, serverKeypair: { privateKeyJwk: domainPrivJwk } |
|||
, csr: accountStuff.csr |
|||
, domains: domains |
|||
, skipDryRun: $('input[name="skip-dryrun"]:checked') && true |
|||
, agreeToTerms: checkTos |
|||
, challenges: { |
|||
'dns-01': { |
|||
set: function (opts) { |
|||
console.info('dns-01 set challenge:'); |
|||
console.info('TXT', opts.dnsHost); |
|||
console.info(opts.dnsAuthorization); |
|||
return new Promise(function (resolve) { |
|||
while (!window.confirm("Did you set the challenge?")) {} |
|||
resolve(); |
|||
}); |
|||
} |
|||
, remove: function (opts) { |
|||
console.log('dns-01 remove challenge:'); |
|||
console.info('TXT', opts.dnsHost); |
|||
console.info(opts.dnsAuthorization); |
|||
return new Promise(function (resolve) { |
|||
while (!window.confirm("Did you delete the challenge?")) {} |
|||
resolve(); |
|||
}); |
|||
} |
|||
} |
|||
, 'http-01': { |
|||
set: function (opts) { |
|||
console.info('http-01 set challenge:'); |
|||
console.info(opts.challengeUrl); |
|||
console.info(opts.keyAuthorization); |
|||
return new Promise(function (resolve) { |
|||
while (!window.confirm("Did you set the challenge?")) {} |
|||
resolve(); |
|||
}); |
|||
} |
|||
, remove: function (opts) { |
|||
console.log('http-01 remove challenge:'); |
|||
console.info(opts.challengeUrl); |
|||
console.info(opts.keyAuthorization); |
|||
return new Promise(function (resolve) { |
|||
while (!window.confirm("Did you delete the challenge?")) {} |
|||
resolve(); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
, challengeTypes: [$('input[name="acme-challenge-type"]:checked').value] |
|||
}).then(function (results) { |
|||
console.log('Got Certificates:'); |
|||
console.log(results); |
|||
$('.js-toc-acme-order-response').hidden = false; |
|||
$('.js-acme-order-response').innerText = JSON.stringify(results, null, 2); |
|||
}).catch(function (err) { |
|||
console.error("challenge failed:"); |
|||
console.error(err); |
|||
window.alert("failed! " + err.message || JSON.stringify(err)); |
|||
}); |
|||
}); |
|||
}); |
|||
$('.js-generate').hidden = false; |
|||
} |
|||
|
|||
$('.js-generate').hidden = false; |
|||
} |
|||
function getDomainPrivkey() { |
|||
if (accountStuff.domainPrivateJwk) { |
|||
return Promise.resolve(accountStuff.domainPrivateJwk); |
|||
} |
|||
return Keypairs.generate({ |
|||
kty: $('input[name="kty"]:checked').value, |
|||
namedCurve: $('input[name="ec-crv"]:checked').value, |
|||
modulusLength: $('input[name="rsa-len"]:checked').value |
|||
}).then(function(pair) { |
|||
console.log('domain keypair:', pair); |
|||
accountStuff.domainPrivateJwk = pair.private; |
|||
return pair.private; |
|||
}); |
|||
} |
|||
|
|||
function getDomainPrivkey() { |
|||
if (accountStuff.domainPrivateJwk) { return Promise.resolve(accountStuff.domainPrivateJwk); } |
|||
return Keypairs.generate({ |
|||
kty: $('input[name="kty"]:checked').value |
|||
, namedCurve: $('input[name="ec-crv"]:checked').value |
|||
, modulusLength: $('input[name="rsa-len"]:checked').value |
|||
}).then(function (pair) { |
|||
console.log('domain keypair:', pair); |
|||
accountStuff.domainPrivateJwk = pair.private; |
|||
return pair.private; |
|||
}); |
|||
} |
|||
function generateCsr() { |
|||
var domains = ($('.js-domains').value || 'example.com').split(/[, ]+/g); |
|||
//var privJwk = JSON.parse($('.js-jwk').innerText).private;
|
|||
return getDomainPrivkey().then(function(privJwk) { |
|||
accountStuff.domainPrivateJwk = privJwk; |
|||
return CSR({ jwk: privJwk, domains: domains }).then(function(pem) { |
|||
// Verify with https://www.sslshopper.com/csr-decoder.html
|
|||
accountStuff.csr = pem; |
|||
console.log('Created CSR:'); |
|||
console.log(pem); |
|||
|
|||
function generateCsr() { |
|||
var domains = ($('.js-domains').value||'example.com').split(/[, ]+/g); |
|||
//var privJwk = JSON.parse($('.js-jwk').innerText).private;
|
|||
return getDomainPrivkey().then(function (privJwk) { |
|||
accountStuff.domainPrivateJwk = privJwk; |
|||
return CSR({ jwk: privJwk, domains: domains }).then(function (pem) { |
|||
// Verify with https://www.sslshopper.com/csr-decoder.html
|
|||
accountStuff.csr = pem; |
|||
console.log('Created CSR:'); |
|||
console.log(pem); |
|||
console.log('CSR info:'); |
|||
console.log(CSR._info(pem)); |
|||
|
|||
console.log('CSR info:'); |
|||
console.log(CSR._info(pem)); |
|||
return pem; |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
return pem; |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
window.addEventListener('load', run); |
|||
}()); |
|||
window.addEventListener('load', run); |
|||
})(); |
|||
|
@ -0,0 +1,6 @@ |
|||
ENV=DEV |
|||
SUBSCRIBER_EMAIL=letsencrypt+staging@example.com |
|||
BASE_DOMAIN=test.example.com |
|||
CHALLENGE_TYPE=dns-01 |
|||
CHALLENGE_PLUGIN=digitalocean |
|||
CHALLENGE_OPTIONS='{"token":"xxxxxxxxxxxx"}' |
@ -1,153 +1,238 @@ |
|||
<html> |
|||
<head> |
|||
<title>Bluecrypt ACME - A Root Project</title> |
|||
<style> |
|||
textarea { |
|||
width: 42em; |
|||
height: 10em; |
|||
} |
|||
/* need to word wrap the binary no space der */ |
|||
.js-der-public, .js-der-private{ |
|||
white-space: pre-wrap; /* CSS3 */ |
|||
white-space: -moz-pre-wrap; /* Firefox */ |
|||
white-space: -pre-wrap; /* Opera <7 */ |
|||
white-space: -o-pre-wrap; /* Opera 7 */ |
|||
word-wrap: break-word; /* IE */ |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<h1>@bluecrypt/acme: Let's Encrypt for the Browser</h1> |
|||
<head> |
|||
<title>Bluecrypt ACME - A Root Project</title> |
|||
<meta charset="UTF-8" /> |
|||
<style> |
|||
textarea { |
|||
width: 42em; |
|||
height: 10em; |
|||
} |
|||
/* need to word wrap the binary no space der */ |
|||
.js-der-public, |
|||
.js-der-private { |
|||
white-space: pre-wrap; /* CSS3 */ |
|||
white-space: -moz-pre-wrap; /* Firefox */ |
|||
white-space: -pre-wrap; /* Opera <7 */ |
|||
white-space: -o-pre-wrap; /* Opera 7 */ |
|||
word-wrap: break-word; /* IE */ |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<h1> |
|||
@bluecrypt/acme: Let's Encrypt for the Browser |
|||
</h1> |
|||
|
|||
<p>This is intended to be explored with your JavaScript console open.</p> |
|||
<pre><code><script src="<a href="https://rootprojects.org/acme/bluecrypt-acme.js">https://rootprojects.org/acme/bluecrypt-acme.js</a>"></script></code></pre> |
|||
<pre><code><script src="<a href="https://rootprojects.org/acme/bluecrypt-acme.min.js">https://rootprojects.org/acme/bluecrypt-acme.min.js</a>"></script></code></pre> |
|||
<a href="https://git.rootprojects.org/root/bluecrypt-acme.js">Documentation</a> |
|||
<p> |
|||
This is intended to be explored with your JavaScript console open. |
|||
</p> |
|||
<pre><code><script src="<a href="https://rootprojects.org/acme/bluecrypt-acme.js">https://rootprojects.org/acme/bluecrypt-acme.js</a>"></script></code></pre> |
|||
<pre><code><script src="<a href="https://rootprojects.org/acme/bluecrypt-acme.min.js">https://rootprojects.org/acme/bluecrypt-acme.min.js</a>"></script></code></pre> |
|||
<a href="https://git.rootprojects.org/root/bluecrypt-acme.js" |
|||
>Documentation</a |
|||
> |
|||
|
|||
<h2>1. Keypair Generation</h2> |
|||
<form class="js-keygen"> |
|||
<p>Key Type:</p> |
|||
<div> |
|||
<input type="radio" id="-ktyEC" |
|||
name="kty" value="EC" checked> |
|||
<label for="-ktyEC">ECDSA</label> |
|||
<input type="radio" id="-ktyRSA" |
|||
name="kty" value="RSA"> |
|||
<label for="-ktyRSA">RSA</label> |
|||
</div> |
|||
<div class="js-ec-opts"> |
|||
<p>EC Options:</p> |
|||
<label for="-crv2"><input type="radio" id="-crv2" |
|||
name="ec-crv" value="P-256" checked>P-256</label> |
|||
<label for="-crv3"><input type="radio" id="-crv3" |
|||
name="ec-crv" value="P-384">P-384</label> |
|||
<!-- label for="-crv5"><input type="radio" id="-crv5" |
|||
<h2>1. Keypair Generation</h2> |
|||
<form class="js-keygen"> |
|||
<p>Key Type:</p> |
|||
<div> |
|||
<input type="radio" id="-ktyEC" name="kty" value="EC" checked /> |
|||
<label for="-ktyEC">ECDSA</label> |
|||
<input type="radio" id="-ktyRSA" name="kty" value="RSA" /> |
|||
<label for="-ktyRSA">RSA</label> |
|||
</div> |
|||
<div class="js-ec-opts"> |
|||
<p>EC Options:</p> |
|||
<label for="-crv2" |
|||
><input |
|||
type="radio" |
|||
id="-crv2" |
|||
name="ec-crv" |
|||
value="P-256" |
|||
checked |
|||
/>P-256</label |
|||
> |
|||
<label for="-crv3" |
|||
><input |
|||
type="radio" |
|||
id="-crv3" |
|||
name="ec-crv" |
|||
value="P-384" |
|||
/>P-384</label |
|||
> |
|||
<!-- label for="-crv5"><input type="radio" id="-crv5" |
|||
name="ec-crv" value="P-521">P-521</label --> |
|||
</div> |
|||
<div class="js-rsa-opts" hidden> |
|||
<p>RSA Options:</p> |
|||
<label for="-modlen2"><input type="radio" id="-modlen2" |
|||
name="rsa-len" value="2048" checked>2048</label> |
|||
<label for="-modlen3"><input type="radio" id="-modlen3" |
|||
name="rsa-len" value="3072">3072</label> |
|||
<label for="-modlen5"><input type="radio" id="-modlen5" |
|||
name="rsa-len" value="4096">4096</label> |
|||
</div> |
|||
<button class="js-generate" hidden>Generate</button> |
|||
</form> |
|||
</div> |
|||
<div class="js-rsa-opts" hidden> |
|||
<p>RSA Options:</p> |
|||
<label for="-modlen2" |
|||
><input |
|||
type="radio" |
|||
id="-modlen2" |
|||
name="rsa-len" |
|||
value="2048" |
|||
checked |
|||
/>2048</label |
|||
> |
|||
<label for="-modlen3" |
|||
><input |
|||
type="radio" |
|||
id="-modlen3" |
|||
name="rsa-len" |
|||
value="3072" |
|||
/>3072</label |
|||
> |
|||
<label for="-modlen5" |
|||
><input |
|||
type="radio" |
|||
id="-modlen5" |
|||
name="rsa-len" |
|||
value="4096" |
|||
/>4096</label |
|||
> |
|||
</div> |
|||
<button class="js-generate" hidden>Generate</button> |
|||
</form> |
|||
|
|||
<h2>2. ACME Account</h2> |
|||
<form class="js-acme-account"> |
|||
<label for="-acmeEmail">Email:</label> |
|||
<input class="js-email" type="email" id="-acmeEmail" value="john.doe@gmail.com"> |
|||
<br> |
|||
<label for="-acmeTos"><input class="js-tos" name="tos" type="checkbox" id="-acmeTos" checked> |
|||
Agree to Let's Encrypt Terms of Service</label> |
|||
<br> |
|||
<button class="js-create-account" hidden>Create Account</button> |
|||
</form> |
|||
<h2>2. ACME Account</h2> |
|||
<form class="js-acme-account"> |
|||
<label for="-acmeEmail">Email:</label> |
|||
<input |
|||
class="js-email" |
|||
type="email" |
|||
id="-acmeEmail" |
|||
value="john.doe@gmail.com" |
|||
/> |
|||
<br /> |
|||
<label for="-acmeTos" |
|||
><input |
|||
class="js-tos" |
|||
name="tos" |
|||
type="checkbox" |
|||
id="-acmeTos" |
|||
checked |
|||
/> |
|||
Agree to Let's Encrypt Terms of Service</label |
|||
> |
|||
<br /> |
|||
<button class="js-create-account" hidden>Create Account</button> |
|||
</form> |
|||
|
|||
<h2>3. (optional) Certificate Signing Request</h2> |
|||
<form class="js-csr"> |
|||
<label for="-acmeDomains">Domains:</label> |
|||
<input class="js-domains" type="text" id="-acmeDomains" value="example.com www.example.com"> |
|||
<br> |
|||
<button class="js-create-csr" hidden>Create CSR</button> |
|||
</form> |
|||
<h2>3. (optional) Certificate Signing Request</h2> |
|||
<form class="js-csr"> |
|||
<label for="-acmeDomains">Domains:</label> |
|||
<input |
|||
class="js-domains" |
|||
type="text" |
|||
id="-acmeDomains" |
|||
value="example.com www.example.com" |
|||
/> |
|||
<br /> |
|||
<button class="js-create-csr" hidden>Create CSR</button> |
|||
</form> |
|||
|
|||
<h2>4. ACME Certificate Order</h2> |
|||
<form class="js-acme-order"> |
|||
Challenge type: |
|||
<label for="-http01"><input type="radio" id="-http01" |
|||
name="acme-challenge-type" value="http-01" checked>http-01</label> |
|||
<label for="-dns01"><input type="radio" id="-dns01" |
|||
name="acme-challenge-type" value="dns-01">dns-01</label> |
|||
<br> |
|||
<label for="-skipDryrun"><input class="js-skip-dryrun" name="skip-dryrun" |
|||
type="checkbox" id="-skipDryrun" checked> Skip dry-run challenge</label> |
|||
<br> |
|||
<button class="js-create-order" hidden>Create Order</button> |
|||
</form> |
|||
<h2>4. ACME Certificate Order</h2> |
|||
<form class="js-acme-order"> |
|||
Challenge type: |
|||
<label for="-http01" |
|||
><input |
|||
type="radio" |
|||
id="-http01" |
|||
name="acme-challenge-type" |
|||
value="http-01" |
|||
checked |
|||
/>http-01</label |
|||
> |
|||
<label for="-dns01" |
|||
><input |
|||
type="radio" |
|||
id="-dns01" |
|||
name="acme-challenge-type" |
|||
value="dns-01" |
|||
/>dns-01</label |
|||
> |
|||
<br /> |
|||
<label for="-skipDryrun" |
|||
><input |
|||
class="js-skip-dryrun" |
|||
name="skip-dryrun" |
|||
type="checkbox" |
|||
id="-skipDryrun" |
|||
checked |
|||
/> |
|||
Skip dry-run challenge</label |
|||
> |
|||
<br /> |
|||
<button class="js-create-order" hidden>Create Order</button> |
|||
</form> |
|||
|
|||
<div class="js-loading" hidden>Loading</div> |
|||
<div class="js-loading" hidden>Loading</div> |
|||
|
|||
<details class="js-toc-jwk" hidden> |
|||
<summary>JWK Keypair</summary> |
|||
<pre><code class="js-jwk"> </code></pre> |
|||
</details> |
|||
<details class="js-toc-der-private" hidden> |
|||
<summary>DER Private Binary</summary> |
|||
<pre><code class="js-der-private"> </code></pre> |
|||
</details> |
|||
<details class="js-toc-der-public" hidden> |
|||
<summary>DER Public Binary</summary> |
|||
<pre><code class="js-der-public"> </code></pre> |
|||
</details> |
|||
<details class="js-toc-pem js-toc-pem-pkcs1-private" hidden> |
|||
<summary>PEM Private (base64-encoded PKCS1 DER)</summary> |
|||
<pre><code class="js-input-pem-pkcs1-private" ></code></pre> |
|||
</details> |
|||
<details class="js-toc-pem js-toc-pem-sec1-private" hidden> |
|||
<summary>PEM Private (base64-encoded SEC1 DER)</summary> |
|||
<pre><code class="js-input-pem-sec1-private" ></code></pre> |
|||
</details> |
|||
<details class="js-toc-pem js-toc-pem-pkcs8-private" hidden> |
|||
<summary>PEM Private (base64-encoded PKCS8 DER)</summary> |
|||
<pre><code class="js-input-pem-pkcs8-private" ></code></pre> |
|||
</details> |
|||
<details class="js-toc-pem js-toc-pem-pkcs1-public" hidden> |
|||
<summary>PEM Public (base64-encoded PKCS1 DER)</summary> |
|||
<pre><code class="js-input-pem-pkcs1-public" ></code></pre> |
|||
</details> |
|||
<details class="js-toc-pem js-toc-pem-spki-public" hidden> |
|||
<summary>PEM Public (base64-encoded SPKI/PKIX DER)</summary> |
|||
<pre><code class="js-input-pem-spki-public" ></code></pre> |
|||
</details> |
|||
<details class="js-toc-acme-account-response" hidden> |
|||
<summary>ACME Account Request</summary> |
|||
<pre><code class="js-acme-account-response"> </code></pre> |
|||
</details> |
|||
<details class="js-toc-acme-order-response" hidden> |
|||
<summary>ACME Order Response</summary> |
|||
<pre><code class="js-acme-order-response"> </code></pre> |
|||
</details> |
|||
<details class="js-toc-jwk" hidden> |
|||
<summary>JWK Keypair</summary> |
|||
<pre><code class="js-jwk"> </code></pre> |
|||
</details> |
|||
<details class="js-toc-der-private" hidden> |
|||
<summary>DER Private Binary</summary> |
|||
<pre><code class="js-der-private"> </code></pre> |
|||
</details> |
|||
<details class="js-toc-der-public" hidden> |
|||
<summary>DER Public Binary</summary> |
|||
<pre><code class="js-der-public"> </code></pre> |
|||
</details> |
|||
<details class="js-toc-pem js-toc-pem-pkcs1-private" hidden> |
|||
<summary>PEM Private (base64-encoded PKCS1 DER)</summary> |
|||
<pre><code class="js-input-pem-pkcs1-private" ></code></pre> |
|||
</details> |
|||
<details class="js-toc-pem js-toc-pem-sec1-private" hidden> |
|||
<summary>PEM Private (base64-encoded SEC1 DER)</summary> |
|||
<pre><code class="js-input-pem-sec1-private" ></code></pre> |
|||
</details> |
|||
<details class="js-toc-pem js-toc-pem-pkcs8-private" hidden> |
|||
<summary>PEM Private (base64-encoded PKCS8 DER)</summary> |
|||
<pre><code class="js-input-pem-pkcs8-private" ></code></pre> |
|||
</details> |
|||
<details class="js-toc-pem js-toc-pem-pkcs1-public" hidden> |
|||
<summary>PEM Public (base64-encoded PKCS1 DER)</summary> |
|||
<pre><code class="js-input-pem-pkcs1-public" ></code></pre> |
|||
</details> |
|||
<details class="js-toc-pem js-toc-pem-spki-public" hidden> |
|||
<summary>PEM Public (base64-encoded SPKI/PKIX DER)</summary> |
|||
<pre><code class="js-input-pem-spki-public" ></code></pre> |
|||
</details> |
|||
<details class="js-toc-acme-account-response" hidden> |
|||
<summary>ACME Account Request</summary> |
|||
<pre><code class="js-acme-account-response"> </code></pre> |
|||
</details> |
|||
<details class="js-toc-acme-order-response" hidden> |
|||
<summary>ACME Order Response</summary> |
|||
<pre><code class="js-acme-order-response"> </code></pre> |
|||
</details> |
|||
|
|||
<br> |
|||
<p>Bluecrypt™ is a collection of lightweight, zero-dependency, libraries written in VanillaJS. |
|||
They are fast, tiny, and secure, using the native features of modern browsers where possible. |
|||
This means it's easy-to-use crypto in kilobytes, not megabytes.</p> |
|||
<br> |
|||
<footer>View (git) source <a href="https://git.rootprojects.org/root/bluecrypt-acme.js">@bluecrypt/acme</a></footer> |
|||
<br /> |
|||
<p> |
|||
Bluecrypt™ is a collection of lightweight, zero-dependency, |
|||
libraries written in VanillaJS. They are fast, tiny, and secure, |
|||
using the native features of modern browsers where possible. This |
|||
means it's easy-to-use crypto in kilobytes, not megabytes. |
|||
</p> |
|||
<br /> |
|||
<footer> |
|||
View (git) source |
|||
<a href="https://git.rootprojects.org/root/bluecrypt-acme.js" |
|||
>@bluecrypt/acme</a |
|||
> |
|||
</footer> |
|||
|
|||
<script src="./lib/encoding.js"></script> |
|||
<script src="./lib/asn1-packer.js"></script> |
|||
<script src="./lib/x509.js"></script> |
|||
<script src="./lib/ecdsa.js"></script> |
|||
<script src="./lib/rsa.js"></script> |
|||
<script src="./lib/keypairs.js"></script> |
|||
<script src="./lib/asn1-parser.js"></script> |
|||
<script src="./lib/csr.js"></script> |
|||
<script src="./lib/acme.js"></script> |
|||
<script src="./app.js"></script> |
|||
</body> |
|||
<script src="./lib/encoding.js"></script> |
|||
<script src="./lib/asn1-packer.js"></script> |
|||
<script src="./lib/x509.js"></script> |
|||
<script src="./lib/ecdsa.js"></script> |
|||
<script src="./lib/rsa.js"></script> |
|||
<script src="./lib/keypairs.js"></script> |
|||
<script src="./lib/asn1-parser.js"></script> |
|||
<script src="./lib/csr.js"></script> |
|||
<script src="./lib/acme.js"></script> |
|||
<script src="./app.js"></script> |
|||
</body> |
|||
</html> |
|||
|
Loading…
Reference in new issue