Browse code

Merge pull request #2505 from vitalikvoip/master

crypto: add crypto_hmac_sha256() function

Daniel-Constantin Mierla authored on 14/10/2020 09:16:44 • GitHub committed on 14/10/2020 09:16:44
Showing 2 changed files
... ...
@@ -38,6 +38,9 @@
38 38
 #include "crypto_evcb.h"
39 39
 #include "api.h"
40 40
 
41
+#include <openssl/hmac.h>
42
+
43
+
41 44
 MODULE_VERSION
42 45
 
43 46
 int crypto_aes_init(unsigned char *key_data, int key_data_len,
... ...
@@ -61,6 +64,9 @@ static int w_crypto_nio_out(sip_msg_t* msg, char* p1, char* p2);
61 64
 static int w_crypto_nio_encrypt(sip_msg_t* msg, char* p1, char* p2);
62 65
 static int w_crypto_nio_decrypt(sip_msg_t* msg, char* p1, char* p2);
63 66
 
67
+static int w_crypto_hmac_sha256(sip_msg_t* msg, char* inb, char* keyb, char* outb);
68
+static int fixup_crypto_hmac(void** param, int param_no);
69
+
64 70
 static char *_crypto_salt_param = "k8hTm4aZ";
65 71
 
66 72
 static int _crypto_register_callid = 0;
... ...
@@ -82,6 +88,8 @@ static cmd_export_t cmds[]={
82 88
 		0, 0, ANY_ROUTE},
83 89
 	{"crypto_netio_decrypt", (cmd_function)w_crypto_nio_decrypt, 0,
84 90
 		0, 0, ANY_ROUTE},
91
+	{"crypto_hmac_sha256", (cmd_function)w_crypto_hmac_sha256, 3,
92
+		fixup_crypto_hmac, 0, ANY_ROUTE},
85 93
 	{"load_crypto",        (cmd_function)load_crypto, 0, 0, 0, 0},
86 94
 	{0, 0, 0, 0, 0, 0}
87 95
 };
... ...
@@ -286,6 +294,110 @@ static int fixup_crypto_aes_encrypt(void** param, int param_no)
286 294
 	return 0;
287 295
 }
288 296
 
297
+/**
298
+ *
299
+ */
300
+static int ki_crypto_hmac_sha256_helper(sip_msg_t* msg, str *ins, str *key,
301
+		pv_spec_t *dst)
302
+{
303
+	pv_value_t val;
304
+	unsigned char digest[EVP_MAX_MD_SIZE];
305
+	unsigned int digest_len;
306
+
307
+	LM_DBG("ins: %.*s, key: %.*s\n", STR_FMT(ins), STR_FMT(key));
308
+
309
+	if (!HMAC(EVP_sha256(), key->s, key->len, (const unsigned char *)ins->s, ins->len, digest, &digest_len)) {
310
+		LM_ERR("HMAC error\n");
311
+		goto error;
312
+	}
313
+
314
+	memset(&val, 0, sizeof(pv_value_t));
315
+	val.rs.s = pv_get_buffer();
316
+	val.rs.len = base64url_enc((unsigned char *)digest, digest_len, (unsigned char *)val.rs.s, pv_get_buffer_size()-1);
317
+	if (val.rs.len < 0) {
318
+		LM_ERR("base64 output of digest value is too large (need %d)\n", -val.rs.len);
319
+		goto error;
320
+	}
321
+
322
+	if (val.rs.len > 1 && val.rs.s[val.rs.len-1] == '=') {
323
+		val.rs.len--;
324
+		if (val.rs.len > 1 && val.rs.s[val.rs.len-1] == '=') {
325
+			val.rs.len--;
326
+		}
327
+	}
328
+	val.rs.s[val.rs.len] = '\0';
329
+
330
+	LM_DBG("base64 digest result: [%.*s]\n", val.rs.len, val.rs.s);
331
+	val.flags = PV_VAL_STR;
332
+	dst->setf(msg, &dst->pvp, (int)EQ_T, &val);
333
+
334
+	return 1;
335
+
336
+error:
337
+	return -1;
338
+}
339
+
340
+/**
341
+ *
342
+ */
343
+static int ki_crypto_hmac_sha256(sip_msg_t* msg, str *ins, str *keys, str *dpv)
344
+{
345
+	pv_spec_t *dst;
346
+
347
+	dst = pv_cache_get(dpv);
348
+
349
+	if(dst==NULL) {
350
+		LM_ERR("failed getting pv: %.*s\n", dpv->len, dpv->s);
351
+		return -1;
352
+	}
353
+
354
+	return ki_crypto_hmac_sha256_helper(msg, ins, keys, dst);
355
+}
356
+
357
+/**
358
+ *
359
+ */
360
+static int w_crypto_hmac_sha256(sip_msg_t* msg, char* inb, char* keyb, char* outb)
361
+{
362
+	str ins;
363
+	str keys;
364
+	pv_spec_t *dst;
365
+
366
+	if (fixup_get_svalue(msg, (gparam_t*)inb, &ins) != 0) {
367
+		LM_ERR("cannot get input value\n");
368
+		return -1;
369
+	}
370
+	if (fixup_get_svalue(msg, (gparam_t*)keyb, &keys) != 0) {
371
+		LM_ERR("cannot get key value\n");
372
+		return -1;
373
+	}
374
+	dst = (pv_spec_t*)outb;
375
+
376
+	return ki_crypto_hmac_sha256_helper(msg, &ins, &keys, dst);
377
+}
378
+
379
+/**
380
+ *
381
+ */
382
+static int fixup_crypto_hmac(void** param, int param_no)
383
+{
384
+	if(param_no==1 || param_no==2) {
385
+		if(fixup_spve_null(param, 1)<0)
386
+			return -1;
387
+		return 0;
388
+	} else if(param_no==3) {
389
+		if (fixup_pvar_null(param, 1) != 0) {
390
+			LM_ERR("failed to fixup result pvar\n");
391
+			return -1;
392
+		}
393
+		if (((pv_spec_t *)(*param))->setf == NULL) {
394
+			LM_ERR("result pvar is not writeble\n");
395
+			return -1;
396
+		}
397
+	}
398
+	return 0;
399
+}
400
+
289 401
 /**
290 402
  *
291 403
  */
... ...
@@ -401,6 +513,7 @@ static int fixup_crypto_aes_decrypt(void** param, int param_no)
401 513
 	return 0;
402 514
 }
403 515
 
516
+
404 517
 /**
405 518
  * testing function
406 519
  */
... ...
@@ -534,4 +647,4 @@ int mod_register(char *path, int *dlflags, void *p1, void *p2)
534 647
 {
535 648
 	sr_kemi_modules_add(sr_kemi_crypto_exports);
536 649
 	return 0;
537
-}
538 650
\ No newline at end of file
651
+}
... ...
@@ -226,6 +226,30 @@ crypto_aes_decrypt("$var(encrypted)", "my-secret-key", "$var(text)");
226 226
 	    </example>
227 227
 	</section>
228 228
 
229
+	<section id="async.f.crypto_hmac_sha256">
230
+		<title>
231
+			<function moreinfo="none">crypto_hmac_sha256(text, key, res)</function>
232
+		</title>
233
+		<para>
234
+			Calculates HMAC (keyed-hash message authentication code) with SHA256
235
+			as a cryptographic hash function. The result is encoded in base64 url
236
+			encoded format and stored in res. The parameter res must be a read-write
237
+			variable. The parameters text and key can be static strings or strings
238
+			with variables (dynamic strings).
239
+		</para>
240
+		<para>
241
+		This function can be used from ANY_ROUTE.
242
+		</para>
243
+		<example>
244
+			<title><function>crypto_hmac_sha256</function> usage</title>
245
+			<programlisting format="linespecific">
246
+...
247
+crypto_hmac_sha256("$var(text)", "my-secret-key", "$var(hmac)");
248
+...
249
+</programlisting>
250
+		</example>
251
+	</section>
252
+	
229 253
 	<section id="async.f.crypto_netio_in">
230 254
 	    <title>
231 255
 		<function moreinfo="none">crypto_netio_in)</function>