2020-11-22 11:28:28 +01:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html lang="en">
|
|
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
|
|
|
|
|
|
<!-- Bootstrap CSS -->
|
|
|
|
<link rel="stylesheet" href="../public/css/styles.min.css">
|
|
|
|
<meta name="theme-color" content="#ffffff">
|
|
|
|
|
|
|
|
<title>CSR generation in browser</title>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="container">
|
|
|
|
<h1>CSR generation in browser</h1>
|
|
|
|
<div class="row">
|
|
|
|
<div class="col-12">
|
|
|
|
<form id="csr-form">
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="nameInput">Your name</label>
|
|
|
|
<input type="text" class="form-control" id="nameInput" aria-describedby="nameHelp" required
|
|
|
|
minlength="3">
|
|
|
|
<small id="nameHelp" class="form-text text-muted">Please input your name as it should be added to
|
|
|
|
your certificate</small>
|
|
|
|
</div>
|
|
|
|
<fieldset class="form-group">
|
|
|
|
<legend>RSA Key Size</legend>
|
|
|
|
<div class="form-check">
|
|
|
|
<input class="form-check-input" type="radio" name="keySize" id="size3072" value="3072"
|
|
|
|
checked>
|
|
|
|
<label class="form-check-label" for="size3072">3072 Bit</label>
|
|
|
|
</div>
|
|
|
|
<div class="form-check">
|
|
|
|
<input class="form-check-input" type="radio" name="keySize" id="size2048" value="2048">
|
|
|
|
<label class="form-check-label" for="size2048">2048 Bit (not recommended</label>
|
|
|
|
</div>
|
|
|
|
<div class="form-check">
|
|
|
|
<input class="form-check-input" type="radio" name="keySize" id="size4096" value="4096">
|
|
|
|
<label class="form-check-label" for="size4096">4096 Bit</label>
|
|
|
|
</div>
|
|
|
|
<small id="keySizeHelp" class="form-text text-muted">An RSA key pair will be generated in your
|
|
|
|
browser. Longer key sizes provide better security but take longer to generate.</small>
|
|
|
|
</fieldset>
|
|
|
|
<button type="submit" id="gen-csr-button" class="btn btn-primary">Generate Signing Request</button>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div id="status-block" class="d-none row">
|
|
|
|
<div class="col-12">
|
|
|
|
<div class="d-flex align-items-center">
|
|
|
|
<strong id="status-text">Loading ...</strong>
|
|
|
|
<div class="spinner-border ml-auto" id="status-spinner" role="status" aria-hidden="true"></div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<pre id="key"></pre>
|
|
|
|
<pre id="csr"></pre>
|
|
|
|
</div>
|
|
|
|
<script src="../public/js/jquery.slim.min.js"></script>
|
|
|
|
<script src="../public/js/forge.all.min.js"></script>
|
|
|
|
<script src="../public/js/bootstrap.bundle.min.js"></script>
|
|
|
|
<script>
|
|
|
|
const keyElement = document.getElementById('key');
|
|
|
|
document.getElementById('csr-form').onsubmit = function (event) {
|
|
|
|
const subject = event.target["nameInput"].value;
|
|
|
|
const keySize = parseInt(event.target["keySize"].value);
|
|
|
|
if (isNaN(keySize)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const spinner = document.getElementById('status-spinner');
|
|
|
|
const statusText = document.getElementById('status-text');
|
|
|
|
const statusBlock = document.getElementById('status-block');
|
|
|
|
statusBlock.classList.remove('d-none');
|
|
|
|
spinner.classList.remove('d-none');
|
|
|
|
|
|
|
|
const state = forge.pki.rsa.createKeyPairGenerationState(keySize, 0x10001);
|
|
|
|
statusText.innerHTML = 'started key generation';
|
|
|
|
const startDate = new Date();
|
|
|
|
const step = function () {
|
|
|
|
let duration = (new Date()).getTime() - startDate.getTime();
|
|
|
|
let seconds = Math.floor(duration / 100) / 10;
|
|
|
|
if (!forge.pki.rsa.stepKeyPairGenerationState(state, 100)) {
|
|
|
|
setTimeout(step, 1);
|
|
|
|
statusText.innerHTML = `key generation running for ${seconds} seconds`;
|
|
|
|
} else {
|
|
|
|
statusText.innerHTML = `key generated in ${seconds} seconds`
|
|
|
|
spinner.classList.add('d-none');
|
|
|
|
const keys = state.keys;
|
|
|
|
keyElement.innerHTML = forge.pki.privateKeyToPem(keys.privateKey);
|
|
|
|
const csr = forge.pki.createCertificationRequest();
|
|
|
|
|
|
|
|
csr.publicKey = keys.publicKey;
|
|
|
|
csr.setSubject([{
|
|
|
|
name: 'commonName',
|
|
|
|
value: subject,
|
2020-11-22 20:56:03 +01:00
|
|
|
valueTagClass: forge.asn1.Type.UTF8,
|
2020-11-22 11:28:28 +01:00
|
|
|
}]);
|
|
|
|
csr.sign(keys.privateKey, forge.md.sha256.create());
|
|
|
|
|
|
|
|
const verified = csr.verify();
|
|
|
|
if (verified) {
|
|
|
|
document.getElementById("csr").innerHTML = forge.pki.certificationRequestToPem(csr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
setTimeout(step);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
|