Coverage Report

Created: 2026-07-07 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/util/derdec.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "secder.h"
6
#include "secerr.h"
7
8
static PRUint32
9
der_indefinite_length(unsigned char *buf, unsigned char *end)
10
0
{
11
0
    PRUint32 len, ret, dataLen;
12
0
    unsigned char tag, lenCode;
13
0
    int dataLenLen;
14
15
0
    len = 0;
16
0
    while (1) {
17
0
        if ((buf + 2) > end) {
18
0
            return (0);
19
0
        }
20
21
0
        tag = *buf++;
22
0
        lenCode = *buf++;
23
0
        len += 2;
24
25
0
        if ((tag == 0) && (lenCode == 0)) {
26
0
            return (len);
27
0
        }
28
29
0
        if (lenCode == 0x80) {                     /* indefinite length */
30
0
            ret = der_indefinite_length(buf, end); /* recurse to find length */
31
0
            if (ret == 0)
32
0
                return 0;
33
0
            len += ret;
34
0
            buf += ret;
35
0
        } else { /* definite length */
36
0
            if (lenCode & 0x80) {
37
                /* Length of data is in multibyte format */
38
0
                dataLenLen = lenCode & 0x7f;
39
0
                if (dataLenLen < 1 || dataLenLen > 4 ||
40
0
                    buf + dataLenLen > end) {
41
0
                    PORT_SetError(SEC_ERROR_BAD_DER);
42
0
                    return SECFailure;
43
0
                }
44
0
                switch (dataLenLen) {
45
0
                    case 1:
46
0
                        dataLen = buf[0];
47
0
                        break;
48
0
                    case 2:
49
0
                        dataLen = (buf[0] << 8) | buf[1];
50
0
                        break;
51
0
                    case 3:
52
0
                        dataLen = ((unsigned long)buf[0] << 16) | (buf[1] << 8) | buf[2];
53
0
                        break;
54
0
                    case 4:
55
0
                        dataLen = ((unsigned long)buf[0] << 24) |
56
0
                                  ((unsigned long)buf[1] << 16) | (buf[2] << 8) | buf[3];
57
0
                        break;
58
0
                    default:
59
0
                        PORT_SetError(SEC_ERROR_BAD_DER);
60
0
                        return SECFailure;
61
0
                }
62
0
            } else {
63
                /* Length of data is in single byte */
64
0
                dataLen = lenCode;
65
0
                dataLenLen = 0;
66
0
            }
67
68
            /* skip this item */
69
0
            buf = buf + dataLenLen + dataLen;
70
0
            len = len + dataLenLen + dataLen;
71
0
        }
72
0
    }
73
0
}
74
75
/*
76
** Capture the next thing in the buffer.
77
** Returns the length of the header and the length of the contents.
78
*/
79
static SECStatus
80
der_capture(unsigned char *buf, unsigned char *end,
81
            int *header_len_p, PRUint32 *contents_len_p)
82
0
{
83
0
    unsigned char *bp;
84
0
    unsigned char whole_tag;
85
0
    PRUint32 contents_len;
86
0
    int tag_number;
87
88
0
    if ((buf + 2) > end) {
89
0
        *header_len_p = 0;
90
0
        *contents_len_p = 0;
91
0
        if (buf == end)
92
0
            return SECSuccess;
93
0
        return SECFailure;
94
0
    }
95
96
0
    bp = buf;
97
98
    /* Get tag and verify that it is ok. */
99
0
    whole_tag = *bp++;
100
0
    tag_number = whole_tag & DER_TAGNUM_MASK;
101
102
    /*
103
     * XXX This code does not (yet) handle the high-tag-number form!
104
     */
105
0
    if (tag_number == DER_HIGH_TAG_NUMBER) {
106
0
        PORT_SetError(SEC_ERROR_BAD_DER);
107
0
        return SECFailure;
108
0
    }
109
110
0
    if ((whole_tag & DER_CLASS_MASK) == DER_UNIVERSAL) {
111
        /* Check that the universal tag number is one we implement.  */
112
0
        switch (tag_number) {
113
0
            case DER_BOOLEAN:
114
0
            case DER_INTEGER:
115
0
            case DER_BIT_STRING:
116
0
            case DER_OCTET_STRING:
117
0
            case DER_NULL:
118
0
            case DER_OBJECT_ID:
119
0
            case DER_SEQUENCE:
120
0
            case DER_SET:
121
0
            case DER_PRINTABLE_STRING:
122
0
            case DER_T61_STRING:
123
0
            case DER_IA5_STRING:
124
0
            case DER_VISIBLE_STRING:
125
0
            case DER_UTC_TIME:
126
0
            case 0: /* end-of-contents tag */
127
0
                break;
128
0
            default:
129
0
                PORT_SetError(SEC_ERROR_BAD_DER);
130
0
                return SECFailure;
131
0
        }
132
0
    }
133
134
    /*
135
     * Get first byte of length code (might contain entire length, might not).
136
     */
137
0
    contents_len = *bp++;
138
139
    /*
140
     * If the high bit is set, then the length is in multibyte format,
141
     * or the thing has an indefinite-length.
142
     */
143
0
    if (contents_len & 0x80) {
144
0
        int bytes_of_encoded_len;
145
146
0
        bytes_of_encoded_len = contents_len & 0x7f;
147
0
        contents_len = 0;
148
149
0
        if (bytes_of_encoded_len > 4 ||
150
0
            (bytes_of_encoded_len > 0 && bp + bytes_of_encoded_len > end)) {
151
0
            PORT_SetError(SEC_ERROR_BAD_DER);
152
0
            return SECFailure;
153
0
        }
154
155
0
        switch (bytes_of_encoded_len) {
156
0
            case 4:
157
0
                contents_len |= *bp++;
158
0
                contents_len <<= 8;
159
            /* fallthru */
160
0
            case 3:
161
0
                contents_len |= *bp++;
162
0
                contents_len <<= 8;
163
            /* fallthru */
164
0
            case 2:
165
0
                contents_len |= *bp++;
166
0
                contents_len <<= 8;
167
            /* fallthru */
168
0
            case 1:
169
0
                contents_len |= *bp++;
170
0
                break;
171
172
0
            case 0:
173
0
                contents_len = der_indefinite_length(bp, end);
174
0
                if (contents_len)
175
0
                    break;
176
            /* fallthru */
177
0
            default:
178
0
                PORT_SetError(SEC_ERROR_BAD_DER);
179
0
                return SECFailure;
180
0
        }
181
0
    }
182
183
0
    if ((bp + contents_len) > end) {
184
        /* Ran past end of buffer */
185
0
        PORT_SetError(SEC_ERROR_BAD_DER);
186
0
        return SECFailure;
187
0
    }
188
189
0
    *header_len_p = (int)(bp - buf);
190
0
    *contents_len_p = contents_len;
191
192
0
    return SECSuccess;
193
0
}
194
195
SECStatus
196
DER_Lengths(SECItem *item, int *header_len_p, PRUint32 *contents_len_p)
197
0
{
198
0
    return (der_capture(item->data, &item->data[item->len], header_len_p,
199
0
                        contents_len_p));
200
0
}