Compare commits
	
		
			5 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b22f957124 | |||
| 48bee9204d | |||
| 5dc3795a17 | |||
| 3c84a7e1bd | |||
| 65db78a3c5 | 
							
								
								
									
										71
									
								
								keypairs.js
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								keypairs.js
									
									
									
									
									
								
							| @ -229,13 +229,21 @@ Keypairs.signJws = function (opts) { | ||||
|       } | ||||
| 
 | ||||
|       // node specifies RSA-SHAxxx even whet it's actually ecdsa (it's all encoded x509 shasums anyway)
 | ||||
|       var nodeAlg = "RSA-SHA" + (((protect||header).alg||'').replace(/^[^\d]+/, '')||'256'); | ||||
|       var nodeAlg = "SHA" + (((protect||header).alg||'').replace(/^[^\d]+/, '')||'256'); | ||||
|       var protected64 = Enc.strToUrlBase64(protectedHeader); | ||||
|       var payload64 = Enc.bufToUrlBase64(payload); | ||||
|       var sig = require('crypto') | ||||
|       var binsig = require('crypto') | ||||
|         .createSign(nodeAlg) | ||||
|         .update(protect ? (protected64 + "." + payload64) : payload64) | ||||
|         .sign(pem, 'base64') | ||||
|         .sign(pem) | ||||
|       ; | ||||
|       if ('EC' === opts.jwk.kty) { | ||||
|         // ECDSA JWT signatures differ from "normal" ECDSA signatures
 | ||||
|         // https://tools.ietf.org/html/rfc7518#section-3.4
 | ||||
|         binsig = ecdsaAsn1SigToJoseSig(binsig); | ||||
|       } | ||||
| 
 | ||||
|       var sig = binsig.toString('base64') | ||||
|         .replace(/\+/g, '-') | ||||
|         .replace(/\//g, '_') | ||||
|         .replace(/=/g, '') | ||||
| @ -249,6 +257,41 @@ Keypairs.signJws = function (opts) { | ||||
|       }; | ||||
|     } | ||||
| 
 | ||||
|     function ecdsaAsn1SigToJoseSig(binsig) { | ||||
|       // should have asn1 sequence header of 0x30
 | ||||
|       if (0x30 !== binsig[0]) { throw new Error("Impossible EC SHA head marker"); } | ||||
|       var index = 2; // first ecdsa "R" header byte
 | ||||
|       var len = binsig[1]; | ||||
|       var lenlen = 0; | ||||
|       // Seek length of length if length is greater than 127 (i.e. two 512-bit / 64-byte R and S values)
 | ||||
|       if (0x80 & len) { | ||||
|         lenlen = len - 0x80; // should be exactly 1
 | ||||
|         len = binsig[2]; // should be <= 130 (two 64-bit SHA-512s, plus padding)
 | ||||
|         index += lenlen; | ||||
|       } | ||||
|       // should be of BigInt type
 | ||||
|       if (0x02 !== binsig[index]) { throw new Error("Impossible EC SHA R marker"); } | ||||
|       index += 1; | ||||
| 
 | ||||
|       var rlen = binsig[index]; | ||||
|       var bits = 32; | ||||
|       if (rlen > 49) { | ||||
|         bits = 64; | ||||
|       } else if (rlen > 33) { | ||||
|         bits = 48; | ||||
|       } | ||||
|       var r = binsig.slice(index + 1, index + 1 + rlen).toString('hex'); | ||||
|       var slen = binsig[index + 1 + rlen + 1]; // skip header and read length
 | ||||
|       var s = binsig.slice(index + 1 + rlen + 1 + 1).toString('hex'); | ||||
|       if (2 *slen !== s.length) { throw new Error("Impossible EC SHA S length"); } | ||||
|       // There may be one byte of padding on either
 | ||||
|       while (r.length < 2*bits) { r = '00' + r; } | ||||
|       while (s.length < 2*bits) { s = '00' + s; } | ||||
|       if (2*(bits+1) === r.length) { r = r.slice(2); } | ||||
|       if (2*(bits+1) === s.length) { s = s.slice(2); } | ||||
|       return Buffer.concat([Buffer.from(r, 'hex'), Buffer.from(s, 'hex')]); | ||||
|     } | ||||
| 
 | ||||
|     if (opts.pem && opts.jwk) { | ||||
|       return sign(opts.pem); | ||||
|     } else { | ||||
| @ -299,3 +342,25 @@ Enc.bufToUrlBase64 = function (buf) { | ||||
|   return Buffer.from(buf).toString('base64') | ||||
|     .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); | ||||
| }; | ||||
| 
 | ||||
| // For 'rsa-compat' module only
 | ||||
| // PLEASE do not use these sync methods, they are deprecated
 | ||||
| Keypairs._importSync = function (opts) { | ||||
|   try { | ||||
|     return Eckles.importSync(opts); | ||||
|   } catch(e) { | ||||
|     try { | ||||
|       return Rasha.importSync(opts); | ||||
|     } catch(e) { | ||||
|       console.error("options.pem does not appear to be a valid RSA or ECDSA public or private key"); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| // PLEASE do not use these, they are deprecated
 | ||||
| Keypairs._exportSync = function (opts) { | ||||
|   if ('RSA' === opts.jwk.kty) { | ||||
|     return Rasha.exportSync(opts); | ||||
|   } else { | ||||
|     return Eckles.exportSync(opts); | ||||
|   } | ||||
| }; | ||||
|  | ||||
							
								
								
									
										10
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								package.json
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | ||||
| { | ||||
|   "name": "keypairs", | ||||
|   "version": "1.2.9", | ||||
|   "description": "Lightweight RSA/ECDSA keypair generation and JWK <-> PEM", | ||||
|   "version": "1.2.14", | ||||
|   "description": "Lightweight RSA/ECDSA keypair generation and JWK <-> PEM using node's native RSA and ECDSA support", | ||||
|   "main": "keypairs.js", | ||||
|   "files": [ | ||||
|     "bin/keypairs.js" | ||||
| @ -21,7 +21,11 @@ | ||||
|     "RSA", | ||||
|     "ECDSA", | ||||
|     "PEM", | ||||
|     "JWK" | ||||
|     "JWK", | ||||
|     "keypair", | ||||
|     "crypto", | ||||
|     "sign", | ||||
|     "verify" | ||||
|   ], | ||||
|   "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", | ||||
|   "license": "MPL-2.0", | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user