87 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| /*global Promise*/
 | |
| (function (exports) {
 | |
| 'use strict';
 | |
| 
 | |
| var Keypairs = exports.Keypairs = {};
 | |
| 
 | |
| Keypairs._stance = "We take the stance that if you're knowledgeable enough to"
 | |
|   + " properly and securely use non-standard crypto then you shouldn't need Bluecrypt anyway.";
 | |
| Keypairs._universal = "Bluecrypt only supports crypto with standard cross-browser and cross-platform support.";
 | |
| Keypairs.generate = function (opts) {
 | |
|   var wcOpts = {};
 | |
|   if (!opts) {
 | |
|     opts = {};
 | |
|   }
 | |
|   if (!opts.kty) {
 | |
|     opts.kty = 'EC';
 | |
|   }
 | |
| 
 | |
|   // ECDSA has only the P curves and an associated bitlength
 | |
|   if (/^EC/i.test(opts.kty)) {
 | |
|     wcOpts.name = 'ECDSA';
 | |
|     if (!opts.namedCurve) {
 | |
|       opts.namedCurve = 'P-256';
 | |
|     }
 | |
|     wcOpts.namedCurve = opts.namedCurve; // true for supported curves
 | |
|     if (/256/.test(wcOpts.namedCurve)) {
 | |
|       wcOpts.namedCurve = 'P-256';
 | |
|       wcOpts.hash = { name: "SHA-256" };
 | |
|     } else if (/384/.test(wcOpts.namedCurve)) {
 | |
|       wcOpts.namedCurve = 'P-384';
 | |
|       wcOpts.hash = { name: "SHA-384" };
 | |
|     } else {
 | |
|       return Promise.Reject(new Error("'" + wcOpts.namedCurve + "' is not an NIST approved ECDSA namedCurve. "
 | |
|         + " Please choose either 'P-256' or 'P-384'. "
 | |
|         + Keypairs._stance));
 | |
|     }
 | |
|   } else if (/^RSA$/i.test(opts.kty)) {
 | |
|     // Support PSS? I don't think it's used for Let's Encrypt
 | |
|     wcOpts.name = 'RSASSA-PKCS1-v1_5';
 | |
|     if (!opts.modulusLength) {
 | |
|       opts.modulusLength = 2048;
 | |
|     }
 | |
|     wcOpts.modulusLength = opts.modulusLength;
 | |
|     if (wcOpts.modulusLength >= 2048 && wcOpts.modulusLength < 3072) {
 | |
|       // erring on the small side... for no good reason
 | |
|       wcOpts.hash = { name: "SHA-256" };
 | |
|     } else if (wcOpts.modulusLength >= 3072 && wcOpts.modulusLength < 4096) {
 | |
|       wcOpts.hash = { name: "SHA-384" };
 | |
|     } else if (wcOpts.modulusLength < 4097) {
 | |
|       wcOpts.hash = { name: "SHA-512" };
 | |
|     } else {
 | |
|       // Public key thumbprints should be paired with a hash of similar length,
 | |
|       // so anything above SHA-512's keyspace would be left under-represented anyway.
 | |
|       return Promise.Reject(new Error("'" + wcOpts.modulusLength + "' is not within the safe and universally"
 | |
|         + " acceptable range of 2048-4096. Typically you should pick 2048, 3072, or 4096, though other values"
 | |
|         + " divisible by 8 are allowed. " + Keypairs._stance));
 | |
|     }
 | |
|     // TODO maybe allow this to be set to any of the standard values?
 | |
|     wcOpts.publicExponent = new Uint8Array([0x01, 0x00, 0x01]);
 | |
|   } else {
 | |
|     return Promise.Reject(new Error("'" + opts.kty + "' is not a well-supported key type."
 | |
|       + Keypairs._universal
 | |
|       + " Please choose either 'EC' or 'RSA' keys."));
 | |
|   }
 | |
| 
 | |
|   var extractable = true;
 | |
|   return window.crypto.subtle.generateKey(
 | |
|     wcOpts
 | |
|   , extractable
 | |
|   , [ 'sign', 'verify' ]
 | |
|   ).then(function (result) {
 | |
|     return window.crypto.subtle.exportKey(
 | |
|       "jwk"
 | |
|     , result.privateKey
 | |
|     ).then(function (privJwk) {
 | |
|       // TODO remove
 | |
|       console.log('private jwk:');
 | |
|       console.log(JSON.stringify(privJwk, null, 2));
 | |
|       return {
 | |
|         privateKey: privJwk
 | |
|       };
 | |
|     });
 | |
|   });
 | |
| };
 | |
| 
 | |
| }(window));
 |