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:
parent
20f0a5e4bb
commit
f1cf3d19f2
7 changed files with 11189 additions and 0 deletions
10721
clientcert/css/styles.css
Normal file
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
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
449
clientcert/index.html
Normal 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
7
clientcert/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
clientcert/js/bootstrap.bundle.min.js.map
Normal file
1
clientcert/js/bootstrap.bundle.min.js.map
Normal file
File diff suppressed because one or more lines are too long
2
clientcert/js/forge.min.js
vendored
Normal file
2
clientcert/js/forge.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
clientcert/js/forge.min.js.map
Normal file
1
clientcert/js/forge.min.js.map
Normal file
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"forge.min.js","sources":["webpack://[name]/forge.min.js"],"mappings":"AAAA","sourceRoot":""}
|
Loading…
Reference in a new issue