Coverage Report

Created: 2025-07-11 06:42

/src/libhtp/htp/htp_parsers.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 * Copyright (c) 2009-2010 Open Information Security Foundation
3
 * Copyright (c) 2010-2013 Qualys, Inc.
4
 * All rights reserved.
5
 * 
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are
8
 * met:
9
 * 
10
 * - Redistributions of source code must retain the above copyright
11
 *   notice, this list of conditions and the following disclaimer.
12
13
 * - Redistributions in binary form must reproduce the above copyright
14
 *   notice, this list of conditions and the following disclaimer in the
15
 *   documentation and/or other materials provided with the distribution.
16
17
 * - Neither the name of the Qualys, Inc. nor the names of its
18
 *   contributors may be used to endorse or promote products derived from
19
 *   this software without specific prior written permission.
20
 * 
21
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
 ***************************************************************************/
33
34
/**
35
 * @file
36
 * @author Ivan Ristic <ivanr@webkreator.com>
37
 */
38
39
#include "htp_config_auto.h"
40
41
#include "htp_private.h"
42
43
/**
44
 * Determines protocol number from a textual representation (i.e., "HTTP/1.1"). This
45
 * function will only understand a properly formatted protocol information. It does
46
 * not try to be flexible.
47
 * 
48
 * @param[in] protocol
49
 * @return Protocol version or PROTOCOL_UNKNOWN.
50
 */
51
56.1k
int htp_parse_protocol(bstr *protocol) {
52
56.1k
    if (protocol == NULL) return HTP_PROTOCOL_INVALID;
53
    
54
    // TODO This function uses a very strict approach to parsing, whereas
55
    //      browsers will typically be more flexible, allowing whitespace
56
    //      before and after the forward slash, as well as allowing leading
57
    //      zeroes in the numbers. We should be able to parse such malformed
58
    //      content correctly (but emit a warning).
59
56.1k
    if (bstr_len(protocol) == 8) {
60
10.1k
        unsigned char *ptr = bstr_ptr(protocol);
61
10.1k
        if ((ptr[0] == 'H') && (ptr[1] == 'T') && (ptr[2] == 'T') && (ptr[3] == 'P')
62
10.1k
            && (ptr[4] == '/') && (ptr[6] == '.')) {
63
            // Check the version numbers
64
2.94k
            if (ptr[5] == '0') {
65
575
                if (ptr[7] == '9') {
66
201
                    return HTP_PROTOCOL_0_9;
67
201
                }
68
2.36k
            } else if (ptr[5] == '1') {
69
1.90k
                if (ptr[7] == '0') {
70
323
                    return HTP_PROTOCOL_1_0;
71
1.58k
                } else if (ptr[7] == '1') {
72
1.30k
                    return HTP_PROTOCOL_1_1;
73
1.30k
                }
74
1.90k
            }
75
2.94k
        }
76
10.1k
    }
77
78
54.3k
    return HTP_PROTOCOL_INVALID;
79
56.1k
}
80
81
/**
82
 * Determines the numerical value of a response status given as a string.
83
 *
84
 * @param[in] status
85
 * @return Status code on success, or HTP_STATUS_INVALID on error.
86
 */
87
44.6k
int htp_parse_status(bstr *status) {
88
44.6k
    int64_t r = htp_parse_positive_integer_whitespace((unsigned char *) bstr_ptr(status), bstr_len(status), 10);
89
44.6k
    if (r >= HTP_VALID_STATUS_MIN && r <= HTP_VALID_STATUS_MAX) {
90
43.5k
        return (int)r;
91
43.5k
    } else {
92
1.09k
        return HTP_STATUS_INVALID;
93
1.09k
    }
94
44.6k
}
95
96
/**
97
 * Parses Digest Authorization request header.
98
 *
99
 * @param[in] connp
100
 * @param[in] auth_header
101
 */
102
0
int htp_parse_authorization_digest(htp_connp_t *connp, htp_header_t *auth_header) {    
103
    // Extract the username
104
0
    int i = bstr_index_of_c(auth_header->value, "username=");
105
0
    if (i == -1) return HTP_DECLINED;
106
107
0
    unsigned char *data = bstr_ptr(auth_header->value);
108
0
    size_t len = bstr_len(auth_header->value);
109
0
    size_t pos = i + 9;
110
111
    // Ignore whitespace
112
0
    while ((pos < len) && (isspace((int) data[pos]))) pos++;   
113
0
    if (pos == len) return HTP_DECLINED;
114
115
0
    if (data[pos] != '"') return HTP_DECLINED;
116
117
0
    return htp_extract_quoted_string_as_bstr(data + pos, len - pos, &(connp->in_tx->request_auth_username), NULL);
118
0
}
119
120
/**
121
 * Parses Basic Authorization request header.
122
 * 
123
 * @param[in] connp
124
 * @param[in] auth_header
125
 */
126
0
int htp_parse_authorization_basic(htp_connp_t *connp, htp_header_t *auth_header) {
127
0
    unsigned char *data = bstr_ptr(auth_header->value);
128
0
    size_t len = bstr_len(auth_header->value);
129
0
    size_t pos = 5;
130
131
    // Ignore whitespace
132
0
    while ((pos < len) && (isspace((int) data[pos]))) pos++;
133
0
    if (pos == len) return HTP_DECLINED;
134
135
    // Decode base64-encoded data
136
0
    bstr *decoded = htp_base64_decode_mem(data + pos, len - pos);
137
0
    if (decoded == NULL) return HTP_ERROR;
138
139
    // Now extract the username and password
140
0
    int i = bstr_index_of_c(decoded, ":");
141
0
    if (i == -1) {
142
0
        bstr_free(decoded);    
143
0
        return HTP_DECLINED;
144
0
    }
145
146
0
    connp->in_tx->request_auth_username = bstr_dup_ex(decoded, 0, i);
147
0
    if (connp->in_tx->request_auth_username == NULL) {
148
0
        bstr_free(decoded);
149
0
        return HTP_ERROR;
150
0
    }
151
    
152
0
    connp->in_tx->request_auth_password = bstr_dup_ex(decoded, i + 1, bstr_len(decoded) - i - 1);
153
0
    if (connp->in_tx->request_auth_password == NULL) {
154
0
        bstr_free(decoded);
155
0
        bstr_free(connp->in_tx->request_auth_username);
156
0
        return HTP_ERROR;
157
0
    }
158
159
0
    bstr_free(decoded);
160
161
0
    return HTP_OK;
162
0
}
163
164
/**
165
 * Parses Bearer Authorization request header.
166
 *
167
 * @param[in] connp
168
 * @param[in] auth_header
169
 */
170
0
int htp_parse_authorization_bearer(htp_connp_t *connp, htp_header_t *auth_header) {
171
0
    unsigned char *data = bstr_ptr(auth_header->value);
172
0
    size_t len = bstr_len(auth_header->value);
173
0
    size_t pos = 6;
174
175
    // Ignore whitespace
176
0
    while ((pos < len) && (isspace((int) data[pos]))) pos++;
177
0
    if (pos == len) return HTP_DECLINED;
178
179
    // There is nothing much else to check with Bearer auth so we just return
180
0
    return HTP_OK;
181
0
}
182
/**
183
 * Parses Authorization request header.
184
 *
185
 * @param[in] connp
186
 */
187
59.8k
int htp_parse_authorization(htp_connp_t *connp) {
188
59.8k
    htp_header_t *auth_header = htp_table_get_c(connp->in_tx->request_headers, "authorization");
189
59.8k
    if (auth_header == NULL) {
190
59.8k
        connp->in_tx->request_auth_type = HTP_AUTH_NONE;
191
59.8k
        return HTP_OK;
192
59.8k
    }
193
194
    // TODO Need a flag to raise when failing to parse authentication headers.
195
196
0
    if (bstr_begins_with_c_nocase(auth_header->value, "basic")) {
197
        // Basic authentication
198
0
        connp->in_tx->request_auth_type = HTP_AUTH_BASIC;
199
0
        return htp_parse_authorization_basic(connp, auth_header);
200
0
    } else if (bstr_begins_with_c_nocase(auth_header->value, "digest")) {
201
        // Digest authentication
202
0
        connp->in_tx->request_auth_type = HTP_AUTH_DIGEST;
203
0
        return htp_parse_authorization_digest(connp, auth_header);
204
0
    } else if (bstr_begins_with_c_nocase(auth_header->value, "bearer")) {
205
        // OAuth Bearer authentication
206
0
        connp->in_tx->request_auth_type = HTP_AUTH_BEARER;
207
0
        return htp_parse_authorization_bearer(connp, auth_header);
208
0
    } else {
209
        // Unrecognized authentication method
210
0
        connp->in_tx->request_auth_type = HTP_AUTH_UNRECOGNIZED;        
211
0
    }
212
213
0
    return HTP_OK;
214
0
}