nexus site path corrected
[portal.git] / ecomp-portal-BE / war / static / oid-connect / js / lib / jwt.js
1 var jwt = {};
2
3 var JWTInternals = (function() {
4
5   // convert a base64url string to hex
6   var b64urlmap="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
7   function b64urltohex(s) {
8     var ret = ""
9     var i;
10     var k = 0; // b64 state, 0-3
11     var slop;
12     for(i = 0; i < s.length; ++i) {
13       var v = b64urlmap.indexOf(s.charAt(i));
14       if(v < 0) continue;
15       if(k == 0) {
16         ret += int2char(v >> 2);
17         slop = v & 3;
18         k = 1;
19       }
20       else if(k == 1) {
21         ret += int2char((slop << 2) | (v >> 4));
22         slop = v & 0xf;
23         k = 2;
24       }
25       else if(k == 2) {
26         ret += int2char(slop);
27         ret += int2char(v >> 2);
28         slop = v & 3;
29         k = 3;
30       }
31       else {
32         ret += int2char((slop << 2) | (v >> 4));
33         ret += int2char(v & 0xf);
34         k = 0;
35       }
36     }
37     if(k == 1)
38       ret += int2char(slop << 2);
39     return ret;
40   }
41
42
43
44   function base64urlencode(arg)
45   {
46     var s = window.btoa(arg); // Standard base64 encoder
47     s = s.split('=')[0]; // Remove any trailing '='s
48     s = s.replace(/\+/g, '-'); // 62nd char of encoding
49     s = s.replace(/\//g, '_'); // 63rd char of encoding
50     // TODO optimize this; we can do much better
51     return s;
52   }
53
54   function base64urldecode(arg)
55   {
56     var s = arg;
57     s = s.replace(/-/g, '+'); // 62nd char of encoding
58     s = s.replace(/_/g, '/'); // 63rd char of encoding
59     switch (s.length % 4) // Pad with trailing '='s
60     {
61       case 0: break; // No pad chars in this case
62       case 2: s += "=="; break; // Two pad chars
63       case 3: s += "="; break; // One pad char
64       default: throw new InputException("Illegal base64url string!");
65     }
66     return window.atob(s); // Standard base64 decoder
67   }
68
69   function NoSuchAlgorithmException(message) {
70     this.message = message;
71     this.toString = function() { return "No such algorithm: "+this.message; };
72   }
73   function NotImplementedException(message) {
74     this.message = message;
75     this.toString = function() { return "Not implemented: "+this.message; };
76   }
77   function InputException(message) {
78     this.message = message;
79     this.toString = function() { return "Malformed input: "+this.message; };
80   }
81
82   function HMACAlgorithm(hash, key)
83   {
84     if (hash == "sha256") {
85       this.hash = sjcl.hash.sha256;
86     } else {
87       throw new NoSuchAlgorithmException("HMAC does not support hash " + hash);
88     }
89     this.key = sjcl.codec.utf8String.toBits(key);
90   }
91
92   HMACAlgorithm.prototype =
93   {
94     update: function _update(data)
95     {
96       this.data = data;
97     },
98     
99     finalize: function _finalize()
100     {
101     },
102     
103     sign: function _sign()
104     {
105       var hmac = new sjcl.misc.hmac(this.key, this.hash);
106       var result = hmac.encrypt(this.data);
107       return base64urlencode(window.atob(sjcl.codec.base64.fromBits(result)));
108     },
109     
110     verify: function _verify(sig)
111     {
112       var hmac = new sjcl.misc.hmac(this.key, this.hash);
113       var result = hmac.encrypt(this.data);
114       
115       return base64urlencode(window.atob(sjcl.codec.base64.fromBits(result))) == sig;
116     }
117   }
118
119   function RSASHAAlgorithm(hash, keyPEM)
120   {
121     if (hash == "sha1") {
122       this.hash = "sha1";
123     } else if (hash == "sha256") {
124       this.hash = "sha256";
125     } else {
126       throw new NoSuchAlgorithmException("JWT algorithm: " + hash);
127     }
128     this.keyPEM = keyPEM;
129   }
130   RSASHAAlgorithm.prototype =
131   {
132     update: function _update(data)
133     {
134       this.data = data;
135     },
136     finalize: function _finalize()
137     {
138     
139     },
140     sign: function _sign()
141     {
142       var rsa = new RSAKey();
143       rsa.readPrivateKeyFromPEMString(this.keyPEM);
144       var hSig = rsa.signString(this.data, this.hash);
145       return base64urlencode(base64urldecode(hex2b64(hSig))); // TODO replace this with hex2b64urlencode!
146     },
147     verify: function _verify(sig)
148     {
149       var result = this.keyPEM.verifyString(this.data, b64urltohex(sig));
150       return result;
151     }
152   }
153
154   function WebToken(objectStr, algorithm)
155   {
156     this.objectStr = objectStr;
157     this.pkAlgorithm = algorithm;
158   }
159
160   var WebTokenParser = {
161
162     parse: function _parse(input)
163     {
164       var parts = input.split(".");
165       if (parts.length != 3) {
166         throw new MalformedWebToken("Must have three parts");
167       }
168       var token = new WebToken();
169       token.headerSegment = parts[0];
170       token.payloadSegment = parts[1];
171       token.cryptoSegment = parts[2];
172
173       token.pkAlgorithm = base64urldecode(parts[0]);
174       return token;
175     }
176   }
177
178   function jsonObj(strOrObject)
179   {
180     if (typeof strOrObject == "string") {
181       return JSON.parse(strOrObject);
182     }
183     return strOrObject;
184   }
185
186   function constructAlgorithm(jwtAlgStr, key)
187   {
188     if ("ES256" === jwtAlgStr) {
189       throw new NotImplementedException("ECDSA-SHA256 not yet implemented");
190     } else if ("ES384" === jwtAlgStr) {
191       throw new NotImplementedException("ECDSA-SHA384 not yet implemented");
192     } else if ("ES512" === jwtAlgStr) {
193       throw new NotImplementedException("ECDSA-SHA512 not yet implemented");
194     } else if ("HS256" === jwtAlgStr) {
195       return new HMACAlgorithm("sha256", key);
196     } else if ("HS384" === jwtAlgStr) {
197       throw new NotImplementedException("HMAC-SHA384 not yet implemented");
198     } else if ("HS512" === jwtAlgStr) {
199       throw new NotImplementedException("HMAC-SHA512 not yet implemented");
200     } else if ("RS256" === jwtAlgStr) {
201       return new RSASHAAlgorithm("sha256", key);
202     } else if ("RS384" === jwtAlgStr) {
203       throw new NotImplementedException("RSA-SHA384 not yet implemented");
204     } else if ("RS512" === jwtAlgStr) {
205       throw new NotImplementedException("RSA-SHA512 not yet implemented");
206     } else {
207       throw new NoSuchAlgorithmException("Unknown algorithm: " + jwtAlgStr);
208     }
209   }
210
211   WebToken.prototype =
212   {
213     serialize: function _serialize(key)
214     {
215       var header = jsonObj(this.pkAlgorithm);
216       var jwtAlgStr = header.alg;
217       var algorithm = constructAlgorithm(jwtAlgStr, key);
218       var algBytes = base64urlencode(this.pkAlgorithm);
219       var jsonBytes = base64urlencode(this.objectStr);
220
221       var stringToSign = algBytes + "." + jsonBytes;
222       algorithm.update(stringToSign);
223       var digestValue = algorithm.finalize();
224
225       var signatureValue = algorithm.sign();
226       return algBytes + "." + jsonBytes + "." + signatureValue;
227     },
228     
229     verify: function _verify(key)
230     {
231       var header = jsonObj(this.pkAlgorithm);
232       var jwtAlgStr = header.alg;
233       var algorithm = constructAlgorithm(jwtAlgStr, key);
234       algorithm.update(this.headerSegment + "." + this.payloadSegment);
235       algorithm.finalize();
236       return algorithm.verify(this.cryptoSegment);
237     }
238   }
239   
240   jwt.WebToken = WebToken;
241   jwt.WebTokenParser = WebTokenParser;
242   jwt.base64urlencode = base64urlencode;
243   jwt.base64urldecode = base64urldecode;
244 })();