Move application code to external file

This commit moves the application code to a separate JavaScript file. Error
handling for missing CA certificates has been added to avoid endless loops.
This commit is contained in:
Jan Dittberner 2023-05-20 11:15:33 +02:00
parent 90cca97ce3
commit 4bb13ff982
2 changed files with 300 additions and 295 deletions

View file

@ -13,23 +13,20 @@
<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>
<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">
@ -167,283 +164,6 @@
</footer>
<script src="../public/js/forge.min.js"></script>
<script src="../public/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>
<script src="../public/js/app.min.js"></script>
</body>
</html>

285
src/js/app.js Normal file
View file

@ -0,0 +1,285 @@
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];
let foundNext = true;
while (foundNext && !lastCert.isIssuer(lastCert)) {
foundNext = false;
for (let certIndex in rootCerts) {
let rootCert = rootCerts[certIndex];
if (lastCert.isIssuer(rootCert)) {
certificates.push(rootCert);
foundNext = true;
break;
}
}
lastCert = certificates[certificates.length - 1];
}
if (!foundNext) {
console.warn(`chain construction may be incomplete, could not find certificate for issuer`)
}
// 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;
}
});
});