Jan Dittberner
564c1bd76b
This commit implements a basic static HTML page that uses Bootstrap 4 for layout and node-forge to generate a RSA key pair and a certificate signing request. The subject of the CSR and the key size can be chosen by the user. The implementation uses gulp to collect static assets and to allow bootstrap customization.
111 lines
4.9 KiB
HTML
111 lines
4.9 KiB
HTML
<!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,
|
|
}]);
|
|
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>
|
|
|