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)); |