Add client certificate application

This commit adds published code built from
https://code.cacert.org/cacert/browser-csr-generation/src/tag/0.1.0 to
https://community.cacert.org/clientcert/.
This commit is contained in:
Jan Dittberner 2023-05-19 19:53:09 +02:00
parent 20f0a5e4bb
commit f1cf3d19f2
7 changed files with 11189 additions and 0 deletions

10721
clientcert/css/styles.css Normal file

File diff suppressed because it is too large Load diff

8
clientcert/css/styles.min.css vendored Normal file

File diff suppressed because one or more lines are too long

449
clientcert/index.html Normal file
View file

@ -0,0 +1,449 @@
<!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="css/styles.min.css">
<meta name="theme-color" content="#ffffff">
<title>CAcert client certificate generation in your browser</title>
</head>
<body>
<header class="sticky-top text-bg-dark py-2 mb-3" id="header">
<div class="container">
<svg id="CAcert-logo" width="510" height="116.25" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g id="b" transform="matrix(1.25,0,0,-1.25,0,116.25)"><g id="c" transform="scale(.1)"><path id="d" d="m2031.8 34.969c-56.31 0-107.84 6.4062-154.59 19.281-46.35 12.844-86.77 32.656-121.25 59.469-34.1 26.781-60.53 60.531-79.3 101.31-18.77 40.75-28.16 88.469-28.16 143.12 0 57.656 9.96 107.38 29.88 149.22 20.29 41.844 48.47 76.531 84.48 104.06 34.86 26.062 75.08 45.156 120.67 57.25 45.6 12.124 92.91 18.187 141.94 18.187 44.06 0 84.67-4.594 121.85-13.781 37.15-9.156 71.82-21.094 104-35.782v-169.03h-29.3c-8.05 6.594-17.83 14.281-29.31 23.094-11.11 8.844-24.91 17.469-41.38 25.937-15.7 8.032-32.95 14.688-51.72 19.782-18.78 5.531-40.61 8.25-65.51 8.25-55.17 0-97.69-16.875-127.58-50.625-29.49-33.438-44.25-78.907-44.25-136.56 0-59.468 15.12-104.62 45.4-135.41 30.66-30.875 73.94-46.281 129.88-46.281 26.05 0 49.42 2.781 70.11 8.25 21.06 5.875 38.5 12.687 52.3 20.375 13.01 7.344 24.51 15.062 34.47 23.125 9.96 8.093 19.15 15.969 27.59 23.687h29.3v-169.03c-32.55-14.688-66.66-26.219-102.29-34.688-35.25-8.8125-74.32-13.219-117.23-13.219" fill="#11568c"/><path
id="e"
d="m2981 330.9h-458.79c2.97-50.008 21.54-88.27 55.68-114.79 34.52-26.519 85.19-39.777 152-39.777 42.32 0 83.33 7.766 123.05 23.297 39.72 15.535 71.08 32.203 94.09 50.008h22.27v-164.23c-45.28-18.562-87.96-32.012-128.05-40.348-40.09-8.332-84.45-12.5-133.07-12.5-125.46 0-221.6 28.789-288.41 86.375-66.81 57.582-100.22 139.6-100.22 246.06 0 105.32 31.55 188.66 94.65 250.04 63.47 61.75 150.33 92.625 260.57 92.629 101.71-4e-3 178.17-26.332 229.39-78.992 51.22-52.277 76.84-127.67 76.84-226.17v-71.601m-199.33 119.91c-1.11 42.808-11.51 75.008-31.18 96.601-19.67 21.594-50.3 32.391-91.87 32.395-38.6-4e-3 -70.34-10.231-95.2-30.688-24.87-20.457-38.79-53.23-41.76-98.308h260.01"
fill="#11568c"/><path id="f"
d="m3514.5 477.77h-18.23c-8.74 2.953-22.79 5.172-42.17 6.656s-35.53 2.234-48.44 2.234c-29.26 0-55.09-1.859-77.5-5.562-22.42-3.703-46.55-10-72.39-18.891v-417.52h-205.16v623.5h205.16v-91.594c45.21 37.75 84.54 62.734 117.98 74.937 33.42 12.594 64.2 18.875 92.31 18.875 7.22 0 15.39-0.172 24.51-0.547s17.1-0.921 23.93-1.671v-190.42"
fill="#11568c"/><path id="g"
d="m3874.5 836.26-207.5-80.5v-94.75h-85.75v-133.5h85.75v-287c0-75.071 19.63-128.03 59-159 39.74-30.98 99.97-46.5 181-46.5 36.27 0 67.16 1.7188 92.25 5 25.08 2.9141 48.61 7.0313 71 12.5v135h-17.25c-6.95-3.645-19.25-7.633-37-12-17.37-4.375-31.45-6.504-42.25-6.5-26.24-8e-3 -46.36 3.461-60.25 10.75-13.51 7.652-23.1 17.988-28.5 30.75-5.79 12.754-8.87 27.211-9.25 43.25-0.39 16.035-0.5 34.746-0.5 56.25v217.5h195v133.5h-195v175.25h-0.75"
fill="#11568c"/><path id="h"
d="m439.12 20.273c-62.25 0-119.81 9.1875-172.69 27.562-52.5 18.375-97.688 45.75-135.56 82.125-37.875 36.375-67.312 81.75-88.312 136.12-20.625 54.375-30.938 117.19-30.938 188.44 0 66.375 9.9375 126.56 29.812 180.56 19.875 53.996 48.75 100.31 86.624 138.94 36.376 37.122 81.376 65.809 135 86.063 54 20.246 112.88 30.371 176.63 30.375 35.25-4e-3 66.933-2.066 95.062-6.188 28.496-3.753 54.746-8.816 78.75-15.187 25.121-7.129 47.809-15.191 68.062-24.188 20.622-8.628 38.622-16.691 54-24.187v-203.06h-24.75c-10.503 9-23.816 19.684-39.937 32.063-15.754 12.371-33.754 24.559-54 36.562-20.629 11.997-42.941 22.122-66.937 30.375-24.004 8.247-49.688 12.372-77.063 12.375-30.375-3e-3 -59.25-4.878-86.625-14.625-27.375-9.378-52.688-25.128-75.938-47.25-22.124-21.378-40.124-49.687-54-84.937-13.5-35.25-20.25-78-20.25-128.25 0-52.5 7.313-96.375 21.938-131.62 15-35.25 33.75-63 56.25-83.25 22.875-20.625 48.375-35.438 76.5-44.438 28.125-8.625 55.875-12.937 83.25-12.937 26.25 0 52.121 3.937 77.625 11.812 25.871 7.875 49.684 18.563 71.437 32.063 18.372 10.875 35.434 22.5 51.188 34.875 15.746 12.375 28.684 23.062 38.812 32.062h22.5v-200.25c-21.003-9.375-41.066-18.188-60.187-26.438-19.129-8.25-39.191-15.375-60.187-21.375-27.379-7.875-53.067-13.875-77.063-18-24.004-4.125-57-6.1875-99-6.1875"
fill="#11568c"/><path id="i"
d="m1672.2 45.082h-223.31l-57.94 169.31h-310.5l-57.94-169.31h-217.68l309.38 837.56h248.63l309.37-837.56m-333.56 322.88-102.94 300.38-102.94-300.38h205.88"
fill="#11568c"/><path
id="j"
d="m529.66 684.46c-36.738-1.871-77.344-32.203-81.344-73.883-4.417-45.98 17.786-71.976 51.626-89.816 16.921-8.922 36.476-11.504 56.164-8.313 19.683 3.192 38.996 12.778 52.886 32.239 5.774 8.136 3.856 19.41-4.281 25.183-8.137 5.774-19.41 3.856-25.184-4.281-8.914-12.488-18.597-15.906-29.214-17.629-10.618-1.723-22.473-1.027-33.497 4.785-22.046 11.621-34.374 29.988-32.992 54.609 1.391 24.7 26.168 40.575 49.614 41.09 23.449 0.52 45.949-10.675 53.894-41.804 0.942-6.871 5.746-12.473 12.344-14.606 6.594-2.137 13.851-0.488 18.637 4.531 4.781 5.02 6.226 12.403 3.777 18.887-11.832 46.344-52.047 69.836-89.66 69.008-0.879-0.02-1.887 0.043-2.77 0zm-503.69-11.332c-0.5546-0.07-1.0859-0.332-1.5117-0.504-0.125-0.055-0.3906-0.191-0.5039-0.254-0.0351-0.023-0.2187-0.226-0.25-0.25-0.0664-0.051-0.1953-0.199-0.2539-0.254-0.0547-0.055-0.1992-0.191-0.25-0.25-0.0234-0.031-0.2305-0.219-0.2539-0.254-0.0586-0.101-0.207-0.39-0.25-0.504-0.0156-0.035 0.0117-0.211 0-0.25-0.0352-0.117-0.2305-0.375-0.2539-0.504-0.0039-0.043 0.0078-0.207 0-0.25-0.4102-4.816 14.48-20.425 20.402-26.445 6.1016-6.211 56.524-46.558 84.871-65.73 28.527-19.297 94.066-54.223 110.81-62.461 16.594-8.16 68.145-29.715 102.25-40.043 58.672-17.77 118.95-28.031 177.3-32.488 58.348-4.454 114.86-2.961 165.97 3.023 102.22 11.965 184 38.824 222.38 85.879 19.191 23.527 29.098 61.598 7.305 85.375-23.711 25.871-78.68 46.996-82.102 47.097-0.191 0-0.582 0.012-0.754 0-0.113-0.011-0.402 0.016-0.504 0-0.051-0.011-0.203 0.012-0.254 0-0.047-0.015-0.207-0.238-0.25-0.253-0.043-0.016-0.211 0.019-0.254 0-0.117-0.055-0.398-0.18-0.503-0.25-0.032-0.028-0.219-0.227-0.25-0.254-0.028-0.028-0.227-0.223-0.254-0.25-0.067-0.098-0.196-0.395-0.25-0.504-0.043-0.117-0.223-0.375-0.254-0.504-0.016-0.086 0.011-0.41 0-0.504-4e-3 -0.047 4e-3 -0.203 0-0.254v-0.25c0.316-8.516 16.094-27.164 27.785-40.113 9.016-9.981 16.566-16.922 19.832-21.176 12.211-15.898 3.715-27.934-4.047-39.703-18.082-27.414-96.656-58.742-192.91-70.012-48.129-5.633-101.41-6.867-156.4-2.519-54.985 4.347-111.62 14.078-166.72 30.726-37.449 11.317-88.692 31.836-107.54 39.793-19.356 8.168-77.43 36.235-97.215 46.086-19.625 9.774-93.238 55.328-99.227 59.688-5.9882 4.359-21.301 9.871-25.688 9.32zm416.56-262.43c-1.821-0.109-3.649-0.5-5.04-1.008-0.453-0.175-1.101-0.535-1.511-0.754-0.199-0.113-0.567-0.382-0.754-0.503-0.184-0.126-0.582-0.368-0.754-0.504-0.227-0.188-0.555-0.551-0.758-0.754-0.199-0.211-0.578-0.532-0.754-0.758-0.129-0.172-0.387-0.574-0.504-0.754-0.3-0.496-0.539-1.203-0.757-1.766-0.254-0.711-0.629-1.707-0.754-2.515-1.094-8.11 4.429-21.043 16.371-36.266 23.273-29.68 22.093-53.344 22.414-80.844 0.316-27.5-17.395-56.957-41.051-84.621-27.258-31.871-58.082-59.094-86.109-80.883-27.844-21.644-82.547-55.171-100.01-68.714-17.219-13.352-30.551-21.672-33.242-29.211-0.153-0.4532-0.418-1.086-0.504-1.5118-0.063-0.3554 0.019-0.9257 0-1.2617-4e-3 -0.1992-0.012-0.5625 0-0.7539 0.015-0.1914-0.032-0.5703 0-0.7578 0.039-0.1797 0.195-0.5781 0.25-0.7539 0.043-0.1133 0.207-0.3906 0.254-0.5039 0.05-0.1094 0.191-0.3945 0.25-0.5039 0.129-0.211 0.347-0.5586 0.503-0.7539 0.043-0.0508 0.211-0.2071 0.254-0.2539 0.043-0.0469 0.204-0.2032 0.25-0.25 0.051-0.0469 0.204-0.2071 0.254-0.2539 0.625-0.5196 1.614-1.1211 2.52-1.5118 6.336-2.5625 19.394-1.9765 39.539 3.5274 15.758 4.3086 34.66 10.809 47.348 15.613 13.023 4.9375 74.964 38.465 109 63.152 33.785 24.508 71.421 62.141 87.437 83.172 15.879 20.848 41.262 53.235 43.32 118.37 1.371 43.528-8.191 72.75-54.902 99.731-19.402 11.207-33.578 15.898-42.562 15.363"
fill="#00be00" fill-rule="evenodd"/><path id="k"
d="m1298.3 33.055c-64.72 19.762-128.5 42.133-168.77 74.433-42.17 33.824-51.52 48.008-75.3 80.746-29.81 41.043-59.63 125.99-62.228 205.96-1.933 59.375 6.25 107.64 25.268 151.56 16.31 37.664 50.72 85.133 66.86 83.586 16.79-1.613 12.79-22.199 1.8-68.606-12.97-54.804-14.7-69.25-14.78-123.54-0.1-65.406 6-96.316 28.15-162.39 9.16-27.34 20.57-61.301 52.72-97.508 25.63-28.879 61.73-56.82 127.17-93.027 52.63-29.117 66.92-42.023 67.68-50.742 0.35-3.9531-3.72-6.789-10.93-6.9336-9.68-0.2031-23.7 2.211-37.64 6.4649zm219.34 469.26c-42.18 10.309-58.18 20.684-88.8 33.672-96.79 41.055-164.89 71.496-185.55 78.805-27.01 9.551-112.64 39.285-163.57 51.039-57.65 13.309-142.41 29.652-175.3 31.434-29.926 1.621-72.531-2.672-90.598-12.86-21.546-12.152-18.187-34.172 9.403-79.953 4.918-8.16 9.805-13.461 7.773-16.984-1.883-3.27-12.652-0.403-21.808 3.894-12.336 5.786-29.75 23.145-39.18 37.668-22.016 33.914-9.391 79.172 30.613 101.15 28.953 15.906 60.739 19.273 126.74 13.832 73.885-6.094 143.36-26.278 176.2-36.188 180.42-54.453 245.08-80.371 317.15-119.35 33.6-18.176 63.75-39.961 71.71-44.762 6.56-3.953 29.91-18.887 40.27-29.125 4.14-4.094 5.63-7.664 4.93-9.129-1.52-3.176-15.1-4.34-19.98-3.149zm-467.18 247.14c-13.3 5.957-22.54 18.926-29.18 31.254-4.52 8.375-7.28 21.266-6.57 35.387 0.71 14.113 1.87 25.601 10.46 43.691 11.5 24.199 28.57 41.508 51.45 52.16 14.78 6.883 17.58 7.863 36.23 7.906 18.8 0.04 24.33-3.253 34.76-9.316 13.03-7.57 19.42-18.258 23.87-28.062 4.41-9.68 6.72-16.102 6.87-33.622 0.14-17.671-4.96-37.812-21.27-63.027-8-12.375-21.5-24.558-41.88-36.012-14.21-7.988-43.3-9.964-64.74-0.359zm60.84 33.828c18.94 16.098 25.2 29.086 26.87 54.242 1.75 26.485-19.08 44.25-28.66 45.25-25.17 2.621-47.61-15.839-52.81-50.113-1.11-7.344-0.44-14.316 2.39-25.043 3.08-11.683 10.74-23.902 23.13-27.586 12.77-3.793 22.57-0.824 29.08 3.25"
fill="#c7ff00"/></g></g></svg>
<h1>Client certificate generation in your browser</h1>
<div class="row mb-3">
<div class="col-12">
<div class="progress" style="height: 2rem">
<div id="progress-bar" class="progress-bar" role="progressbar" aria-valuenow="1" aria-valuemin="1"
aria-valuemax="5" style="width:20%">Start
</div>
</div>
</div>
</div>
</div>
</header>
<main>
<div class="container">
<div class="row mb-3">
<div class="col-12">
<h2>1. Generate a key pair</h2>
<form id="csr-form">
<div class="mb-3">
<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>
<p>Choose an RSA key size</p>
<fieldset class="mb-3">
<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>
<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 (most compatible, least
secure)</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>
</fieldset>
<button type="submit" id="gen-csr-button" class="btn btn-primary">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-key-fill" viewBox="0 0 16 16">
<path d="M3.5 11.5a3.5 3.5 0 1 1 3.163-5H14L15.5 8 14 9.5l-1-1-1 1-1-1-1 1-1-1-1 1H6.663a3.5 3.5 0 0 1-3.163 2zM2.5 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/>
</svg>
Generate key pair and signing request
</button>
</form>
</div>
</div>
<div class="row mb-3 d-none" id="key-wrapper">
<div class="col-12">
<button class="btn btn-danger" type="button" data-bs-toggle="collapse"
data-bs-target="#collapse-key-output"
aria-expanded="false" aria-controls="collapse-key-output">Show private key
</button>
<div class="collapse mt-3" id="collapse-key-output">
<pre id="key-output"></pre>
</div>
</div>
</div>
<div id="csr-wrapper" class="row mb-3 d-none">
<div class="col-12">
<h2>2. Paste the CSR into the CAcert form</h2>
<p>The CAcert web application allows you to paste a custom Certificate Signing Request (CSR) when you
request a client certificate. Use the button below to copy your CSR to the clipboard.
</p>
<pre id="csr-output"></pre>
<button class="btn btn-primary" id="copy-csr-to-clipboard">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-clipboard-fill" viewBox="0 0 16 16">
<path fill-rule="evenodd"
d="M10 1.5a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-1Zm-5 0A1.5 1.5 0 0 1 6.5 0h3A1.5 1.5 0 0 1 11 1.5v1A1.5 1.5 0 0 1 9.5 4h-3A1.5 1.5 0 0 1 5 2.5v-1Zm-2 0h1v1A2.5 2.5 0 0 0 6.5 5h3A2.5 2.5 0 0 0 12 2.5v-1h1a2 2 0 0 1 2 2V14a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3.5a2 2 0 0 1 2-2Z"/>
</svg>
Copy CSR to Clipboard
</button>
</div>
</div>
<div id="crt-input-wrapper" class="row mb-3 d-none">
<div class="col-12">
<h2>3. Get your certificate signed</h2>
<p>Go to the <a href="https://secure.cacert.org/account.php?id=3" target="_blank">New client certificate
page</a> of the CAcert web application and click the checkbox "Show advanced options". This will
show
you a text area where you can paste the copied CSR.</p>
<label id="crt-input-label" for="crt-input">Paste the signed certificate from the CAcert web
application</label>
<textarea class="form-control" id="crt-input" name="crt-input" rows="20" autocomplete="off"
placeholder="Paste the certificate here" aria-labelledby="crt-input-label"></textarea>
</div>
</div>
<div id="prepare-download-wrapper" class="row mb-3 d-none">
<div class="col-12">
<h2>4. Build the client certificate file</h2>
<p>You now have all the ingredients for downloading your certificate and corresponding key pair. Enter a
password of your choice and click on the "Prepare Download" button to generate a file that you can
use
in your Browser, email client, or other applications.</p>
<div class="mb-3">
<label for="passwordInput">Password for your client certificate file</label>
<input type="password" class="form-control" id="passwordInput" aria-describedby="nameHelp" required
minlength="8">
</div>
<button class="btn btn-primary" id="generate-p12">
Prepare Download
</button>
</div>
</div>
<div class="row d-none mb-3" id="download-wrapper">
<div class="col-12">
<h2>5. Download ready</h2>
<p>Your key material is ready for download. The downloadable file contains your private
key and your certificate encrypted with your password. You can now use the file to install your
certificate in your browser or other applications.</p>
<a class="btn btn-success" id="download-link" href="#">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-file-earmark-arrow-down-fill" viewBox="0 0 16 16">
<path d="M9.293 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.707A1 1 0 0 0 13.707 4L10 .293A1 1 0 0 0 9.293 0zM9.5 3.5v-2l3 3h-2a1 1 0 0 1-1-1zm-1 4v3.793l1.146-1.147a.5.5 0 0 1 .708.708l-2 2a.5.5 0 0 1-.708 0l-2-2a.5.5 0 0 1 .708-.708L7.5 11.293V7.5a.5.5 0 0 1 1 0z"/>
</svg>
Download
</a>
</div>
</div>
</div>
</main>
<footer class="sticky-bottom text-bg-dark py-2">
<div class="container">
<p><small>© 2023 CAcert</small></p>
</div>
</footer>
<script src="js/forge.min.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
const csrForm = document.getElementById("csr-form");
const crtInput = document.getElementById("crt-input");
const app = {
keyPair: undefined,
certificate: undefined,
progressBar: document.getElementById("progress-bar"),
keyOutput: document.getElementById("key-output"),
csrOutput: document.getElementById("csr-output"),
prepareButton: document.getElementById("generate-p12"),
downloadButton: document.getElementById("download-link"),
updateProgress(percent, valuenow, title, ...tokens) {
this.progressBar.classList.add(...tokens)
this.progressBar.style.width = `${percent}%`;
this.progressBar.setAttribute("aria-valuenow", `${valuenow}`)
this.progressBar.innerHTML = title;
},
generateKeyPair(keySize) {
this.updateProgress(40, 2, "Started key generation", 'progress-bar-striped', 'progress-bar-animated');
const state = forge.pki.rsa.createKeyPairGenerationState(keySize, 0x10001);
const startDate = new Date();
return new Promise(done => {
const step = () => {
let duration = (new Date()).getTime() - startDate.getTime();
let seconds = Math.floor(duration / 100) / 10;
if (!forge.pki.rsa.stepKeyPairGenerationState(state, 100)) {
setTimeout(step, 1);
this.progressBar.innerHTML = `Key pair generation running for ${seconds} seconds`;
} else {
this.progressBar.classList.remove("progress-bar-animated", 'progress-bar-striped');
this.progressBar.innerHTML = "Key pair generated";
const keys = state.keys;
document.getElementById("key-wrapper").classList.remove("d-none");
this.keyOutput.innerHTML = forge.pki.privateKeyToPem(keys.privateKey);
this.keyPair = state.keys;
done();
}
}
step();
});
},
generateCSR(subjectName) {
const csr = forge.pki.createCertificationRequest();
csr.publicKey = this.keyPair.publicKey;
csr.setSubject([{
name: 'commonName',
value: subjectName,
valueTagClass: forge.asn1.Type.UTF8,
}]);
csr.sign(this.keyPair.privateKey, forge.md.sha256.create());
const verified = csr.verify();
if (verified) {
let csrPem = forge.pki.certificationRequestToPem(csr);
this.updateProgress(60, 3, "CSR generated");
document.getElementById("csr-output").innerHTML = csrPem;
const csrWrapper = document.getElementById("csr-wrapper");
csrWrapper.classList.remove("d-none");
csrWrapper.scrollIntoView();
document.getElementById("copy-csr-to-clipboard").addEventListener("click", (event) => {
event.preventDefault();
navigator.clipboard.writeText(csrPem)
const crtInputWrapper = document.getElementById("crt-input-wrapper");
crtInputWrapper.classList.remove("d-none");
crtInputWrapper.scrollIntoView();
this.updateProgress(80, 4, "CSR copied to clipboard, waiting for certificate");
});
}
},
handleCertificate(certificate) {
this.certificate = certificate;
const prepareDownloadWrapper = document.getElementById("prepare-download-wrapper");
prepareDownloadWrapper.classList.remove("d-none");
prepareDownloadWrapper.scrollIntoView();
this.progressBar.innerHTML = "Certificate pasted";
this.prepareButton.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
const passwordInput = document.getElementById("passwordInput");
let password = passwordInput.value;
if (password === "" || password.length < 8) {
return false;
}
this.buildKeyStore(password);
});
},
buildKeyStore(password) {
this.updateProgress(100, 5, "Building keystore");
let certificates = [];
certificates.push(this.certificate);
let rootCerts = [];
// add CAcert class 3 certificate from http://www.cacert.org/certs/CAcert_Class3Root_x14E228.crt
rootCerts.push(forge.pki.certificateFromPem("-----BEGIN CERTIFICATE-----\n" +
"MIIGPTCCBCWgAwIBAgIDFOIoMA0GCSqGSIb3DQEBDQUAMHkxEDAOBgNVBAoTB1Jv\n" +
"b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ\n" +
"Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y\n" +
"dEBjYWNlcnQub3JnMB4XDTIxMDQxOTEyMTgzMFoXDTMxMDQxNzEyMTgzMFowVDEU\n" +
"MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0\n" +
"Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN\n" +
"AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a\n" +
"iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1\n" +
"aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C\n" +
"jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia\n" +
"pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0\n" +
"FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt\n" +
"XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL\n" +
"oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6\n" +
"R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp\n" +
"rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/\n" +
"LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA\n" +
"BfvpAgMBAAGjgfIwge8wDwYDVR0TAQH/BAUwAwEB/zBhBggrBgEFBQcBAQRVMFMw\n" +
"IwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLkNBY2VydC5vcmcvMCwGCCsGAQUFBzAC\n" +
"hiBodHRwOi8vd3d3LkNBY2VydC5vcmcvY2xhc3MzLmNydDBFBgNVHSAEPjA8MDoG\n" +
"CysGAQQBgZBKAgMBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y\n" +
"Zy9jcHMucGhwMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHBzOi8vd3d3LmNhY2VydC5v\n" +
"cmcvY2xhc3MzLmNybDANBgkqhkiG9w0BAQ0FAAOCAgEAxh6td1y0KJvRyI1EEsC9\n" +
"dnYEgyEH+BGCf2vBlULAOBG1JXCNiwzB1Wz9HBoDfIv4BjGlnd5BKdSLm4TXPcE3\n" +
"hnGjH1thKR5dd3278K25FRkTFOY1gP+mGbQ3hZRB6IjDX+CyBqS7+ECpHTms7eo/\n" +
"mARN+Yz5R3lzUvXs3zSX+z534NzRg4i6iHNHWqakFcQNcA0PnksTB37vGD75pQGq\n" +
"eSmx51L6UzrIpn+274mhsaFNL85jhX+lKuk71MGjzwoThbuZ15xmkITnZtRQs6Hh\n" +
"LSIqJWjDILIrxLqYHehK71xYwrRNhFb3TrsWaEJskrhveM0Os/vvoLNkh/L3iEQ5\n" +
"/LnmLMCYJNRALF7I7gsduAJNJrgKGMYvHkt1bo8uIXO8wgNV7qoU4JoaB1ML30QU\n" +
"qGcFr0TI06FFdgK2fwy5hulPxm6wuxW0v+iAtXYx/mRkwQpYbcVQtrIDvx1CT1k5\n" +
"0cQxi+jIKjkcFWHw3kBoDnCos0/ukegPT7aQnk2AbL4c7nCkuAcEKw1BAlSETkfq\n" +
"i5btdlhh58MhewZv1LcL5zQyg8w1puclT3wXQvy8VwPGn0J/mGD4gLLZ9rGcHDUE\n" +
"CokxFoWk+u5MCcVqmGbsyG4q5suS3CNslsHURfM8bQK4oLvHR8LCHEBMRcdFBn87\n" +
"cSvOK6eB1kdGKLA8ymXxZp8=\n" +
"-----END CERTIFICATE-----"));
// add CAcert root certificate from http://www.cacert.org/certs/root_X0F.crt
rootCerts.push(forge.pki.certificateFromPem("-----BEGIN CERTIFICATE-----\n" +
"MIIG7jCCBNagAwIBAgIBDzANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQKEwdSb290\n" +
"IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n" +
"IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n" +
"Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n" +
"BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi\n" +
"MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ\n" +
"ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC\n" +
"CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ\n" +
"8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6\n" +
"zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y\n" +
"fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7\n" +
"w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc\n" +
"G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k\n" +
"epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q\n" +
"laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ\n" +
"QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU\n" +
"fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826\n" +
"YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAX8w\n" +
"ggF7MB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TAPBgNVHRMBAf8EBTAD\n" +
"AQH/MDQGCWCGSAGG+EIBCAQnFiVodHRwOi8vd3d3LmNhY2VydC5vcmcvaW5kZXgu\n" +
"cGhwP2lkPTEwMFYGCWCGSAGG+EIBDQRJFkdUbyBnZXQgeW91ciBvd24gY2VydGlm\n" +
"aWNhdGUgZm9yIEZSRUUgaGVhZCBvdmVyIHRvIGh0dHA6Ly93d3cuY2FjZXJ0Lm9y\n" +
"ZzAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vY3JsLmNhY2VydC5vcmcvcmV2b2tl\n" +
"LmNybDAzBglghkgBhvhCAQQEJhYkVVJJOmh0dHA6Ly9jcmwuY2FjZXJ0Lm9yZy9y\n" +
"ZXZva2UuY3JsMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29j\n" +
"c3AuY2FjZXJ0Lm9yZzAfBgNVHSMEGDAWgBQWtTIb1Mfz4OaO873SsDrusjkY0TAN\n" +
"BgkqhkiG9w0BAQsFAAOCAgEAR5zXs6IX01JTt7Rq3b+bNRUhbO9vGBMggczo7R0q\n" +
"Ih1kdhS6WzcrDoO6PkpuRg0L3qM7YQB6pw2V+ubzF7xl4C0HWltfzPTbzAHdJtja\n" +
"JQw7QaBlmAYpN2CLB6Jeg8q/1Xpgdw/+IP1GRwdg7xUpReUA482l4MH1kf0W0ad9\n" +
"4SuIfNWQHcdLApmno/SUh1bpZyeWrMnlhkGNDKMxCCQXQ360TwFHc8dfEAaq5ry6\n" +
"cZzm1oetrkSviE2qofxvv1VFiQ+9TX3/zkECCsUB/EjPM0lxFBmu9T5Ih+Eqns9i\n" +
"vmrEIQDv9tNyJHuLsDNqbUBal7OoiPZnXk9LH+qb+pLf1ofv5noy5vX2a5OKebHe\n" +
"+0Ex/A7e+G/HuOjVNqhZ9j5Nispfq9zNyOHGWD8ofj8DHwB50L1Xh5H+EbIoga/h\n" +
"JCQnRtxWkHP699T1JpLFYwapgplivF4TFv4fqp0nHTKC1x9gGrIgvuYJl1txIKmx\n" +
"XdfJzgscMzqpabhtHOMXOiwQBpWzyJkofF/w55e0LttZDBkEsilV/vW0CJsPs3eN\n" +
"aQF+iMWscGOkgLFlWsAS3HwyiYLNJo26aqyWPaIdc8E4ck7Sk08WrFrHIK3EHr4n\n" +
"1FZwmLpFAvucKqgl0hr+2jypyh5puA3KksHF3CsUzjMUvzxMhykh9zrMxQAHLBVr\n" +
"Gwc=\n" +
"-----END CERTIFICATE-----"));
let lastCert = certificates[certificates.length - 1];
while (!lastCert.isIssuer(lastCert)) {
for (let certIndex in rootCerts) {
let rootCert = rootCerts[certIndex];
if (lastCert.isIssuer(rootCert)) {
certificates.push(rootCert);
break;
}
}
lastCert = certificates[certificates.length - 1];
}
// browsers have trouble importing anything but 3des encrypted PKCS#12
const p12asn1 = forge.pkcs12.toPkcs12Asn1(
this.keyPair.privateKey, certificates, password,
{algorithm: '3des'}
);
const p12Der = forge.asn1.toDer(p12asn1).getBytes();
const p12B64 = forge.util.encode64(p12Der);
this.downloadButton.download = 'client_certificate.p12';
this.downloadButton.setAttribute('href', 'data:application/x-pkcs12;base64,' + p12B64);
const downloadWrapper = document.getElementById("download-wrapper");
downloadWrapper.classList.remove("d-none");
downloadWrapper.scrollIntoView();
this.progressBar.innerHTML = "Client certificate ready";
this.progressBar.classList.add("bg-success")
}
};
csrForm.addEventListener("submit", (event) => {
event.preventDefault();
let valid = csrForm.checkValidity();
if (!valid) {
event.stopPropagation();
}
csrForm.classList.add("was-validated");
if (!valid) {
return;
}
let subjectName = event.target["nameInput"].value;
let keySize = parseInt(event.target["keySize"].value);
if (isNaN(keySize)) {
return;
}
app.generateKeyPair(keySize).then(function () {
app.generateCSR(subjectName);
});
}, false);
crtInput.addEventListener("paste", (event) => {
let crtData = (event.clipboardData || window.clipboardData).getData("text");
try {
const certificate = forge.pki.certificateFromPem(crtData);
app.handleCertificate(certificate);
} catch (e) {
console.warn(e);
return false;
}
});
});
</script>
</body>
</html>

7
clientcert/js/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
clientcert/js/forge.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
{"version":3,"file":"forge.min.js","sources":["webpack://[name]/forge.min.js"],"mappings":"AAAA","sourceRoot":""}