]> WPIA git - gigi.git/blob - static/static/keygenIE.js
add: js-managed default values for certificate-issue-form
[gigi.git] / static / static / keygenIE.js
1 /*
2 LibreSSL - CAcert web application
3 Copyright (C) 2004-2012  CAcert Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 var CAcert_keygen_IE = function () {
20
21         /// Makes a new DOM text node
22         var textnode = function (text) {
23                 return document.createTextNode(text);
24         }
25
26         /// makes a new <p> element
27         var paragraph = function (text) {
28                 var paragraph = document.createElement("p");
29                 paragraph.appendChild(textnode(text));
30                 return paragraph;
31         }
32
33         /// makes a new <pre> elemtent
34         var pre = function (text) {
35                 var pre = document.createElement("pre");
36                 pre.appendChild(textnode(text));
37                 return pre;
38         }
39
40         /// makes a new <option> element
41         var option = function (text, value) {
42                 var option = document.createElement("option");
43                 if (value !== undefined) {
44                         option.setAttribute("value", value);
45                 }
46                 option.appendChild(textnode(text));
47                 return option;
48         }
49
50         /// Removes all child nodes from the element
51         var removeChildren = function (element) {
52                 element.innerHTML = "";
53         }
54
55         /// Show error message to user from exception
56         var showError = function (message, exception) {
57                 window.alert(
58                         message +
59                         "\n\nError: " + exception.message +
60                         " (0x" + (0xFFFFFFFF + exception.number + 1).toString(16) +
61                         " / " + exception.number + ")"
62                         );
63         }
64
65         // Get important elements from the DOM
66         var form = document.getElementById("CertReqForm");
67         var securityLevel = document.getElementById("SecurityLevel");
68         var customSettings = document.getElementById("customSettings");
69         var provider = document.getElementById("CspProvider");
70         var algorithm = document.getElementById("algorithm");
71         var algorithmParagraph = document.getElementById("algorithmParagraph");
72         var keySize = document.getElementById("keySize");
73         var keySizeMin = document.getElementById("keySizeMin");
74         var keySizeMax = document.getElementById("keySizeMax");
75         var keySizeStep = document.getElementById("keySizeStep");
76         var genReq = document.getElementById("GenReq");
77         var csr = document.getElementById("CSR");
78         var noActiveX = document.getElementById("noActiveX");
79         var generatingKeyNotice = document.getElementById("generatingKeyNotice");
80         var createRequestErrorChooseAlgorithm = document.getElementById("createRequestErrorChooseAlgorithm");
81         var createRequestErrorConfirmDialogue = document.getElementById("createRequestErrorConfirmDialogue");
82         var createRequestErrorConnectDevice = document.getElementById("createRequestErrorConnectDevice");
83         var createRequestError = document.getElementById("createRequestError");
84         var invalidKeySizeError = document.getElementById("invalidKeySizeError");
85         var unsupportedPlatformError = document.getElementById("unsupportedPlatformError");
86
87         /// Initialise the CertEnroll code (Vista and higher)
88         /// returns false if initialisation fails
89         var initCertEnroll = function () {
90                 var factory = null;
91                 var providerList = null;
92                 var cspStats = null;
93
94                 // Try to initialise the ActiveX element. Requires permissions by the user
95                 try {
96                         factory = new ActiveXObject("X509Enrollment.CX509EnrollmentWebClassFactory");
97                         if (!factory) {
98                                 throw {
99                                         name: "NoObjectError",
100                                         message: "Got null at object creation"
101                                         };
102                         }
103
104                         // also try to create a useless object here so the library gets
105                         // initialised and we don't need to check everytime later
106                         factory.CreateObject("X509Enrollment.CObjectId");
107
108                         form.style.display = "";
109                         noActiveX.style.display = "none";
110                 } catch (e) {
111                         return false;
112                 }
113
114                 /// Get the selected provider
115                 var getProvider = function () {
116                         var providerIndex = provider.options[provider.selectedIndex].value;
117                         return providerList.ItemByIndex(providerIndex);
118                 }
119
120                 /// Get the selected algorithm
121                 var getAlgorithm = function () {
122                         var algorithmIndex = algorithm.options[algorithm.selectedIndex].value;
123                         return alg = cspStats.ItemByIndex(algorithmIndex).CspAlgorithm;
124                 }
125
126                 /// Get the selected key size
127                 var getKeySize = function () {
128                         var alg = getAlgorithm();
129
130                         var bits = parseInt(keySize.value, 10);
131                         if (
132                                 (bits < alg.MinLength) ||
133                                 (bits > alg.MaxLength) ||
134                                 (
135                                         alg.IncrementLength &&
136                                         ((bits - alg.MinLength) % alg.IncrementLength !== 0)
137                                 )
138                         ) {
139                                 return false;
140                         }
141
142                         return bits;
143                 }
144
145                 /// Fill the key size list
146                 var getKeySizeList = function () {
147                         if (!cspStats) {
148                                 return false;
149                         }
150
151                         var alg = getAlgorithm();
152
153                         // HTML5 attributes
154                         keySize.setAttribute("min", alg.MinLength);
155                         keySize.setAttribute("max", alg.MaxLength);
156                         keySize.setAttribute("step", alg.IncrementLength);
157                         keySize.setAttribute("value", alg.DefaultLength);
158                         keySize.value = ""+alg.DefaultLength;
159
160                         // ugly, but buggy otherwise if done with text nodes
161                         keySizeMin.innerHTML = alg.MinLength;
162                         keySizeMax.innerHTML = alg.MaxLength;
163                         keySizeStep.innerHTML = alg.IncrementLength;
164
165                         return true;
166                 }
167
168                 /// Fill the algorithm list
169                 var getAlgorithmList = function () {
170                         var i;
171                         
172                         if (!providerList) {
173                                 return false;
174                         }
175
176                         var csp = getProvider();
177
178                         cspStats = providerList.GetCspStatusesFromOperations(
179                                 0x1c, //XCN_NCRYPT_ANY_ASYMMETRIC_OPERATION
180                                 //0x10, //XCN_NCRYPT_SIGNATURE_OPERATION
181                                 //0x8, //XCN_NCRYPT_SECRET_AGREEMENT_OPERATION
182                                 //0x4, //XCN_NCRYPT_ASYMMETRIC_ENCRYPTION_OPERATION
183                                 csp
184                                 );
185
186                         removeChildren(algorithm);
187                         for (i = 0; i < cspStats.Count; i++) {
188                                 var alg = cspStats.ItemByIndex(i).CspAlgorithm;
189                                 algorithm.appendChild(option(alg.Name, i));
190                         }
191
192                         return getKeySizeList();
193                 }
194
195                 /// Fill the crypto provider list
196                 var getProviderList = function () {
197                         var i;
198                         
199                         var csps = factory.CreateObject("X509Enrollment.CCspInformations");
200
201                         // Get provider information
202                         csps.AddAvailableCsps();
203
204                         removeChildren(provider);
205
206                         for (i = 0; i < csps.Count; i++) {
207                                 var csp = csps.ItemByIndex(i);
208                                 provider.appendChild(option(csp.Name, i));
209                         }
210
211                         providerList = csps;
212
213                         return getAlgorithmList();
214                 }
215
216                 /// Generate a key and create and submit the actual CSR
217                 var createCSR = function () {
218                         var providerName, algorithmOid, bits;
219
220                         var level = securityLevel.options[securityLevel.selectedIndex];
221                         if (level.value === "custom") {
222                                 providerName = getProvider().Name;
223                                 var alg = getAlgorithm();
224                                 algorithmOid = alg.GetAlgorithmOid(0, 0)
225                                 bits = getKeySize();
226                                 if (!bits) {
227                                         window.alert(invalidKeySizeError.innerHTML);
228                                         return false;
229                                 }
230                         } else {
231                                 providerName = "Microsoft Software Key Storage Provider";
232
233                                 algorithmOid = factory.CreateObject("X509Enrollment.CObjectId");
234                                 algorithmOid.InitializeFromValue("1.2.840.113549.1.1.1"); // RSA
235                                 // "1.2.840.10040.4.1" == DSA
236                                 // "1.2.840.10046.2.1" == DH
237
238                                 if (level.value === "high") {
239                                         bits = 4096;
240                                 } else { // medium
241                                         bits = 2048;
242                                 }
243                         }
244
245                         var privateKey = factory.CreateObject("X509Enrollment.CX509PrivateKey");
246                         privateKey.ProviderName = providerName;
247                         privateKey.Algorithm = algorithmOid;
248                         privateKey.Length = bits;
249                         privateKey.KeyUsage = 0xffffff; // XCN_NCRYPT_ALLOW_ALL_USAGES
250                         privateKey.ExportPolicy = 0x1; // XCN_NCRYPT_ALLOW_EXPORT_FLAG
251
252                         var request = factory.CreateObject("X509Enrollment.CX509CertificateRequestPkcs10");
253                         request.InitializeFromPrivateKey(
254                                 1, // ContextUser
255                                 privateKey,
256                                 "" // don't use a template
257                                 );
258
259                         var enroll = factory.CreateObject("X509Enrollment.CX509Enrollment");
260                         enroll.InitializeFromRequest(request);
261
262                         generatingKeyNotice.style.display = "";
263
264                         // The request needs to be created after we return so the "please wait"
265                         // message gets rendered
266                         var createCSRHandler = function () {
267                                 try {
268                                         csr.value = enroll.CreateRequest(0x1); //XCN_CRYPT_STRING_BASE64
269                                         form.submit();
270                                 } catch (e) {
271                                         showError(createRequestErrorChooseAlgorithm.innerHTML, e);
272                                 }
273
274                                 generatingKeyNotice.style.display = "none";
275                         }
276
277                         window.setTimeout(createCSRHandler, 0);
278
279                         // Always return false, form is submitted by deferred method
280                         return false;
281                 }
282
283                 /// Call if securityLevel has changed
284                 var refreshSecurityLevel = function () {
285                         var level = securityLevel.options[securityLevel.selectedIndex];
286                         if (level.value === "custom") {
287                                 getProviderList();
288                                 customSettings.style.display = "";
289                         } else {
290                                 customSettings.style.display = "none";
291                         }
292                 }
293
294                 securityLevel.onchange = refreshSecurityLevel;
295                 provider.onchange = getAlgorithmList;
296                 algorithm.onchange = getKeySizeList;
297                 genReq.onclick = createCSR;
298
299                 return true;
300         } // end of initCertEnroll()
301
302         /// Initialise Xenroll code (XP and lower)
303         /// returns false if initialisation fails
304         var initXEnroll = function () {
305                 cenroll = null;
306
307                 providerTypes = Array(
308                                  1, //PROV_RSA_FULL
309                                  2, //PROV_RSA_SIG
310                                  3, //PROV_DSS
311                                  4, //PROV_FORTEZZA
312                                  5, //PROV_MS_EXCHANGE
313                                  6, //PROV_SSL
314                                 12, //PROV_RSA_SCHANNEL
315                                 13, //PROV_DSS_DH
316                                 14, //PROV_EC_ECDSA_SIG
317                                 15, //PROV_EC_ECNRA_SIG
318                                 16, //PROV_EC_ECDSA_FULL
319                                 17, //PROV_EC_ECNRA_FULL
320                                 18, //PROV_DH_SCHANNEL
321                                 20, //PROV_SPYRUS_LYNKS
322                                 21, //PROV_RNG
323                                 22, //PROV_INTEL_SEC
324                                 23, //PROV_REPLACE_OWF
325                                 24  //PROV_RSA_AES
326                         );
327
328                 algClasses = Array(
329                         1 << 13, //ALG_CLASS_SIGNATURE
330                         //2 << 13, //ALG_CLASS_MSG_ENCRYPT
331                         //3 << 13, //ALG_CLASS_DATA_ENCRYPT
332                         //4 << 13, //ALG_CLASS_HASH
333                         5 << 13  //ALG_CLASS_KEY_EXCHANGE
334                         );
335
336                 // Try to initialise the ActiveX element.
337                 try {
338                         cenroll = new ActiveXObject("CEnroll.CEnroll");
339
340                         if (!cenroll) {
341                                 throw {
342                                         name: "NoObjectError",
343                                         message: "Got null at object creation"
344                                 };
345                         }
346
347                         form.style.display = "";
348                         algorithm.disabled = true;
349                         noActiveX.style.display = "none";
350                 } catch (e) {
351                         return false;
352                 }
353
354                 /// Get the name of the selected provider
355                 var getProviderName = function () {
356                         return provider.options[provider.selectedIndex].text;
357                 }
358
359                 /// Get the type of the selected provider
360                 var getProviderType = function () {
361                         return parseInt(provider.options[provider.selectedIndex].value, 10);
362                 }
363
364                 var refreshProvider = function () {
365                         cenroll.ProviderName = getProviderName();
366                         cenroll.ProviderType = getProviderType();
367                 }
368
369                 /// Get the ID of the selected algorithm
370                 var getAlgorithmId = function () {
371                         return parseInt(algorithm.options[algorithm.selectedIndex].value, 10);
372                 }
373
374                 /// Minimum bit length for exchange keys
375                 var getMinExKeyLength = function () {
376                         refreshProvider();
377
378                         try {
379                                 return cenroll.GetKeyLen(true, true);
380                         } catch (e) {
381                                 return false;
382                         }
383                 }
384
385                 /// Maximum bit length for exchange keys
386                 var getMaxExKeyLength = function () {
387                         refreshProvider();
388
389                         try {
390                                 return cenroll.GetKeyLen(false, true);
391                         } catch (e) {
392                                 return false;
393                         }
394                 }
395
396                 /// Step size for exchange keys
397                 /// This might not be available on older platforms
398                 var getStepExKeyLength = function () {
399                         refreshProvider();
400
401                         try {
402                                 return cenroll.GetKeyLenEx(3, 1);
403                         } catch (e) {
404                                 return false;
405                         }
406                 }
407
408                 /// Minimum bit length for signature keys
409                 var getMinSigKeyLength = function () {
410                         refreshProvider();
411
412                         try {
413                                 return cenroll.GetKeyLen(true, false);
414                         } catch (e) {
415                                 return false;
416                         }
417                 }
418
419                 /// Maximum bit length for signature keys
420                 var getMaxSigKeyLength = function () {
421                         refreshProvider();
422
423                         try {
424                                 return cenroll.GetKeyLen(false, false);
425                         } catch (e) {
426                                 return false;
427                         }
428                 }
429
430                 /// Step size for signature keys
431                 /// This might not be available on older platforms
432                 var getStepSigKeyLength = function () {
433                         refreshProvider();
434
435                         try {
436                                 return cenroll.GetKeyLenEx(3, 2);
437                         } catch (e) {
438                                 return false;
439                         }
440                 }
441
442                 /// Get the selected key size
443                 var getKeySize = function () {
444                         var bits = parseInt(keySize.value, 10);
445                         if (
446                                 (bits < getMinSigKeyLength()) ||
447                                 (bits > getMaxSigKeyLength()) ||
448                                 (
449                                         getStepSigKeyLength() &&
450                                         ((bits - getMinSigKeyLength()) % getStepSigKeyLength() !== 0)
451                                 )
452                         ) {
453                                 return false;
454                         }
455
456                         return bits;
457                 }
458
459                 var getKeySizeLimits = function () {
460                         // HTML5 attributes
461                         keySize.setAttribute("min", getMinSigKeyLength());
462                         keySize.setAttribute("max", getMaxSigKeyLength());
463                         if (getStepSigKeyLength()) {
464                                 keySize.setAttribute("step", getStepSigKeyLength());
465                         }
466
467                         // ugly, but buggy otherwise if done with text nodes
468                         keySizeMin.innerHTML = getMinSigKeyLength();
469                         keySizeMax.innerHTML = getMaxSigKeyLength();
470                         keySizeStep.innerHTML = getStepSigKeyLength();
471
472                         if (getMinSigKeyLength() === getMaxSigKeyLength()) {
473                                 keySize.value = getMaxSigKeyLength();
474                         }
475
476                         return true;
477                 }
478
479                 /// Fill the algorithm selection box
480                 var getAlgorithmList = function () {
481                         var i, j;
482                         
483                         refreshProvider();
484
485                         removeChildren(algorithm);
486
487                         for (i = 0; i < algClasses.length; ++i) {
488                                 for (j = 0; true; ++j) {
489                                         try {
490                                                 var algId = cenroll.EnumAlgs(j, algClasses[i]);
491                                                 var algName = cenroll.GetAlgName(algId);
492                                                 algorithm.appendChild(option(algName, algId));
493                                         } catch (e) {
494                                                 break;
495                                         }
496                                 }
497                         }
498
499                         getKeySizeLimits();
500                 }
501
502                 /// Fill the provider selection box
503                 var getProviderList = function () {
504                         var i, j;
505                         
506                         removeChildren(provider);
507
508                         for (i = 0; i < providerTypes.length; ++i) {
509                                 cenroll.providerType = providerTypes[i];
510
511                                 var providerName = "invalid";
512                                 for (j = 0; true; ++j) {
513                                         try {
514                                                 providerName = cenroll.enumProviders(j, 0);
515                                                 provider.appendChild(option(providerName, providerTypes[i]));
516                                         } catch (e) {
517                                                 break;
518                                         }
519                                 }
520                         }
521
522                         return getAlgorithmList();
523                 }
524
525                 var createCSR = function () {
526                         var providerName, bits;
527
528                         var level = securityLevel.options[securityLevel.selectedIndex];
529                         if (level.value === "custom") {
530                                 refreshProvider();
531
532                                 bits = getKeySize();
533                                 if (bits === false) {
534                                         window.alert(invalidKeySizeError.innerHTML);
535                                         return false;
536                                 }
537                         } else {
538                                 cenroll.ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";
539                                 cenroll.ProviderType = 1; //PROV_RSA_FULL
540
541                                 if (level.value === "high") {
542                                         bits = 4096;
543                                 } else { // medium
544                                         bits = 2048;
545                                 }
546                         }
547
548                         cenroll.GenKeyFlags = bits << 16; // keysize is encoded in the uper 16 bits
549                         // Allow exporting the private key
550                         cenroll.GenKeyFlags = cenroll.GenKeyFlags | 0x1; //CRYPT_EXPORTABLE
551
552                         generatingKeyNotice.style.display = "";
553
554                         // The request needs to be created after we return so the "please wait"
555                         // message gets rendered
556                         var createCSRHandler = function () {
557                                 try {
558                                         csr.value = cenroll.createPKCS10("", "1.3.6.1.5.5.7.3.2");
559                                         form.submit();
560                                 } catch (e) {
561                                         if (e.number === -2147023673) {
562                                                 // 0x800704c7 => dialogue declined
563                                                 showError(createRequestErrorConfirmDialogue.innerHTML, e);
564                                         } else if (e.number === -2146435043) {
565                                                 // 0x8010001d => crypto-device not connected
566                                                 showError(createRequestErrorConnectDevice.innerHTML, e);
567                                         } else {
568                                                 showError(createRequestError.innerHTML, e);
569                                         }
570                                 }
571
572                                 generatingKeyNotice.style.display = "none";
573                                 cenroll.Reset();
574                         }
575
576                         window.setTimeout(createCSRHandler, 0);
577
578                         // Always return false, form is submitted by deferred method
579                         return false;
580                 }
581
582                 /// Call if securityLevel has changed
583                 var refreshSecurityLevel = function () {
584                         var level = securityLevel.options[securityLevel.selectedIndex];
585                         if (level.value === "custom") {
586                                 getProviderList();
587                                 customSettings.style.display = "";
588                         } else {
589                                 customSettings.style.display = "none";
590                         }
591                 }
592
593                 securityLevel.onchange = refreshSecurityLevel;
594                 provider.onchange = getAlgorithmList;
595                 algorithm.onchange = getKeySizeLimits;
596                 genReq.onclick = createCSR;
597
598                 return true;
599         };
600
601         // Run the init functions until one is successful
602         if (initCertEnroll()) {
603                 form.style.display = "";
604                 noActiveX.style.display = "none";
605         } else if (initXEnroll()) {
606                 form.style.display = "";
607                 noActiveX.style.display = "none";
608         } else {
609                 window.alert(unsupportedPlatformError.innerHTML);
610         }
611 } ();