semi-merge more-acme updates
This commit is contained in:
parent
f1e11f1be7
commit
b902907a7c
18
app.js
18
app.js
|
@ -1,3 +1,4 @@
|
||||||
|
/*global Promise*/
|
||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -5,6 +6,9 @@
|
||||||
var Rasha = window.Rasha;
|
var Rasha = window.Rasha;
|
||||||
var Eckles = window.Eckles;
|
var Eckles = window.Eckles;
|
||||||
var x509 = window.x509;
|
var x509 = window.x509;
|
||||||
|
var CSR = window.CSR;
|
||||||
|
var ACME = window.ACME;
|
||||||
|
var accountStuff = {};
|
||||||
|
|
||||||
function $(sel) {
|
function $(sel) {
|
||||||
return document.querySelector(sel);
|
return document.querySelector(sel);
|
||||||
|
@ -13,6 +17,11 @@
|
||||||
return Array.prototype.slice.call(document.querySelectorAll(sel));
|
return Array.prototype.slice.call(document.querySelectorAll(sel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkTos(tos) {
|
||||||
|
console.log("TODO checkbox for agree to terms");
|
||||||
|
return tos;
|
||||||
|
}
|
||||||
|
|
||||||
function run() {
|
function run() {
|
||||||
console.log('hello');
|
console.log('hello');
|
||||||
|
|
||||||
|
@ -49,8 +58,10 @@
|
||||||
, namedCurve: $('input[name="ec-crv"]:checked').value
|
, namedCurve: $('input[name="ec-crv"]:checked').value
|
||||||
, modulusLength: $('input[name="rsa-len"]:checked').value
|
, modulusLength: $('input[name="rsa-len"]:checked').value
|
||||||
};
|
};
|
||||||
|
var then = Date.now();
|
||||||
console.log('opts', opts);
|
console.log('opts', opts);
|
||||||
Keypairs.generate(opts).then(function (results) {
|
Keypairs.generate(opts).then(function (results) {
|
||||||
|
console.log("Key generation time:", (Date.now() - then) + "ms");
|
||||||
var pubDer;
|
var pubDer;
|
||||||
var privDer;
|
var privDer;
|
||||||
if (/EC/i.test(opts.kty)) {
|
if (/EC/i.test(opts.kty)) {
|
||||||
|
@ -99,12 +110,13 @@
|
||||||
$$('input').map(function ($el) { $el.disabled = false; });
|
$$('input').map(function ($el) { $el.disabled = false; });
|
||||||
$$('button').map(function ($el) { $el.disabled = false; });
|
$$('button').map(function ($el) { $el.disabled = false; });
|
||||||
$('.js-toc-jwk').hidden = false;
|
$('.js-toc-jwk').hidden = false;
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
$('.js-create-account').hidden = false;
|
||||||
|
$('.js-create-csr').hidden = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$('.js-generate').hidden = false;
|
$('.js-generate').hidden = false;
|
||||||
$('.js-create-account').hidden = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('load', run);
|
window.addEventListener('load', run);
|
||||||
|
|
31
index.html
31
index.html
|
@ -34,27 +34,21 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="js-ec-opts">
|
<div class="js-ec-opts">
|
||||||
<p>EC Options:</p>
|
<p>EC Options:</p>
|
||||||
<input type="radio" id="-crv2"
|
<label for="-crv2"><input type="radio" id="-crv2"
|
||||||
name="ec-crv" value="P-256" checked>
|
name="ec-crv" value="P-256" checked>P-256</label>
|
||||||
<label for="-crv2">P-256</label>
|
<label for="-crv3"><input type="radio" id="-crv3"
|
||||||
<input type="radio" id="-crv3"
|
name="ec-crv" value="P-384">P-384</label>
|
||||||
name="ec-crv" value="P-384">
|
<!-- label for="-crv5"><input type="radio" id="-crv5"
|
||||||
<label for="-crv3">P-384</label>
|
name="ec-crv" value="P-521">P-521</label -->
|
||||||
<!-- input type="radio" id="-crv5"
|
|
||||||
name="ec-crv" value="P-521">
|
|
||||||
<label for="-crv5">P-521</label -->
|
|
||||||
</div>
|
</div>
|
||||||
<div class="js-rsa-opts" hidden>
|
<div class="js-rsa-opts" hidden>
|
||||||
<p>RSA Options:</p>
|
<p>RSA Options:</p>
|
||||||
<input type="radio" id="-modlen2"
|
<label for="-modlen2"><input type="radio" id="-modlen2"
|
||||||
name="rsa-len" value="2048" checked>
|
name="rsa-len" value="2048" checked>2048</label>
|
||||||
<label for="-modlen2">2048</label>
|
<label for="-modlen3"><input type="radio" id="-modlen3"
|
||||||
<input type="radio" id="-modlen3"
|
name="rsa-len" value="3072">3072</label>
|
||||||
name="rsa-len" value="3072">
|
<label for="-modlen5"><input type="radio" id="-modlen5"
|
||||||
<label for="-modlen3">3072</label>
|
name="rsa-len" value="4096">4096</label>
|
||||||
<input type="radio" id="-modlen5"
|
|
||||||
name="rsa-len" value="4096">
|
|
||||||
<label for="-modlen5">4096</label>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="js-generate" hidden>Generate</button>
|
<button class="js-generate" hidden>Generate</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -100,7 +94,6 @@
|
||||||
<script src="./lib/ecdsa.js"></script>
|
<script src="./lib/ecdsa.js"></script>
|
||||||
<script src="./lib/rsa.js"></script>
|
<script src="./lib/rsa.js"></script>
|
||||||
<script src="./lib/keypairs.js"></script>
|
<script src="./lib/keypairs.js"></script>
|
||||||
<script src="./lib/acme.js"></script>
|
|
||||||
<script src="./app.js"></script>
|
<script src="./app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -110,6 +110,8 @@ Enc.binToHex = function (bin) {
|
||||||
return h;
|
return h;
|
||||||
}).join('');
|
}).join('');
|
||||||
};
|
};
|
||||||
|
// TODO are there any nuance differences here?
|
||||||
|
Enc.utf8ToHex = Enc.binToHex;
|
||||||
|
|
||||||
Enc.hexToBase64 = function (hex) {
|
Enc.hexToBase64 = function (hex) {
|
||||||
return btoa(Enc.hexToBin(hex));
|
return btoa(Enc.hexToBin(hex));
|
||||||
|
|
|
@ -180,14 +180,6 @@ Keypairs.signJws = function (opts) {
|
||||||
var msg = protected64 + '.' + payload64;
|
var msg = protected64 + '.' + payload64;
|
||||||
|
|
||||||
return Keypairs._sign(opts, msg).then(function (buf) {
|
return Keypairs._sign(opts, msg).then(function (buf) {
|
||||||
/*
|
|
||||||
* This will come back into play for CSRs, but not for JOSE
|
|
||||||
if ('EC' === opts.jwk.kty) {
|
|
||||||
// ECDSA JWT signatures differ from "normal" ECDSA signatures
|
|
||||||
// https://tools.ietf.org/html/rfc7518#section-3.4
|
|
||||||
binsig = convertIfEcdsa(binsig);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
var signedMsg = {
|
var signedMsg = {
|
||||||
protected: protected64
|
protected: protected64
|
||||||
, payload: payload64
|
, payload: payload64
|
||||||
|
@ -212,40 +204,6 @@ Keypairs.signJws = function (opts) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Keypairs._convertIfEcdsa = function (binsig) {
|
|
||||||
// should have asn1 sequence header of 0x30
|
|
||||||
if (0x30 !== binsig[0]) { throw new Error("Impossible EC SHA head marker"); }
|
|
||||||
var index = 2; // first ecdsa "R" header byte
|
|
||||||
var len = binsig[1];
|
|
||||||
var lenlen = 0;
|
|
||||||
// Seek length of length if length is greater than 127 (i.e. two 512-bit / 64-byte R and S values)
|
|
||||||
if (0x80 & len) {
|
|
||||||
lenlen = len - 0x80; // should be exactly 1
|
|
||||||
len = binsig[2]; // should be <= 130 (two 64-bit SHA-512s, plus padding)
|
|
||||||
index += lenlen;
|
|
||||||
}
|
|
||||||
// should be of BigInt type
|
|
||||||
if (0x02 !== binsig[index]) { throw new Error("Impossible EC SHA R marker"); }
|
|
||||||
index += 1;
|
|
||||||
|
|
||||||
var rlen = binsig[index];
|
|
||||||
var bits = 32;
|
|
||||||
if (rlen > 49) {
|
|
||||||
bits = 64;
|
|
||||||
} else if (rlen > 33) {
|
|
||||||
bits = 48;
|
|
||||||
}
|
|
||||||
var r = binsig.slice(index + 1, index + 1 + rlen).toString('hex');
|
|
||||||
var slen = binsig[index + 1 + rlen + 1]; // skip header and read length
|
|
||||||
var s = binsig.slice(index + 1 + rlen + 1 + 1).toString('hex');
|
|
||||||
if (2 *slen !== s.length) { throw new Error("Impossible EC SHA S length"); }
|
|
||||||
// There may be one byte of padding on either
|
|
||||||
while (r.length < 2*bits) { r = '00' + r; }
|
|
||||||
while (s.length < 2*bits) { s = '00' + s; }
|
|
||||||
if (2*(bits+1) === r.length) { r = r.slice(2); }
|
|
||||||
if (2*(bits+1) === s.length) { s = s.slice(2); }
|
|
||||||
return Enc.hexToBuf(r + s);
|
|
||||||
};
|
|
||||||
|
|
||||||
Keypairs._sign = function (opts, payload) {
|
Keypairs._sign = function (opts, payload) {
|
||||||
return Keypairs._import(opts).then(function (privkey) {
|
return Keypairs._import(opts).then(function (privkey) {
|
||||||
|
@ -259,9 +217,12 @@ Keypairs._sign = function (opts, payload) {
|
||||||
, privkey
|
, privkey
|
||||||
, payload
|
, payload
|
||||||
).then(function (signature) {
|
).then(function (signature) {
|
||||||
// convert buffer to urlsafe base64
|
signature = new Uint8Array(signature); // ArrayBuffer -> u8
|
||||||
//return Enc.bufToUrlBase64(new Uint8Array(signature));
|
// This will come back into play for CSRs, but not for JOSE
|
||||||
return new Uint8Array(signature);
|
if ('EC' === opts.jwk.kty && /x509/i.test(opts.format)) {
|
||||||
|
signature = Keypairs._ecdsaJoseSigToAsn1Sig(signature);
|
||||||
|
}
|
||||||
|
return signature;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -287,7 +248,6 @@ Keypairs._getName = function (opts) {
|
||||||
return 'RSASSA-PKCS1-v1_5';
|
return 'RSASSA-PKCS1-v1_5';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Keypairs._import = function (opts) {
|
Keypairs._import = function (opts) {
|
||||||
return Promise.resolve().then(function () {
|
return Promise.resolve().then(function () {
|
||||||
var ops;
|
var ops;
|
||||||
|
@ -316,6 +276,30 @@ Keypairs._import = function (opts) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// ECDSA JOSE / JWS / JWT signatures differ from "normal" ASN1/X509 ECDSA signatures
|
||||||
|
// https://tools.ietf.org/html/rfc7518#section-3.4
|
||||||
|
Keypairs._ecdsaJoseSigToAsn1Sig = function (bufsig) {
|
||||||
|
// it's easier to do the manipulation in the browser with an array
|
||||||
|
bufsig = Array.from(bufsig);
|
||||||
|
var hlen = bufsig.length / 2; // should be even
|
||||||
|
var r = bufsig.slice(0, hlen);
|
||||||
|
var s = bufsig.slice(hlen);
|
||||||
|
// unpad positive ints less than 32 bytes wide
|
||||||
|
while (!r[0]) { r = r.slice(1); }
|
||||||
|
while (!s[0]) { s = s.slice(1); }
|
||||||
|
// pad (or re-pad) ambiguously non-negative BigInts, up to 33 bytes wide
|
||||||
|
if (0x80 & r[0]) { r.unshift(0); }
|
||||||
|
if (0x80 & s[0]) { s.unshift(0); }
|
||||||
|
|
||||||
|
var len = 2 + r.length + 2 + s.length;
|
||||||
|
var head = [0x30];
|
||||||
|
// hard code 0x80 + 1 because it won't be longer than
|
||||||
|
// two SHA512 plus two pad bytes (130 bytes <= 256)
|
||||||
|
if (len >= 0x80) { head.push(0x81); }
|
||||||
|
head.push(len);
|
||||||
|
|
||||||
|
return Uint8Array.from(head.concat([0x02, r.length], r, [0x02, s.byteLength], s));
|
||||||
|
};
|
||||||
|
|
||||||
function setTime(time) {
|
function setTime(time) {
|
||||||
if ('number' === typeof time) { return time; }
|
if ('number' === typeof time) { return time; }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use strict';
|
|
||||||
(function (exports) {
|
(function (exports) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var x509 = exports.x509 = {};
|
var x509 = exports.x509 = {};
|
||||||
var ASN1 = exports.ASN1;
|
var ASN1 = exports.ASN1;
|
||||||
var Enc = exports.Enc;
|
var Enc = exports.Enc;
|
||||||
|
|
Loading…
Reference in New Issue