core: fix another bunch of 'no real prototype' warnings, add doxygen docs
[sip-router] / modules / auth / nonce.c
1 /*
2  * $Id$
3  *
4  * Nonce related functions
5  *
6  * Copyright (C) 2001-2003 FhG Fokus
7  *
8  * This file is part of ser, a free SIP server.
9  *
10  * ser is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * For a license to use the ser software under conditions
16  * other than those described here, or to purchase support for this
17  * software, please contact iptel.org by e-mail at the following addresses:
18  *    info@iptel.org
19  *
20  * ser is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License 
26  * along with this program; if not, write to the Free Software 
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  */
29 /*
30  * History:
31  * --------
32  *            ...
33  * 2007-10-19 auth extra checks: longer nonces that include selected message
34  *            parts to protect against various reply attacks without keeping
35  *            state (andrei)
36  * 2008-07-01 switched to base64 for nonces; check staleness in check_nonce
37  *            (andrei)
38  * 2008-07-04 nonce-count support (andrei)
39  */
40
41
42 #include <time.h>
43 #include <string.h>
44 #include <sys/types.h>
45 #include <netinet/in.h>
46 #include "../../compiler_opt.h"
47 #include "../../md5.h"
48 #include "../../dprint.h"
49 #include "../../ut.h"
50 #include "../../parser/msg_parser.h"
51 #include "../../parser/parse_from.h"
52 #include "../../ip_addr.h"
53 #include "nonce.h"
54 #include "../../globals.h"
55 #include "../../ser_time.h"
56 #include <assert.h>
57 #ifdef USE_NC
58 #include "nc.h"
59 #endif
60 #ifdef USE_OT_NONCE
61 #include "ot_nonce.h"
62 #endif
63
64
65 int auth_checks_reg = 0;
66 int auth_checks_ood = 0;
67 int auth_checks_ind = 0;
68
69 /* maximum time drift accepted for the nonce creation time
70  * (e.g. nonce generated by another proxy in the same cluster with the
71  * clock slightly in the future)
72  */
73 unsigned int nonce_auth_max_drift = 3; /* in s */
74
75 /** Select extra check configuration based on request type.
76  * This function determines which configuration variable for
77  * extra authentication checks is to be used based on the
78  * type of the request. It returns the value of auth_checks_reg
79  * for REGISTER requests, the value auth_checks_ind for requests
80  * that contain valid To tag and the value of auth_checks_ood
81  * otherwise.
82  */
83 int get_auth_checks(struct sip_msg* msg)
84 {
85         str tag;
86
87         if (msg == NULL) return 0;
88
89         if (msg->REQ_METHOD == METHOD_REGISTER) {
90                 return auth_checks_reg;
91         }
92                 
93         if (!msg->to && parse_headers(msg, HDR_TO_F, 0) == -1) {
94                 DBG("auth: Error while parsing To header field\n");
95                 return auth_checks_ood;
96         }
97         if (msg->to) {
98                 tag = get_to(msg)->tag_value;
99                 if (tag.s && tag.len > 0) return auth_checks_ind;
100         }
101         return auth_checks_ood;
102 }
103
104
105
106 /* takes a pre-filled bin_nonce union (see BIN_NONCE_PREPARE), fills the
107  * MD5s and returns the length of the binary nonce (cannot return error).
108  * See calc_nonce below for more details.*/
109 inline static int calc_bin_nonce_md5(union bin_nonce* b_nonce, int cfg,
110                                                                                 str* secret1, str* secret2,
111                                                                                 struct sip_msg* msg)
112 {
113         MD5_CTX ctx;
114         
115         str* s;
116         int len;
117
118         MD5Init(&ctx);
119         
120         U_MD5Update(&ctx, &b_nonce->raw[0], 4 + 4);
121         if (cfg && msg){
122                 /* auth extra checks => 2 md5s */
123                 len = 4 + 4 + 16 + 16;
124 #if defined USE_NC  || defined USE_OT_NONCE
125                 if (b_nonce->n.nid_pf & (NF_VALID_NC_ID | NF_VALID_OT_ID)){
126                         /* if extra auth checks enabled, nid & pf are after the 2nd md5 */
127                         U_MD5Update(&ctx, (unsigned char*)&b_nonce->n.nid_i,
128                                                         nonce_nid_extra_size);
129                         len+=nonce_nid_extra_size;
130                 }
131 #endif /* USE_NC || USE_OT_NONCE */
132                 MD5Update(&ctx, secret1->s, secret1->len);
133                 MD5Final(&b_nonce->n.md5_1[0], &ctx);
134                 /* second MD5(auth_extra_checks) */
135                 MD5Init(&ctx);
136                 if (cfg & AUTH_CHECK_FULL_URI) {
137                         s = GET_RURI(msg);
138                         MD5Update(&ctx, s->s, s->len);
139                 }
140                 if ((cfg & AUTH_CHECK_CALLID) && 
141                         !(parse_headers(msg, HDR_CALLID_F, 0) < 0 || msg->callid == 0)) {
142                         MD5Update(&ctx, msg->callid->body.s, msg->callid->body.len);
143                 }
144                 if ((cfg & AUTH_CHECK_FROMTAG) &&
145                         !(parse_from_header(msg) < 0 )) {
146                         MD5Update(&ctx, get_from(msg)->tag_value.s, 
147                                           get_from(msg)->tag_value.len);
148                 }
149                 if (cfg & AUTH_CHECK_SRC_IP) {
150                         U_MD5Update(&ctx, msg->rcv.src_ip.u.addr, msg->rcv.src_ip.len);
151                 }
152                 MD5Update(&ctx, secret2->s, secret2->len);
153                 MD5Final(&b_nonce->n.md5_2[0], &ctx);
154         }else{
155                 /* no extra checks => only one md5 */
156                 len = 4 + 4 + 16;
157 #if defined USE_NC || USE_OT_NONCE
158                 if (b_nonce->n_small.nid_pf & (NF_VALID_NC_ID | NF_VALID_OT_ID)){
159                         /* if extra auth checks are not enabled, nid & pf are after the
160                          *  1st md5 */
161                         U_MD5Update(&ctx, (unsigned char*)&b_nonce->n_small.nid_i,
162                                                         nonce_nid_extra_size);
163                         len+=nonce_nid_extra_size;
164                 }
165 #endif /* USE_NC  || USE_OT_NONCE*/
166                 MD5Update(&ctx, secret1->s, secret1->len);
167                 MD5Final(&b_nonce->n.md5_1[0], &ctx);
168         }
169         
170         return len;
171 }
172
173
174
175 /** Calculates the nonce string for RFC2617 digest authentication.
176  * This function creates the nonce string as it will be sent to the
177  * user agent in digest challenge. The format of the nonce string
178  * depends on the value of three module parameters, auth_checks_register,
179  * auth_checks_no_dlg, and auth_checks_in_dlg. These module parameters
180  * control the amount of information from the SIP requst that will be
181  * stored in the nonce string for verification purposes.
182  *
183  * If all three parameters contain zero then the nonce string consists
184  * of time in seconds since 1.1. 1970 and a secret phrase:
185  * <expire_time> <valid_since> MD5(<expire_time>, <valid_since>, secret)
186  * If any of the parameters is not zero (some optional checks are enabled
187  * then the nonce string will also contain MD5 hash of selected parts
188  * of the SIP request:
189  * <expire_time> <valid_since> MD5(<expire_time>, <valid_since>, secret1) MD5(<extra_checks>, secret2)
190  * @param nonce  Pointer to a buffer of *nonce_len. It must have enough
191  *               space to hold the nonce. MAX_NONCE_LEN should be always 
192  *               safe.
193  * @param nonce_len A value/result parameter. Initially it contains the
194  *                  nonce buffer length. If the length is too small, it 
195  *                  will be set to the needed length and the function will 
196  *                  return error immediately. After a succesfull call it will 
197  *                  contain the size of nonce written into the buffer, 
198  *                  without the terminating 0.
199  * @param cfg This is the value of one of the tree module parameters that
200  *            control which optional checks are enabled/disabled and which
201  *            parts of the message will be included in the nonce string.
202  * @param since Time when nonce was created, i.e. nonce is valid since <valid_since> up to <expires>
203  * @param expires Time in seconds after which the nonce will be considered 
204  *                stale.
205  * @param n_id    Nounce count and/or one-time nonce index value
206  *                (32 bit counter)
207  * @param pf      First 2 bits are flags, the rest is the index pool number
208  *                 used if nonce counts or one-time nonces are enabled.
209  *                The possible flags values are: NF_VALID_NC_ID which means
210  *                the nonce-count support is enabled and NF_VALID_OT_ID 
211  *                which means the one-time nonces support is enabled.
212  *                The pool number can be obtained by and-ing with
213  *                NF_POOL_NO_MASK
214  * @param secret1 A secret used for the nonce expires integrity check:
215  *                MD5(<expire_time>, <valid_since>, secret1).
216  * @param secret2 A secret used for integrity check of the message parts 
217  *                selected by auth_extra_checks (if any):
218  *                MD5(<msg_parts(auth_extra_checks)>, secret2).
219  * @param msg     The message for which the nonce is computed. If 
220  *                auth_extra_checks is set, the MD5 of some fields of the
221  *                message will be included in the  generated nonce.
222  * @return 0 on success and -1 on error
223  */
224 int calc_nonce(char* nonce, int *nonce_len, int cfg, int since, int expires,
225 #if defined USE_NC || defined USE_OT_NONCE
226                                         unsigned int n_id, unsigned char pf,
227 #endif /* USE_NC || USE_OT_NONCE */
228                                         str* secret1, str* secret2,
229                                         struct sip_msg* msg)
230 {
231         union bin_nonce b_nonce;
232         int len;
233         if (unlikely(*nonce_len < MAX_NONCE_LEN)) {
234                 len=get_nonce_len(cfg, pf & NF_VALID_NC_ID);
235                 if (unlikely(*nonce_len<len)){
236                         *nonce_len=len;
237                         return -1;
238                 }
239         }
240
241         BIN_NONCE_PREPARE(&b_nonce, expires, since, n_id, pf, cfg, msg);
242         len=calc_bin_nonce_md5(&b_nonce, cfg, secret1, secret2, msg);
243         *nonce_len=base64_enc(&b_nonce.raw[0], len, 
244                                                         (unsigned char*)nonce, *nonce_len);
245         assert(*nonce_len>=0); /*FIXME*/
246         return 0;
247 }
248
249
250
251 /** Returns the expire time of the nonce string.
252  * This function returns the absolute expire time
253  * extracted from the nonce string in the parameter.
254  * @param bn is a valid pointer to a union bin_nonce (decoded nonce)
255  * @return Absolute time when the nonce string expires.
256  */
257
258 #define get_bin_nonce_expire(bn) ((time_t)ntohl((bn)->n.expire))
259
260 /** Returns the valid_since time of the nonce string.
261  * This function returns the absolute time
262  * extracted from the nonce string in the parameter.
263  * @param bn is a valid pointer to a union bin_nonce (decoded nonce)
264  * @return Absolute time when the nonce string was created.
265  */
266 #define get_bin_nonce_since(bn) ((time_t)ntohl((bn)->n.since))
267
268
269
270 /** Checks if nonce is stale.
271  * This function checks if a nonce given to it in the parameter is stale. 
272  * A nonce is stale if the expire time stored in the nonce is in the past.
273  * @param b_nonce a pointer to a union bin_nonce to be checked.
274  * @return 1 the nonce is stale, 0 the nonce is not stale.
275  */
276 #define is_bin_nonce_stale(b_nonce, t) (get_bin_nonce_expire(b_nonce) < (t))
277
278
279
280 /** Utility to convert 8 hex digit string to int */
281 static inline int l8hex2int(char* _s, unsigned int *_r)
282 {
283     unsigned int i, res = 0;
284
285     for(i = 0; i < 8; i++) {
286         res *= 16;
287         if ((_s[i] >= '0') && (_s[i] <= '9')) {
288             res += _s[i] - '0';
289         } else if ((_s[i] >= 'a') && (_s[i] <= 'f')) {
290             res += _s[i] - 'a' + 10;
291         } else if ((_s[i] >= 'A') && (_s[i] <= 'F')) {
292             res += _s[i] - 'A' + 10;
293         } else return -1;
294     }
295     
296     *_r = res;
297     return 0;
298 }
299
300
301
302 /** Check whether the nonce returned by UA is valid.
303  * This function checks whether the nonce string returned by UA
304  * in digest response is valid. The function checks if the nonce
305  * string hasn't expired, it verifies the secret stored in the nonce
306  * string with the secret configured on the server. If any of the
307  * optional extra integrity checks are enabled then it also verifies
308  * whether the corresponding parts in the new SIP requests are same.
309  * @param nonce A nonce string to be verified.
310  * @param secret1 A secret used for the nonce expires integrity check:
311  *                MD5(<expire_time>,, secret1).
312  * @param secret2 A secret used for integrity check of the message parts 
313  *                selected by auth_extra_checks (if any):
314  *                MD5(<msg_parts(auth_extra_checks)>, secret2).
315  * @param msg The message which contains the nonce being verified. 
316  * @return 0 - success (the nonce was not tampered with and if 
317  *             auth_extra_checks are enabled - the selected message fields
318  *             have not changes from the time the nonce was generated)
319  *         -1 - invalid nonce
320  *          1 - nonce length too small
321  *          2 - no match
322  *          3 - nonce expires ok, but the auth_extra checks failed
323  *          4 - stale
324  *          5 - invalid nc value (not an unsigned int)
325  *          6 - nonce reused
326  */
327 int check_nonce(auth_body_t* auth, str* secret1, str* secret2,
328                                         struct sip_msg* msg)
329 {
330         str * nonce;
331         int since, b_nonce2_len, b_nonce_len, cfg;
332         union bin_nonce b_nonce;
333         union bin_nonce b_nonce2;
334         time_t t;
335 #if defined USE_NC || defined USE_OT_NONCE
336         unsigned int n_id;
337         unsigned char pf;
338 #endif /* USE_NC || USE_OT_NONCE */
339 #ifdef USE_NC
340         unsigned int nc;
341 #endif
342
343         cfg = get_auth_checks(msg);
344         nonce=&auth->digest.nonce;
345
346         if (unlikely(nonce->s == 0)) {
347                 return -1;  /* Invalid nonce */
348         }
349         
350         if (unlikely(nonce->len<MIN_NONCE_LEN)){ 
351                 return 1; /* length musth be >= then minimum length */
352         }
353         
354 #if defined USE_NC || defined USE_OT_NONCE
355         /* clear all possible nonce flags positions prior to decoding,
356          * to make sure they can be used even if the nonce is shorter */
357         b_nonce.n.nid_pf=0;
358         b_nonce.n_small.nid_pf=0;
359 #endif /* USE_NC || USE_OT_NONCE */
360         
361         /* decode nonce */
362         b_nonce_len=base64_dec((unsigned char*)nonce->s, nonce->len,
363                                                         &b_nonce.raw[0], sizeof(b_nonce));
364         if (unlikely(b_nonce_len < MIN_BIN_NONCE_LEN)){
365                 DBG("auth: check_nonce: base64_dec failed\n");
366                 return -1; /* error decoding the nonce (invalid nonce since we checked
367                               the len of the base64 enc. nonce above)*/
368         }
369         
370         since = get_bin_nonce_since(&b_nonce);
371         if (unlikely(since < up_since)) {
372                 /* if valid_since time is time pointing before ser was started 
373                  * then we consider nonce as stalled. 
374                    It may be the nonce generated by previous ser instance having
375                    different length (for example because of different auth.
376                    checks)..  Therefore we force credentials to be rebuilt by UAC
377                    without prompting for password */
378                 return 4;
379         }
380         t=ser_time(0);
381         if (unlikely((since > t) && ((since-t) > nonce_auth_max_drift) )){
382                 /* the nonce comes from the future, either because of an external
383                  * time adjustment, or because it was generated by another host
384                  * which has the time slightly unsynchronized */
385                 return 4; /* consider it stale */
386         }
387         b_nonce2=b_nonce; /*pre-fill it with the values from the received nonce*/
388         b_nonce2.n.expire=b_nonce.n.expire;
389         b_nonce2.n.since=b_nonce.n.since;
390 #if defined USE_NC || defined USE_OT_NONCE
391         if (cfg){
392                 b_nonce2.n.nid_i=b_nonce.n.nid_i;
393                 b_nonce2.n.nid_pf=b_nonce.n.nid_pf;
394                 pf=b_nonce.n.nid_pf;
395                 n_id=ntohl(b_nonce.n.nid_i);
396         }else{
397                 b_nonce2.n_small.nid_i=b_nonce.n_small.nid_i;
398                 b_nonce2.n_small.nid_pf=b_nonce.n_small.nid_pf;
399                 pf=b_nonce.n_small.nid_pf;
400                 n_id=ntohl(b_nonce.n_small.nid_i);
401         }
402 #ifdef UE_NC
403         if (unlikely(nc_enabled && !(pf & NF_VALID_NC_ID)) )
404                 /* nounce count enabled, but nonce is not marked as nonce count ready
405                  * or is too short => either an old nonce (should
406                  * be caught by the ser start time  check) or truncated nonce  */
407                 return 4; /* return stale for now */
408         }
409 #endif /* USE_NC */
410 #ifdef USE_OT_NONCE
411         if (unlikely(otn_enabled && !(pf & NF_VALID_OT_ID))){
412                 /* same as above for one-time-nonce */
413                 return 4; /* return stale for now */
414         }
415 #endif  /* USE_OT_NONCE */
416         /* don't check if we got the expected length, if the length is smaller 
417          * then expected then  the md5 check below will fail (since the nid 
418          * members of the bin_nonce struct will be 0); if the length is bigger
419          * and it was not caught by the base64_dec above, and the md5 matches,
420          * we ignore the extra stuff */
421 #endif /* USE_NC || USE_OT_NONCE */
422         b_nonce2_len=calc_bin_nonce_md5(&b_nonce2, cfg, secret1, secret2, msg);
423         if (!memcmp(&b_nonce.n.md5_1[0], &b_nonce2.n.md5_1[0], 16)) {
424 #ifdef USE_NC
425                 /* if nounce-count checks enabled & auth. headers has nc */
426                 if (nc_enabled && (pf & NF_VALID_NC_ID) && auth->digest.nc.s &&
427                                 auth->digest.nc.len){
428                         if ((auth->digest.nc.len != 8) ||
429                             l8hex2int(auth->digest.nc.s, &nc) != 0) {
430                             ERR("check_nonce: bad nc value %.*s\n",
431                                 auth->digest.nc.len, auth->digest.nc.s);
432                             return 5; /* invalid nc */
433                         }
434                         switch(nc_check_val(n_id, pf & NF_POOL_NO_MASK, nc)){
435                                 case NC_OK:
436                                         /* don't perform extra checks or one-time nonce checks
437                                          * anymore, if we have nc */
438                                         goto check_stale;
439                                 case NC_ID_OVERFLOW: /* id too old => stale */
440                                 case NC_TOO_BIG:  /* nc overlfow => force re-auth => stale */
441                                 case NC_REPLAY:    /* nc seen before => re-auth => stale */
442                                 case NC_INV_POOL: /* pool-no too big, maybe ser restart?*/
443                                         return 4; /* stale */
444                         }
445                 }
446 #endif /* USE_NC */
447 #ifdef USE_OT_NONCE
448                 if (otn_enabled && (pf & NF_VALID_OT_ID)){
449                         switch(otn_check_id(n_id, pf & NF_POOL_NO_MASK)){
450                                 case OTN_OK:
451                                         /* continue in case auth extra checks are enabled */
452                                         break;
453                                 case OTN_ID_OVERFLOW:
454                                 case OTN_INV_POOL:
455                                 case OTN_REPLAY:
456                                         return 6; /* reused */
457                         }
458                 }
459 #endif
460                 if (cfg) {
461                         if (unlikely(b_nonce_len != b_nonce2_len))
462                                 return 2; /* someone truncated our nonce? */
463                         if (memcmp(&b_nonce.n.md5_2[0], &b_nonce2.n.md5_2[0], 16))
464                                 return 3; /* auth_extra_checks failed */
465                 }
466 #ifdef USE_NC
467 check_stale:
468 #endif /* USE_NC */
469                 if (unlikely(is_bin_nonce_stale(&b_nonce, t)))
470                         return 4;
471                 return 0;
472         }
473         
474         return 2;
475 }
476