浏览代码

crypto: option to register a callid generator callback

- use libssl random and hashing for generating RFC 4122 version 4 UUID
  with high quality entropy that can be used as callid for requests sent
  by tm, through sip routing core api
- new mod param: register_callid - set to 1 in order to register callid
  genrator callback to core (default is 0)
Daniel-Constantin Mierla 9 年之前
父节点
当前提交
0085398d08
共有 3 个文件被更改,包括 287 次插入1 次删除
  1. 22 1
      modules/crypto/crypto_mod.c
  2. 197 0
      modules/crypto/crypto_uuid.c
  3. 68 0
      modules/crypto/crypto_uuid.h

+ 22 - 1
modules/crypto/crypto_mod.c

@@ -32,6 +32,8 @@
 #include "../../lvalue.h"
 #include "../../basex.h"
 
+#include "crypto_uuid.h"
+
 #include <openssl/evp.h>
 
 #define AES_BLOCK_SIZE 256
@@ -58,6 +60,8 @@ static int fixup_crypto_aes_decrypt(void** param, int param_no);
 static char _crypto_salt[CRYPTO_SALT_BSIZE];
 static char *_crypto_salt_param = "k8hTm4aZ";
 
+static int _crypto_register_callid = 0;
+
 static cmd_export_t cmds[]={
 	{"crypto_aes_encrypt", (cmd_function)w_crypto_aes_encrypt, 3,
 		fixup_crypto_aes_encrypt, 0, ANY_ROUTE},
@@ -67,7 +71,8 @@ static cmd_export_t cmds[]={
 };
 
 static param_export_t params[]={
-	{ "salt", PARAM_STRING, &_crypto_salt_param },
+	{ "salt",            PARAM_STRING, &_crypto_salt_param },
+	{ "register_callid", PARAM_INT, &_crypto_register_callid },
 	{ 0, 0, 0 }
 };
 
@@ -109,6 +114,17 @@ static int mod_init(void)
 			k = _crypto_salt[i];
 		}
 	}
+	if(_crypto_register_callid!=0) {
+		if(crypto_init_callid()<0) {
+			LM_ERR("failed to init callid callback\n");
+			return -1;
+		}
+		if(crypto_register_callid_func()<0) {
+			LM_ERR("unable to register callid callback\n");
+			return -1;
+		}
+		LM_DBG("registered crypto callid callback\n");
+	}
 	return 0;
 }
 
@@ -117,6 +133,11 @@ static int mod_init(void)
  */
 static int child_init(int rank)
 {
+	if(_crypto_register_callid!=0 && crypto_child_init_callid(rank)<0) {
+		LM_ERR("failed to register callid callback\n");
+		return -1;
+	}
+
 	return 0;
 }
 

+ 197 - 0
modules/crypto/crypto_uuid.c

@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2016 Daniel-Constantin Mierla (asipto.com)
+ * Copyright (C) 2016 Travis Cross <[email protected]>
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief Crypto :: Fast enough high entropy Call-ID generator
+ *
+ * Fast enough high entropy Call-ID generator. The Call-ID generated
+ * is an RFC 4122 version 4 UUID using high quality entropy from
+ * OpenSSL.  This entropy is extracted only once at startup and is
+ * then combined in each child with the process ID and a counter.  The
+ * result is whitened with SHA1 and formatted per RFC 4122.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+#include "../../dprint.h"
+#include "../../srapi.h"
+#include "crypto_uuid.h"
+
+#define SEED_LEN 16
+#define CTR_LEN 16
+static unsigned char crypto_callid_seed[SEED_LEN] = {0};
+static unsigned char crypto_callid_counter[CTR_LEN] = {0};
+
+
+/**
+ * \brief Convert value to hex character
+ * \param x unsigned char byte
+ * \return lowercase hex charater
+ */
+static inline char crypto_byte2hex(unsigned char x) {
+	return x < 10 ? '0' + x : 'a' + (x-10);
+}
+
+/**
+ * \brief Convert array of bytes to hexidecimal string
+ * \param sbuf output character array
+ * \param sbuf_len allocated size of sbuf, must be 2x buf_len
+ * \param buf input byte array
+ * \param buf_len number of bytes of buf
+ * \return 0 on success, -1 on error
+ */
+static inline int crypto_bytes2hex(char *sbuf, size_t sbuf_len,
+							unsigned char *buf, size_t buf_len) {
+	size_t i, j;
+	if (sbuf_len < 2*buf_len) return -1;
+	for (i=0, j=(2*buf_len)-1; i<sbuf_len; i++, j--) {
+		sbuf[i] = crypto_byte2hex((buf[j/2] >> (j%2 ? 0 : 4)) % 0x0f);
+		if (j == 0) break;
+	}
+	return 0;
+}
+
+
+/**
+ * \brief Initialize the Call-ID generator
+ * \return 0 on success, -1 on error
+ */
+int crypto_init_callid(void)
+{
+	static char crypto_callid_seed_str[2*SEED_LEN] = {0};
+	if (!(RAND_bytes(crypto_callid_seed,sizeof(crypto_callid_seed)))) {
+		LOG(L_ERR, "ERROR: Unable to get random bytes for Call-ID seed\n");
+		return -1;
+	}
+	crypto_bytes2hex(crypto_callid_seed_str, sizeof(crypto_callid_seed_str),
+			crypto_callid_seed, sizeof(crypto_callid_seed));
+	DBG("Call-ID initialization: '0x%.*s'\n", 2*SEED_LEN,
+			crypto_callid_seed_str);
+	return 0;
+}
+
+
+/**
+ * \brief Child initialization, permute seed with pid
+ * \param rank not used
+ * \return 0 on success, -1 on error
+ */
+int crypto_child_init_callid(int rank)
+{
+	static char crypto_callid_seed_str[2*SEED_LEN] = {0};
+	unsigned int pid = my_pid();
+	if (SEED_LEN < 2) {
+		LOG(L_CRIT, "BUG: Call-ID seed is too short\n");
+		return -1;
+	}
+	crypto_callid_seed[0] ^= (pid >> 0) % 0xff;
+	crypto_callid_seed[1] ^= (pid >> 8) % 0xff;
+	crypto_bytes2hex(crypto_callid_seed_str, sizeof(crypto_callid_seed_str),
+			crypto_callid_seed, sizeof(crypto_callid_seed));
+	DBG("Call-ID initialization: '0x%.*s'\n", 2*SEED_LEN,
+			crypto_callid_seed_str);
+	return 0;
+}
+
+
+/**
+ * \brief Increment a counter
+ * \param ctr input array of bytes
+ * \param len length of byte array
+ * \return void
+ */
+static inline void crypto_inc_counter(unsigned char* ctr, size_t len)
+{
+	size_t i;
+	for (i=0; i < len; i++) {
+		ctr[i] += 1;
+		if (ctr[i]) break;
+	}
+}
+
+
+/**
+ * \brief Convert array of bytes to RFC 4122 UUID (version 4)
+ * \param sbuf output character array
+ * \param sbuf_len allocated size of sbuf, must be at least 36
+ * \param buf input byte array
+ * \param buf_len number of bytes of buf, must be at least 16
+ * \return 0 on success, -1 on error
+ */
+#define UUID_LEN 36
+static inline int crypto_format_rfc4122_uuid(char *sbuf, size_t sbuf_len,
+		unsigned char *buf, size_t buf_len)
+{
+	size_t i, j;
+	if (sbuf_len < UUID_LEN) return -1;
+	if (buf_len < UUID_LEN/2) return -1;
+	buf[6] &= 0x0f;
+	buf[6] |= 4 << 4;
+	buf[8] &= 0x3f;
+	buf[8] |= 2 << 6;
+	for (i=0, j=0; i<UUID_LEN; i++) {
+		if (i == 8 || i == 13 || i == 18 || i == 23) {
+			sbuf[i] = '-';
+			continue;
+		}
+		sbuf[i] = crypto_byte2hex((buf[j/2] >> (j%2 ? 0 : 4)) % 0x0f);
+		if (!(++j/2 < buf_len)) break;
+	}
+	return 0;
+}
+
+
+/**
+ * \brief Get a unique Call-ID
+ * \param callid returned Call-ID
+ */
+void crypto_generate_callid(str* callid)
+{
+	static SHA_CTX crypto_ctx = {0};
+	static unsigned char crypto_buf[SHA_DIGEST_LENGTH] = {0};
+	static char crypto_sbuf[UUID_LEN] = {0};
+	crypto_inc_counter(crypto_callid_counter, CTR_LEN);
+	SHA1_Init(&crypto_ctx);
+	SHA1_Update(&crypto_ctx, crypto_callid_seed, SEED_LEN);
+	SHA1_Update(&crypto_ctx, crypto_callid_counter, CTR_LEN);
+	SHA1_Final(crypto_buf, &crypto_ctx);
+	crypto_format_rfc4122_uuid(crypto_sbuf, sizeof(crypto_sbuf),
+			crypto_buf, sizeof(crypto_buf));
+	callid->s = crypto_sbuf;
+	callid->len = sizeof(crypto_sbuf);
+}
+
+
+/**
+ *
+ */
+int crypto_register_callid_func(void)
+{
+	if(sr_register_callid_func(crypto_generate_callid)<0) {
+		LM_ERR("unable to register callid func\n");
+		return -1;
+	}
+	return 0;
+}

+ 68 - 0
modules/crypto/crypto_uuid.h

@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 Daniel-Constantin Mierla (asipto.com)
+ * Copyright (C) 2016 Travis Cross <[email protected]>
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief Crypto :: Fast enough high entropy Call-ID generator
+ * \ingroup tm
+ */
+
+
+#ifndef __CRYPTO_UUID_H__
+#define __CRYPTO_UUID_H__
+
+#include "../../str.h"
+
+
+/**
+ * \brief Initialize the Call-ID generator
+ * \return 0 on success, -1 on error
+ */
+int crypto_init_callid(void);
+
+
+/**
+ * \brief Child initialization
+ * \param rank not used
+ * \return 0 on success, -1 on error
+ */
+int crypto_child_init_callid(int rank);
+
+
+/**
+ * \brief TM API export
+ */
+typedef void (*generate_callid_f)(str*);
+
+
+/**
+ * \brief Get a unique Call-ID
+ * \param callid returned Call-ID
+ */
+void crypto_generate_callid(str* callid);
+
+/**
+ *
+ */
+int crypto_register_callid_func(void);
+
+#endif /* CALLID_H */