Coverage Report

Created: 2025-07-11 06:28

/src/opensips/parser/digest/digest.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Digest credentials parser interface
3
 *
4
 * Copyright (C) 2001-2003 FhG Fokus
5
 *
6
 * This file is part of opensips, a free SIP server.
7
 *
8
 * opensips is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version
12
 *
13
 * opensips is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
21
 */
22
23
24
#include "digest.h"
25
#include "../../mem/mem.h"  /* pkg_malloc */
26
#include "../../dprint.h"   /* Guess what */
27
#include <stdio.h>          /* printf */
28
#include <string.h>         /* strncasecmp */
29
30
31
/*
32
 * Create and initialize a new credentials structure
33
 */
34
static inline int new_credentials(struct hdr_field* _h)
35
0
{
36
0
  auth_body_t* b;
37
38
0
  b = (auth_body_t*)pkg_malloc(sizeof(auth_body_t));
39
0
  if (b == 0) {
40
0
    LM_ERR("no pkg memory left\n");
41
0
    return -1;
42
0
  }
43
44
0
  init_dig_cred(&(b->digest));
45
0
  b->stale = 0;
46
0
  b->authorized = 0;
47
48
0
  _h->parsed = (void*)b;
49
50
0
  return 0;
51
0
}
52
53
54
/*
55
 * Parse digest credentials
56
 * Return value -1 means that the function was unable to allocate
57
 * memory and therefore the server should return Internal Server Error,
58
 * not Bad Request in this case !
59
 * Bad Request should be send when return value != -1
60
 */
61
int parse_credentials(struct hdr_field* _h)
62
0
{
63
0
  int res;
64
65
0
  if (_h->parsed) {
66
0
    return 0;  /* Already parsed */
67
0
  }
68
69
0
  if (new_credentials(_h) < 0) {
70
0
    LM_ERR("failed to create new credentials\n");
71
0
    return -1;
72
0
  }
73
74
       /* parse_digest_cred must return < -1 on error otherwise we will be
75
        * unable to distinguish if the error was caused by the server or if the
76
        * credentials are broken
77
        */
78
0
  res = parse_digest_cred(&(_h->body), &(((auth_body_t*)(_h->parsed))->digest));
79
80
0
  if (res != 0) {
81
0
    free_credentials((auth_body_t**)(void*)&(_h->parsed));
82
0
  }
83
84
0
  return res;
85
0
}
86
87
88
/*
89
 * Free all memory
90
 */
91
void free_credentials(auth_body_t** _b)
92
0
{
93
0
  pkg_free(*_b);
94
0
  *_b = 0;
95
0
}
96
97
98
/*
99
 * Check semantics of a digest credentials structure
100
 * Make sure that all attributes needed to verify response
101
 * string are set or at least have a default value
102
 *
103
 * The returned value is logical OR of all errors encountered
104
 * during the check, see dig_err_t type for more details
105
 */
106
dig_err_t check_dig_cred(dig_cred_t* _c)
107
0
{
108
0
  dig_err_t res = E_DIG_OK;
109
110
       /* Username must be present */
111
0
  if (_c->username.user.s == 0) res |= E_DIG_USERNAME;
112
113
       /* Realm must be present */
114
0
  if (_c->realm.s == 0)  res |= E_DIG_REALM;
115
116
       /* Nonce that was used must be specified */
117
0
  if (_c->nonce.s == 0) res |= E_DIG_NONCE;
118
119
       /* URI must be specified */
120
0
  if (_c->uri.s == 0) res |= E_DIG_URI;
121
122
       /* We cannot check credentials without response */
123
0
  if (_c->response.s == 0) res |= E_DIG_RESPONSE;
124
125
       /* If QOP parameter is present, some additional
126
        * requirements must be met
127
        */
128
0
  if (_c->qop.qop_parsed != QOP_UNSPEC_D) {
129
         /* CNONCE must be specified */
130
0
    if (_c->cnonce.s == 0) res |= E_DIG_CNONCE;
131
         /* and also nonce count must be specified */
132
0
    if (_c->nc.s == 0) res |= E_DIG_NC;
133
0
  }
134
135
0
  return res;
136
0
}
137
138
139
/*
140
 * Print credential structure content to stdout
141
 * Just for debugging
142
 */
143
void print_cred(dig_cred_t* _c)
144
0
{
145
0
  printf("===Digest credentials===\n");
146
0
  if (_c) {
147
0
    printf("Username\n");
148
0
    printf("+--whole  = \'%.*s\'\n", _c->username.whole.len, _c->username.whole.s);
149
0
    printf("+--user   = \'%.*s\'\n", _c->username.user.len, _c->username.user.s);
150
0
    printf("\\--domain = \'%.*s\'\n", _c->username.domain.len, _c->username.domain.s);
151
0
    printf("Realm     = \'%.*s\'\n", _c->realm.len, _c->realm.s);
152
0
    printf("Nonce     = \'%.*s\'\n", _c->nonce.len, _c->nonce.s);
153
0
    printf("URI       = \'%.*s\'\n", _c->uri.len, _c->uri.s);
154
0
    printf("Response  = \'%.*s\'\n", _c->response.len, _c->response.s);
155
0
    printf("Algorithm = \'%.*s\'\n", _c->alg.alg_str.len, _c->alg.alg_str.s);
156
0
    printf("\\--parsed = ");
157
158
0
    switch(_c->alg.alg_parsed) {
159
0
    CASE_PRINTENUM(ALG_UNSPEC);
160
0
    CASE_PRINTENUM(ALG_MD5);
161
0
    CASE_PRINTENUM(ALG_MD5SESS);
162
0
    CASE_PRINTENUM(ALG_SHA256);
163
0
    CASE_PRINTENUM(ALG_SHA256SESS);
164
0
    CASE_PRINTENUM(ALG_SHA512_256);
165
0
    CASE_PRINTENUM(ALG_SHA512_256SESS);
166
0
    CASE_PRINTENUM(ALG_AKAv1_MD5);
167
0
    CASE_PRINTENUM(ALG_AKAv1_MD5SESS);
168
0
    CASE_PRINTENUM(ALG_AKAv1_SHA256);
169
0
    CASE_PRINTENUM(ALG_AKAv1_SHA256SESS);
170
0
    CASE_PRINTENUM(ALG_AKAv1_SHA512_256);
171
0
    CASE_PRINTENUM(ALG_AKAv1_SHA512_256SESS);
172
0
    CASE_PRINTENUM(ALG_AKAv2_MD5);
173
0
    CASE_PRINTENUM(ALG_AKAv2_MD5SESS);
174
0
    CASE_PRINTENUM(ALG_AKAv2_SHA256);
175
0
    CASE_PRINTENUM(ALG_AKAv2_SHA256SESS);
176
0
    CASE_PRINTENUM(ALG_AKAv2_SHA512_256);
177
0
    CASE_PRINTENUM(ALG_AKAv2_SHA512_256SESS);
178
0
    CASE_PRINTENUM(ALG_OTHER);
179
0
    }
180
181
0
    printf("Cnonce    = \'%.*s\'\n", _c->cnonce.len, _c->cnonce.s);
182
0
    printf("Opaque    = \'%.*s\'\n", _c->opaque.len, _c->opaque.s);
183
0
    printf("QOP       = \'%.*s\'\n", _c->qop.qop_str.len, _c->qop.qop_str.s);
184
0
    printf("\\--parsed = ");
185
186
0
    switch(_c->qop.qop_parsed) {
187
0
    CASE_PRINTENUM(QOP_UNSPEC_D);
188
0
    CASE_PRINTENUM(QOP_AUTH_D);
189
0
    CASE_PRINTENUM(QOP_AUTHINT_D);
190
0
    CASE_PRINTENUM(QOP_AUTHINT_AUTH_D);
191
0
    CASE_PRINTENUM(QOP_AUTH_AUTHINT_D);
192
0
    CASE_PRINTENUM(QOP_OTHER_D);
193
0
    }
194
0
    printf("NC        = \'%.*s\'\n", _c->nc.len, _c->nc.s);
195
0
  }
196
0
  printf("===/Digest credentials===\n");
197
0
}
198
199
200
/*
201
 * Mark credentials as selected so functions
202
 * following authorize know which credentials
203
 * to use if the message contained more than
204
 * one
205
 */
206
int mark_authorized_cred(struct sip_msg* _m, struct hdr_field* _h)
207
0
{
208
0
  struct hdr_field* f;
209
210
0
  switch(_h->type) {
211
0
  case HDR_AUTHORIZATION_T: f = _m->authorization; break;
212
0
  case HDR_PROXYAUTH_T:     f = _m->proxy_auth;    break;
213
0
  default:
214
0
    LM_ERR("invalid header field type\n");
215
0
    return -1;
216
0
  }
217
218
0
  if (!(f->parsed)) {
219
0
    if (new_credentials(f) < 0) {
220
0
      LM_ERR("new_credentials failed\n");
221
0
      return -1;
222
0
    }
223
0
  }
224
225
0
  ((auth_body_t*)(f->parsed))->authorized = _h;
226
227
0
  return 0;
228
0
}
229
230
231
/*
232
 * Get pointer to authorized credentials, if there are no
233
 * authorized credentials, 0 is returned
234
 */
235
int get_authorized_cred(struct hdr_field* _f, struct hdr_field** _h)
236
0
{
237
0
  if (_f && _f->parsed) {
238
0
    *_h = ((auth_body_t*)(_f->parsed))->authorized;
239
0
  } else {
240
0
    *_h = 0;
241
0
  }
242
243
0
  return 0;
244
0
}