Coverage Report

Created: 2025-07-12 06:16

/src/krb5/src/include/k5-der.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* include/k5-der.h - Distinguished Encoding Rules (DER) declarations */
3
/*
4
 * Copyright (C) 2023 by the Massachusetts Institute of Technology.
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 *
11
 * * Redistributions of source code must retain the above copyright
12
 *   notice, this list of conditions and the following disclaimer.
13
 *
14
 * * Redistributions in binary form must reproduce the above copyright
15
 *   notice, this list of conditions and the following disclaimer in
16
 *   the documentation and/or other materials provided with the
17
 *   distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30
 * OF THE POSSIBILITY OF SUCH DAMAGE.
31
 */
32
33
/*
34
 * Most ASN.1 encoding and decoding is done using the table-driven framework in
35
 * libkrb5.  When that is not an option, these helpers can be used to encode
36
 * and decode simple types.
37
 */
38
39
#ifndef K5_DER_H
40
#define K5_DER_H
41
42
#include <stdint.h>
43
#include <stdbool.h>
44
#include "k5-buf.h"
45
#include "k5-input.h"
46
47
/* Return the number of bytes needed to encode len as a DER encoding length. */
48
static inline size_t
49
k5_der_len_len(size_t len)
50
12.5k
{
51
12.5k
    size_t llen;
52
53
12.5k
    if (len < 128)
54
12.5k
        return 1;
55
0
    llen = 1;
56
0
    while (len > 0) {
57
0
        len >>= 8;
58
0
        llen++;
59
0
    }
60
0
    return llen;
61
12.5k
}
Unexecuted instantiation: g_glue.c:k5_der_len_len
Unexecuted instantiation: iakerb.c:k5_der_len_len
Unexecuted instantiation: k5unsealiov.c:k5_der_len_len
spnego_mech.c:k5_der_len_len
Line
Count
Source
50
12.5k
{
51
12.5k
    size_t llen;
52
53
12.5k
    if (len < 128)
54
12.5k
        return 1;
55
0
    llen = 1;
56
0
    while (len > 0) {
57
0
        len >>= 8;
58
0
        llen++;
59
0
    }
60
0
    return llen;
61
12.5k
}
Unexecuted instantiation: util_token.c:k5_der_len_len
Unexecuted instantiation: g_imp_name.c:k5_der_len_len
62
63
/* Return the number of bytes needed to encode a DER value (with identifier
64
 * byte and length) for a given contents length. */
65
static inline size_t
66
k5_der_value_len(size_t contents_len)
67
6.25k
{
68
6.25k
    return 1 + k5_der_len_len(contents_len) + contents_len;
69
6.25k
}
Unexecuted instantiation: g_glue.c:k5_der_value_len
Unexecuted instantiation: iakerb.c:k5_der_value_len
Unexecuted instantiation: k5unsealiov.c:k5_der_value_len
spnego_mech.c:k5_der_value_len
Line
Count
Source
67
6.25k
{
68
6.25k
    return 1 + k5_der_len_len(contents_len) + contents_len;
69
6.25k
}
Unexecuted instantiation: util_token.c:k5_der_value_len
Unexecuted instantiation: g_imp_name.c:k5_der_value_len
70
71
/* Add a DER identifier byte (composed by the caller, including the ASN.1
72
 * class, tag, and constructed bit) and length. */
73
static inline void
74
k5_der_add_taglen(struct k5buf *buf, uint8_t idbyte, size_t len)
75
6.25k
{
76
6.25k
    uint8_t *p;
77
6.25k
    size_t llen = k5_der_len_len(len);
78
79
6.25k
    p = k5_buf_get_space(buf, 1 + llen);
80
6.25k
    if (p == NULL)
81
0
        return;
82
6.25k
    *p++ = idbyte;
83
6.25k
    if (len < 128) {
84
6.25k
        *p = len;
85
6.25k
    } else {
86
0
        *p = 0x80 | (llen - 1);
87
        /* Encode the length bytes backwards so the most significant byte is
88
         * first. */
89
0
        p += llen;
90
0
        while (len > 0) {
91
0
            *--p = len & 0xFF;
92
0
            len >>= 8;
93
0
        }
94
0
    }
95
6.25k
}
Unexecuted instantiation: g_glue.c:k5_der_add_taglen
Unexecuted instantiation: iakerb.c:k5_der_add_taglen
Unexecuted instantiation: k5unsealiov.c:k5_der_add_taglen
spnego_mech.c:k5_der_add_taglen
Line
Count
Source
75
6.25k
{
76
6.25k
    uint8_t *p;
77
6.25k
    size_t llen = k5_der_len_len(len);
78
79
6.25k
    p = k5_buf_get_space(buf, 1 + llen);
80
6.25k
    if (p == NULL)
81
0
        return;
82
6.25k
    *p++ = idbyte;
83
6.25k
    if (len < 128) {
84
6.25k
        *p = len;
85
6.25k
    } else {
86
0
        *p = 0x80 | (llen - 1);
87
        /* Encode the length bytes backwards so the most significant byte is
88
         * first. */
89
0
        p += llen;
90
0
        while (len > 0) {
91
0
            *--p = len & 0xFF;
92
0
            len >>= 8;
93
0
        }
94
0
    }
95
6.25k
}
Unexecuted instantiation: util_token.c:k5_der_add_taglen
Unexecuted instantiation: g_imp_name.c:k5_der_add_taglen
96
97
/* Add a DER value (identifier byte, length, and contents). */
98
static inline void
99
k5_der_add_value(struct k5buf *buf, uint8_t idbyte, const void *contents,
100
                 size_t len)
101
1.56k
{
102
1.56k
    k5_der_add_taglen(buf, idbyte, len);
103
1.56k
    k5_buf_add_len(buf, contents, len);
104
1.56k
}
Unexecuted instantiation: g_glue.c:k5_der_add_value
Unexecuted instantiation: iakerb.c:k5_der_add_value
Unexecuted instantiation: k5unsealiov.c:k5_der_add_value
spnego_mech.c:k5_der_add_value
Line
Count
Source
101
1.56k
{
102
1.56k
    k5_der_add_taglen(buf, idbyte, len);
103
1.56k
    k5_buf_add_len(buf, contents, len);
104
1.56k
}
Unexecuted instantiation: util_token.c:k5_der_add_value
Unexecuted instantiation: g_imp_name.c:k5_der_add_value
105
106
/*
107
 * If the next byte in in matches idbyte and the subsequent DER length is
108
 * valid, advance in past the tag and length, set *len_out to the decoded
109
 * length, and return true.  Otherwise return false.  Only set an error on in
110
 * if the next byte matches idbyte but the ensuing length is invalid.
111
 */
112
static inline bool
113
k5_der_get_taglen(struct k5input *in, uint8_t idbyte, size_t *len_out)
114
13.3k
{
115
13.3k
    uint8_t lenbyte, i;
116
13.3k
    size_t len;
117
118
    /* Do nothing if in is empty or the next byte doesn't match idbyte. */
119
13.3k
    if (in->status || in->len == 0 || *in->ptr != idbyte)
120
713
        return false;
121
122
    /* Advance past the identifier byte and decode the length. */
123
12.5k
    (void)k5_input_get_byte(in);
124
12.5k
    lenbyte = k5_input_get_byte(in);
125
12.5k
    if (lenbyte < 128) {
126
9.93k
        len = lenbyte;
127
9.93k
    } else {
128
2.65k
        len = 0;
129
27.2k
        for (i = 0; i < (lenbyte & 0x7F); i++) {
130
25.1k
            if (len > (SIZE_MAX >> 8)) {
131
578
                k5_input_set_status(in, EOVERFLOW);
132
578
                return false;
133
578
            }
134
24.6k
            len = (len << 8) | k5_input_get_byte(in);
135
24.6k
        }
136
2.65k
    }
137
138
12.0k
    if (in->status)
139
223
        return false;
140
141
11.7k
    *len_out = len;
142
11.7k
    return true;
143
12.0k
}
Unexecuted instantiation: g_glue.c:k5_der_get_taglen
Unexecuted instantiation: iakerb.c:k5_der_get_taglen
Unexecuted instantiation: k5unsealiov.c:k5_der_get_taglen
spnego_mech.c:k5_der_get_taglen
Line
Count
Source
114
9.43k
{
115
9.43k
    uint8_t lenbyte, i;
116
9.43k
    size_t len;
117
118
    /* Do nothing if in is empty or the next byte doesn't match idbyte. */
119
9.43k
    if (in->status || in->len == 0 || *in->ptr != idbyte)
120
635
        return false;
121
122
    /* Advance past the identifier byte and decode the length. */
123
8.80k
    (void)k5_input_get_byte(in);
124
8.80k
    lenbyte = k5_input_get_byte(in);
125
8.80k
    if (lenbyte < 128) {
126
6.70k
        len = lenbyte;
127
6.70k
    } else {
128
2.09k
        len = 0;
129
19.9k
        for (i = 0; i < (lenbyte & 0x7F); i++) {
130
18.3k
            if (len > (SIZE_MAX >> 8)) {
131
446
                k5_input_set_status(in, EOVERFLOW);
132
446
                return false;
133
446
            }
134
17.8k
            len = (len << 8) | k5_input_get_byte(in);
135
17.8k
        }
136
2.09k
    }
137
138
8.35k
    if (in->status)
139
164
        return false;
140
141
8.19k
    *len_out = len;
142
8.19k
    return true;
143
8.35k
}
util_token.c:k5_der_get_taglen
Line
Count
Source
114
3.86k
{
115
3.86k
    uint8_t lenbyte, i;
116
3.86k
    size_t len;
117
118
    /* Do nothing if in is empty or the next byte doesn't match idbyte. */
119
3.86k
    if (in->status || in->len == 0 || *in->ptr != idbyte)
120
78
        return false;
121
122
    /* Advance past the identifier byte and decode the length. */
123
3.78k
    (void)k5_input_get_byte(in);
124
3.78k
    lenbyte = k5_input_get_byte(in);
125
3.78k
    if (lenbyte < 128) {
126
3.22k
        len = lenbyte;
127
3.22k
    } else {
128
560
        len = 0;
129
7.30k
        for (i = 0; i < (lenbyte & 0x7F); i++) {
130
6.87k
            if (len > (SIZE_MAX >> 8)) {
131
132
                k5_input_set_status(in, EOVERFLOW);
132
132
                return false;
133
132
            }
134
6.74k
            len = (len << 8) | k5_input_get_byte(in);
135
6.74k
        }
136
560
    }
137
138
3.65k
    if (in->status)
139
59
        return false;
140
141
3.59k
    *len_out = len;
142
3.59k
    return true;
143
3.65k
}
Unexecuted instantiation: g_imp_name.c:k5_der_get_taglen
144
145
/*
146
 * If the next byte in in matches idbyte and the subsequent DER length is
147
 * valid, advance in past the value, set *contents_out to the value contents,
148
 * and return true.  Otherwise return false.  Only set an error on in if the
149
 * next byte matches idbyte but the ensuing length is invalid.  contents_out
150
 * may be aliased to in; it will only be written to on successful decoding of a
151
 * value.
152
 */
153
static inline bool
154
k5_der_get_value(struct k5input *in, uint8_t idbyte,
155
                 struct k5input *contents_out)
156
11.2k
{
157
11.2k
    size_t len;
158
11.2k
    const void *bytes;
159
160
11.2k
    if (!k5_der_get_taglen(in, idbyte, &len))
161
1.34k
        return false;
162
9.94k
    bytes = k5_input_get_bytes(in, len);
163
9.94k
    if (bytes == NULL)
164
914
        return false;
165
9.02k
    k5_input_init(contents_out, bytes, len);
166
9.02k
    return true;
167
9.94k
}
Unexecuted instantiation: g_glue.c:k5_der_get_value
Unexecuted instantiation: iakerb.c:k5_der_get_value
Unexecuted instantiation: k5unsealiov.c:k5_der_get_value
spnego_mech.c:k5_der_get_value
Line
Count
Source
156
9.43k
{
157
9.43k
    size_t len;
158
9.43k
    const void *bytes;
159
160
9.43k
    if (!k5_der_get_taglen(in, idbyte, &len))
161
1.24k
        return false;
162
8.19k
    bytes = k5_input_get_bytes(in, len);
163
8.19k
    if (bytes == NULL)
164
802
        return false;
165
7.39k
    k5_input_init(contents_out, bytes, len);
166
7.39k
    return true;
167
8.19k
}
util_token.c:k5_der_get_value
Line
Count
Source
156
1.84k
{
157
1.84k
    size_t len;
158
1.84k
    const void *bytes;
159
160
1.84k
    if (!k5_der_get_taglen(in, idbyte, &len))
161
99
        return false;
162
1.74k
    bytes = k5_input_get_bytes(in, len);
163
1.74k
    if (bytes == NULL)
164
112
        return false;
165
1.63k
    k5_input_init(contents_out, bytes, len);
166
1.63k
    return true;
167
1.74k
}
Unexecuted instantiation: g_imp_name.c:k5_der_get_value
168
169
#endif /* K5_DER_H */