· 6 years ago · Dec 13, 2018, 12:20 PM
1<?php
2/* Jaxl (Jabber XMPP Library)
3*
4* Copyright (c) 2009-2010, Abhinav Singh <me@abhinavsingh.com>.
5* All rights reserved.
6*
7* Redistribution and use in source and binary forms, with or without
8* modification, are permitted provided that the following conditions
9* are met:
10*
11* * Redistributions of source code must retain the above copyright
12* notice, this list of conditions and the following disclaimer.
13*
14* * Redistributions in binary form must reproduce the above copyright
15* notice, this list of conditions and the following disclaimer in
16* the documentation and/or other materials provided with the
17* distribution.
18*
19* * Neither the name of Abhinav Singh nor the names of his
20* contributors may be used to endorse or promote products derived
21* from this software without specific prior written permission.
22*
23* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
32* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34* POSSIBILITY OF SUCH DAMAGE.
35*/
36
37 // include required classes
38 jaxl_require(array(
39 'JAXLUtil',
40 'JAXLPlugin'
41 ));
42
43 /*
44 * XMPP Auth class for performing various SASL auth mechanisms
45 * DIGEST-MD5, X-FACEBOOK-PLATFORM, SCRAM-SHA-1, CRAM-MD5
46 */
47 class XMPPAuth {
48
49 public static function getResponse($authType, $challenge, $jaxl) {
50 $response = array();
51 $decoded = base64_decode($challenge);
52 $xml = '<response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">';
53
54 if($authType == 'X-FACEBOOK-PLATFORM') {
55 $decoded = explode('&', $decoded);
56 foreach($decoded as $k=>$v) {
57 list($kk, $vv) = explode('=', $v);
58 $decoded[$kk] = $vv;
59 unset($decoded[$k]);
60 }
61
62 list($secret, $decoded['api_key'], $decoded['oauth_token']) = JAXLPlugin::execute('jaxl_get_facebook_key', false, $jaxl);
63
64 $decoded['call_id'] = time();
65 $decoded['v'] = '1.0';
66
67 $base_string = '';
68 foreach(array('api_key', 'call_id', 'method', 'nonce', 'oauth_token', 'v') as $key) {
69 if(isset($decoded[$key])) {
70 $response[$key] = $decoded[$key];
71 $base_string .= $key.'='.$decoded[$key];
72 }
73 }
74
75 $base_string .= $secret;
76 // $response['sig'] = md5($base_string);
77
78 $responseURI = '';
79 foreach($response as $k=>$v) {
80 if($responseURI == '') $responseURI .= $k.'='.urlencode($v);
81 else $responseURI .= '&'.$k.'='.urlencode($v);
82 }
83
84 $xml .= base64_encode($responseURI);
85 }
86 else if($authType == 'DIGEST-MD5') {
87 $decoded = JAXLUtil::explodeData($decoded);
88 if(!isset($decoded['digest-uri'])) $decoded['digest-uri'] = 'xmpp/'.$jaxl->domain;
89 $decoded['cnonce'] = base64_encode(JAXLUtil::generateNonce());
90
91 if(isset($decoded['qop'])
92 && $decoded['qop'] != 'auth'
93 && strpos($decoded['qop'],'auth') !== false
94 ) {
95 $decoded['qop'] = 'auth';
96 }
97
98 $response = array('username'=>$jaxl->user,
99 'response' => JAXLUtil::encryptPassword(array_merge($decoded,array('nc'=>'00000001'))),
100 'charset' => 'utf-8',
101 'nc' => '00000001',
102 'qop' => 'auth');
103
104 foreach(array('nonce', 'digest-uri', 'realm', 'cnonce') as $key)
105 if(isset($decoded[$key]))
106 $response[$key] = $decoded[$key];
107
108 $xml .= base64_encode(JAXLUtil::implodeData($response));
109 }
110 else if($authType == 'SCRAM-SHA-1') {
111 $decoded = JAXLUtil::explodeData($decoded);
112
113 // SaltedPassword := Hi(Normalize(password), salt, i)
114 $saltedPasswd = JAXLUtil::pbkdf2($jaxl->pass, $decoded['s'], $decoded['i']);
115
116 // ClientKey := HMAC(SaltedPassword, "Client Key")
117 $clientKey = JAXLUtil::hashMD5($saltedPassword, "Client Key");
118
119 // StoredKey := H(ClientKey)
120 $storedKey = sha1("Client Key");
121
122 // assemble client-final-message-without-proof
123 $clientFinalMessage = "c=bwis,r=".$decoded['r'];
124
125 // AuthMessage := client-first-message-bare + "," + server-first-message + "," + client-final-message-without-proof
126 // ClientSignature := HMAC(StoredKey, AuthMessage)
127
128 // ClientProof := ClientKey XOR ClientSignature
129 // ServerKey := HMAC(SaltedPassword, "Server Key")
130 // ServerSignature := HMAC(ServerKey, AuthMessage)
131
132 foreach(array('c', 'r', 'p') as $key)
133 if(isset($decoded[$key]))
134 $response[$key] = $decoded[$key];
135
136 $xml .= base64_encode(JAXLUtil::implodeData($response));
137 }
138 else if($authType == 'CRAM-MD5') {
139 $xml .= base64_encode($jaxl->user.' '.hash_hmac('md5', $jaxl->pass, $arr['challenge']));
140 }
141
142 $xml .= '</response>';
143 $jaxl->secondChallenge = true;
144
145 return $xml;
146 }
147 }
148
149?>