Browse code

modules/auth_ephemeral: new module for ephemeral credential based authentication

Peter Dunkley authored on 26/05/2013 23:25:03
Showing 9 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+# $Id$
1
+#
2
+# 
3
+# WARNING: do not run this directly, it should be run by the master Makefile
4
+
5
+include ../../Makefile.defs
6
+auto_gen=
7
+NAME=auth_ephemeral.so
8
+
9
+ifeq ($(CROSS_COMPILE),)
10
+SSL_BUILDER=$(shell \
11
+	if pkg-config --exists libssl; then \
12
+		echo 'pkg-config libssl'; \
13
+	fi)
14
+endif
15
+
16
+ifneq ($(SSL_BUILDER),)
17
+	DEFS += $(shell $(SSL_BUILDER) --cflags)
18
+	LIBS += $(shell $(SSL_BUILDER) --libs)
19
+else
20
+	DEFS += -I$(LOCALBASE)/ssl/include
21
+	LIBS += -L$(LOCALBASE)/lib -L$(LOCALBASE)/ssl/lib \
22
+			-L$(LOCALBASE)/lib64 -L$(LOCALBASE)/ssl/lib64 \
23
+			-lssl -lcrypto
24
+	# NOTE: depending on the way in which libssl was compiled you might
25
+	#       have to add -lz -lkrb5   (zlib and kerberos5).
26
+	#       E.g.: make TLS_HOOKS=1 TLS_EXTRA_LIBS="-lz -lkrb5"
27
+endif
28
+
29
+LIBS+= $(TLS_EXTRA_LIBS)
30
+
31
+# Static linking, if you'd like to use TLS and AUTH_EPHEMERAL at the same time
32
+#
33
+#LIBS+= /usr/lib/libcurl.a /usr/lib/libssl.a /usr/lib/libcrypto.a -lkrb5 -lidn -lz -lgssapi_krb5 -lrt
34
+DEFS+=-DKAMAILIO_MOD_INTERFACE
35
+
36
+SERLIBPATH=../../lib
37
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
38
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
39
+
40
+include ../../Makefile.modules
0 41
new file mode 100644
... ...
@@ -0,0 +1,250 @@
0
+Auth_ephemeral Module
1
+
2
+Peter Dunkley
3
+
4
+   Crocodile RCS Ltd
5
+   <peter.dunkley@crocodile-rcs.com>
6
+
7
+   Copyright © 2013 Crocdile RCS Ltd
8
+     __________________________________________________________________
9
+
10
+   Table of Contents
11
+
12
+   1. Admin Guide
13
+
14
+        1. Overview
15
+
16
+              1.1. How ephemeral credentials work
17
+
18
+                    1.1.1. Request
19
+                    1.1.2. Response
20
+
21
+        2. Dependencies
22
+
23
+              2.1. Kamailio Modules
24
+              2.2. External Libraries or Applications
25
+
26
+        3. Parameters
27
+
28
+              3.1. secret (string)
29
+
30
+        4. Functions
31
+
32
+              4.1. autheph_proxy(realm)
33
+              4.2. autheph_www(realm[, method])
34
+              4.3. autheph_check(realm)
35
+
36
+   List of Examples
37
+
38
+   1.1.
39
+   1.2.
40
+   1.3. secret parameter usage
41
+   1.4. autheph_proxy usage
42
+   1.5. autheph_www usage
43
+   1.6. autheph_check usage
44
+
45
+Chapter 1. Admin Guide
46
+
47
+   Table of Contents
48
+
49
+   1. Overview
50
+
51
+        1.1. How ephemeral credentials work
52
+
53
+              1.1.1. Request
54
+              1.1.2. Response
55
+
56
+   2. Dependencies
57
+
58
+        2.1. Kamailio Modules
59
+        2.2. External Libraries or Applications
60
+
61
+   3. Parameters
62
+
63
+        3.1. secret (string)
64
+
65
+   4. Functions
66
+
67
+        4.1. autheph_proxy(realm)
68
+        4.2. autheph_www(realm[, method])
69
+        4.3. autheph_check(realm)
70
+
71
+1. Overview
72
+
73
+   1.1. How ephemeral credentials work
74
+
75
+        1.1.1. Request
76
+        1.1.2. Response
77
+
78
+   This module contains all authentication related functions that can work
79
+   with ephemeral credentials. This module should be used together with
80
+   the auth module - it cannot be used independently because it depends on
81
+   the auth module. Use this module if you want to use ephemeral
82
+   credentials instead of ordinary usernames and passwords.
83
+
84
+1.1. How ephemeral credentials work
85
+
86
+   Ephemeral credentials are generated by a web-service and enforced on
87
+   Kamailio. This usage of ephemeral credentials ensures that access to
88
+   Kamailio is controlled even if the credentials cannot be kept secret,
89
+   as can be the case in WebRTC where the credentials may be specified in
90
+   Javascript.
91
+
92
+   To use this mechanism, the only interaction needed between the
93
+   web-service and Kamailio is to share a secret key.
94
+
95
+   Typically, credentials will be requested from the web-service using an
96
+   HTTP GET and provided in a JSON response. To prevent unauthorised use
97
+   the HTTP requests can be ACLd by various means.
98
+
99
+   This mechanism is based on the Google proposal for a "TURN Server REST
100
+   API".
101
+
102
+1.1.1. Request
103
+
104
+   The request should contain the following parameters:
105
+     * service - specifies the desired service (msrp, sip, etc)
106
+     * username - a user identifier for the service
107
+     * ttl - an optional TTL request for the lifetime of the credentials,
108
+       in seconds.
109
+
110
+   Example 1.1.
111
+GET /?service=sip&username=foobar;&ttl=86400;
112
+
113
+1.1.2. Response
114
+
115
+   The response should include the following parameters:
116
+     * username - the username to use, which is a combination of the
117
+       username parameter from the request, with a timestamp in time_t
118
+       format, colon-separated.
119
+     * password - the password to use; this value is computed from the
120
+       secret key and the returned username value, by performing
121
+       base64(hmac-sha1(secret key, returned username)).
122
+     * ttl - the duration for which the username and password are valid,
123
+       in seconds. This number will be less than or equal to the requested
124
+       TTL.
125
+     * uris - an array of URIs indicating servers that the username and
126
+       password are valid for.
127
+
128
+   Example 1.2.
129
+{
130
+  "username" : "foobar:1234567890",
131
+  "password" : "asdfghjklauio=",
132
+  "ttl" : 86400,
133
+  "uris" : [
134
+    "sip:1.2.3.4;transport=ws",
135
+    "sip:5.6.7.8;transport=ws"
136
+  ]
137
+}
138
+
139
+2. Dependencies
140
+
141
+   2.1. Kamailio Modules
142
+   2.2. External Libraries or Applications
143
+
144
+2.1. Kamailio Modules
145
+
146
+   The module must be loaded before this module:
147
+     * auth.
148
+
149
+2.2. External Libraries or Applications
150
+
151
+   The following libraries must be installed before running Kamailio with
152
+   this module loaded:
153
+     * OpenSSL.
154
+
155
+3. Parameters
156
+
157
+   3.1. secret (string)
158
+
159
+3.1. secret (string)
160
+
161
+   The shared secret to use for generating credentials. This parameter can
162
+   be set multiple times - this enables the secret used for new
163
+   credentials to be changed without causing existing credentials to stop
164
+   working. The last secret set is the first that will be tried.
165
+
166
+   Example 1.3. secret parameter usage
167
+...
168
+modparam("auth_ephemeral", "secret", "kamailio_rules")
169
+...
170
+
171
+4. Functions
172
+
173
+   4.1. autheph_proxy(realm)
174
+   4.2. autheph_www(realm[, method])
175
+   4.3. autheph_check(realm)
176
+
177
+4.1.  autheph_proxy(realm)
178
+
179
+   This function performs proxy authentication. the rest.
180
+
181
+   The meaning of the parameters are as follows:
182
+     * realm - Realm is an opaque string that the user agent should
183
+       present to the user so that he can decide what username and
184
+       password to use. Usually this is domain of the host the server is
185
+       running on.
186
+       It must not be an empty string “”. Apart from a static string, a
187
+       typical value is the From-URI domain (i.e., $fd).
188
+       The string may contain pseudo variables.
189
+
190
+   This function can be used from REQUEST_ROUTE.
191
+
192
+   Example 1.4. autheph_proxy usage
193
+...
194
+if (!autheph_proxy("$fd")) {
195
+    auth_challenge("$fd", "1");
196
+    exit;
197
+}
198
+...
199
+
200
+4.2.  autheph_www(realm[, method])
201
+
202
+   This function performs WWW digest authentication.
203
+
204
+   The meaning of the parameters are as follows:
205
+     * realm - Realm is an opaque string that the user agent should
206
+       present to the user so that he can decide what username and
207
+       password to use. Usually this is domain of the host the server is
208
+       running on.
209
+       It must not be an empty string “”. Apart from a static string, a
210
+       typical value is the From-URI domain (i.e., $fd).
211
+       The string may contain pseudo variables.
212
+     * method - the method to be used for authentication. This parameter
213
+       is optional and if not set the first "word" on the request-line is
214
+       used.
215
+
216
+   This function can be used from REQUEST_ROUTE.
217
+
218
+   Example 1.5. autheph_www usage
219
+...
220
+if (!autheph_www("$fd")) {
221
+    auth_challenge("$fd", "1");
222
+    exit;
223
+}
224
+...
225
+
226
+4.3.  autheph_check(realm)
227
+
228
+   This function combines the functionalities of autheph_www and
229
+   autheph_proxy, the first being exectuted if the SIP request is a
230
+   REGISTER, the second for the rest.
231
+
232
+   The meaning of the parameters are as follows:
233
+     * realm - Realm is an opaque string that the user agent should
234
+       present to the user so that he can decide what username and
235
+       password to use. Usually this is domain of the host the server is
236
+       running on.
237
+       It must not be an empty string “”. Apart from a static string, a
238
+       typical value is the From-URI domain (i.e., $fd).
239
+       The string may contain pseudo variables.
240
+
241
+   This function can be used from REQUEST_ROUTE.
242
+
243
+   Example 1.6. autheph_check usage
244
+...
245
+if (!autheph_check("$fd")) {
246
+    auth_challenge("$fd", "1");
247
+    exit;
248
+}
249
+...
0 250
new file mode 100644
... ...
@@ -0,0 +1,168 @@
0
+/* 
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2013 Crocodile RCS Ltd
4
+ *
5
+ * This file is part of Kamailio, a free SIP server.
6
+ *
7
+ * Kamailio is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * Kamailio 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 General Public License 
18
+ * along with this program; if not, write to the Free Software 
19
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
+ *
21
+ */
22
+#include "../../dprint.h"
23
+#include "../../mod_fix.h"
24
+#include "../../sr_module.h"
25
+#include "../../str.h"
26
+#include "../../modules/auth/api.h"
27
+
28
+#include "autheph_mod.h"
29
+#include "authorize.h"
30
+
31
+MODULE_VERSION
32
+
33
+static int mod_init(void);
34
+static void destroy(void);
35
+
36
+static int secret_param(modparam_t type, void* param);
37
+struct secret *secret_list = NULL;
38
+
39
+auth_api_s_t eph_auth_api;
40
+
41
+static cmd_export_t cmds[]=
42
+{
43
+	{ "autheph_check", (cmd_function) autheph_check,
44
+	  1, fixup_var_str_1, 0,
45
+	  REQUEST_ROUTE },
46
+	{ "autheph_www", (cmd_function) autheph_www,
47
+	  1, fixup_var_str_1, 0,
48
+	  REQUEST_ROUTE },
49
+	{ "autheph_www", (cmd_function) autheph_www2,
50
+	  2, fixup_var_str_12, 0,
51
+	  REQUEST_ROUTE },
52
+	{ "autheph_proxy", (cmd_function) autheph_proxy,
53
+	  1, fixup_var_str_1, 0,
54
+	  REQUEST_ROUTE },
55
+
56
+	{0, 0, 0, 0, 0, 0}
57
+};
58
+
59
+static param_export_t params[]=
60
+{
61
+	{ "secret",		STR_PARAM|USE_FUNC_PARAM,
62
+	  (void *) secret_param },
63
+	{0, 0, 0}
64
+};
65
+
66
+struct module_exports exports=
67
+{
68
+	"auth_ephemeral", 
69
+	DEFAULT_DLFLAGS,	/* dlopen flags */
70
+	cmds,			/* Exported functions */
71
+	params,			/* Exported parameters */
72
+	0,			/* exported statistics */
73
+	0,			/* exported MI functions */
74
+	0,			/* exported pseudo-variables */
75
+	0,			/* extra processes */
76
+	mod_init,		/* module initialization function */
77
+	0,			/* response function */
78
+	destroy,		/* destroy function */
79
+	0			/* child initialization function */
80
+};
81
+
82
+static int mod_init(void)
83
+{
84
+	bind_auth_s_t bind_auth;
85
+
86
+	if (secret_list == NULL)
87
+	{
88
+		LM_ERR("secret modparam not set\n");
89
+		return -1;
90
+	}
91
+
92
+	bind_auth = (bind_auth_s_t) find_export("bind_auth_s", 0, 0);
93
+	if (!bind_auth)
94
+	{
95
+		LM_ERR("unable to find bind_auth function. Check if you have"
96
+			" loaded the auth module.\n");
97
+		return -2;
98
+	}
99
+
100
+	if (bind_auth(&eph_auth_api) < 0)
101
+	{
102
+		LM_ERR("unable to bind to auth module\n");
103
+		return -3;
104
+	}
105
+
106
+	return 0;
107
+}
108
+
109
+static void destroy(void)
110
+{
111
+	struct secret *secret_struct;
112
+
113
+	while (secret_list != NULL)
114
+	{
115
+		secret_struct = secret_list;
116
+		secret_list = secret_struct->next;
117
+
118
+		if (secret_struct->secret_key.s != NULL)
119
+		{
120
+			shm_free(secret_struct->secret_key.s);
121
+		}
122
+		shm_free(secret_struct);
123
+	}
124
+}
125
+
126
+static int add_secret(str secret_key)
127
+{
128
+	struct secret *secret_struct;
129
+
130
+	secret_struct = (struct secret *) shm_malloc(sizeof(struct secret));
131
+	if (secret_struct == NULL)
132
+	{
133
+		LM_ERR("unable to allocate shared memory\n");
134
+		return -1;
135
+	}
136
+
137
+	memset(secret_struct, 0, sizeof (struct secret));
138
+	secret_struct->next = secret_list;
139
+	secret_list = secret_struct;
140
+	secret_struct->secret_key = secret_key;
141
+
142
+	return 0;
143
+}
144
+
145
+static int secret_param(modparam_t type, void *val)
146
+{
147
+	str sval;
148
+
149
+	if (val == NULL)
150
+	{
151
+		LM_ERR("bad parameter\n");
152
+		return -1;
153
+	}
154
+
155
+	LM_INFO("adding %s to secret list\n", (char *) val);
156
+
157
+	sval.len = strlen((char *) val);
158
+	sval.s = (char *) shm_malloc(sizeof(char) * sval.len);
159
+	if (sval.s == NULL)
160
+	{
161
+		LM_ERR("unable to allocate shared memory\n");
162
+		return -1;
163
+	}
164
+	memcpy(sval.s, (char *) val, sval.len);
165
+
166
+	return add_secret(sval);
167
+}
0 168
new file mode 100644
... ...
@@ -0,0 +1,31 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2013 Crocodile RCS Ltd
4
+ *
5
+ * This file is part of Kamailio, a free SIP server.
6
+ *
7
+ * Kamailio is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * Kamailio 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 General Public License 
18
+ * along with this program; if not, write to the Free Software 
19
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
+ *
21
+ */
22
+#ifndef AUTHEPH_MOD_H
23
+#define AUTHEPH_MOD_H
24
+
25
+#include "../../str.h"
26
+#include "../../modules/auth/api.h"
27
+
28
+extern auth_api_s_t eph_auth_api;
29
+
30
+#endif /* AUTHEPH_MOD_H */
0 31
new file mode 100644
... ...
@@ -0,0 +1,346 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2013 Crocodile RCS Ltd
4
+ *
5
+ * This file is part of Kamailio, a free SIP server.
6
+ *
7
+ * Kamailio is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * Kamailio 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 General Public License 
18
+ * along with this program; if not, write to the Free Software 
19
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
+ *
21
+ */
22
+#include <openssl/hmac.h>
23
+
24
+#include "../../basex.h"
25
+#include "../../dprint.h"
26
+#include "../../mod_fix.h"
27
+#include "../../str.h"
28
+#include "../../ut.h"
29
+#include "../../parser/digest/digest.h"
30
+#include "../../parser/hf.h"
31
+#include "../../mod_fix.h"
32
+
33
+#include "autheph_mod.h"
34
+#include "authorize.h"
35
+
36
+#if !defined(SHA_DIGEST_LENGTH)
37
+#define SHA_DIGEST_LENGTH (20)
38
+#endif
39
+
40
+static inline int get_ha1(struct username* _username, str* _domain,
41
+				str* _secret, char* _ha1)
42
+{
43
+	unsigned int hmac_len = SHA_DIGEST_LENGTH;
44
+	unsigned char hmac_sha1[hmac_len];
45
+	unsigned char password[base64_enc_len(hmac_len)];
46
+	str spassword;
47
+
48
+	LM_INFO("using secret: %.*s\n", _secret->len, _secret->s);
49
+	if (HMAC(EVP_sha1(), _secret->s, _secret->len,
50
+			(unsigned char *) _username->whole.s,
51
+			_username->whole.len, hmac_sha1, &hmac_len) == NULL) {
52
+		LM_ERR("HMAC-SHA1 failed\n");
53
+		return -1;
54
+	}
55
+
56
+	spassword.len = base64_enc(hmac_sha1, hmac_len, password,
57
+					base64_enc_len(hmac_len));
58
+	spassword.s = (char *) password;
59
+	LM_INFO("calculated password: %.*s\n", spassword.len, spassword.s);
60
+
61
+	eph_auth_api.calc_HA1(HA_MD5, &_username->whole, _domain, &spassword,
62
+				0, 0, _ha1);
63
+	LM_INFO("HA1 string calculated: %s\n", _ha1);
64
+
65
+	return 0;
66
+}
67
+
68
+static int do_auth(struct sip_msg* msg, struct hdr_field *h, str *realm,
69
+			str *method, str* secret)
70
+{
71
+	int ret;
72
+	char ha1[256];
73
+	auth_body_t *cred = (auth_body_t*) h->parsed;
74
+
75
+	ret = get_ha1(&cred->digest.username, realm, secret, ha1);
76
+	if (ret < 0)
77
+	{
78
+		return AUTH_ERROR;
79
+	}
80
+
81
+	ret = eph_auth_api.check_response(&(cred->digest), method, ha1);
82
+	if (ret == AUTHENTICATED)
83
+	{
84
+		if (eph_auth_api.post_auth(msg, h) != AUTHENTICATED)
85
+		{
86
+			return AUTH_ERROR;
87
+		}
88
+	}
89
+	else if (ret == NOT_AUTHENTICATED)
90
+	{
91
+		return AUTH_INVALID_PASSWORD;
92
+	}
93
+	else
94
+	{
95
+		ret = AUTH_ERROR;
96
+	}
97
+
98
+	return AUTH_OK;
99
+}
100
+
101
+static int verify_timestamp(str* username)
102
+{
103
+	int pos = 0;
104
+	unsigned int expires;
105
+	str time_str = {0, 0};
106
+
107
+	LM_INFO("username: %.*s\n", username->len, username->s);
108
+
109
+	while (pos < username->len && username->s[pos] != ':')
110
+		pos++;
111
+
112
+	if (pos < username->len - 1)
113
+	{
114
+		time_str.s = username->s + pos + 1;
115
+		time_str.len = username->len - pos - 1;
116
+	}
117
+	else
118
+	{
119
+		LM_ERR("unable to extract timestamp from username\n");
120
+		return -1;
121
+	}
122
+
123
+	LM_INFO("username timestamp: %.*s\n", time_str.len, time_str.s);
124
+
125
+	if (str2int(&time_str, &expires) < 0)
126
+	{
127
+		LM_ERR("unable to convert timestamp to int\n");
128
+		return -1;
129
+	}
130
+
131
+	if ((int) time(NULL) > expires)
132
+	{
133
+		LM_WARN("username has expired\n");
134
+		return -1;
135
+	}
136
+
137
+	return 0;
138
+}
139
+
140
+static int digest_authenticate(struct sip_msg* msg, str *realm,
141
+				hdr_types_t hftype, str *method)
142
+{
143
+	struct hdr_field* h;
144
+	int ret;
145
+	struct secret *secret_struct = secret_list;
146
+
147
+	ret = eph_auth_api.pre_auth(msg, realm, hftype, &h, NULL);
148
+	switch(ret) {
149
+		case NONCE_REUSED:
150
+			LM_DBG("nonce reused\n");
151
+			return AUTH_NONCE_REUSED;
152
+		case STALE_NONCE:
153
+			LM_DBG("stale nonce\n");
154
+			return AUTH_STALE_NONCE;
155
+		case NO_CREDENTIALS:
156
+			LM_DBG("no credentials\n");
157
+			return AUTH_NO_CREDENTIALS;
158
+		case ERROR:
159
+		case BAD_CREDENTIALS:
160
+			LM_DBG("error or bad credentials\n");
161
+			return AUTH_ERROR;
162
+		case CREATE_CHALLENGE:
163
+			LM_ERR("CREATE_CHALLENGE is not a valid state\n");
164
+			return AUTH_ERROR;
165
+		case DO_RESYNCHRONIZATION:
166
+			LM_ERR("DO_RESYNCHRONIZATION is not a valid state\n");
167
+			return AUTH_ERROR;
168
+		case NOT_AUTHENTICATED:
169
+			LM_DBG("not authenticated\n");
170
+			return AUTH_ERROR;
171
+		case DO_AUTHENTICATION:
172
+			break;
173
+		case AUTHENTICATED:
174
+			return AUTH_OK;
175
+	}
176
+
177
+	if (verify_timestamp(&((auth_body_t*) h->parsed)->digest.username.whole)
178
+			< 0)
179
+	{
180
+		LM_ERR("invalid timestamp in username\n");
181
+		return AUTH_ERROR;
182
+	}
183
+
184
+	while (secret_struct != NULL)
185
+	{
186
+		ret = do_auth(msg, h, realm, method,
187
+				&secret_struct->secret_key);
188
+		if (ret == AUTH_OK)
189
+		{
190
+			break;
191
+		}
192
+		secret_struct = secret_struct->next;
193
+	}
194
+
195
+	return ret;
196
+}
197
+
198
+int autheph_check(struct sip_msg* _m, char* _realm)
199
+{
200
+	str srealm;
201
+
202
+	if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL))
203
+	{
204
+		return AUTH_OK;
205
+	}
206
+
207
+	if(_m==NULL || _realm==NULL)
208
+	{
209
+		LM_ERR("invalid parameters\n");
210
+		return AUTH_ERROR;
211
+	}
212
+
213
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
214
+	{
215
+		LM_ERR("failed to get realm value\n");
216
+		return AUTH_ERROR;
217
+	}
218
+
219
+	if (srealm.len==0)
220
+	{
221
+		LM_ERR("invalid realm parameter - empty value\n");
222
+		return AUTH_ERROR;
223
+	}
224
+
225
+	LM_DBG("realm [%.*s]\n", srealm.len, srealm.s);
226
+
227
+	if(_m->REQ_METHOD==METHOD_REGISTER)
228
+		return digest_authenticate(_m, &srealm, HDR_AUTHORIZATION_T,
229
+					&_m->first_line.u.request.method);
230
+	else
231
+		return digest_authenticate(_m, &srealm, HDR_PROXYAUTH_T,
232
+					&_m->first_line.u.request.method);
233
+}
234
+
235
+int autheph_www(struct sip_msg* _m, char* _realm)
236
+{
237
+	str srealm;
238
+
239
+	if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL))
240
+	{
241
+		return AUTH_OK;
242
+	}
243
+
244
+	if(_m==NULL || _realm==NULL)
245
+	{
246
+		LM_ERR("invalid parameters\n");
247
+		return AUTH_ERROR;
248
+	}
249
+
250
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
251
+	{
252
+		LM_ERR("failed to get realm value\n");
253
+		return AUTH_ERROR;
254
+	}
255
+
256
+	if (srealm.len==0)
257
+	{
258
+		LM_ERR("invalid realm parameter - empty value\n");
259
+		return AUTH_ERROR;
260
+	}
261
+
262
+	LM_DBG("realm [%.*s]\n", srealm.len, srealm.s);
263
+
264
+	return digest_authenticate(_m, &srealm, HDR_AUTHORIZATION_T,
265
+					&_m->first_line.u.request.method);
266
+}
267
+
268
+int autheph_www2(struct sip_msg* _m, char* _realm, char *_method)
269
+{
270
+	str srealm;
271
+	str smethod;
272
+
273
+	if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL))
274
+	{
275
+		return AUTH_OK;
276
+	}
277
+
278
+	if(_m==NULL || _realm==NULL)
279
+	{
280
+		LM_ERR("invalid parameters\n");
281
+		return AUTH_ERROR;
282
+	}
283
+
284
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
285
+	{
286
+		LM_ERR("failed to get realm value\n");
287
+		return AUTH_ERROR;
288
+	}
289
+
290
+	if (srealm.len==0)
291
+	{
292
+		LM_ERR("invalid realm parameter - empty value\n");
293
+		return AUTH_ERROR;
294
+	}
295
+
296
+	if (get_str_fparam(&smethod, _m, (fparam_t*)_method) < 0)
297
+	{
298
+		LM_ERR("failed to get method value\n");
299
+		return AUTH_ERROR;
300
+	}
301
+
302
+	if (smethod.len == 0)
303
+	{
304
+		LM_ERR("invalid method value - empty value\n");
305
+		return AUTH_ERROR;
306
+	}
307
+
308
+	LM_DBG("realm [%.*s] method [%.*s]\n", srealm.len, srealm.s,
309
+		smethod.len, smethod.s);
310
+
311
+	return digest_authenticate(_m, &srealm, HDR_AUTHORIZATION_T, &smethod);
312
+}
313
+
314
+int autheph_proxy(struct sip_msg* _m, char* _realm)
315
+{
316
+	str srealm;
317
+
318
+	if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL))
319
+	{
320
+		return AUTH_OK;
321
+	}
322
+
323
+	if(_m==NULL || _realm==NULL)
324
+	{
325
+		LM_ERR("invalid parameters\n");
326
+		return AUTH_ERROR;
327
+	}
328
+
329
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
330
+	{
331
+		LM_ERR("failed to get realm value\n");
332
+		return AUTH_ERROR;
333
+	}
334
+
335
+	if (srealm.len==0)
336
+	{
337
+		LM_ERR("invalid realm parameter - empty value\n");
338
+		return AUTH_ERROR;
339
+	}
340
+
341
+	LM_DBG("realm [%.*s]\n", srealm.len, srealm.s);
342
+
343
+	return digest_authenticate(_m, &srealm, HDR_PROXYAUTH_T,
344
+					&_m->first_line.u.request.method);
345
+}
0 346
new file mode 100644
... ...
@@ -0,0 +1,42 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2013 Crocodile RCS Ltd
4
+ *
5
+ * This file is part of Kamailio, a free SIP server.
6
+ *
7
+ * Kamailio is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * Kamailio 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 General Public License 
18
+ * along with this program; if not, write to the Free Software 
19
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
+ *
21
+ */
22
+#ifndef AUTHORIZE_H
23
+#define AUTHORIZE_H
24
+
25
+#include "../../str.h"
26
+#include "../../parser/msg_parser.h"
27
+
28
+struct secret
29
+{
30
+	str secret_key;
31
+	struct secret *next;
32
+};
33
+
34
+extern struct secret *secret_list;
35
+
36
+int autheph_check(struct sip_msg* _m, char* _realm);
37
+int autheph_www(struct sip_msg* _m, char* _realm);
38
+int autheph_www2(struct sip_msg* _m, char* _realm, char *_method);
39
+int autheph_proxy(struct sip_msg* _m, char* _realm);
40
+
41
+#endif /* AUTHORIZE_H */
0 42
new file mode 100644
... ...
@@ -0,0 +1,4 @@
0
+docs = auth_ephemeral.xml
1
+
2
+docbook_dir = ../../../docbook
3
+include $(docbook_dir)/Makefile.module
0 4
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+<?xml version="1.0" encoding='ISO-8859-1'?>
1
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
2
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
3
+
4
+<!-- Include general documentation entities -->
5
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
6
+%docentities;
7
+
8
+]>
9
+
10
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
11
+	<bookinfo>
12
+	<title>Auth_ephemeral Module</title>
13
+	<authorgroup>
14
+		<author>
15
+		<firstname>Peter</firstname>
16
+		<surname>Dunkley</surname>
17
+		<affiliation><orgname>Crocodile RCS Ltd</orgname></affiliation>
18
+		<email>peter.dunkley@crocodile-rcs.com</email>
19
+		</author>
20
+	</authorgroup>
21
+	<copyright>
22
+		<year>2013</year>
23
+		<holder>Crocdile RCS Ltd</holder>
24
+	</copyright>
25
+	</bookinfo>
26
+	<toc></toc>
27
+
28
+	<xi:include href="auth_ephemeral_admin.xml"/>
29
+</book>
0 30
new file mode 100644
... ...
@@ -0,0 +1,306 @@
0
+<?xml version="1.0" encoding='ISO-8859-1'?>
1
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
2
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
3
+
4
+<!-- Include general documentation entities -->
5
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
6
+%docentities;
7
+
8
+]>
9
+
10
+<!-- Auth_ephemeral Module User's Guide -->
11
+
12
+<chapter>
13
+	
14
+	<title>&adminguide;</title>
15
+	
16
+	<section>
17
+	<title>Overview</title>
18
+	<para>
19
+	This module contains all authentication related functions that can work
20
+	with ephemeral credentials. This module should be used together with the
21
+	auth module - it cannot be used independently because it depends on the
22
+	auth module. Use this module if you want to use ephemeral credentials
23
+	instead of ordinary usernames and passwords.
24
+	</para>
25
+
26
+	<section>
27
+	<title>How ephemeral credentials work</title>
28
+	<para>
29
+	Ephemeral credentials are generated by a web-service and enforced on
30
+	Kamailio. This usage of ephemeral credentials ensures that access to
31
+	Kamailio is controlled even if the credentials cannot be kept secret,
32
+	as can be the case in WebRTC where the credentials may be specified in
33
+	Javascript.
34
+	</para>
35
+	<para>
36
+	To use this mechanism, the only interaction needed between the
37
+	web-service and Kamailio is to share a secret key.
38
+	</para>
39
+	<para>
40
+	Typically, credentials will be requested from the web-service using an
41
+	HTTP GET and provided in a JSON response. To prevent unauthorised use
42
+	the HTTP requests can be ACLd by various means.
43
+	</para>
44
+	<para>
45
+	This mechanism is based on the Google proposal for a &quot;TURN Server
46
+	REST API&quot;.
47
+	</para>
48
+	<section>
49
+	<title>Request</title>
50
+	<para>
51
+	The request should contain the following parameters:
52
+	<itemizedlist>
53
+	<listitem>
54
+	<para><emphasis>service</emphasis> - specifies the desired service
55
+	(msrp, sip, etc)</para>
56
+	</listitem>
57
+	<listitem>
58
+	<para><emphasis>username</emphasis> - a user identifier for the
59
+	service</para>
60
+	</listitem>
61
+	<listitem>
62
+	<para><emphasis>ttl</emphasis> - an optional TTL request for the
63
+	lifetime of the credentials, in seconds.</para>
64
+	</listitem>
65
+	</itemizedlist>
66
+	</para>
67
+	<example>
68
+	<programlisting format="linespecific">
69
+GET /?service=sip&amp;username=foobar;&amp;ttl=86400;
70
+</programlisting>
71
+	</example>
72
+	</section>
73
+	<section>
74
+	<title>Response</title>
75
+	<para>
76
+	The response should include the following parameters:
77
+	<itemizedlist>
78
+	<listitem>
79
+	<para><emphasis>username</emphasis> - the username to use, which is a
80
+	combination of the username parameter from the request, with a timestamp
81
+	in time_t format, colon-separated.</para>
82
+	</listitem>
83
+	<listitem>
84
+	<para><emphasis>password</emphasis> - the password to use; this value is
85
+	computed from the secret key and the returned username value, by
86
+	performing base64(hmac-sha1(secret key, returned username)).</para>
87
+	</listitem>
88
+	<listitem>
89
+	<para><emphasis>ttl</emphasis> - the duration for which the username and
90
+	password are valid, in seconds. This number will be less than or equal
91
+	to the requested TTL.</para>
92
+	</listitem>
93
+	<listitem>
94
+	<para><emphasis>uris</emphasis> - an array of URIs indicating servers that
95
+	the username and password are valid for.</para>
96
+	</listitem>
97
+	</itemizedlist>
98
+	</para>
99
+	<example>
100
+	<programlisting format="linespecific">
101
+{
102
+  "username" : "foobar:1234567890",
103
+  "password" : "asdfghjklauio=",
104
+  "ttl" : 86400,
105
+  "uris" : [
106
+    "sip:1.2.3.4;transport=ws",
107
+    "sip:5.6.7.8;transport=ws"
108
+  ]
109
+}
110
+</programlisting>
111
+	</example>
112
+	</section>
113
+	</section>
114
+	</section>
115
+
116
+	<section>
117
+	<title>Dependencies</title>
118
+	<section>
119
+		<title>&kamailio; Modules</title>
120
+		<para>
121
+		The module must be loaded before this module:
122
+		<itemizedlist>
123
+		<listitem>
124
+		<para><emphasis>auth</emphasis>.</para>
125
+		</listitem>
126
+		</itemizedlist>
127
+		</para>
128
+	</section>
129
+
130
+	<section>
131
+		<title>External Libraries or Applications</title>
132
+		<para>
133
+		The following libraries must be installed before running
134
+		&kamailio; with this module loaded:
135
+		<itemizedlist>
136
+		<listitem>
137
+		<para><emphasis>OpenSSL</emphasis>.</para>
138
+		</listitem>
139
+		</itemizedlist>
140
+		</para>
141
+	</section>
142
+	</section>
143
+
144
+
145
+	<section>
146
+	<title>Parameters</title>
147
+	<section>
148
+		<title><varname>secret</varname> (string)</title>
149
+		<para>
150
+		The shared secret to use for generating credentials. This
151
+		parameter can be set multiple times - this enables the secret
152
+		used for new credentials to be changed without causing existing
153
+		credentials to stop working. The last secret set is the first
154
+		that will be tried.
155
+		</para>
156
+		<example>
157
+		<title><varname>secret</varname> parameter usage</title>
158
+		<programlisting format="linespecific">
159
+...
160
+modparam("auth_ephemeral", "secret", "kamailio_rules")
161
+...
162
+</programlisting>
163
+		</example>
164
+	</section>
165
+	</section>
166
+
167
+	<section>
168
+	<title>Functions</title>
169
+	<section>
170
+		<title>
171
+			<function moreinfo="none">autheph_proxy(realm)</function>
172
+		</title>
173
+		<para>This function performs proxy authentication.
174
+		the rest.
175
+		</para>
176
+		<para>The meaning of the parameters are as follows:</para>
177
+		<itemizedlist>
178
+		<listitem>
179
+			<para><emphasis>realm</emphasis> - Realm is an opaque
180
+			string that the user agent should present to the user so
181
+			that he can decide what username and password to use.
182
+			Usually this is domain of the host the server is running
183
+			on.
184
+			</para>
185
+			<para>
186
+			It must not be an empty string <quote></quote>. Apart
187
+			from a static string, a typical value is the From-URI
188
+			domain (i.e., $fd).
189
+			</para>
190
+			<para>
191
+			The string may contain pseudo variables.
192
+			</para>
193
+		</listitem>
194
+		</itemizedlist>
195
+		<para>
196
+		This function can be used from REQUEST_ROUTE.
197
+		</para>
198
+		<example>
199
+		<title>autheph_proxy usage</title>
200
+		<programlisting format="linespecific">
201
+...
202
+if (!autheph_proxy("$fd")) {
203
+    auth_challenge("$fd", "1");
204
+    exit;
205
+}
206
+...
207
+</programlisting>
208
+		</example>
209
+	</section>
210
+
211
+	<section>
212
+		<title>
213
+			<function moreinfo="none">autheph_www(realm[, method])</function>
214
+		</title>
215
+		<para>This function performs WWW digest authentication.
216
+		</para>
217
+		<para>The meaning of the parameters are as follows:</para>
218
+		<itemizedlist>
219
+		<listitem>
220
+			<para><emphasis>realm</emphasis> - Realm is an opaque
221
+			string that the user agent should present to the user so
222
+			that he can decide what username and password to use.
223
+			Usually this is domain of the host the server is running
224
+			on.
225
+			</para>
226
+			<para>
227
+			It must not be an empty string <quote></quote>. Apart
228
+			from a static string, a typical value is the From-URI
229
+			domain (i.e., $fd).
230
+			</para>
231
+			<para>
232
+			The string may contain pseudo variables.
233
+			</para>
234
+		</listitem>
235
+		<listitem>
236
+			<para><emphasis>method</emphasis> - the method to be
237
+			used for authentication. This parameter is optional and
238
+			if not set the first "word" on the request-line is used.
239
+			</para>
240
+		</listitem>
241
+		</itemizedlist>
242
+		<para>
243
+		This function can be used from REQUEST_ROUTE.
244
+		</para>
245
+		<example>
246
+		<title>autheph_www usage</title>
247
+		<programlisting format="linespecific">
248
+...
249
+if (!autheph_www("$fd")) {
250
+    auth_challenge("$fd", "1");
251
+    exit;
252
+}
253
+...
254
+</programlisting>
255
+		</example>
256
+	</section>
257
+
258
+
259
+	<section>
260
+		<title>
261
+			<function moreinfo="none">autheph_check(realm)</function>
262
+		</title>
263
+		<para>This function combines the functionalities of
264
+		<function moreinfo="none">autheph_www</function> and
265
+		<function moreinfo="none">autheph_proxy</function>, the first
266
+		being exectuted if the SIP request is a REGISTER, the second for
267
+		the rest.
268
+		</para>
269
+		<para>The meaning of the parameters are as follows:</para>
270
+		<itemizedlist>
271
+		<listitem>
272
+			<para><emphasis>realm</emphasis> - Realm is an opaque
273
+			string that the user agent should present to the user so
274
+			that he can decide what username and password to use.
275
+			Usually this is domain of the host the server is running
276
+			on.
277
+			</para>
278
+			<para>
279
+			It must not be an empty string <quote></quote>. Apart
280
+			from a static string, a typical value is the From-URI
281
+			domain (i.e., $fd).
282
+			</para>
283
+			<para>
284
+			The string may contain pseudo variables.
285
+			</para>
286
+		</listitem>
287
+		</itemizedlist>
288
+		<para>
289
+		This function can be used from REQUEST_ROUTE.
290
+		</para>
291
+		<example>
292
+		<title>autheph_check usage</title>
293
+		<programlisting format="linespecific">
294
+...
295
+if (!autheph_check("$fd")) {
296
+    auth_challenge("$fd", "1");
297
+    exit;
298
+}
299
+...
300
+</programlisting>
301
+		</example>
302
+	</section>
303
+	</section>
304
+</chapter>
305
+