Coverage Report

Created: 2026-09-14 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pjsip/tests/fuzz/fuzz-auth.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2026 Teluu Inc. (http://www.teluu.com)
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 2 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 */
18
#include <stdio.h>
19
#include <stdint.h>
20
#include <stdlib.h>
21
#include <string.h>
22
23
#include <pjlib.h>
24
#include <pjlib-util.h>
25
#include <pjsip.h>
26
#include <pjsip/sip_auth.h>
27
28
16.9k
#define POOL_SIZE 4000
29
8.49k
#define MAX_FUZZ_MSG_SIZE (POOL_SIZE - 1)
30
31
/* Global resources (one-time initialization) */
32
static pj_caching_pool caching_pool;
33
static pjsip_endpoint *endpt;
34
static pjsip_auth_srv auth_srv;
35
36
/* Credential lookup for server authentication */
37
static pj_status_t lookup_cred(pj_pool_t *pool, const pj_str_t *realm,
38
                                const pj_str_t *acc_name, pjsip_cred_info *cred)
39
0
{
40
0
    PJ_UNUSED_ARG(pool);
41
0
    pj_bzero(cred, sizeof(*cred));
42
0
    cred->realm = *realm;
43
0
    cred->username = *acc_name;
44
0
    cred->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
45
0
    cred->data = pj_str("secret");
46
0
    return PJ_SUCCESS;
47
0
}
48
49
/* Helper: Parse SIP message from fuzzer input */
50
static pjsip_msg* parse_sip_message(pj_pool_t *pool, const uint8_t *data, 
51
                                     size_t size, int require_full_headers)
52
8.49k
{
53
8.49k
    char *msg_buf;
54
8.49k
    pjsip_parser_err_report err_list;
55
8.49k
    pjsip_msg *msg;
56
57
8.49k
    if (size < 10)
58
14
        return NULL;
59
60
8.48k
    if (size > MAX_FUZZ_MSG_SIZE)
61
12
        size = MAX_FUZZ_MSG_SIZE;
62
63
    /* Copy to null-terminated buffer */
64
8.48k
    msg_buf = (char*)pj_pool_alloc(pool, size + 1);
65
8.48k
    pj_memcpy(msg_buf, data, size);
66
8.48k
    msg_buf[size] = '\0';
67
68
    /* Parse SIP message */
69
8.48k
    pj_list_init(&err_list);
70
8.48k
    msg = pjsip_parse_msg(pool, msg_buf, (pj_size_t)size, &err_list);
71
72
8.48k
    if (!msg || msg->type != PJSIP_REQUEST_MSG || !msg->line.req.uri)
73
8.23k
        return NULL;
74
75
    /* Check required headers for response creation */
76
248
    if (require_full_headers) {
77
124
        if (!pjsip_msg_find_hdr(msg, PJSIP_H_VIA, NULL) ||
78
99
            !pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL) ||
79
96
            !pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL) ||
80
94
            !pjsip_msg_find_hdr(msg, PJSIP_H_CALL_ID, NULL) ||
81
93
            !pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL))
82
32
            return NULL;
83
124
    }
84
85
216
    return msg;
86
248
}
87
88
/* Server authentication verification */
89
static void test_auth_server_verify(pj_pool_t *pool, pjsip_msg *msg)
90
124
{
91
124
    pjsip_rx_data rdata;
92
124
    pjsip_authorization_hdr *auth_hdr;
93
94
    /* Look for Authorization or Proxy-Authorization header */
95
124
    auth_hdr = (pjsip_authorization_hdr*)
96
124
               pjsip_msg_find_hdr(msg, PJSIP_H_AUTHORIZATION, NULL);
97
124
    if (!auth_hdr) {
98
124
        auth_hdr = (pjsip_authorization_hdr*)
99
124
                   pjsip_msg_find_hdr(msg, PJSIP_H_PROXY_AUTHORIZATION, NULL);
100
124
    }
101
124
    if (!auth_hdr)
102
124
        return;
103
104
    /* Setup minimal rdata */
105
0
    pj_bzero(&rdata, sizeof(rdata));
106
0
    rdata.msg_info.msg = msg;
107
0
    rdata.tp_info.pool = pool;
108
109
    /* Test verification */
110
0
    int status_code;
111
0
    pjsip_auth_srv_verify(&auth_srv, &rdata, &status_code);
112
0
}
113
114
/* Server challenge generation */
115
static void test_auth_server_challenge(pj_pool_t *pool, pjsip_msg *msg)
116
92
{
117
92
    pjsip_rx_data rdata;
118
92
    pjsip_tx_data *tdata;
119
92
    pj_status_t status;
120
121
    /* Setup minimal rdata */
122
92
    pj_bzero(&rdata, sizeof(rdata));
123
92
    rdata.msg_info.msg = msg;
124
92
    rdata.tp_info.pool = pool;
125
126
    /* Populate required msg_info shortcuts; bail if any are missing */
127
92
    rdata.msg_info.via = (pjsip_via_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_VIA, NULL);
128
92
    rdata.msg_info.from = (pjsip_fromto_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL);
129
92
    rdata.msg_info.to = (pjsip_fromto_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL);
130
92
    rdata.msg_info.cseq = (pjsip_cseq_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL);
131
92
    rdata.msg_info.cid = (pjsip_cid_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CALL_ID, NULL);
132
92
    if (!rdata.msg_info.via || !rdata.msg_info.from || !rdata.msg_info.to ||
133
92
        !rdata.msg_info.cseq || !rdata.msg_info.cid || !rdata.msg_info.cid->id.slen)
134
0
        return;
135
136
92
    if (msg->line.req.method.id == PJSIP_ACK_METHOD)
137
1
        return;
138
139
    /* Create 401 response */
140
91
    status = pjsip_endpt_create_response(endpt, &rdata, 401, NULL, &tdata);
141
91
    if (status != PJ_SUCCESS || !tdata)
142
0
        return;
143
144
    /* Add authentication challenge */
145
91
    pjsip_auth_srv_challenge(&auth_srv, NULL, NULL, NULL, PJ_FALSE, tdata);
146
91
    pjsip_tx_data_dec_ref(tdata);
147
91
}
148
149
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
150
4.24k
{
151
4.24k
    static int initialized = 0;
152
4.24k
    pj_pool_t *pool;
153
4.24k
    pjsip_msg *msg;
154
4.24k
    pj_time_val timeout = {0, 0};
155
156
    /* === One-time initialization === */
157
4.24k
    if (!initialized) {
158
1
        pj_status_t status;
159
1
        pj_pool_t *init_pool;
160
1
        pj_str_t realm;
161
162
1
        pj_init();
163
1
        pj_caching_pool_init(&caching_pool, &pj_pool_factory_default_policy, 0);
164
1
        pj_log_set_level(0);
165
166
        /* Create SIP endpoint */
167
1
        status = pjsip_endpt_create(&caching_pool.factory, "fuzz", &endpt);
168
1
        if (status != PJ_SUCCESS)
169
0
            return 0;
170
171
        /* Initialize auth server */
172
1
        init_pool = pj_pool_create(&caching_pool.factory, "init", 1000, 1000, NULL);
173
1
        realm = pj_str("example.com");
174
1
        pjsip_auth_srv_init(init_pool, &auth_srv, &realm, &lookup_cred, 0);
175
176
1
        initialized = 1;
177
1
    }
178
179
4.24k
    pool = pjsip_endpt_create_pool(endpt, "fuzz", POOL_SIZE, POOL_SIZE);
180
4.24k
    if (!pool)
181
0
        return 0;
182
183
    /* Parse message and test auth server functions */
184
4.24k
    msg = parse_sip_message(pool, Data, Size, 0);
185
4.24k
    if (msg) {
186
124
        test_auth_server_verify(pool, msg);
187
124
    }
188
189
4.24k
    msg = parse_sip_message(pool, Data, Size, 1);
190
4.24k
    if (msg) {
191
92
        test_auth_server_challenge(pool, msg);
192
92
    }
193
194
    /* Cleanup */
195
4.24k
    pjsip_endpt_release_pool(endpt, pool);
196
4.24k
    pjsip_endpt_handle_events(endpt, &timeout);
197
198
4.24k
    return 0;
199
4.24k
}