1 /*  RTMPDump - Diffie-Hellmann Key Exchange
2  *  Copyright (C) 2009 Andrej Stepanchuk
3  *  Copyright (C) 2009-2010 Howard Chu
4  *
5  *  This file is part of librtmp.
6  *
7  *  librtmp is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as
9  *  published by the Free Software Foundation; either version 2.1,
10  *  or (at your option) any later version.
11  *
12  *  librtmp is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with librtmp see the file COPYING.  If not, write to
19  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA  02110-1301, USA.
21  *  http://www.gnu.org/copyleft/lgpl.html
22  */
23 
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <limits.h>
29 
30 #ifdef USE_POLARSSL
31 #include <polarssl/dhm.h>
32 typedef mpi * MP_t;
33 #define MP_new(m)	m = malloc(sizeof(mpi)); mpi_init(m)
34 #define MP_set_w(mpi, w)	mpi_lset(mpi, w)
35 #define MP_cmp(u, v)	mpi_cmp_mpi(u, v)
36 #define MP_set(u, v)	mpi_copy(u, v)
37 #define MP_sub_w(mpi, w)	mpi_sub_int(mpi, mpi, w)
38 #define MP_cmp_1(mpi)	mpi_cmp_int(mpi, 1)
39 #define MP_modexp(r, y, q, p)	mpi_exp_mod(r, y, q, p, NULL)
40 #define MP_free(mpi)	mpi_free(mpi); free(mpi)
41 #define MP_gethex(u, hex, res)	MP_new(u); res = mpi_read_string(u, 16, hex) == 0
42 #define MP_bytes(u)	mpi_size(u)
43 #define MP_setbin(u,buf,len)	mpi_write_binary(u,buf,len)
44 #define MP_getbin(u,buf,len)	MP_new(u); mpi_read_binary(u,buf,len)
45 
46 typedef struct MDH {
47   MP_t p;
48   MP_t g;
49   MP_t pub_key;
50   MP_t priv_key;
51   long length;
52   dhm_context ctx;
53 } MDH;
54 
55 #define MDH_new()	calloc(1,sizeof(MDH))
56 #define MDH_free(vp)	{MDH *_dh = vp; dhm_free(&_dh->ctx); MP_free(_dh->p); MP_free(_dh->g); MP_free(_dh->pub_key); MP_free(_dh->priv_key); free(_dh);}
57 
MDH_generate_key(MDH * dh)58 static int MDH_generate_key(MDH *dh)
59 {
60   unsigned char out[2];
61   MP_set(&dh->ctx.P, dh->p);
62   MP_set(&dh->ctx.G, dh->g);
63   dh->ctx.len = 128;
64   dhm_make_public(&dh->ctx, 1024, out, 1, havege_random, &RTMP_TLS_ctx->hs);
65   MP_new(dh->pub_key);
66   MP_new(dh->priv_key);
67   MP_set(dh->pub_key, &dh->ctx.GX);
68   MP_set(dh->priv_key, &dh->ctx.X);
69   return 1;
70 }
71 
MDH_compute_key(uint8_t * secret,size_t len,MP_t pub,MDH * dh)72 static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
73 {
74   MP_set(&dh->ctx.GY, pub);
75   dhm_calc_secret(&dh->ctx, secret, &len);
76   return 0;
77 }
78 
79 #elif defined(USE_GNUTLS)
80 #include <gmp.h>
81 #include <nettle/bignum.h>
82 #include <gnutls/crypto.h>
83 typedef mpz_ptr MP_t;
84 #define MP_new(m)	m = malloc(sizeof(*m)); mpz_init2(m, 1)
85 #define MP_set_w(mpi, w)	mpz_set_ui(mpi, w)
86 #define MP_cmp(u, v)	mpz_cmp(u, v)
87 #define MP_set(u, v)	mpz_set(u, v)
88 #define MP_sub_w(mpi, w)	mpz_sub_ui(mpi, mpi, w)
89 #define MP_cmp_1(mpi)	mpz_cmp_ui(mpi, 1)
90 #define MP_modexp(r, y, q, p)	mpz_powm(r, y, q, p)
91 #define MP_free(mpi)	mpz_clear(mpi); free(mpi)
92 #define MP_gethex(u, hex, res)	u = malloc(sizeof(*u)); mpz_init2(u, 1); res = (mpz_set_str(u, hex, 16) == 0)
93 #define MP_bytes(u)	(mpz_sizeinbase(u, 2) + 7) / 8
94 #define MP_setbin(u,buf,len)	nettle_mpz_get_str_256(len,buf,u)
95 #define MP_getbin(u,buf,len)	u = malloc(sizeof(*u)); mpz_init2(u, 1); nettle_mpz_set_str_256_u(u,len,buf)
96 
97 typedef struct MDH {
98   MP_t p;
99   MP_t g;
100   MP_t pub_key;
101   MP_t priv_key;
102   long length;
103 } MDH;
104 
105 #define	MDH_new()	calloc(1,sizeof(MDH))
106 #define MDH_free(dh)	do {MP_free(((MDH*)(dh))->p); MP_free(((MDH*)(dh))->g); MP_free(((MDH*)(dh))->pub_key); MP_free(((MDH*)(dh))->priv_key); free(dh);} while(0)
107 
MDH_generate_key(MDH * dh)108 static int MDH_generate_key(MDH *dh)
109 {
110   int num_bytes;
111   uint32_t seed;
112   gmp_randstate_t rs;
113 
114   num_bytes = (mpz_sizeinbase(dh->p, 2) + 7) / 8 - 1;
115   if (num_bytes <= 0 || num_bytes > 18000)
116     return 0;
117 
118   dh->priv_key = calloc(1, sizeof(*dh->priv_key));
119   if (!dh->priv_key)
120     return 0;
121   mpz_init2(dh->priv_key, 1);
122   gnutls_rnd(GNUTLS_RND_RANDOM, &seed, sizeof(seed));
123   gmp_randinit_mt(rs);
124   gmp_randseed_ui(rs, seed);
125   mpz_urandomb(dh->priv_key, rs, num_bytes);
126   gmp_randclear(rs);
127 
128   dh->pub_key = calloc(1, sizeof(*dh->pub_key));
129   if (!dh->pub_key)
130     return 0;
131   mpz_init2(dh->pub_key, 1);
132   if (!dh->pub_key) {
133     mpz_clear(dh->priv_key);
134     free(dh->priv_key);
135     return 0;
136   }
137 
138   mpz_powm(dh->pub_key, dh->g, dh->priv_key, dh->p);
139 
140   return 1;
141 }
142 
MDH_compute_key(uint8_t * secret,size_t len,MP_t pub,MDH * dh)143 static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
144 {
145   mpz_ptr k;
146   int num_bytes;
147 
148   num_bytes = (mpz_sizeinbase(dh->p, 2) + 7) / 8;
149   if (num_bytes <= 0 || num_bytes > 18000)
150     return -1;
151 
152   k = calloc(1, sizeof(*k));
153   if (!k)
154     return -1;
155   mpz_init2(k, 1);
156 
157   mpz_powm(k, pub, dh->priv_key, dh->p);
158   nettle_mpz_get_str_256(len, secret, k);
159   mpz_clear(k);
160   free(k);
161 
162   /* return the length of the shared secret key like DH_compute_key */
163   return len;
164 }
165 
166 #else /* USE_OPENSSL */
167 #include <openssl/bn.h>
168 #include <openssl/dh.h>
169 
170 typedef BIGNUM * MP_t;
171 #define MP_new(m)	m = BN_new()
172 #define MP_set_w(mpi, w)	BN_set_word(mpi, w)
173 #define MP_cmp(u, v)	BN_cmp(u, v)
174 #define MP_set(u, v)	BN_copy(u, v)
175 #define MP_sub_w(mpi, w)	BN_sub_word(mpi, w)
176 #define MP_cmp_1(mpi)	BN_cmp(mpi, BN_value_one())
177 #define MP_modexp(r, y, q, p)	do {BN_CTX *ctx = BN_CTX_new(); BN_mod_exp(r, y, q, p, ctx); BN_CTX_free(ctx);} while(0)
178 #define MP_free(mpi)	BN_free(mpi)
179 #define MP_gethex(u, hex, res)	res = BN_hex2bn(&u, hex)
180 #define MP_bytes(u)	BN_num_bytes(u)
181 #define MP_setbin(u,buf,len)	BN_bn2bin(u,buf)
182 #define MP_getbin(u,buf,len)	u = BN_bin2bn(buf,len,0)
183 
184 #define MDH	DH
185 #define MDH_new()	DH_new()
186 #define MDH_free(dh)	DH_free(dh)
187 #define MDH_generate_key(dh)	DH_generate_key(dh)
188 #define MDH_compute_key(secret, seclen, pub, dh)	DH_compute_key(secret, pub, dh)
189 
190 #endif
191 
192 #include "log.h"
193 #include "dhgroups.h"
194 
195 /* RFC 2631, Section 2.1.5, http://www.ietf.org/rfc/rfc2631.txt */
196 static int
isValidPublicKey(MP_t y,MP_t p,MP_t q)197 isValidPublicKey(MP_t y, MP_t p, MP_t q)
198 {
199   int ret = TRUE;
200   MP_t bn;
201   assert(y);
202 
203   MP_new(bn);
204   assert(bn);
205 
206   /* y must lie in [2,p-1] */
207   MP_set_w(bn, 1);
208   if (MP_cmp(y, bn) < 0)
209     {
210       RTMP_Log(RTMP_LOGERROR, "DH public key must be at least 2");
211       ret = FALSE;
212       goto failed;
213     }
214 
215   /* bn = p-2 */
216   MP_set(bn, p);
217   MP_sub_w(bn, 1);
218   if (MP_cmp(y, bn) > 0)
219     {
220       RTMP_Log(RTMP_LOGERROR, "DH public key must be at most p-2");
221       ret = FALSE;
222       goto failed;
223     }
224 
225   /* Verify with Sophie-Germain prime
226    *
227    * This is a nice test to make sure the public key position is calculated
228    * correctly. This test will fail in about 50% of the cases if applied to
229    * random data.
230    */
231   if (q)
232     {
233       /* y must fulfill y^q mod p = 1 */
234       MP_modexp(bn, y, q, p);
235 
236       if (MP_cmp_1(bn) != 0)
237 	{
238 	  RTMP_Log(RTMP_LOGWARNING, "DH public key does not fulfill y^q mod p = 1");
239 	}
240     }
241 
242 failed:
243   MP_free(bn);
244   return ret;
245 }
246 
247 static MDH *
DHInit(int nKeyBits)248 DHInit(int nKeyBits)
249 {
250   size_t res;
251   MDH *dh = MDH_new();
252 
253   if (!dh)
254     goto failed;
255 
256   MP_new(dh->g);
257 
258   if (!dh->g)
259     goto failed;
260 
261   MP_gethex(dh->p, P1024, res);	/* prime P1024, see dhgroups.h */
262   if (!res)
263     {
264       goto failed;
265     }
266 
267   MP_set_w(dh->g, 2);	/* base 2 */
268 
269   dh->length = nKeyBits;
270   return dh;
271 
272 failed:
273   if (dh)
274     MDH_free(dh);
275 
276   return 0;
277 }
278 
279 static int
DHGenerateKey(MDH * dh)280 DHGenerateKey(MDH *dh)
281 {
282   size_t res = 0;
283   if (!dh)
284     return 0;
285 
286   while (!res)
287     {
288       MP_t q1 = NULL;
289 
290       if (!MDH_generate_key(dh))
291 	return 0;
292 
293       MP_gethex(q1, Q1024, res);
294       assert(res);
295 
296       res = isValidPublicKey(dh->pub_key, dh->p, q1);
297       if (!res)
298 	{
299 	  MP_free(dh->pub_key);
300 	  MP_free(dh->priv_key);
301 	  dh->pub_key = dh->priv_key = 0;
302 	}
303 
304       MP_free(q1);
305     }
306   return 1;
307 }
308 
309 /* fill pubkey with the public key in BIG ENDIAN order
310  * 00 00 00 00 00 x1 x2 x3 .....
311  */
312 
313 static int
DHGetPublicKey(MDH * dh,uint8_t * pubkey,size_t nPubkeyLen)314 DHGetPublicKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen)
315 {
316   int len;
317   if (!dh || !dh->pub_key)
318     return 0;
319 
320   len = MP_bytes(dh->pub_key);
321   if (len <= 0 || len > (int) nPubkeyLen)
322     return 0;
323 
324   memset(pubkey, 0, nPubkeyLen);
325   MP_setbin(dh->pub_key, pubkey + (nPubkeyLen - len), len);
326   return 1;
327 }
328 
329 #if 0	/* unused */
330 static int
331 DHGetPrivateKey(MDH *dh, uint8_t *privkey, size_t nPrivkeyLen)
332 {
333   if (!dh || !dh->priv_key)
334     return 0;
335 
336   int len = MP_bytes(dh->priv_key);
337   if (len <= 0 || len > (int) nPrivkeyLen)
338     return 0;
339 
340   memset(privkey, 0, nPrivkeyLen);
341   MP_setbin(dh->priv_key, privkey + (nPrivkeyLen - len), len);
342   return 1;
343 }
344 #endif
345 
346 /* computes the shared secret key from the private MDH value and the
347  * other party's public key (pubkey)
348  */
349 static int
DHComputeSharedSecretKey(MDH * dh,uint8_t * pubkey,size_t nPubkeyLen,uint8_t * secret)350 DHComputeSharedSecretKey(MDH *dh, uint8_t *pubkey, size_t nPubkeyLen,
351 			 uint8_t *secret)
352 {
353   MP_t q1 = NULL, pubkeyBn = NULL;
354   size_t len;
355   int res;
356 
357   if (!dh || !secret || nPubkeyLen >= INT_MAX)
358     return -1;
359 
360   MP_getbin(pubkeyBn, pubkey, nPubkeyLen);
361   if (!pubkeyBn)
362     return -1;
363 
364   MP_gethex(q1, Q1024, len);
365   assert(len);
366 
367   if (isValidPublicKey(pubkeyBn, dh->p, q1))
368     res = MDH_compute_key(secret, nPubkeyLen, pubkeyBn, dh);
369   else
370     res = -1;
371 
372   MP_free(q1);
373   MP_free(pubkeyBn);
374 
375   return res;
376 }
377