| OLD | NEW | 
| (Empty) |  | 
 |    1 /* | 
 |    2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
 |    3  * Copyright (C) 2006-2016 Eyeo GmbH | 
 |    4  * | 
 |    5  * Adblock Plus is free software: you can redistribute it and/or modify | 
 |    6  * it under the terms of the GNU General Public License version 3 as | 
 |    7  * published by the Free Software Foundation. | 
 |    8  * | 
 |    9  * Adblock Plus 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 Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
 |   16  */ | 
 |   17  | 
 |   18  | 
 |   19 /** | 
 |   20  * This is a specialized RSA library meant only to verify SHA1-based signatures. | 
 |   21  * It requires jsbn.js and sha1.js to work. | 
 |   22  */ | 
 |   23  | 
 |   24 (function(globalObj) | 
 |   25 { | 
 |   26   // Define ASN.1 templates for the data structures used | 
 |   27   function seq() | 
 |   28   { | 
 |   29     return {type: 0x30, children: Array.prototype.slice.call(arguments)}; | 
 |   30   } | 
 |   31   function obj(id) | 
 |   32   { | 
 |   33     return {type: 0x06, content: id}; | 
 |   34   } | 
 |   35   function bitStr(contents) | 
 |   36   { | 
 |   37     return {type: 0x03, encapsulates: contents}; | 
 |   38   } | 
 |   39   function intResult(id) | 
 |   40   { | 
 |   41     return {type: 0x02, out: id}; | 
 |   42   } | 
 |   43   function octetResult(id) | 
 |   44   { | 
 |   45     return {type: 0x04, out: id}; | 
 |   46   } | 
 |   47  | 
 |   48   // See http://www.cryptopp.com/wiki/Keys_and_Formats#RSA_PublicKey | 
 |   49   // 2A 86 48 86 F7 0D 01 01 01 means 1.2.840.113549.1.1.1 | 
 |   50   var publicKeyTemplate = seq(seq(obj("\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01"), {
     }), bitStr(seq(intResult("n"), intResult("e")))); | 
 |   51  | 
 |   52   // See http://tools.ietf.org/html/rfc3447#section-9.2 step 2 | 
 |   53   // 2B 0E 03 02 1A means 1.3.14.3.2.26 | 
 |   54   var signatureTemplate = seq(seq(obj("\x2B\x0E\x03\x02\x1A"), {}), octetResult(
     "sha1")); | 
 |   55  | 
 |   56   /** | 
 |   57    * Reads ASN.1 data matching the template passed in. This will throw an | 
 |   58    * exception if the data format doesn't match the template. On success an | 
 |   59    * object containing result properties is returned. | 
 |   60    * | 
 |   61    * See http://luca.ntop.org/Teaching/Appunti/asn1.html for info on the format. | 
 |   62    */ | 
 |   63   function readASN1(data, templ) | 
 |   64   { | 
 |   65     var pos = 0; | 
 |   66     function next() | 
 |   67     { | 
 |   68       return data.charCodeAt(pos++); | 
 |   69     } | 
 |   70  | 
 |   71     function readLength() | 
 |   72     { | 
 |   73       var len = next(); | 
 |   74       if (len & 0x80) | 
 |   75       { | 
 |   76         var cnt = len & 0x7F; | 
 |   77         if (cnt > 2 || cnt == 0) | 
 |   78           throw "Unsupported length"; | 
 |   79  | 
 |   80         len = 0; | 
 |   81         for (var i = 0; i < cnt; i++) | 
 |   82           len += next() << (cnt - 1 - i) * 8; | 
 |   83         return len; | 
 |   84       } | 
 |   85       else | 
 |   86         return len; | 
 |   87     } | 
 |   88  | 
 |   89     function readNode(curTempl) | 
 |   90     { | 
 |   91       var type = next(); | 
 |   92       var len = readLength(); | 
 |   93       if ("type" in curTempl && curTempl.type != type) | 
 |   94         throw "Unexpected type"; | 
 |   95       if ("content" in curTempl && curTempl.content != data.substr(pos, len)) | 
 |   96         throw "Unexpected content"; | 
 |   97       if ("out" in curTempl) | 
 |   98         out[curTempl.out] = new BigInteger(data.substr(pos, len), 256); | 
 |   99       if ("children" in curTempl) | 
 |  100       { | 
 |  101         var i, end; | 
 |  102         for (i = 0, end = pos + len; pos < end; i++) | 
 |  103         { | 
 |  104           if (i >= curTempl.children.length) | 
 |  105             throw "Too many children"; | 
 |  106           readNode(curTempl.children[i]); | 
 |  107         } | 
 |  108         if (i < curTempl.children.length) | 
 |  109           throw "Too few children"; | 
 |  110         if (pos > end) | 
 |  111           throw "Children too large"; | 
 |  112       } | 
 |  113       else if ("encapsulates" in curTempl) | 
 |  114       { | 
 |  115         if (next() != 0) | 
 |  116           throw "Encapsulation expected"; | 
 |  117         readNode(curTempl.encapsulates); | 
 |  118       } | 
 |  119       else | 
 |  120         pos += len; | 
 |  121     } | 
 |  122  | 
 |  123     var out = {}; | 
 |  124     readNode(templ); | 
 |  125     if (pos != data.length) | 
 |  126       throw "Too much data"; | 
 |  127     return out; | 
 |  128   } | 
 |  129  | 
 |  130   /** | 
 |  131    * Reads a BER-encoded RSA public key. On success returns an object with the | 
 |  132    * properties n and e (the components of the key), otherwise null. | 
 |  133    */ | 
 |  134   function readPublicKey(key) | 
 |  135   { | 
 |  136     try | 
 |  137     { | 
 |  138       return readASN1(atob(key), publicKeyTemplate); | 
 |  139     } | 
 |  140     catch (e) | 
 |  141     { | 
 |  142       console.log("Invalid RSA public key: " + e); | 
 |  143       return null; | 
 |  144     } | 
 |  145   } | 
 |  146  | 
 |  147   /** | 
 |  148    * Checks whether the signature is valid for the given public key and data. | 
 |  149    */ | 
 |  150   function verifySignature(key, signature, data) | 
 |  151   { | 
 |  152     var keyData = readPublicKey(key); | 
 |  153     if (!keyData) | 
 |  154       return false; | 
 |  155  | 
 |  156     // We need the exponent as regular number | 
 |  157     keyData.e = parseInt(keyData.e.toString(16), 16); | 
 |  158  | 
 |  159     // Decrypt signature data using RSA algorithm | 
 |  160     var sigInt = new BigInteger(atob(signature), 256); | 
 |  161     var digest = sigInt.modPowInt(keyData.e, keyData.n).toString(256); | 
 |  162  | 
 |  163     try | 
 |  164     { | 
 |  165       var pos = 0; | 
 |  166       function next() | 
 |  167       { | 
 |  168         return digest.charCodeAt(pos++); | 
 |  169       } | 
 |  170  | 
 |  171       // Skip padding, see http://tools.ietf.org/html/rfc3447#section-9.2 step 5 | 
 |  172       if (next() != 1) | 
 |  173         throw "Wrong padding in signature digest"; | 
 |  174       while (next() == 255) {} | 
 |  175       if (digest.charCodeAt(pos - 1) != 0) | 
 |  176         throw "Wrong padding in signature digest"; | 
 |  177  | 
 |  178       // Rest is an ASN.1 structure, get the SHA1 hash from it and compare to | 
 |  179       // the real one | 
 |  180       var sha1 = readASN1(digest.substr(pos), signatureTemplate).sha1; | 
 |  181       var expected = new BigInteger(SHA1(data), 16); | 
 |  182       return (sha1.compareTo(expected) == 0); | 
 |  183     } | 
 |  184     catch (e) | 
 |  185     { | 
 |  186       console.log("Invalid encrypted signature: " + e); | 
 |  187       return false; | 
 |  188     } | 
 |  189   } | 
 |  190  | 
 |  191   // Export verifySignature function, everything else is private. | 
 |  192   globalObj.verifySignature = verifySignature; | 
 |  193 })(this); | 
| OLD | NEW |